#!/bin/bash

## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

implicit_dist_type_vm() {
   if echo "${args[@]}" | grep --quiet --fixed-string -- "--type" ; then
      return 0
   fi
   if [ ! "$dist_build_type" = "" ]; then
      return 0
   fi
   echo "${cyan}INFO: implicitly setting '--type vm' because using '$1'.${reset}"
   dist_build_type="vm"
}

implicit_dist_type_host() {
   if echo "${args[@]}" | grep --quiet --fixed-string -- "--type" ; then
      return 0
   fi
   if [ ! "$dist_build_type" = "" ]; then
      return 0
   fi
   echo "${cyan}INFO: implicitly setting '--type host' because using '$1'.${reset}"
   dist_build_type="host"
}

parse_cmd_type_error() {
   echo "${red}${bold}ERROR: --type must be either 'vm' or 'host' and cannot be used multiple times.${reset}"
   exit 1
}

parse_cmd_target_error() {
   echo "${red}${bold}ERROR: --target must be either virtualbox, qcow2, utm, iso, raw, dist-installer-cli, windows or root and can be used multiple times.${reset}"
   exit 1
}

parse_cmd_flavor_error() {
   echo "${red}${bold}You must add either:
--flavor whonix-gateway-xfce
--flavor whonix-gateway-rpi
--flavor whonix-gateway-cli
--flavor whonix-workstation-xfce
--flavor whonix-workstation-cli
--flavor whonix-custom-workstation
--flavor whonix-host-xfce
--flavor whonix-host-cli
--flavor kicksecure-cli
--flavor kicksecure-xfce
--flavor dist-installer-cli
${reset}"
   exit 1
}

