diff options
Diffstat (limited to 'src/treepkg')
-rwxr-xr-x | src/treepkg | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/src/treepkg b/src/treepkg new file mode 100755 index 0000000..8219ce6 --- /dev/null +++ b/src/treepkg @@ -0,0 +1,224 @@ +#!/usr/bin/env bash +#set -x +# (c) 2012 Nicolás Reynolds <fauno@parabola.nu> +# +# 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 <http://www.gnu.org/licenses/>. + +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 $? |