commit ae1c8f14d6b4e874dc388bd9a352ce6c57ce8d09 Author: lurk Date: Fri Sep 20 18:48:39 2024 -0700 stole everything diff --git a/configure b/configure new file mode 100755 index 0000000..004581e --- /dev/null +++ b/configure @@ -0,0 +1,1652 @@ +#!/bin/bash +set -uo pipefail + + +################################################ +# Initialize script environment + +# Find the directory this script is stored in. (from: http://stackoverflow.com/questions/59895) +function get_source_dir() { + local source="${BASH_SOURCE[0]}" + while [[ -h $source ]]; do + local tmp + tmp="$(cd -P "$(dirname "${source}")" && pwd)" + source="$(readlink "${source}")" + [[ $source != /* ]] && source="${tmp}/${source}" + done + + echo -n "$(realpath "$(dirname "${source}")")" +} + +GENTOO_INSTALL_REPO_DIR="$(get_source_dir)" +export GENTOO_INSTALL_REPO_DIR +export GENTOO_INSTALL_REPO_SCRIPT_ACTIVE=true + +# shellcheck source=./scripts/utils.sh +source "$GENTOO_INSTALL_REPO_DIR/scripts/utils.sh" + +# Remember actual config file path +CONFIG_FILE="$(realpath "${1-"gentoo.conf"}" 2>/dev/null)" +RELA_CONFIG_FILE="$(realpath --relative-to="$(pwd)" "$CONFIG_FILE" 2>/dev/null)" + +# Check if help is requested +while [[ $# -gt 0 ]]; do + case "$1" in + ""|"help"|"--help"|"-help"|"-h") + echo "Usage: $0 [config]" + echo "Starts the gentoo configurator. If no file is given, it defaults to 'gentoo.conf'." + echo "If the file doesn't exist, the configurator loads default values, otherwise, the" + echo "the configuration is loaded into the configurator." + exit 0 + ;; + esac + shift +done + +check_wanted_programs dialog ncurses=ncursesw6-config + +# Determine whether EFI is available +HAS_EFI_SUPPORT=$([[ -d /sys/firmware/efi ]] && echo -n "true" || echo -n "false") +DEFAULT_BOOT_TYPE=$([[ $HAS_EFI_SUPPORT == true ]] && echo -n "efi" || echo -n "bios") +EFI_UNSUPPORTED_MESSAGE_SHORT="Missing EFI support on this system!" +EFI_UNSUPPORTED_MESSAGE="Apparently, your system does NOT support efi. Double-check before proceeding!" + +# Wrap dialog in two functions to prevent it from cluttering stderr. +function dialog_wrapper() { dialog_out=$(command dialog --colors "$@" 3>&2 2>&1 1>&3 3>&-); } +function dialog() { dialog_wrapper "$@" 2>&1; } + + +################################################ +# Configuration helper functions + +function get_timezone() { + local file + if file="$(readlink /etc/localtime)"; then + # /etc/localtime is a symlink as expected + local timezone + timezone=${file#*zoneinfo/} + if [[ $timezone == "$file" ]]; then + # not pointing to expected location or not Region/City + echo "Europe/London" + else + echo "$timezone" + fi + else + # compare files by contents + find /usr/share/zoneinfo -type f -exec cmp -s {} /etc/localtime \; -print \ + | sed -e 's,.*/zoneinfo/,,' \ + | head -1 + fi +} + +function get_default_keymap() { + local keymap + keymap="$(grep KEYMAP /etc/vconsole.conf 2>/dev/null || echo "KEYMAP=us")" + keymap="${keymap#KEYMAP=}" + + local map + for map in "${ALL_KEYMAPS[@]}"; do + if [[ $map == "$keymap" ]]; then + echo -n "${keymap}" + return + fi + done + + # Fallback to us + echo -n "us" +} + +function get_all_keymaps() { + ALL_KEYMAPS=() + local map + for map in $(find /usr/share/keymaps/ /usr/share/kbd/keymaps/ -type f -iname '*.map.gz' -printf "%f\n" 2>/dev/null | sort -u); do + ALL_KEYMAPS+=("${map%%.map.gz}") + done +} + +function get_all_timezones() { + readarray -t ALL_TIMEZONES < <(find /usr/share/zoneinfo -type f -printf "%P\n" | sort -u) +} + +function recalculate_locales() { + LOCALES="" + N_LOCALES=0 + + local selected_index_list="$SELECTED_LOCALES" + local next_selected + next_selected="${selected_index_list%% *}" + selected_index_list="${selected_index_list#* }" + + local i=0 + for item in "${SUPPORTED_LOCALES[@]}"; do + if [[ "$i" == "$next_selected" ]]; then + LOCALES="$LOCALES"$'\n'"$item" + next_selected="${selected_index_list%% *}" + selected_index_list="${selected_index_list#* }" + ((++N_LOCALES)) + fi + ((++i)) + done + + LOCALES="${LOCALES:1}" +} + +function define_disk_configuration_function() { + cat << EOF +function disk_configuration() { + $* ; +} +EOF +} + +function define_swap() { + if [[ $PARTITIONING_USE_SWAP == "true" ]]; then + echo -n "${PARTITIONING_SWAP@Q}" + else + echo -n "false" + fi +} + +function define_zfs_compression() { + if [[ $PARTITIONING_ZFS_USE_COMPRESSION != "false" ]]; then + echo -n "${PARTITIONING_ZFS_COMPRESSION@Q}" + else + echo -n "false" + fi +} + +function define_disk_layout() { + local swapdev + case "$PARTITIONING_SCHEME" in + "classic_single_disk") define_disk_configuration_function "create_classic_single_disk_layout swap=$(define_swap) type=${PARTITIONING_BOOT_TYPE@Q} luks=${PARTITIONING_USE_LUKS@Q} root_fs=${PARTITIONING_ROOT_FS@Q}" "${PARTITIONING_DEVICE@Q}" ;; + "existing_partitions") + if [[ "$PARTITIONING_USE_SWAP" ]]; then + swapdev=${PARTITIONING_SWAP_DEVICE:-false} + else + swapdev=false + fi + define_disk_configuration_function "create_existing_partitions_layout boot=${PARTITIONING_BOOT_DEVICE@Q} swap=${swapdev@Q} type=${PARTITIONING_BOOT_TYPE@Q}" "${PARTITIONING_DEVICE@Q}" ;; + "zfs_centric") define_disk_configuration_function "create_zfs_centric_layout swap=$(define_swap) type=${PARTITIONING_BOOT_TYPE@Q} encrypt=${PARTITIONING_ZFS_USE_ENCRYPTION@Q} compress=$(define_zfs_compression) pool_type=${PARTITIONING_ZFS_POOL_TYPE@Q}" "${PARTITIONING_DEVICES[@]@Q}" ;; + "btrfs_centric") define_disk_configuration_function "create_btrfs_centric_layout swap=$(define_swap) type=${PARTITIONING_BOOT_TYPE@Q} raid_type=${PARTITIONING_BTRFS_RAID_TYPE@Q} luks=${PARTITIONING_USE_LUKS@Q}" "${PARTITIONING_DEVICES[@]@Q}" ;; + "raid0_luks") define_disk_configuration_function "create_raid0_luks_layout swap=$(define_swap) type=${PARTITIONING_BOOT_TYPE@Q} luks=${PARTITIONING_USE_LUKS@Q} root_fs=${PARTITIONING_ROOT_FS@Q}" "${PARTITIONING_DEVICES[@]@Q}" ;; + "raid1_luks") define_disk_configuration_function "create_raid1_luks_layout swap=$(define_swap) type=${PARTITIONING_BOOT_TYPE@Q} luks=${PARTITIONING_USE_LUKS@Q} root_fs=${PARTITIONING_ROOT_FS@Q}" "${PARTITIONING_DEVICES[@]@Q}" ;; + "custom") + # Show current function declaration, trim trailing whitespace + declare -f disk_configuration \ + | sed -e 's/\s*$//' + ;; + esac +} + +ALL_GENTOO_ARCHS=("x86" "amd64" "arm" "arm64") +ALL_STAGE3_VARIANTS=( + "openrc" "openrc | Minimal OpenRC base (recommended)" + "desktop-openrc" "openrc-desktop | OpenRC, desktop profile, might have blockers" + "systemd" "systemd | Minimal systemd base (recommended)" + "systemd-mergedusr" "systemd-mergedusr | Minimal systemd base with merged filesystem layout" + "desktop-systemd" "systemd-desktop | systemd, desktop profile, might have blockers" + "nomultilib-openrc" "nomultilib-openrc | Minimal OpenRC base without 32bits support (Experimental)" + "nomultilib-systemd" "nomultilib-systemd | Minimal systemd base without 32bits support (Experimental)" + "nomultilib-systemd-mergedusr" "nomultilib-systemd-mergedusr | Minimal systemd base with merged filesystem layout and without 32bits support (Experimental)" + "x32-openrc" "x32-openrc | Minimal OpenRC base without 64bits support (Experimental)" + "x32-systemd" "x32-systemd | Minimal systemd base without 64bits support (Experimental)" + "x32-systemd-mergedusr" "x32-systemd-mergedusr | Minimal systemd base with merged filesystem layout and without 64bits support (Experimental)" + "llvm-openrc" "llvm-openrc | Minimal OpenRC base compiled with LLVM (Experimental)" + "llvm-systemd" "llvm-systemd | Minimal systemd base compiled with LLVM (Experimental)" + "llvm-systemd-mergedusr" "llvm-systemd-mergedusr | Minimal systemd base with merged filesystem layout compiled with LLVM (Experimental)" + "hardened-openrc" "hardened-openrc | Hardened OpenRC base (Experimental)" + "hardened-nomultilib-openrc" "hardened-nomultilib-openrc | Hardened OpenRC base without 32bits support (Experimental)" + "hardened-selinux-openrc" "hardened-selinux-openrc | Hardened OpenRC base with SELinux (Experimental)" + "hardened-nomultilib-selinux-openrc" "hardened-nomultilib-selinux-openrc | Hardened OpenRC base with SELinux and without 32bits support (Experimental)" + "musl" "musl-openrc | Minimal OpenRC base using musl (Experimental)" + "musl-llvm" "musl-llvm-openrc | Minimal OpenRC base using musl compiled with LLVM (Experimental)" + "musl-hardened" "musl-hardened-openrc | Hardened OpenRC base using musl (Experimental)" +) + +ALL_PARTITIONING_SCHEMES=( + "classic_single_disk" "Classic single disk layout (boot/efi, swap?, root)" + "existing_partitions" "Skip partitioning, use existing pre-formatted partitions" + "zfs_centric" "ZFS centric (optional ZFS compression and encryption)" + "btrfs_centric" "Btrfs centric (optional raid0/1 via btrfs)" + "raid0_luks" "Raid0 (N>=2 disks) and luks for root" + "raid1_luks" "Raid1 (N>=2 disks) and luks for root" + "custom" "Custom (expert option; edit the config manually later)" +) + +PARTITIONING_BOOT_TYPES=( + "efi" "efi$([[ $HAS_EFI_SUPPORT == true ]] && echo -n "" || echo -n " (!! $EFI_UNSUPPORTED_MESSAGE_SHORT !!)")" + "bios" "bios" +) +PARTITIONING_ROOT_FS_TYPES=("ext4" "btrfs") +PARTITIONING_BTRFS_RAID_TYPES=("raid0" "raid1") +PARTITIONING_ZFS_POOL_TYPES=("standard" "custom") +PARTITIONING_ZFS_COMPRESSIONS=("on" "gzip" "lz4" "lzjb" "zle" "zstd" "zstd-fast") + +PORTAGE_SYNC_TYPES=("git" "rsync") + +function create_single_disk_layout() { + create_classic_single_disk_layout "$@" +} + +function parse_swap() { + if [[ $1 == "false" ]]; then + PARTITIONING_USE_SWAP=false + PARTITIONING_SWAP=8GiB + else + PARTITIONING_USE_SWAP=true + PARTITIONING_SWAP="$1" + fi +} + +function parse_zfs_compression() { + if [[ $1 == "false" ]]; then + PARTITIONING_ZFS_USE_COMPRESSION=false + PARTITIONING_ZFS_COMPRESSION=zstd + else + PARTITIONING_ZFS_USE_COMPRESSION=true + PARTITIONING_ZFS_COMPRESSION="$1" + fi +} + +function create_classic_single_disk_layout() { + PARTITIONING_SCHEME="classic_single_disk" + + local known_arguments=('+swap' '?type' '?luks' '?root_fs') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICE="${extra_arguments[0]}" + parse_swap "${arguments[swap]}" + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_USE_LUKS="${arguments[luks]:-false}" + PARTITIONING_ROOT_FS="${arguments[root_fs]:-ext4}" +} + +function create_existing_partitions_layout() { + PARTITIONING_SCHEME="existing_partitions" + + local known_arguments=('+swap' '+boot' '?type') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICE="${extra_arguments[0]}" + if [[ "${arguments[swap]}" == "false" ]]; then + PARTITIONING_USE_SWAP=false + PARTITIONING_SWAP_DEVICE="" + else + PARTITIONING_USE_SWAP=true + PARTITIONING_SWAP_DEVICE="${arguments[swap]}" + fi + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_BOOT_DEVICE="${arguments[boot]}" +} + +function create_raid0_luks_layout() { + PARTITIONING_SCHEME="raid0_luks" + + local known_arguments=('+swap' '?type' '?luks' '?root_fs') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICES=("${extra_arguments[@]}") + parse_swap "${arguments[swap]}" + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_USE_LUKS="${arguments[luks]:-true}" + PARTITIONING_ROOT_FS="${arguments[root_fs]:-ext4}" +} + +function create_raid1_luks_layout() { + PARTITIONING_SCHEME="raid1_luks" + + local known_arguments=('+swap' '?type' '?luks' '?root_fs') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICES=("${extra_arguments[@]}") + parse_swap "${arguments[swap]}" + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_USE_LUKS="${arguments[luks]:-true}" + PARTITIONING_ROOT_FS="${arguments[root_fs]:-ext4}" +} + +function create_zfs_centric_layout() { + PARTITIONING_SCHEME="zfs_centric" + + local known_arguments=('+swap' '?type' '?pool_type' '?encrypt' '?compress') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICES=("${extra_arguments[@]}") + parse_swap "${arguments[swap]}" + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_ZFS_POOL_TYPE="${arguments[pool_type]:-standard}" + PARTITIONING_ZFS_USE_ENCRYPTION="${arguments[encrypt]:-false}" + parse_zfs_compression "${arguments[compress]:-false}" +} + +function create_btrfs_raid_layout() { + create_btrfs_centric_layout "$@" +} + +function create_btrfs_centric_layout() { + PARTITIONING_SCHEME="btrfs_centric" + + # shellcheck disable=SC2034 + local known_arguments=('+swap' '?type' '?raid_type' '?luks') + local extra_arguments=() + declare -A arguments; parse_arguments "$@" + + PARTITIONING_DEVICES=("${extra_arguments[@]}") + parse_swap "${arguments[swap]}" + PARTITIONING_BOOT_TYPE="${arguments[type]}" + PARTITIONING_USE_LUKS="${arguments[luks]:-false}" + PARTITIONING_BTRFS_RAID_TYPE="${arguments[raid_type]:-raid0}" +} + + +################################################ +# Configuration constants + +get_all_keymaps +get_all_timezones +readarray -t SUPPORTED_LOCALES < "$GENTOO_INSTALL_REPO_DIR/contrib/i18n_supported" +readarray -t LOCALE_A < <(locale -a) + + +################################################ +# Load/Default configuration + +function load_selected_locales() { + local sel_locales=() + local IFS=$'\n' + declare -A selected_by_name + for i in $LOCALES; do + selected_by_name["$i"]=true + done + + local i=0 + for item in "${SUPPORTED_LOCALES[@]}"; do + [[ "${selected_by_name[$item]:-}" == true ]] \ + && sel_locales+=("$i") + ((++i)) + done + + local IFS=" " + SELECTED_LOCALES="${sel_locales[*]}" +} + +function process_config() { + disk_configuration + + if [[ "$KEYMAP" == "$KEYMAP_INITRAMFS" ]]; then + KEYMAP_INITRAMFS_OTHER=false + else + KEYMAP_INITRAMFS_OTHER=true + fi + + load_selected_locales + recalculate_locales +} + +function load_config() { + # First load defaults, then replace by sourcing config. + load_default_config + + # Fallback to custom partitioning scheme if it isn't set in the actual config + PARTITIONING_SCHEME="custom" + + # Load settings + # shellcheck disable=SC1090 + source "$1" || die "Could not load given configuration." + + # After loading a config, no unsaved changes exist. + UNSAVED_CHANGES=false +} + +function load_default_config() { + HOSTNAME="gentoo" + TIMEZONE="$(get_timezone)" + KEYMAP="$(get_default_keymap)" + KEYMAP_INITRAMFS="$KEYMAP" + LOCALES="C.UTF-8 UTF-8" + LOCALE="C.UTF-8" + + SYSTEMD_NETWORKD=true + SYSTEMD_NETWORKD_INTERFACE_NAME="en*" + SYSTEMD_NETWORKD_DHCP=true + SYSTEMD_NETWORKD_ADDRESSES=("192.168.1.100/32" "fd00::1/64") + SYSTEMD_NETWORKD_GATEWAY="192.168.1.1" + SYSTEMD_INITRAMFS_SSHD=false + + function disk_configuration() { + #create_zfs_centric_layout swap=8GiB type="$DEFAULT_BOOT_TYPE" encrypt=true compress=zstd pool_type=standard /dev/sdX + create_classic_single_disk_layout swap=8GiB type="$DEFAULT_BOOT_TYPE" luks=true root_fs=ext4 /dev/sdX + } + + STAGE3_VARIANT="systemd" + PORTAGE_SYNC_TYPE="git" + PORTAGE_GIT_FULL_HISTORY=false + PORTAGE_GIT_MIRROR="https://anongit.gentoo.org/git/repo/sync/gentoo.git" + + GENTOO_MIRROR="https://mirror.eu.oneandone.net/linux/distributions/gentoo/gentoo" + GENTOO_ARCH="amd64" + + USE_PORTAGE_TESTING=true + SELECT_MIRRORS=false + SELECT_MIRRORS_LARGE_FILE=false + + ADDITIONAL_PACKAGES=() + ENABLE_SSHD=true + ENABLE_BINPKG=false + ROOT_SSH_AUTHORIZED_KEYS="" + + + # All settings are unsaved. + UNSAVED_CHANGES=true +} + +SAVE_AS_FILENAME="$RELA_CONFIG_FILE" +if [[ -e "$CONFIG_FILE" ]]; then + load_config "$CONFIG_FILE" +else + load_default_config +fi +process_config + + +################################################ +# Menu helpers and constants + +# $1: exit code +function clear_and_exit() { + dialog --clear + clear -x + exit "$1" +} + +function ellipsis() { + local len="$1" + shift + local str="$*" + if [[ "${#str}" -gt "$len" ]]; then + echo "${str:0:$len}…" + else + echo "$str" + fi +} + +function on_off_toggle() { + if [[ "${!1}" == true ]]; then + declare -g "$1"=false + else + declare -g "$1"=true + fi +} + +function on_off_str() { + if [[ "$1" == true ]]; then + echo -n "$2" + else + echo -n "$3" + fi +} + +function on_off_label() { + local prefix="${2:-}" + on_off_str "$1" "${prefix}[*]" "${prefix}[ ]" +} + +function on_off_label_inverted() { + local var=$1 + shift + on_off_label "$(is_on "$var" && echo false || echo true)" "$@" +} + +function is_on() { + [[ "$1" == true ]] +} + +function is_off() { + [[ "$1" != true ]] +} + +# if $1 is in $2.. +function one_of() { + local what="$1" + shift + for i in "$@"; do + [[ "$i" == "$what" ]] \ + && return 0 + done + return 1 +} + +# $1: title +# $2: description +# $3: space separated index list of selected items (e.g. "0 1 5 6") +# $@: all items +function menu_splitlist() { + local title="$1" + local description="$2" + local selected_index_list="$3" + shift 3 + + # Build option array + local items=() + local item + local i=0 + local next_selected="${selected_index_list%% *}" + local selected_index_list="${selected_index_list#* }" + for item in "$@"; do + if [[ "$i" == "$next_selected" ]]; then + items+=("$i" "$item" "on") + next_selected="${selected_index_list%% *}" + selected_index_list="${selected_index_list#* }" + else + items+=("$i" "$item" "off") + fi + ((++i)) + done + + # Show selection dialog + dialog \ + --title "$title" \ + --buildlist "$description\nUse ^ to focus the list of unselected items and $ to focus the list of selected items. Use to select/deselect an item and select by pressing when finished." \ + "${BUILDLIST_SIZE[@]}" "${items[@]}" + + local diag_exit=$? + if [[ $diag_exit == 0 ]]; then + # + return 0 + elif [[ $diag_exit == 1 ]]; then + # + return 1 + else + # + return 1 + fi +} + +# $1: title +# $2: description +# $3: default item +# $@: [tag label]... +function menu_radiolist_labeled() { + local title="$1" + local description="$2" + local default_item="$3" + shift 3 + + # Build option array + local items=() + local tag + local label + while [[ "$#" -gt 0 ]]; do + tag="$1" + label="$2" + shift 2 + + if [[ $tag == "$default_item" ]]; then + items+=("$tag" "$label" "on") + else + items+=("$tag" "$label" "off") + fi + done + + # Show selection dialog + dialog \ + --no-tags \ + --title "$title" \ + --help-button \ + --help-label "Select" \ + --help-status \ + --ok-label "OK" \ + --default-item "$default_item" \ + --default-button help \ + --radiolist "$description\nUse + local sel="${dialog_out#HELP }" + local sel_cur="${sel% *}" + #local sel_radio="${sel#* }" + dialog_out="$sel_cur" + return 0 + else + # + return 1 + fi +} + +# $1: title +# $2: description +# $3: default item +# $@: items +function menu_radiolist() { + local title="$1" + local description="$2" + local default_item="$3" + shift 3 + + # Build option array + local items=() + local item + for item in "$@"; do + if [[ $item == "$default_item" ]]; then + items+=("$item" "on") + else + items+=("$item" "off") + fi + done + + # Show selection dialog + dialog \ + --no-items \ + --title "$title" \ + --help-button \ + --help-label "Select" \ + --help-status \ + --ok-label "OK" \ + --default-item "$default_item" \ + --default-button help \ + --radiolist "$description\nUse + local sel="${dialog_out#HELP }" + local sel_cur="${sel% *}" + #local sel_radio="${sel#* }" + dialog_out="$sel_cur" + return 0 + else + # + return 1 + fi +} + +# $1: title +# $2: description +# $3: current device (will be canonicalized if possible) +function menu_select_device() { + local title="$1" + local desc="$2" + local prev_selected + prev_selected=$(canonicalize_device "$3") + + while true; do + local all_devices=() + for dev in /dev/disk/by-id/*; do + all_devices+=("$dev" "$(basename "$dev")") + done + all_devices+=("/dev/null" "") + + if menu_radiolist_labeled "$title" "$desc" "$prev_selected" "${all_devices[@]}"; then + if [[ "$dialog_out" == "/dev/null" ]]; then + while true; do + if dialog \ + --title "$1" \ + --inputbox "$([[ -e $prev_selected ]] || echo -n "\Z1The previously selected device $prev_selected does not exist!\Zn ")Enter the path of the desired device." \ + "${INPUTBOX_SIZE[@]}" "$prev_selected" + then + # Repeat until selected device exists or cancelled + prev_selected="$dialog_out" + [[ ! -e "$dialog_out" ]] && continue + return 0 + else + # -> return to previous menu + break + fi + done + + # Return to radiolist + continue + else + return 0 + fi + else + # + return 1 + fi + done +} + +function msgbox_help() { + dialog --msgbox "$1" "${HELP_POPUP_SIZE[@]}" +} + +function menu_exit() { + if [[ $UNSAVED_CHANGES == "true" ]]; then + dialog \ + --help-button --help-label "Back" \ + --yes-label "Save" --no-label "Discard" \ + --yesno "Do you want to save your configuration?\n(Press , or choose to continue gentoo configuration)." \ + "${CONFIRM_SIZE[@]}" + + local diag_exit="$?" + if [[ $diag_exit == 0 ]]; then + # + save "$CONFIG_FILE" + clear_and_exit 0 + elif [[ $diag_exit == 1 ]]; then + # + clear_and_exit 0 + else + # Back to menu (, ) + true + fi + else + # Nothing was changed. Exit immediately. + clear_and_exit 0 + fi +} + +function menu_save_as() { + dialog \ + --ok-label "Save" \ + --inputbox "Enter a filename to which this configuration should be saved.\n(Press , or choose to abort)." \ + "${INPUTBOX_SIZE[@]}" "$SAVE_AS_FILENAME" + + local diag_exit="$?" + if [[ $diag_exit == 0 ]]; then + # + SAVE_AS_FILENAME="$dialog_out" + save "$SAVE_AS_FILENAME" + UNSAVED_CHANGES=false + else + # Back to menu (, ) + true + fi +} + +function menu() { + local item + local item_tag + local tag_item_list=() + declare -A reverse_lookup + + # Create menu list + for item in "${MENU_ITEMS[@]}"; do + # Only if item is visible + "${item}_show" || continue + + item_tag="$("${item}_tag")" + tag_item_list+=("$item_tag" "$("${item}_label")") + reverse_lookup["$item_tag"]="$item" + done + + dialog --colors \ + --title "Gentoo configuration ($RELA_CONFIG_FILE)" \ + --extra-button --extra-label "Exit" \ + --help-button \ + --default-item "$SELECTED_MENU_ITEM" \ + --ok-label "Select" --cancel-label "Save" \ + --menu "This is the gentoo configuration menu. Read and adjust all options below carefully. Save your desired configuration and run ./install afterwards. Use if you want further information on any option." \ + "${MENU_SIZE[@]}" "${tag_item_list[@]}" + + local diag_exit="$?" + if [[ $diag_exit == 0 ]]; then + #