#!/usr/bin/env bash set -euE # libremakepkg # Copyright (C) 2010-2012 Nicolás Reynolds # Copyright (C) 2010-2012 Joshua Ismael Haase Hernández (xihh) # Copyright (C) 2012 Michał Masłowski # Copyright (C) 2012-2015, 2017-2018 Luke Shumaker # # License: GNU GPLv2+ # # This file is part of Parabola. # # Parabola 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 2 of the License, or # (at your option) any later version. # # Parabola 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Parabola. If not, see . . "$(librelib conf)" . "$(librelib messages)" . "$(librelib chroot/makechrootpkg)" set -o pipefail shopt -s nullglob umask 0022 # Global variables: readonly _indent="$(librelib chroot/indent)" readonly INCHROOT=$([[ -f /.arch-chroot ]] && echo true || echo false) NONET=true # can be changed with the -N flag # {PKG,SRC,SRCPKG,LOG}DEST set at runtime by makepkg.conf # MAKEFLAGS, PACKAGER set at runtime by makepkg.conf # LIBREUSER, LIBREHOME are set by conf.sh librechroot_flags=() # Hooks ######################################################################## hook_pre_build=(:) hook_post_build=(:) hook_check_pkgbuild=(:) hook_check_pkg=(:) . "$(librelib chroot/hooks-chcleanup.sh)" . "$(librelib chroot/hooks-check.sh)" . "$(librelib chroot/hooks-distcc.sh)" # Boring/mundane functions ##################################################### indent() { "$_indent" ' | ' } # Usage: exit_copy $copydir $src_owner # End immediately, but copy log files out exit_copy() { local copydir=$1 local src_owner=$2 if ! $INCHROOT; then msg "Copying log and package files out of the chroot..." move_products "$copydir" "$src_owner" fi } # Usage; run_hook $hookname $args... run_hook() { local hookname=$1; shift local hookvar="hook_${hookname}[@]" local fails=() for hook in "${!hookvar}"; do # The "& wait $!" trick is to prevent "||" from # disabling "set -e" { "$hook" "$@" |& indent; } & wait $! || fails+=("$hook") done if [[ ${#fails[@]} -gt 0 ]]; then error "Failure(s) in %s: %s" "$hookname" "${fails[*]}" return $EXIT_FAILURE else return $EXIT_SUCCESS fi } # Usage: add_to_local_repo $copydir $pkgfiles... add_to_local_repo() { local copydir=$1; shift mkdir -p "$copydir/repo" local pkgfile for pkgfile in "$@"; do cp "$pkgfile" "$copydir/repo" pushd "$copydir/repo" >/dev/null repo-add repo.db.tar.gz "${pkgfile##*/}" popd >/dev/null done } hook_post_build+=('chroot_cleanup') chroot_cleanup() { local copydir=$1 rm -f -- "$copydir"/chrootbuild } build() ( local copydir=$1 local srcpkg=$2 local repack=$3 local makepkg_args=("${@:4}") local startdir startdir=$(mktemp -d) chown "$LIBREUSER:" "$startdir" trap "rm -rf -- ${startdir@Q}" EXIT sudo -u "$LIBREUSER" bsdtar -xf "$srcpkg" -C "$startdir" --strip-components 1 local run_ynet=() local run_nnet=() if $INCHROOT; then local _run=(sh -c "mount --bind -o ro -- ${startdir@Q} ${startdir@Q} && cd ${startdir@Q} && \$@" --) run_ynet=(unshare --mount -- "${_run[@]}") run_nnet=(unshare --mount --net -- "${_run[@]}") else librechroot_flags+=(-r "$startdir:/startdir") run_ynet=(librechroot "${librechroot_flags[@]}" run) run_nnet=(librechroot "${librechroot_flags[@]}" -N run) fi $NONET || run_nnet=("${run_ynet[@]}") prepare_chroot "$copydir" "$LIBREHOME" "$repack" false run_hook pre_build "$copydir" trap "run_hook post_build ${copydir@Q}; rm -rf -- ${startdir@Q}" EXIT "${run_nnet[@]}" /chrootbuild "${makepkg_args[@]}" " 'Name of the chroot to use' \ "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use' \ "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write' \ "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only' flag 'libremakepkg options:' \ '-N' "Don't disable networking during prepare(), build(), and package(). PLEASE don't use this unless you have a special reason, its use is a violation of Parabola policy." \ '-R' 'Repackage contents of the package without rebuilding' \ '-h' 'Show this message' } # Convenience method for use in option parsing err_chflag() { local flag=$1 error 'The -%s flag does not make sense inside of a chroot' "$flag" exit $EXIT_INVALIDARGUMENT } main() { # Initial variable values ############################################## local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER") local makepkg_args=(--syncdeps --noconfirm --log --holdver --skipinteg) local repack=false local chroot='' # Parse command line options ########################################### while getopts 'n:l:w:r:NRh' flag ; do case "${flag}" in n) if $INCHROOT; then err_chflag "$flag"; else chroot=$OPTARG; fi;; l) if $INCHROOT; then err_chflag "$flag"; else copy=$OPTARG; fi;; w|r) if $INCHROOT; then err_chflag "$flag"; else librechroot_flags+=(-$flag "$OPTARG"); fi;; N) NONET=false;; R) repack=true; makepkg_args+=(-R);; h) usage; exit $EXIT_SUCCESS;; *) usage >&2; exit $EXIT_INVALIDARGUMENT;; esac done shift $((OPTIND - 1)) if [[ $# != 0 ]]; then error 'Extra arguments: %s' "$*" exit $EXIT_INVALIDARGUMENT fi # Resolve the chroot path ############################################## local copydir if $INCHROOT; then copydir='/' else load_conf chroot.conf CHROOTDIR CHROOT || exit [[ -z ${chroot} ]] || CHROOT=$chroot if [[ ${copy:0:1} = / ]]; then copydir=$copy else copydir="${CHROOTDIR}/${CHROOT}/${copy}" fi unset CHROOTDIR CHROOTEXTRAPKG fi unset chroot # Load makepkg configuration ########################################### # Note that all of these are globals PKGDEST="$(get_var makepkg PKGDEST "$PWD")" SRCDEST="$(get_var makepkg SRCDEST "$PWD")" SRCPKGDEST="$(get_var makepkg SRCPKGDEST "$PWD")" LOGDEST="$(get_var makepkg LOGDEST "$PWD")" MAKEFLAGS="$(get_var makepkg MAKEFLAGS '')" PACKAGER="$(get_var makepkg PACKAGER '')" # Quick sanity check ################################################### if (( EUID )); then error "This program must be run as root" exit $EXIT_NOPERMISSION fi if [[ ! -f PKGBUILD ]]; then # This is the message used by makepkg error "PKGBUILD does not exist." exit $EXIT_FAILURE fi # Make sure that the various *DEST directories exist sudo -u "$LIBREUSER" mkdir -p -- "$PKGDEST" "$SRCDEST" "$SRCPKGDEST" "$LOGDEST" # OK, we are starting now ############################################## if $INCHROOT; then lock 9 "/build/.lock" \ "Waiting for existing lock on build directory to be released" else librechroot_flags+=( -n "$CHROOT" -l "$copy" ) # Obtain a lock on the chroot lock 9 "$copydir.lock" \ "Waiting for existing lock on chroot copy to be released: [%s]" "$copy" # Create the chroot if it does not exist msg 'Initializing the chroot...' librechroot "${librechroot_flags[@]}" make |& indent fi # Set target CARCH # note that we waited until after locking/creating the chroot to do this CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)" export CARCH # Pre-build msg 'Starting pre-build activities...' run_hook check_pkgbuild msg 'Downloading sources...' local srcpkgdest srcpkg srcpkgdest="$(mktemp -d)" chown "$LIBREUSER:" "$srcpkgdest" trap "rm -rf -- ${srcpkgdest@Q}" EXIT SRCPKGDEST="$srcpkgdest" download_sources "$copydir" "$LIBREUSER" |& indent srcpkg=("$srcpkgdest"/*) if (( ${#srcpkg[@]} != 1 )); then error 'Something went funny with makepkg --allsource' return $EXIT_FAILURE fi # We want to inject "-$pkgarch" in to srcpkg's filename, right before $SRCEXT local srcext pkgarch srcpkg_filename srcext="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg SRCEXT)" if [[ "$(bsdtar xfO "$srcpkg" --include='*/.SRCINFO' | grep $'\tarch =')" = $'\tarch = any' ]]; then pkgarch=any else pkgarch=$CARCH fi srcpkg_filename=${srcpkg##*/} srcpkg_filename=${srcpkg_filename%"${srcext}"}-${pkgarch}${srcext} mv -T -- "$srcpkg" "$SRCPKGDEST/${srcpkg_filename}" srcpkg="$SRCPKGDEST/${srcpkg_filename}" rmdir -- "${srcpkgdest}" trap EXIT # Build msg 'Starting to build the package...' trap "exit_copy '$copydir' '$LIBREUSER'" EXIT build "$copydir" "$srcpkg" "$repack" "${makepkg_args[@]}" # Post-build msg 'Starting post-build activities...' run_hook check_pkg add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* |& indent } main "$@"