#!/bin/bash #set -x # (c) 2012 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 . source libremessages source $(librelib conf.sh) load_files libretools check_vars libretools HOOKPREBUILD FULLBUILDCMD HOOKLOCALRELEASE load_files makepkg term_title "$(basename $0)" # End inmediately but print an useful message trap_exit() { term_title "error!" error "($(basename $0)) $@ (leftovers on ${BUILDDIR})" exit 1 } # Trap signals from makepkg set -E 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 # Add line to build order cache in CSV format # *must* be run from the PKGBUILD path # status;depth;pkgbase;[epoch:]pkgver-pkgrel;path;repo # $1 status # $2 pkgname add_order() { echo "${1};${DEPTH};${2:-${pkgbase}};$(get_full_version ${2});${PWD};$(guess_repo "$PWD")" >> "${BUILDORDER}" ${VERBOSE} && msg2 "%${DEPTH}s${2:-${pkgbase}} [${1}]" || true } # Bury a package deeper in the tree # $1 pkgbase # $2 nextdepth bury() { # Bury only if we are going to build the dep # Get it's current depth and dir name local current_depth=$(grep "build;[0-9]\+;${1};" "${BUILDORDER}" | cut -d ';' -f 2) local current_name="$(printf "%03d" ${current_depth})_${1}" # If there's a depth or the package is not the root of the build tree (which # can lead to funny chicken-and-egg problems), update the depth to the current # package next-depth and rename the dir too if [ -z "${current_depth}" ]; then return; fi if [ -z "${current_name}" ]; then return; fi if [ ${current_depth} -eq 0 ]; then return; fi if [ ${current_depth} -ge $2 ]; then return; fi ${VERBOSE} && msg "Burying ${1} from ${current_depth} to ${2}" { sed -i "s|^\(build;\)\([0-9]\+\)\(;${1};.*\)$|\1${2}\3|" "${BUILDORDER}" && \ mv "${BUILDDIR}/${current_name}" "${BUILDDIR}/$(printf "%03d" ${2})_${1}" } || return 1 } # Guess the repo from the pkgbase path # $1 path, pwd or toru-where guess_repo() { basename "$(dirname "${1}")" } if [ ! -f PKGBUILD ]; then error "Missing PKGBUILD ($PWD)" exit 1 fi if ! load_PKGBUILD ; then error "Can't source PKGBUILD" exit 1 fi # Save resources unset pkgdesc arch license groups backup install md5sums sha1sums \ sha256sums source options >/dev/null 2>&1 unset build package >/dev/null 2>&1 for _pkg in "${pkgname[@]}"; do unset package_${_pkg} >/dev/null 2>&1 || true done ## # Get useful values pkgbase="${pkgbase:-${pkgname[0]}}" # Get or set the work dir BUILDDIR="${1:-$(mktemp -d /tmp/${pkgbase}-treepkg-XXXx)}" BUILDORDER="${BUILDDIR}/BUILDORDER" DEPTH=${2:-0} NEXTDEPTH=$((${DEPTH} + 1)) # This can be set as env vars (ie: $ V=false B=false treepkg) # TODO Turn into flags? VERBOSE=${V:-true} BUILD=${B:-true} CLEANUP=${C:-true} # Skip BUILDORDER creation and build anything on BUILDDIR BUILDNOW=${N:-false} if [[ ! -z $1 ]] && [[ $DEPTH -eq 0 ]]; then BUILDNOW=true fi if ! ${BUILDNOW}; then # ensure it exists touch "${BUILDORDER}" # If this package is already built quit silently for _pkg in "${pkgname[@]}"; do if is_built "${_pkg}" "$(get_full_version ${_pkg})"; then add_order "ignore" exit 0 fi done # Ignore if already in build order egrep -q ";${pkgbase};" "${BUILDORDER}" && exit 0 # Add pkgbase to build order add_order "build" # Copy the directory to the build dir # TODO run makepkg --source to avoid moving garbage around? cp -r "${PWD}" "${BUILDDIR}/$(printf "%03d" ${DEPTH})_${pkgbase}" # Cleanup dep versioning deps=($(echo "${depends[@]} ${makedepends[@]}" | \ sed "s/[=<>]\+[^ ]\+//g" | \ tr ' ' "\n" | \ sort -u)) # NOTE: getting depends from package() is a PITA for _dep in "${deps[@]}"; do # Move deps deeper in the tree if # pkgbase - dep1 # \ dep2 - dep1 # dep1 should be depth + 1 egrep -q ";${_dep};" "${BUILDORDER}" && bury "${_dep}" ${NEXTDEPTH} # Ask toru where's a PKGBUILD depdir="$(toru-where ${_dep})" if [[ -z ${depdir} ]] || [[ ! -d ${depdir} ]]; then # We specify the pkgname because we can't source the dep PKGBUILD # Normally 'any' packages are missing from our work ABS add_order "missing" "${_dep}" continue fi pushd "${depdir}" >/dev/null # Run itself over dependencies $0 "${BUILDDIR}" ${NEXTDEPTH} done # End BUILD now fi # Only build at the end if [ ${DEPTH} -eq 0 ]; then ${VERBOSE} && msg "Starting build" || true if ${BUILD}; then ${VERBOSE} && msg "Build tree stored in ${BUILDORDER}" || true # Build everything sorting the build dir # The reverse order ensures we start by the deepest packages for _pkg in $(ls -r "${BUILDDIR}"); do # Ignore if there's no PKGBUILD if [ ! -f "${BUILDDIR}/${_pkg}/PKGBUILD" ]; then continue; fi # Skip if already built (faster than calling is_build again) if [ -f "${BUILDDIR}/${_pkg}/built_ok" ]; then continue; fi ${VERBOSE} && msg "Building ${_pkg/_/ }" || true # Remove leading zeros and space if any term_title "$(echo ${_pkg/_/ } | sed "s/^0\+ \?//")" # Run build command pushd "${BUILDDIR}/${_pkg}" >/dev/null sudo -E pacman -Syu --noconfirm ${HOOKPREBUILD} ${FULLBUILDCMD} # Run local release hook with $1 = $repo ${HOOKLOCALRELEASE} $(egrep ";${_pkg#*_};" "${BUILDORDER}" | cut -d';' -f6) touch built_ok popd >/dev/null done else # Just print the working dir ${VERBOSE} || echo "${BUILDORDER}" || true fi if ${CLEANUP} ; then msg2 "Removing ${BUILDDIR}" rm -rf "${BUILDDIR}" fi fi term_title "done" exit $?