dist_build_one_script_help() {
   echo "\
derivative-maker

Syntax:
  --flavor [flavor] --target [target]

Description:
  Creates a separate build folder at \$HOMEVAR/derivative-binary.

  For detailed information on build configuration parameters, please refer to the full build documentation.

Flavors:
  --flavor [flavor_option]
  Options:
    whonix-gateway-xfce         : Builds Whonix-Gateway Xfce VM.
    whonix-gateway-rpi          : Builds Whonix-Gateway CLI RPi 3 VM.
    whonix-gateway-cli          : Builds Whonix-Gateway CLI VM.
    whonix-workstation-xfce     : Builds Whonix-Workstation Xfce VM.
    whonix-workstation-cli      : Builds Whonix-Workstation CLI VM.
    whonix-custom-workstation   : Builds Whonix-Custom-Workstation VM.
    whonix-host-cli             : Builds Whonix-Host CLI.
    whonix-host-xfce            : Builds Whonix-Host Xfce.
    kicksecure-cli              : Builds Kicksecure VM CLI VM.
    kicksecure-xfce             : Builds Kicksecure VM Xfce VM.

Targets:
  --target [target_option]
  Options:
    virtualbox              : Builds VirtualBox .ova files.
    qcow2                   : Builds qcow2 images.
    utm                     : Builds UTM images.
    iso                     : Builds ISO images.
    raw                     : Builds raw disk images.
    dist-installer-cli      : Builds dist-installer-cli.
    windows                 : Builds the Windows Installer.
    root                    : Builds for physical installations.
    source                  : Builds a xz source archive.

Types:
  --type [type_option]
  Options:
    host                    : Specifies that the build is for a host system.
    vm                      : Specifies that the build is for a virtual machine.

Optional Parameters:
  --vmram [size]           : Set VM RAM size (e.g., --vmram 128).
  --vram [size]            : Set VM video RAM size (e.g., --vram 12).
  --vmsize [size]          : Set VM disk size (e.g., --vmsize 200G).

  --freshness [option]     : Choose between 'frozen' (frozen sources) or 'current' (current sources).
  --connection [option]    : Select 'clearnet' for clearnet apt sources or 'onion' for onion apt sources.
  --repo [true|false]      : Enable or disable derivative remote repository (default: false).

Environment Variables:
  - flavor_meta_packages_to_install: Define meta packages to be installed.
    Examples:
      flavor_meta_packages_to_install='none'
      flavor_meta_packages_to_install='non-qubes-vm-enhancements-cli kicksecure-dependencies-cli whonix-shared-packages-dependencies-cli whonix-gateway-packages-dependencies-cli'

  - install_package_list: Specify additional custom packages for installation.
    Examples:
      install_package_list='gparted'
      install_package_list='gparted gedit'

  - DERIVATIVE_APT_REPOSITORY_OPTS: Set options for the Derivative APT Repository.
    Examples:
      DERIVATIVE_APT_REPOSITORY_OPTS='--enable --repository stable'
      DERIVATIVE_APT_REPOSITORY_OPTS='--enable --repository testers'
      DERIVATIVE_APT_REPOSITORY_OPTS='--enable --repository developers'
      DERIVATIVE_APT_REPOSITORY_OPTS='--enable --codename bookworm'

Advanced Options:
  --report [true|false]           : Enable or disable build reports (default: false).
  --verifiable [true|false]       : Toggle file deletion in cleanup script for verifiable builds (default: false).
  --sanity-tests [true|false]     : Enable or disable chroot script sanity tests for faster build speed (default: false).
  --retry-max [attempts]          : Set maximum retry attempts. (default: 2)
  --retry-wait [seconds]          : Set wait time between retry attempts.
  --retry-before [script]         : Specify a script to run before retry. [default: none)
  --retry-after [script]          : Specify a script to run after retry. [default: none)
  --allow-uncommitted [true|false]: Permit builds with uncommitted changes (default: false).
  --allow-untagged [true|false]   : Permit builds from non-tagged sources (default: false).
  --kernel [packages]             : Specify kernel packages (e.g., 'linux-image-amd64' or 'none').
  --headers [packages]            : Specify kernel header packages.
  --remote-derivative-packages    : Choose to use remote derivative packages instead of building derivative packages from source code. (default: false).
  --release [unsupported_option]  : Set release option (unsupported). (bookworm|xenial|bionic)
  --arch [architecture]           : Set architecture (e.g., i386, amd64, kfreebsd-i386, kfreebsd-amd64) (default: amd64).
  (Note: amd64 also works with most Intel CPUs.)
  --debug                         : Does not disable verbose/debug (xtrace) during help-steps pre, variables and parse-cmd.

For VMs only:
  --initramfs [packages]          : Specify initramfs packages. (none, initramfs-tools) (default: \$BUILD_INITRAMFS_PKGS)

Configuration Files:
  --confdir [/path/to/config/dir] : Specify an additional configuration directory.
  --conffile [/path/to/config/file]: Specify an additional configuration file.
  --grmlbin [/path/to/grml-debootstrap]: Set the grml-debootstrap path (default: grml-debootstrap).

Miscellaneous:
  --unsafe-io [true|false]        : Toggle unsafe IO options (default: false).
  --freedom [true|false]          : Choose between pure or impure builds (required for host builds).
  --tb [none|closed|open]         : Configure Tor Browser installation options (default: open).
  none: Do not install Tor Browser.
  closed: Abort build, fail closed if Tor Browser cannot be installed.
  open: Do not abort build, fail open if Tor Browser cannot and installed.

Please use the options as per your requirements. For any assistance, refer to the full documentation.
"
    exit 0
}

