summaryrefslogtreecommitdiff
path: root/src/treepkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/treepkg')
-rwxr-xr-xsrc/treepkg237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/treepkg b/src/treepkg
new file mode 100755
index 0000000..1453f41
--- /dev/null
+++ b/src/treepkg
@@ -0,0 +1,237 @@
+#!/bin/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 /etc/libretools.conf
+source $XDG_CONFIG_HOME/libretools/libretools.conf >/dev/null 2>&1|| true
+
+term_title "$(basename $0)"
+
+# Get system variables
+source /etc/makepkg.conf
+source $HOME/makepkg.conf >/dev/null 2>&1|| true
+
+# 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
+
+# return : full version spec, including epoch (if necessary), pkgver, pkgrel
+# usage : get_fullver( ${epoch:-0}, $pkgver, $pkgrel )
+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
+
+}
+
+# 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}};${fullver};${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 ! source 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]}}"
+fullver=$(get_fullver ${epoch:-0} ${pkgver} ${pkgrel})
+
+# 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}" -a ${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}" "${fullver}"; 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}" -o ! -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 $?