#!/bin/bash # TODO # * Detect pkgnames by provides, replaces, etc. instead of dir tree eval $(egrep "PACKAGER|CARCH" /etc/makepkg.conf) eval $(egrep "ABSROOT" /etc/abs.conf) eval $(egrep "REPOS|source" /etc/libretools.conf) source /usr/bin/libremessages [[ -r $XDG_CONFIG_HOME/libretools/libretools.conf ]] && \ source $XDG_CONFIG_HOME/libretools/libretools.conf ## START FUNCTIONS ## function usage { echo "cd to a dir containing a PKGBUILD and run:" echo "$0 [options]" printf "This script will check dependencies, build them if possible " printf "and stage the packages on it's repo." echo echo "OPTIONS:" echo " -h : this message." echo " -c : check deps" # printf " -f pkgname : build even when a package has been built. " # printf " Use it as many times as needed\n" echo " -a absdir : set ABSROOT to this dir" echo } # Queue Management # * Always get the queue list from the server # * Add/Remove from queue # * Check if a package is listed # TODO # * Check for concurrence # Get the queue list from the server get_queue() { wget -N http://repo.parabolangunlinux.org/files/queue $queue_file >/dev/null 2>&1 || { error "Failed to retrieve queue list" return 1 } } # Put the queue list on the server put_queue() { rsync -e ssh -aq $queue_file $PARABOLAHOST:mips64el/queue >/dev/null 2>&1 || { error "Failed to put queue list" return 1 } } # Add packages to the queue update_queue() { get_queue || return $? basename $PWD | sed "s/$/:$PACKAGER/" >> $queue_file || return 2 put_queue || return $? } # Remove a package from the queue remove_queue() { get_queue || return $? grep -vw "^$(basename $PWD)" $queue_file > $queue_file.2 cat $queue_file.2 > $queue_file put_queue && rm $queue_file.2 && return 0 || return $? } # Checks if a package is listed check_queue() { get_queue || return $? local packager=$(grep -w "$(basename $PWD)" ${queue_file} | cut -d ':' -f2) [[ ! -z $packager ]] && [[ "$packager" != "$PACKAGER" ]] && { warning "$(basename $PWD) is being packaged by $packager. Please wait." return 1 } return 0 } # END Queue Management # guess_repo() { basename $(dirname $(pwd)) } # Usage: cleanup [ $(basename $PWD) ] from PKGBUILD dir # cleans the tempdir function cleanup { if [ ! -d $tempdir/ ]; then return 1 elif [ -d $tempdir -a ${#@} -gt 0 ]; then for _dir in $@; do rm -rf $tempdir/$_dir/ done fi } # Usage: find_deps # no parameters function find_deps { [ $level -lt 20 ] || return 20 ## Check this level. source PKGBUILD local repo=${repo:-$(guess_repo)} # TODO: If this package is in force_build: skip this step # If package is built exit if is_built "${pkgbase:-${pkgname[0]}}>=${pkgver}-${pkgrel}"; then msg2 "${pkgbase:-${pkgname[0]}}>=${pkgver}-${pkgrel} : built"; exit 0 fi msg2 "${pkgbase:-${pkgname[0]}}>=${pkgver}-${pkgrel}" # Tell which packages are deeper in deps (even if they are on tempdir) # so we can build them first. echo "${level}: $(basename $PWD)" >> "${tempdir}/.BUILDORDER" # if pkgbuild directory is on tempdir, do not copy and exit if [ -d "${tempdir}/$(basename $PWD)" ]; then exit 0 else cp -r ../$(basename $PWD) ${tempdir}/ # Info to eval later echo "repo=$repo" > "${tempdir}/$(basename $PWD)/.INFO" fi ## Check next levels # Clean version checking deps=$(echo "${depends[@]} ${makedepends[@]} ${pkgdeps[@]}" | \ sed "s/[=<>]\+[^ ]\+//g" | \ tr ' ' "\n" | \ sort -u) declare -i next_level=$level+1 for _dep in ${deps[@]}; do for _repo in ${REPOS[@]}; do # try to find $_dep on each repo from dirname [ -e "$ABSROOT/${_repo}/$_dep/PKGBUILD" ] && { pushd "$ABSROOT/${_repo}/$_dep" >/dev/null "$0 -c '${check_deps_file}' -d '${tempdir}' -l '${next_level}'" # Circular deps must fail [ $? -eq 20 ] && return 20 popd >/dev/null # found, go to next dep break 1 } # search pkgname in repo if that doesn't work # this should find pkgsplits _dir=$(find "$ABSROOT/${_repo}" -type f -name PKGBUILD -print0 | \ "xargs" -0 -e grep -H -E "pkgname|pkgbase" | grep $_dep) && { pushd $(dirname $(echo $_dir | cut -d: -f1)) >/dev/null "$0 -c '${check_deps_file}' -d '${tempdir}' -l '${next_level}'" # Circular deps must fail [ $? -eq 20 ] && return 20 popd > /dev/null # found, go to next dep break 1 } done done unset next_level dir } ## END FUNCTIONS ## force_build="" level=0 while getopts 'ha:c:d:l:' arg; do case $arg in h) usage; exit 0 ;; a) ABSROOT="$OPTARG" ;; c) check_deps_file="$OPTARG" ;; # f) force_build+="-f pkgname " ;; d) tempdir="$OPTARG" ;; # hidden function to know what to build first. # if $level > 0 it will not build l) level=$OPTARG ;; esac done mkdir -p $XDG_CONFIG_HOME/libretools queue_file=$XDG_CONFIG_HOME/libretools/queue ban_file=$XDG_CONFIG_HOME/libretools/ban touch $queue_file $ban_file # Only on level 0 [ $level -eq 0 ] && { # if tempdir exist use it, else make a tempdir tempdir="$(mktemp -d /tmp/fullpkg.XXXXXX)" check_deps_file=$tempdir/deps msg "Updating pacman db and packages" sudo pacman -Syu --noconfirm msg "Checking dependencies" } buildorder=$tempdir/.BUILDORDER touch $buildorder $tempdir/deps $tempdir/false $tempdir/install touch $check_deps_file [[ ! -r PKGBUILD ]] && { error "This isn't a build directory" usage && exit 1 } ## if $level = 20 there is highly likely there are circular deps [ $level -eq 20 ] && exit 20 find_deps || { # if find_deps finds circular deps # it should exit with status 20 [ $? -eq 20 ] && \ # only show message on level 0 [ $level -eq 0 ] && \ error "Check for circular deps on $tempdir/.BUILDORDER"; exit 20 } # levels greater than 0 must only check deps [ $level -gt 0 ] && exit 0 # check .BUILDORDER to not include banned deps and [ $level -eq 0 -a -d $tempdir ] && { # Check for banned deps if [ -w $ban_file -a -r $ban_file ]; then chmod o+rw $ban_file || error "Ban file is not readable/writable ($ban_file)" else wget -N http://repo.parabolagnulinux.org/files/ban $ban_file >/dev/null 2>&1 || \ warning "Failed to get ban list" && [ -r $ban_file ] && { # continue if download failed but local copy search=$(cat $ban_file | tr "\n" "|") echo ${@} | tr " " "\n" | egrep -w $search $buildorder | cleanup echo ${@} | tr " " "\n" | egrep -vw $search $buildorder > $buildorder.2 mv $buildorder.2 $buildorder unset search } fi } ## START Building msg "Building packages:" pushd "$tempdir" [ ! -w $queue_file ] && error "can't write queue file" trap "break" INT trap "remove_queue" EXIT INT QUIT TERM KILL build_packages=$(sort -gr $buildorder | cut -d: -f2) while [ ${#build_packages[@]} -gt 0 ]; do build_packages=$(sort -gr $buildorder | cut -d: -f2) pushd $temp_dir/${build_packages[0]} egrep -vw ${build_packages[0]} $buildorder > $buildorder.2 mv $buildorder.2 $buildorder unset build_packages eval $(egrep "pkgname|pkgbase|pkgver|pkgrel" PKGBUILD) msg2 "${pkgbase:-${pkgname[0]}} $pkgver-$pkgrel" if ! grep mips64el PKGBUILD >/dev/null; then plain "Adding mips64el arch" sed -i "s/^\(arch=([^)anym]\+\))/\1 'mips64el')/" "PKGBUILD" fi # Let everybody know we're building this. update_queue || { warning "Couldn't update the queue, let your partners know about this." } makepkg --noconfirm --nocheck -smciL; r=$? case $r in 0) plain "The build was succesful." source .INFO && [ -n $repo ] && librestage $repo || \ echo "unstaged: $(basename $PWD)" >> $tempdir/failed echo "$(basename $PWD)" >> $tempdir/install cleanup "$(basename $PWD)" msg2 "Sync db again" sudo pacman -Sy ;; 1) error "There were errors while trying to build the package." echo "failed: $(basename $PWD)" >> $tempdir/failed ;; 2) error "The build failed." && echo "failed: $(basename $PWD)" >> $tempdir/failed ;; esac popd >/dev/null done msg "Those packages were installed" plain $(cat $tempdir/install | tr "\n" " ") msg "Uploading packages to the server" librerelease pkgs=$(cat $tempdir/failed | grep "failed:") && { error "Those packages failed to build:" plain "$(echo ${pkgs[@]} | cut -d: -f2)" } pkgs=$(cat $tempdir/failed | grep "unstaged:") && { error "Those packages couldn't be staged because of missing reponame:" plain "$(cat $tempdir/failed | grep "unstaged:" | cut -d: -f2)" } exit 0