dist_build_one_parse_cmd() {
   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/035

   args=("$@")

   if [ ! "$dist_build_internal_run" = "true" ]; then
      if [ "${#args[@]}" -eq 0 ]; then
         echo "${red}${bold}No option chosen! Use '--help'.${reset}"
         exit 1
      fi
   fi

   local build_machines_counter="0"
   local build_target_counter="0"

   ## Using export, so scripts run by run-parts (run by derivative-maker) can read
   ## these variables.

   while :
   do
       case $1 in
           -h | --help | -\?)
               dist_build_one_script_help
               ;;
           --flavor)
               true "${cyan}INFO: --flavor $2 chosen.${reset}"
               dist_build_flavor="$2"
               export dist_build_flavor
               if [ "$dist_build_flavor" = "whonix-gateway-xfce" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-gateway-rpi" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-gateway-cli" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-workstation-xfce" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-workstation-cli" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-custom-workstation" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-host-cli" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "whonix-host-xfce" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "kicksecure-cli" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "kicksecure-xfce" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
               elif [ "$dist_build_flavor" = "dist-installer-cli" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
                  export dist_build_installer_dist="true"
                  dist_build_image_upload_supported="true"
               elif [ "$dist_build_flavor" = "internal" ]; then
                  build_machines_counter="$(( $build_machines_counter + 1 ))"
                  export dist_build_internal_run="true"
               else
                  parse_cmd_flavor_error
               fi
               shift 2
               ;;
           --type)
               true "${cyan}INFO: --type $2 chosen.${reset}"
               if [ "$2" = "host" ]; then
                  dist_build_type="host"
               elif [ "$2" = "vm" ]; then
                  dist_build_type="vm"
               else
                  parse_cmd_type_error
               fi
               shift 2
               ;;
           --target)
               true "${cyan}INFO: --target $2 chosen.${reset}"
               if [ "$2" = "virtualbox" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_virtualbox="true"
                  dist_build_image_upload_supported="true"
                  implicit_dist_type_vm "--target $2"
               elif [ "$2" = "qcow2" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_qcow2="true"
                  dist_build_image_upload_supported="true"
                  implicit_dist_type_vm "--target $2"
               elif [ "$2" = "utm" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_raw="true"
                  export dist_build_utm="true"
                  dist_build_image_upload_supported="false"
                  implicit_dist_type_vm "--target $2"
               elif [ "$2" = "iso" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_iso="true"
                  dist_build_image_upload_supported="true"
                  implicit_dist_type_host "--target $2"
               elif [ "$2" = "raw" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_raw="true"
                  dist_build_image_upload_supported="false"
               elif [ "$2" = "root" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_install_to_root="true"
                  dist_build_image_upload_supported="false"
               elif [ "$2" = "windows" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  export dist_build_windows_installer="true"
                  dist_build_image_upload_supported="true"
                  implicit_dist_type_vm "--target $2"
               elif [ "$2" = "source" ]; then
                  build_target_counter="$(( $build_target_counter + 1 ))"
                  dist_build_source_archive="true"
                  dist_build_image_upload_supported="true"
               else
                  parse_cmd_target_error
               fi
               shift 2
               ;;
           --fast)
               true "${cyan}INFO: --fast $2 chosen.${reset}"
               if [ "$2" = "1" ]; then
                  export dist_build_fast1="1"
               elif [ "$2" = "2" ]; then
                  export dist_build_fast1="1"
                  export dist_build_fast2="1"
               else
                  echo "${red}${bold}ERROR: supported options for --fast are '1' and '2'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --vmram)
               export VMRAM="$2"
               shift 2
               if [ "$VMRAM" = "" ]; then
                  echo "${red}${bold}ERROR: You forgot to specify how much MB to use for --vmram.${reset}"
                  exit 1
               fi
               ;;
           --vram)
               export VRAM="$2"
               shift 2
               if [ "$VRAM" = "" ]; then
                  echo "${red}${bold}ERROR: You forgot to specify how much MB to use for --vram.${reset}"
                  exit 1
               fi
               ;;
           --vmsize)
               export VMSIZE="$2"
               shift 2
               if [ "$VMSIZE" = "" ]; then
                  echo "${red}${bold}ERROR: You forgot to specify how much GB to use for --vmsize.${reset}"
                  exit 1
               fi
               ;;
           --freshness)
               if [ "$2" = "frozen" ]; then
                  true "${red}ERROR: Using frozen sources currently not implement!${reset}"
                  exit 1
               elif [ "$2" = "current" ]; then
                  ## default
                  true "${cyan}INFO: Using current sources.${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --freshness are 'frozen' or 'current'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --connection)
               if [ "$2" = "clearnet" ]; then
                  true "${cyan}INFO: Using clearnet apt sources.${reset}"
                  dist_build_sources_clearnet_or_onion="clearnet"
               elif [ "$2" = "onion" ]; then
                  true "${cyan}INFO: Using onion apt sources.${reset}"
                  dist_build_sources_clearnet_or_onion="onion"
                  ## tb-updater
                  ## https://phabricator.whonix.org/T678
                  tb_onion=true
               else
                  echo "${red}${bold}ERROR: supported options for --connection are 'clearnet' or 'onion'.${reset}"
                  exit 1
               fi
               export tb_onion
               export dist_build_sources_clearnet_or_onion
               shift 2
               ;;
           --release)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --release must not be empty.${reset}"
                  exit 1
               else
                  export BUILD_RELEASE="$2"
                  true "${cyan}BUILD_RELEASE set to $BUILD_RELEASE.${reset}"
               fi
               shift 2
               ;;
           ## TODO
           --testing-frozen-sources)
               export dist_build_sources_list_primary="build_sources/debian_testing_frozen.list"
               shift
               ;;
           --debug)
               ## Implemented in help-steps/pre. Cannot be implemented here, because it runs too late.
               shift
               ;;
           --arch)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --arch must not be empty.${reset}"
                  exit 1
               else
                  export dist_build_target_arch="$2"
                  true "${cyan}dist_build_target_arch set to $dist_build_target_arch.${reset}"
               fi
               shift 2
               ;;
           --initramfs)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --initramfs must not be empty.${reset}"
                  exit 1
               elif [ "$2" = "none" ]; then
                  export BUILD_INITRAMFS_PKGS="none"
                  true "${cyan}BUILD_INITRAMFS_PKGS set to $BUILD_INITRAMFS_PKGS.${reset}"
               else
                  export BUILD_INITRAMFS_PKGS="$BUILD_INITRAMFS_PKGS $2"
                  true "${cyan}BUILD_INITRAMFS_PKGS set to $BUILD_INITRAMFS_PKGS.${reset}"
               fi
               shift 2
               ;;
           --kernel)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --kernel must not be empty.${reset}"
                  exit 1
               elif [ "$2" = "none" ]; then
                  export BUILD_KERNEL_PKGS="none"
                  true "${cyan}BUILD_KERNEL_PKGS set to $BUILD_KERNEL_PKGS.${reset}"
               else
                  export BUILD_KERNEL_PKGS="$BUILD_KERNEL_PKGS $2"
                  true "${cyan}BUILD_KERNEL_PKGS set to $BUILD_KERNEL_PKGS.${reset}"
               fi
               shift 2
               ;;
           --headers)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --headers must not be empty.${reset}"
                  exit 1
               elif [ "$2" = "none" ]; then
                  export BUILD_HEADER_PKGS="none"
                  true "${cyan}BUILD_HEADER_PKGS set to $BUILD_HEADER_PKGS.${reset}"
               else
                  export BUILD_HEADER_PKGS="$BUILD_HEADER_PKGS $2"
                  true "${cyan}BUILD_HEADER_PKGS set to $BUILD_HEADER_PKGS.${reset}"
               fi
               shift 2
               ;;
           --report)
               if [ "$2" = "true" ]; then
                  true "${cyan}INFO: Full report.${reset}"
                  export dist_build_script_create_report="true"
               elif [ "$2" = "false" ]; then
                  true "${cyan}INFO: No report.${reset}"
                  export dist_build_script_create_report="false"
               else
                  echo "${red}${bold}ERROR: supported options for --report are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --verifiable)
               if [ "$2" = "true" ]; then
                  true "${cyan}INFO: Building verifiable.${reset}"
                  export dist_build_script_verifiable="true"
               elif [ "$2" = "false" ]; then
                  true "${cyan}INFO: Not building verifiable.${reset}"
                  export dist_build_script_verifiable="false"
               else
                  echo "${red}${bold}ERROR: supported options for --verifiable are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --sanity-tests)
               if [ "$2" = "true" ]; then
                  true "${cyan}INFO: Sanity tests true.${reset}"
               elif [ "$2" = "false" ]; then
                  ## TODO: opt in rather than opt out.
                  true "${cyan}INFO: Sanity tests false.${reset}"
                  export SKIP_SCRIPTS+=" 20_sanity_checks "
               else
                  echo "${red}${bold}ERROR: supported options for --sanity-tests are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --file-system)
               export dist_build_file_system="$2"
               shift 2
               ;;
           --hostname)
               export dist_build_hostname="$2"
               shift 2
               ;;
           --debopt)
               export dist_build_debopt="$2"
               shift 2
               ;;
           --retry-max)
               export dist_build_auto_retry="$2"
               shift 2
               ;;
           --retry-wait)
               export dist_build_wait_auto_retry="$2"
               shift 2
               ;;
           --retry-before)
               export dist_build_dispatch_before_retry="$2"
               shift 2
               ;;
           --retry-after)
               export dist_build_dispatch_after_retry="$2"
               shift 2
               ;;
           --allow-untagged)
               if [ "$2" = "false" ]; then
                  true "${cyan}INFO: Would stop if building form untagged commits.${reset}"
               elif [ "$2" = "true" ]; then
                  true "${cyan}INFO: Would build form untagged commits.${reset}"
                  export dist_build_ignore_untagged="true"
               else
                  echo "${red}${bold}ERROR: supported options for --allow-untagged are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --allow-uncommitted)
               if [ "$2" = "false" ]; then
                  true "${cyan}INFO: Would stop if uncommitted changes detected.${reset}"
               elif [ "$2" = "true" ]; then
                  true "${cyan}INFO: Would ignore if uncommitted changes detected.${reset}"
                  export dist_build_ignore_uncommitted="true"
               else
                  echo "${red}${bold}ERROR: supported options for --allow-uncommitted are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --confdir)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --confdir may not be empty.${reset}"
                  exit 1
               else
                  export dist_build_custom_config_dir="$2"
                  true "${cyan}INFO: --confdir set to: $dist_build_custom_config_dir${reset}"
                  if [ -d "$dist_build_custom_config_dir" ]; then
                     true "${cyan}INFO: --confdir $dist_build_custom_config_dir exists.${reset}"
                  else
                     echo "${red}${bold}ERROR: --confdir $dist_build_custom_config_dir does not exist!${reset}"
                     exit 1
                  fi
               fi
               shift 2
               ;;
           --conffile)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --conffile may not be empty.${reset}"
                  exit 1
               else
                  export dist_build_conf_file="$2"
                  true "${cyan}INFO: --conffile set to: $dist_build_conf_file${reset}"
                  if [ -f "$dist_build_conf_file" ]; then
                     true "${cyan}INFO: --conffile $dist_build_conf_file exists.${reset}"
                  else
                     echo "${red}${bold}ERROR: --conffile $dist_build_conf_file does not exist!${reset}"
                     exit 1
                  fi
               fi
               shift 2
               ;;
           --grmlbin)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --grmlbin may not be empty.${reset}"
                  exit 1
               else
                  export dist_build_grml_bin="$2"
                  true "${cyan}INFO: --grmlbin set to: $dist_build_grml_bin${reset}"
                  if [ -x "$dist_build_grml_bin" ]; then
                     true "${cyan}INFO: --grmlbin $dist_build_grml_bin exists.${reset}"
                  else
                     echo "${red}${bold}ERROR: --grmlbin $dist_build_grml_bin is not executable!${reset}"
                     exit 1
                  fi
               fi
               shift 2
               ;;
           --tb)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --tb may not be empty.${reset}"
                  exit 1
               else
                  export anon_shared_inst_tb="$2"
                  true "${cyan}INFO: --tb set to: $anon_shared_inst_tb${reset}"
               fi
               shift 2
               ;;
           --unsafe-io)
               if [ "$2" = "false" ]; then
                  true "${cyan}INFO: Not using unsafe io.${reset}"
               elif [ "$2" = "true" ]; then
                  dist_build_unsafe_io="true"
                  export dist_build_unsafe_io
                  true "${cyan}INFO: Using unsafe io.${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --unsafe-io are 'true' or 'false'.${reset}"
                  exit 1
               fi
               shift 2
               ;;
           --repo)
               if [ "$2" = "false" ]; then
                  build_remote_repo_enable="false"
                  true "${cyan}INFO: will ${under}not${eunder} enable remote repository.${reset}"
               elif [ "$2" = "true" ]; then
                  build_remote_repo_enable="true"
                  true "${cyan}INFO: will ${under}enable${eunder} remote repository.${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --repo are 'true' or 'false'.${reset}"
                  exit 1
               fi
               export build_remote_repo_enable
               shift 2
               ;;
           --remote-derivative-packages)
               if [ "$2" = "false" ]; then
                  build_remote_derivative_pkgs="false"
                  true "${cyan}INFO: will ${under}not${eunder} use remote derivative packages.${reset}"
               elif [ "$2" = "true" ]; then
                  build_remote_derivative_pkgs="true"
                  true "${cyan}INFO: will ${under}use${eunder} remote derivative packages.${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --remote-derivative-packages are 'true' or 'false'.${reset}"
                  exit 1
               fi
               export build_remote_derivative_pkgs
               shift 2
               ;;
           --dry-run)
               if [ "$2" = "false" ]; then
                  build_dry_run="false"
                  true "${cyan}INFO:not  --dry-run${eunder}${reset}"
               elif [ "$2" = "true" ]; then
                  build_dry_run="true"
                  true "${cyan}INFO: ${under}--dry-run${eunder}${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --dry-run are 'true' or 'false'.${reset}"
                  exit 1
               fi
               export build_dry_run
               shift 2
               ;;
           --freedom)
               if [ "$2" = "false" ]; then
                  build_freedom_only="false"
                  true "${cyan}INFO: will include nonfreedom software packages.${reset}"
               elif [ "$2" = "true" ]; then
                  build_freedom_only="true"
                  true "${cyan}INFO: will include Freedom Software packages only.${reset}"
               else
                  echo "${red}${bold}ERROR: supported options for --freedom are 'true' or 'false'.${reset}"
                  exit 1
               fi
               export build_freedom_only
               shift 2
               ;;
           --function)
               if [ "$2" = "" ]; then
                  echo "${red}${bold}ERROR: --function may not be empty.${reset}"
                  exit 1
               else
                  FUNCTION="$2"
                  true "${cyan}INFO: --function set to $FUNCTION${reset}"
               fi
               shift 2
               ;;
           --)
               shift
               break
               ;;
           -*)
               echo "${red}${bold}unknown option (1): '$1'${reset}"
               exit 1
               break
               ;;
           *)
               if [ "$1" = "" ]; then
                  true
               else
                  echo "${red}${bold}unknown option (2): '$1'${reset}"
                  exit 1
               fi
               break
               ;;
       esac
   done

   if [ "$dist_build_target_arch" = "i386" ]; then
      [ -n "$virtualbox_suppported_architecture" ] || virtualbox_suppported_architecture="true"
   elif [ "$dist_build_target_arch" = "amd64" ]; then
      [ -n "$virtualbox_suppported_architecture" ] || virtualbox_suppported_architecture="true"
      ## https://forums.whonix.org/t/long-wiki-edits-thread/3477/2009
      [ -n "$target_architecture_pretty_name" ] || target_architecture_pretty_name="Intel_AMD64"
   elif [ "$dist_build_target_arch" = "arm64" ]; then
      [ -n "$virtualbox_suppported_architecture" ] || virtualbox_suppported_architecture="true"
   else
      [ -n "$virtualbox_suppported_architecture" ] || virtualbox_suppported_architecture="false"
   fi

   if [ "$dist_build_virtualbox" = "true" ]; then
      if [ "$virtualbox_suppported_architecture" = "false" ]; then
         error "\
${red}${bold}VirtualBox architecture support test failed!
virtualbox_suppported_architecture: '$virtualbox_suppported_architecture'
dist_build_target_arch is not 'amd64'.
dist_build_target_arch is '$dist_build_target_arch'.
You cannot build '--target virtualbox' if not using 'arch i386' or '--arch amd64'.
This is because at time of writing this check, VirtualBox supports 'i386' and 'amd64' only.
Should VirtualBox meanwhile support other architectures such as 'arm64', then this check can simply be removed in the source code.${reset}"
      fi
   fi

   [ -n "$target_architecture_pretty_name" ] || target_architecture_pretty_name="$dist_build_target_arch"

   [ -n "$BUILD_KERNEL_PKGS" ] || BUILD_KERNEL_PKGS="linux-image-${dist_build_target_arch}"
   [ -n "$BUILD_HEADER_PKGS" ] || BUILD_HEADER_PKGS="linux-headers-${dist_build_target_arch}"

   export BUILD_INITRAMFS_PKGS
   export dist_build_target_arch
   export BUILD_KERNEL_PKGS
   export BUILD_HEADER_PKGS
   export target_architecture_pretty_name

   true "${cyan}INFO: dist_build_target_arch    (--arch): $dist_build_target_arch${reset}"
   true "${cyan}INFO: target_architecture_pretty_name   : $target_architecture_pretty_name${reset}"
   true "${cyan}INFO: BUILD_KERNEL_PKGS       (--kernel): $BUILD_KERNEL_PKGS${reset}"
   true "${cyan}INFO: BUILD_HEADER_PKGS      (--headers): $BUILD_HEADER_PKGS${reset}"

   if [ "$dist_build_sources_clearnet_or_onion" = "" ]; then
      true "${cyan}${bold}INFO: No --connection type 'clearnet' or 'onion' has been chosen. \
Using default dist_build_sources_clearnet_or_onion=${under}clearnet${eunder}.
(Alternative value would be 'onion'.)${reset}"
      export dist_build_sources_clearnet_or_onion="clearnet"
   fi

   ## If there are input files (for example) that follow the options, they
   ## will remain in the "$@" positional parameters.

   if [ "$dist_build_internal_run" = "true" ]; then
      true
   else
      if [ "$build_machines_counter" -gt "1" ]; then
         echo "${red}${bold}You cannot use --flavor multiples times!${reset}"
         exit 1
      fi
   fi

   if [ "$build_machines_counter" -le "0" ]; then
      if [ "$dist_build_one_parsed" = "true" ]; then
         true
      elif [ "$dist_build_internal_run" = "true" ] ; then
         true
      else
         parse_cmd_flavor_error
      fi
   fi

   if [ "$dist_build_install_to_root" = "true" ]; then
      true
   elif [ "$dist_build_virtualbox" = "true" ]; then
      true
   elif [ "$dist_build_qcow2" = "true" ]; then
      true
   elif [ "$dist_build_utm" = "true" ]; then
      true
   elif [ "$dist_build_raw" = "true" ]; then
      true
   elif [ "$dist_build_installer_dist" = "true" ]; then
      true
   elif [ "$dist_build_windows_installer" = "true" ]; then
      true
   elif [ "$dist_build_iso" = "true" ]; then
      true
   elif [ "$dist_build_internal_run" = "true" ]; then
      true
   elif [ "$dist_build_source_archive" = "true" ]; then
      true
   else
      parse_cmd_target_error
   fi

   if [ "$dist_build_install_to_root" = "true" ]; then
      if [ "$build_target_counter" -gt "1" ]; then
         echo "${red}${bold}You can not combine --target root with other targets.${reset}"
         exit 1
      fi
   fi

   if [ "$dist_build_type" = "vm" ]; then
      true
   elif [ "$dist_build_type" = "host" ]; then
      true
   elif [ "$dist_build_internal_run" = "true" ]; then
      true
   elif [ "$dist_build_source_archive" = "true" ]; then
      true
   elif [ "$dist_build_installer_dist" = "true" ]; then
      true
   else
      echo "${red}${bold}You must add either:
'--type vm'
'--type host'
${reset}"
      exit 1
   fi
}

: "${BASH_SOURCE:=""}"
if [ "${BASH_SOURCE}" != "${0}" ]; then
   true "INFO $0: script was sourced."
else
   true "INFO $0: script was executed."
   dist_build_one_parse_cmd "$@"
fi
