#!/bin/bash
# aur-chroot - build packages with systemd-nspawn
[[ -v AUR_DEBUG ]] && set -o xtrace
set -o errexit
argv0=chroot
PATH=/bin:/usr/bin
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
machine=$(uname -m)
startdir=$(pwd -P)

# default arguments
directory=/var/lib/aurbuild/$machine
suffix=extra

# default options
update=0 build=0 packagelist=0 create=0

usage() {
    cat <<EOF
Usage:
  $argv0 [-BU] [-CDM path] -- <makechrootpkg args>
  $argv0 --create [-CDM path] [package...]
  $argv0 --packagelist [-D path]
EOF
    exit 1
}

source /usr/share/makepkg/util/config.sh
source /usr/share/makepkg/util/option.sh
source /usr/share/makepkg/util/pkgbuild.sh
source /usr/share/makepkg/util/parseopts.sh

opt_short='C:D:M:x:BU'
opt_long=('directory:' 'pacman-conf:' 'makepkg-conf:' 'build' 'update'
          'create' 'suffix:' 'bind:' 'bind-rw:' 'packagelist'
          'buildscript:')
opt_hidden=('dump-options')

if ! parseopts "$opt_short" "${opt_long[@]}" "${opt_hidden[@]}" -- "$@"; then
    usage
fi
set -- "${OPTRET[@]}"

unset bindmounts_ro bindmounts_rw buildscript makepkg_conf pacman_conf
while true; do
    case "$1" in
        -B|--build)
            build=1 ;;
        -U|--update)
            update=1 ;;
        --buildscript)
            shift; buildscript=$1 ;;
        --packagelist)
            packagelist=1 ;;
        --create)
            create=1 ;;
        -x|--suffix)
            shift; suffix=$1 ;;
        # devtools options
        -C|--pacman-conf)
            shift; pacman_conf=$1 ;;
        -D|--directory)
            shift; directory=$1 ;;
        -M|--makepkg-conf)
            shift; makepkg_conf=$1 ;;
        --bind)
            shift; bindmounts_ro+=("$1") ;;
        --bind-rw)
            shift; bindmounts_rw+=("$1") ;;
        # other options
        --dump-options)
            printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
            printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
            exit ;;
        --) shift; break ;;
    esac
    shift
done

# required for chroot creation and update
makepkg_conf=${makepkg_conf:-/usr/share/devtools/makepkg-$machine.conf}

if [[ ! -f $makepkg_conf ]]; then
    printf >&2 '%s: %q is not a file\n' "$argv0" "$makepkg_conf"
    exit 2
elif [[ ! -r $makepkg_conf ]]; then
    printf >&2 '%s: %q could not be read\n' "$argv0" "$makepkg_conf"
    exit 1
fi

# required for chroot creation and update
pacman_conf=${pacman_conf:-/usr/share/devtools/pacman-$suffix.conf}

if [[ ! -f $pacman_conf ]]; then
    printf >&2 '%s: %q is not a file\n' "$argv0" "$pacman_conf"
    exit 2
elif [[ ! -r $pacman_conf ]]; then
    printf >&2 '%s: %q could not be read\n' "$argv0" "$pacman_conf"
    exit 1
fi

# bind mount file:// paths to container (#461)
# required for update/build steps
while read -r key _ value; do
    case $key=$value in
        Server=file://*)
            bindmounts_rw+=("${value#file://}") ;;
    esac
done < <(pacman-conf --config "$pacman_conf")
wait $!

# create new container, required for packagelist/update/build steps
if (( create )); then
    # default to base-devel or multilib-devel, unless packages are
    # specified on the command-line.
    # available packages depend on the configured pacman configuration
    if (( $# )); then
        base_packages=("$@")

    # XXX: use pacini to not process Include directives in pacman.conf
    # (not supported by devtools)
    elif [[ $(pacini --section=multilib "$pacman_conf") ]] && [[ $machine == "x86_64" ]]; then
        base_packages=('base-devel' 'multilib-devel')
    else
        base_packages=('base-devel')
    fi

    # parent path is not created by mkarchroot (#371)
    if [[ ! -d $directory ]]; then
        sudo install -d "$directory" -m 755 -v
    fi

    if [[ ! -d $directory/root ]]; then
        sudo mkarchroot -C "$pacman_conf" -M "$makepkg_conf" \
             "$directory"/root "${base_packages[@]}"
    fi
    exit $?
fi

# use libmakepkg to print full package names
if (( packagelist )); then
    if [[ ! -r $directory/root/etc/makepkg.conf ]]; then
        printf >&2 '%s --packagelist: %q: could not be read\n' "$argv0" "$directory"/root/etc/makepkg.conf
        exit 1
    fi

    ( load_makepkg_config "$directory"/root/etc/makepkg.conf
      source_safe "${buildscript-PKGBUILD}"

      PKGDEST="${PKGDEST:-$startdir}" print_all_package_names
    )
    exit $?
fi

if (( update )); then
    # arch-nspawn makes no distinction between a missing working directory
    # and one which does not exist
    if [[ ! -d $directory/root ]]; then
        printf >&2 '%s: %q is not a directory\n' "$argv0" "$directory"/root
        printf >&2 '%s: did you run aur chroot --create?\n' "$argv0"
        exit 20
    fi    

    # locking is done by systemd-nspawn
    sudo arch-nspawn -C "$pacman_conf" -M "$makepkg_conf" "$directory"/root \
         "${bindmounts_ro[@]/#/--bind-ro=}" \
         "${bindmounts_rw[@]/#/--bind=}" pacman -Syu --noconfirm
fi

if (( build )); then
    # use makechrootpkg -c as default build command (sync /root container)
    # arguments after -- (if present) are used as makechrootpkg arguments
    sudo --preserve-env=GNUPGHOME,SSH_AUTH_SOCK,PKGDEST makechrootpkg -r "$directory" \
         "${bindmounts_ro[@]/#/-D}" \
         "${bindmounts_rw[@]/#/-d}" "${@:--c}"
fi

# vim: set et sw=4 sts=4 ft=sh:
