#!/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-2014 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.sh)" 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 "$hook" "$@" || fails+=("$hook") done |& indent if [[ ${#fails[@]} -gt 0 ]]; then error "Failure(s) in %s: %s" "$hookname" "${fails[*]}" return 1 else return 0 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+=('cleanup') cleanup() { local copydir=$1 rm -f -- "$copydir"/chroot{prepare,build} } build() ( local copydir=$1; shift local repack=$1; shift local run_ynet=() local run_nnet=() if $INCHROOT; then run_ynet=(unshare) run_nnet=(unshare -n) else 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_ynet[@]}" /chrootprepare false "$@" |& indent run_hook pre_build "$copydir" trap "run_hook post_build '$copydir'" EXIT "${run_nnet[@]}" /chrootbuild false "$@" |& indent ) # The main program ############################################################# usage() { print "Usage: %s [options] [-- makepkg args]" "${0##*/}" print 'This program will build your package.' echo prose 'If run from outside of a chroot, command will make the following configuration changes in the chroot:' bullet 'whatever changes `librechroot` makes.' bullet 'set `{PKG,SRC,SRCPKG,LOG}DEST` in `/etc/makepkg.conf`' bullet 'set `PACKAGER` in `/etc/makepkg.conf` to reflect the value outside of the chroot.' bullet '(maybe) delete `/build/.makepkg.conf`' bullet '(maybe) delete `/build/.ssh/config`' prose 'If run from inside of a chroot, this command will:' bullet '(maybe) delete `~/.makepkg.conf`' bullet '(maybe) delete `~/.ssh/config`' prose 'The above "maybe"s happen as part of the workarounds to make distcc work in a network-less environment. They will happen if both `socat` and `distcc` are installed in the chroot.' echo prose 'The `-n` and `-l` options behave identically to librechroot, see the documentation there.' echo print 'Options:' print ' %s options:' librechroot flag "-n <$(_ CHROOT)>" 'Name of the chroot to use' flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use' flag "-w <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read/write' flag "-r <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read-only' print ' %s options:' libremakepkg flag '-N' "Don't disable networking during build() and package(). PLEASE don't use this unless you have a special reason, its use is a violation of Parabola policy." flag '-R' 'Repackage contents of the package without rebuilding' flag '-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" return 1 } main() { # Initial variable values ############################################## local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER") local makepkg_args=(-s --noconfirm -L) 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; return 0;; *) usage >&2; return 1;; esac done shift $(($OPTIND - 1)) # Pass all arguments after -- right to makepkg makepkg_args+=("$@") # Resolve the chroot path ############################################## local copydir if $INCHROOT; then copydir='/' else load_files chroot check_vars chroot CHROOTDIR CHROOT [[ -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 1 fi if [[ ! -f PKGBUILD ]]; then # This is the message used by makepkg error "PKGBUILD does not exist." exit 1 fi # Make sure that the various *DEST directories exist 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+=( -r "$PWD:/startdir_host" -r "$SRCDEST:/srcdest_host" -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 export CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)" # Pre-build msg 'Starting pre-build activities...' run_hook check_pkgbuild msg 'Downloading sources...' download_sources "$copydir" "$LIBREUSER" |& indent # Build msg 'Starting to build the package...' trap "exit_copy '$copydir' '$LIBREUSER'" EXIT build "$copydir" "$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 "$@"