#!/bin/bash

## Copyright (C) 2017 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## This script fixes the interaction between multiple tools.
##
## - `cowbuilder` hardcodes setting '--buildplace'.
##
## - `pbuilder` sets by default '--force-check-gpg'.
##   (This could also be sorted in `dist_build_pbuilder_config_file`.)
## - `pbuilder` `/usr/lib/pbuilder/pbuilder-createbuildenv` hardcodes calling `${DEBOOTSTRAP}`.
##
## - `mmdebstrap` does not support '--force-check-gpg'.
## - `mmdebstrap` requires the parameters in a certain order.
##
## - grml-debootstrap deprecated variables:
##   - '$DEBOOTSTRAP' (use of wrapper)
#    - '$DEBOOTSTRAP_OPTS' (adding additional options)
##   https://github.com/grml/grml-debootstrap/pull/309

set -x
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose

## This wrapper is invoked through PATH by grml-debootstrap, so it does
## use plain (uncolored) log messages.
true "INFO: Currently running: $0 (derivative-maker help-steps/mmdebstrap wrapper)"

args_original="$*"

## Diagnostic argument filter.
##
## Replaces the previous string-replacement-based 'args_filtered' approach
## (which had multiple subtle bugs: filtered against the wrong architecture
## variable during cross-builds, depended on exact whitespace, and ignored
## option order). We now walk "$@" token by token and log per-token under
## xtrace whether each token is dropped (with reason) or kept.
##
## NOTE: The wrapper currently does NOT forward 'args_passthrough' to
## mmdebstrap. It hardcodes every mmdebstrap argument explicitly below.
## The filter exists as scaffolding so that, if grml-debootstrap or
## cowbuilder eventually start passing options we want to honor, we can
## start forwarding 'args_passthrough' selectively without re-introducing
## the brittle string-substitution approach. Forwarding it today would
## reintroduce ordering bugs (e.g. a leftover BUILDPLACE positional from
## the grml path appearing before the suite/sources tail) and risk
## conflicting flags (e.g. duplicate '--architectures').
##
## Tokens classified as "drop":
## - default mirror URLs hardcoded by cowbuilder, pbuilder, grml-debootstrap
## - --mirror (we re-supply it via the sources list)
## - the BUILDPLACE positional (we re-emit it later in the required order)
## - --force-check-gpg (mmdebstrap rejects this; it always GPG-checks)
## - --verbose (we re-add it)
## - --include / --include=...        (we provide our own --include)
## - --variant=buildd                 (we use --variant=required)
## - --arch / --arch=ARCH             (we use --architectures=...)
## - --architecture / --architecture=ARCH (cowbuilder spelling)
## - --architectures / --architectures=ARCH (mmdebstrap's own option;
##   would otherwise collide with the wrapper-supplied value)
## - the suite (positional; we re-emit it)
## - the sources list path (positional; we re-emit it)
## - --skip=cleanup/apt, --skip=check/empty (grml-debootstrap)
mmdebstrap_filter_args() {
   local arg next_is_value pending_option
   args_passthrough=()
   next_is_value=""
   pending_option=""
   for arg in "$@"; do
      if [ -n "$next_is_value" ]; then
         true "INFO: drop value of $pending_option (we re-supply it ourselves): $arg"
         next_is_value=""
         pending_option=""
         continue
      fi
      case "$arg" in
         --mirror|--arch|--architecture|--architectures|--include|--variant)
            true "INFO: drop $arg (and next token; we re-supply via --architectures / --include / sources list)"
            next_is_value="1"
            pending_option="$arg"
            continue
            ;;
         --mirror=*|--arch=*|--architecture=*|--architectures=*|--include=*|--variant=*)
            true "INFO: drop $arg (we re-supply via --architectures / --include / sources list)"
            continue
            ;;
         --force-check-gpg)
            true "INFO: drop $arg (mmdebstrap always GPG-checks; the option is unsupported)"
            continue
            ;;
         --verbose)
            true "INFO: drop $arg (we re-add --verbose ourselves)"
            continue
            ;;
         --skip=cleanup/apt|--skip=check/empty)
            true "INFO: drop $arg (set by grml-debootstrap; not desired here)"
            continue
            ;;
         "${dist_build_apt_sources_mirror:-}")
            true "INFO: drop mirror URI $arg (we re-supply via the sources list)"
            continue
            ;;
         "${BUILDPLACE:-}")
            true "INFO: drop BUILDPLACE positional $arg (re-emitted later in the required order)"
            continue
            ;;
         "${dist_build_apt_stable_release:-}")
            true "INFO: drop suite positional $arg (re-emitted later in the required order)"
            continue
            ;;
         "${dist_build_sources_list_primary:-}")
            true "INFO: drop sources-list positional $arg (re-emitted later in the required order)"
            continue
            ;;
         http://ftp.us.debian.org/debian|https://ftp.us.debian.org/debian)
            true "INFO: drop default mirror URI from cowbuilder/pbuilder: $arg"
            continue
            ;;
         http://httpredir.debian.org/debian|https://httpredir.debian.org/debian)
            true "INFO: drop default mirror URI from grml-debootstrap (httpredir): $arg"
            continue
            ;;
         http://deb.debian.org/debian|https://deb.debian.org/debian)
            true "INFO: drop default mirror URI from grml-debootstrap (deb.debian.org): $arg"
            continue
            ;;
         *)
            true "INFO: keep arg (passthrough to mmdebstrap): $arg"
            args_passthrough+=( "$arg" )
            ;;
      esac
   done
}

