#!/usr/bin/env bash # # dagpkg - create a directed graph of package dependencies and build # them in topological order # # (c) 2014 Nicolás Reynolds # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set -e # Source variables from libretools source /etc/libretools.conf source $XDG_CONFIG_HOME/libretools/libretools.conf &>/dev/null || true # Source variables from makepkg source /etc/makepkg.conf source $XDG_CONFIG_HOME/.makepkg.conf &>/dev/null || true # End inmediately but print an useful message trap_exit() { term_title "error!" test ${depth} -eq 0 && error "(%s) %s (leftovers on %s)" \ "${0##*/}" "$@" "${temp_dir}" exit 1 } # Trap signals from makepkg trap 'trap_exit "TERM signal caught. Exiting..."' TERM HUP QUIT trap 'trap_exit "Aborted by user! Exiting..."' INT trap 'trap_exit "An unknown error has occurred. Exiting..."' ERR # Source this PKGBUILD, if it doesn't exist, exit if ! source ./PKGBUILD &>/dev/null ; then error "No PKGBUILD in %s" "$PWD" exit 1 fi # Save resources unset pkgdesc arch license groups backup install md5sums sha1sums \ sha256sums source options &>/dev/null unset build package &>/dev/null for _pkg in ${pkgname[@]}; do unset package_${_pkg} &>/dev/null || true done # This is the name of the package name="${pkgbase:-${pkgname[0]}}" # The name of the previous package prev="${3}" depth="${2:-0}" let next=${depth}+1 || true # A temporary work dir and log file temp_dir="${1:-$(mktemp -dt ${name}-testpkg-XXXX)}" log="${temp_dir}/buildorder" # Generate the full version with epoch get_fullver() { if [ $1 -eq 0 ]; then # zero epoch case, don't include it in version echo $2-$3 else echo $1:$2-$3 fi } # If it's already built we don't bother is_built ${pkgname[0]} $(get_fullver ${epoch:-0} ${pkgver} ${pkgrel}) && exit echo "${arch[@]}" | grep -qw "$CARCH" || warning "%s isn't ported to %s yet" ${name} ${CARCH} # If the envvar I contains this package, ignore it and exit echo "$I" | grep -qw "$name" && msg2 "%s ignored" ${name} && exit msg "%s (%s)" ${name} ${prev} build=false if [ ! -z "${1}" -a ${depth} -eq 0 ]; then build=true fi # If we specified a work dir on the cli it means we want to skip # dependency graph creation and jump to build whatever is there if ! ${build}; then # Export a pair of current and previous package to get a list of graph # edges echo -e "${name}\t${prev:--}" >>${log} # Infinite loop detection, if the inverted pair current+prev was # already seen, skip if grep -q "${prev}[[:space:]]${name}" ${log} ; then msg2 "infinite loop %s<->%s" $name $prev exit fi # Recurse into dependencies for d in ${depends[@]} ${makedepends[@]}; do # Cleanup dependency versions d=$(echo $d | sed "s/[<>=].*//") # Where's the pkgbuild? w=$(toru-where $d) # Skip if not available test -z "$w" && continue # revisited edge detection # we use the basename of the package dir as pkgbase to avoid # recalling an edge using one of the other pkgname's if grep -q "^${w##*/}[[:space:]]" ${log} ; then msg2 "edge %s already visited" ${d} # add edge anyway but avoid reprocessing echo -e "${w##*/}\t${name}" >>${log} continue fi # Go to this dir pushd $w &>/dev/null # Run this same command giving work dir, depth and previous package $0 ${temp_dir} ${next} ${name} popd &>/dev/null done else msg "Resuming build..." fi # end here if we're not the first package test ${depth} -ne 0 && exit # enter work dir pushd "${temp_dir}" &>/dev/null # TODO do something when loops are discovered (fail? skip?) tsort ${log} | head -n-1 | tac | nl | tac | while read order pkg; do # skip if already built test -f "${pkg}/built_ok" && continue # where's this package? w="$(toru-where "$pkg")" test -z "$w" && continue # copy to work dir if not already # this means you can make modifications to the pkgbuild during the # graph build or remove the dir after a build failure and let dagpkg # copy a new version test -d "$pkg" || cp -r "$w" "$pkg" pushd "$pkg" &>/dev/null term_title "$pkg($order)" msg "Building %s" ${pkg} # upgrade the system # this would probably have to go on HOOKPREBUILD if you're working # outside chroots sudo -E pacman -Syu --noconfirm # run the pre build command from libretools.conf ${HOOKPREBUILD} # run the build command ${FULLBUILDCMD} # Run local release hook with $1 = $repo ${HOOKLOCALRELEASE} "$(basename "$(dirname "$w")")" # it's built! touch built_ok popd &>/dev/null done popd &>/dev/null # cleanup rm -rf ${log} "${temp_dir}" term_title "done"