path_variable_remove_help_steps() {
   local path_part path_array

   true "INFO: Old PATH: $PATH"
   ## Example PATH:
   ## /home/user/derivative-maker/help-steps:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

   IFS=':' read -ra path_array <<< "$PATH"

   new_path=""
   for path_part in "${path_array[@]}"; do
      if [[ "${path_part:-}" != *"help-steps"* ]]; then
         new_path+="$path_part:"
      fi
   done

   ## Remove trailing colon.
   new_path="${new_path%:}"

   true "INFO: New PATH: $new_path"
   ## Example PATH:
   ## /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
}

path_variable_remove_help_steps
export PATH="$new_path"

## Example $@ when called by cowbuilder:
## --arch=amd64 --include=apt --variant=buildd --force-check-gpg trixie /var/cache/pbuilder/base.cow_amd64 http://HTTPS///deb.debian.org/debian

### }}}

## Sanity test.
[ -n "${DIST_APTGETOPT_SERIALIZED:-}" ] || error "DIST_APTGETOPT_SERIALIZED is unset!"

## Debugging.
mapfile -t DIST_APTGETOPT <<< "$DIST_APTGETOPT_SERIALIZED"
printf "%s\n" "DIST_APTGETOPT: ${DIST_APTGETOPT[*]}"

## Debugging.
true "BUILDPLACE: ${BUILDPLACE:-}"
true "dist_grml_mount_point: ${dist_grml_mount_point:-}"
true "http_proxy: ${http_proxy:-}"
true "https_proxy: ${https_proxy:-}"
true "ALL_PROXY: ${ALL_PROXY:-}"
true "REPO_PROXY: ${REPO_PROXY:-}"
true "dist_build_target_arch: $dist_build_target_arch"
true "dist_build_multiarch_package_item: $dist_build_multiarch_package_item"
true "dist_build_apt_stable_release: $dist_build_apt_stable_release"
true "dist_build_apt_sources_mirror: $dist_build_apt_sources_mirror"
true "dist_aptgetopt_file: $dist_aptgetopt_file"
cat -- "$dist_aptgetopt_file"
true "dist_build_sources_list_primary: $dist_build_sources_list_primary"
cat -- "$dist_build_sources_list_primary"

true "INFO: walking caller args; each token is logged (drop or keep)."
mmdebstrap_filter_args "$@"
true "FINAL args_passthrough: ${args_passthrough[*]}"

## mmdebstrap needs 3 positional arguments.
## suite buildplace path-to-sources-list
## For example when using grml-debootstrap:
## trixie /mnt/debootstrap.15557 /home/user/derivative-maker/build_sources/debian_stable_current_clearnet.sources
## For example when using cowbuilder:
## trixie /var/cache/pbuilder/base.cow_amd64 /home/user/derivative-maker/build_sources/debian_stable_current_clearnet.sources

## - locales:
##   XXX: Workaround for:
##   https://github.com/grml/grml-debootstrap/issues/48

if [ "${BUILDPLACE:-}" = "" ]; then
   ## For grml-debootstrap.

   true "$0: Variable BUILDPLACE is unset."
   true "$0: This means this script was probably called by grml-debootstrap."
   true "$0: Setting BUILDPLACE to: ${dist_grml_mount_point:-}"
   BUILDPLACE="${dist_grml_mount_point:-}"

   ## - zstd: for faster speed
   ##   grml-debootstrap default '/etc/debootstrap/packages' file contains 'zstd' but we are not using the 'packages' file.
   ##   https://github.com/grml/grml-debootstrap/issues/211
   ##
   ## - libpam-systemd
   ##   dracut requires libpam-systemd
   ##   https://github.com/grml/grml-debootstrap/issues/233
   ##
   ## - dracut-live
   ##   'dracut --add dmsquash-live' requires dracut-live
   ##
   ## TODO: Debian forky: gpg-from-sq gpgv-from-sq
   include_opt="--include=eatmydata,apt-transport-tor,gpg-agent,fasttrack-archive-keyring,zstd,libpam-systemd,dracut-live"

   ## example:
   ## /home/user/derivative_dot/derivative-maker/help-steps/mmdebstrap --verbose --debug --format directory --variant=required --architectures=amd64 --aptopt=/home/user/derivative-binary/30_derivative-maker.conf --include=eatmydata,apt-transport-tor,gpg-agent,fasttrack-archive-keyring trixie /mnt/debootstrap.33132 /home/user/derivative-maker/build_sources/debian_stable_current_clearnet.sources
else
   ## For cowbuilder.

   true "$0: Variable BUILDPLACE is set."
   true "$0: This means this script was probably called by called by pbuilder which was called by cowbuilder."

   ## build dependencies
   include_opt="--include=apt,sudo,devscripts,debhelper,strip-nondeterminism,fakeroot,apt-transport-tor,eatmydata,aptitude,cowdancer,fasttrack-archive-keyring"

   ## example:
   ## /home/user/derivative-maker/help-steps/mmdebstrap --verbose --debug --format directory --variant=required --architectures=amd64 --aptopt=/home/user/derivative-binary/30_derivative-maker.conf --include=apt,sudo,devscripts,debhelper,strip-nondeterminism,fakeroot,apt-transport-tor,eatmydata,aptitude,cowdancer,fasttrack-archive-keyring trixie /var/cache/pbuilder/base.cow_amd64 /home/user/derivative-maker/build_sources/debian_stable_current_clearnet.sources
fi

## Sanity tests.
[ -n "${dist_build_apt_stable_release:-}" ] || error "dist_build_apt_stable_release is unset!"
[ -n "${BUILDPLACE:-}" ] || error "BUILDPLACE is unset!"
[ -n "${dist_build_sources_list_primary:-}" ] || error "dist_build_sources_list_primary is unset!"
[ -n "${DIST_APTGETOPT:-}" ] || error "DIST_APTGETOPT is unset!"

## '--variant=required' is only supported by 'mmdebstrap'. It might not be supported by 'debootstrap'.

#"$dist_source_help_steps_folder/mmdebstrap"

## Deletion of /etc/apt/apt.conf.d/99mmdebstrap is required for compatibility with live-boot (non-customized).
## This is because otherwise 99mmdebstrap results in not installing 'Recommends:' packages, which
## are actually a dependency for a fully functional ISO with functional login.

mmdebstrap \
   --verbose \
   --debug \
   --format directory \
   --variant=required \
   --architectures="$dist_build_multiarch_package_item" \
   --aptopt="$dist_aptgetopt_file" \
   --customize-hook='printf "%s\n" "mmdebstrap hooks START"' \
   --customize-hook='printf "%s\n" "----------"' \
   --customize-hook='ls -la -- "$1" || true' \
   --customize-hook='realpath -- "$1" || true' \
   --customize-hook='printf "%s\n" "----------"' \
   --customize-hook='cat -- "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources" || true' \
   --customize-hook='cat -- "$1/etc/apt/apt.conf.d/99mmdebstrap" || true' \
   --customize-hook='printf "%s\n" "----------"' \
   --customize-hook='rm --force --verbose -- "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources"' \
   --customize-hook='rm --force --verbose -- "$1/etc/apt/apt.conf.d/99mmdebstrap"' \
   --customize-hook='printf "%s\n" "----------"' \
   --customize-hook='printf "%s\n" "mmdebstrap hooks END"' \
   $include_opt \
   "$dist_build_apt_stable_release" \
   "$BUILDPLACE" \
   "$dist_build_sources_list_primary"

true "INFO: End of script: $0 (derivative-maker help-steps/mmdebstrap wrapper)"

## Example execution when cross-buidling ARM64 on AMD64:

## pbuilder:
## + mmdebstrap --verbose --debug --format directory --variant=required --architectures=amd64 --aptopt=/home/ansible/derivative-binary/30_derivative-maker.conf '--customize-hook=echo "mmdebstrap hooks START"' '--customize-hook=echo "----------"' '--customize-hook=ls -la "$1" || true' '--customize-hook=realpath "$1" || true' '--customize-hook=echo "----------"' '--customize-hook=cat "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources" || true' '--customize-hook=cat "$1/etc/apt/apt.conf.d/99mmdebstrap" || true' '--customize-hook=echo "----------"' '--customize-hook=rm --force --verbose "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources"' '--customize-hook=rm --force --verbose "$1/etc/apt/apt.conf.d/99mmdebstrap"' '--customize-hook=echo "----------"' '--customize-hook=echo "mmdebstrap hooks END"' --include=apt,sudo,devscripts,debhelper,strip-nondeterminism,fakeroot,apt-transport-tor,eatmydata,aptitude,cowdancer,fasttrack-archive-keyring trixie /var/cache/pbuilder/base.cow_amd64 /home/ansible/derivative-maker/build_sources/debian_stable_current_clearnet.sources

## grml-debootstrap v0.111:
## + mmdebstrap --verbose --debug --format directory --variant=required --architectures=arm64 --aptopt=/home/ansible/derivative-binary/30_derivative-maker.conf '--customize-hook=echo "mmdebstrap hooks START"' '--customize-hook=echo "----------"' '--customize-hook=ls -la "$1" || true' '--customize-hook=realpath "$1" || true' '--customize-hook=echo "----------"' '--customize-hook=cat "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources" || true' '--customize-hook=cat "$1/etc/apt/apt.conf.d/99mmdebstrap" || true' '--customize-hook=echo "----------"' '--customize-hook=rm --force --verbose "$1/etc/apt/sources.list.d/0000debian_stable_current_clearnet.sources"' '--customize-hook=rm --force --verbose "$1/etc/apt/apt.conf.d/99mmdebstrap"' '--customize-hook=echo "----------"' '--customize-hook=echo "mmdebstrap hooks END"' --include=eatmydata,apt-transport-tor,gpg-agent,fasttrack-archive-keyring,zstd,libpam-systemd,dracut-live trixie /mnt/derivative-maker-grml-debootstrap.49847 /home/ansible/derivative-maker/build_sources/debian_stable_current_clearnet.sources
