code:
#!/usr/bin/env bash
# shellcheck disable=SC1090,SC2155,SC2034
# SC1090: Can't follow non-constant source. Use a directive to specify location.
# SC2155 Declare and assign separately to avoid masking return values
# SC2034: foo appears unused. Verify it or export it.
set -eu

# Arch Linux Install Script Packages (alis-packages) installs software
# packages.
# Copyright (C) 2022 picodotdev

# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.

# This script is hosted at https://github.com/picodotdev/alis. For new features,
# improvements and bugs fill an issue in GitHub or make a pull request.
# Pull Request are welcome!
#
# If you test it in real hardware please send me an email to pico.dev@gmail.com with
# the machine description and tell me if somethig goes wrong or all works fine.
#
# Please, don't ask for support for this script in Arch Linux forums, first read
# the Arch Linux wiki [1], the Installation Guide [2] and the General
# Recomendations [3], later compare the commands with those of this script.
#
# [1] https://wiki.archlinux.org
# [2] https://wiki.archlinux.org/index.php/Installation_guide
# [3] https://wiki.archlinux.org/index.php/General_recommendations

# Installs packages in a Arch Linux system.
#
# Usage:
# # loadkeys es
# # curl -sL https://raw.githubusercontent.com/picodotdev/alis/master/download.sh | bash
# # vim alis-packages.conf
# # ./alis-packages.sh

PACKAGES_STANDALONE="false"

function init_config() {
    local COMMONS_FILE="alis-commons.sh"

    source "$COMMONS_FILE"
    if [ "$PACKAGES_STANDALONE" == "true" ]; then
        source "$COMMONS_CONF_FILE"
    fi
    source "$PACKAGES_CONF_FILE"
}

function sanitize_variables() {
    PACKAGES_PACMAN=$(sanitize_variable "$PACKAGES_PACMAN")
    PACKAGES_PACMAN_PIPEWIRE=$(sanitize_variable "$PACKAGES_PACMAN_PIPEWIRE")
    PACKAGES_FLATPAK=$(sanitize_variable "$PACKAGES_FLATPAK")
    PACKAGES_SDKMAN=$(sanitize_variable "$PACKAGES_SDKMAN")
    PACKAGES_AUR_COMMAND=$(sanitize_variable "$PACKAGES_AUR_COMMAND")
    PACKAGES_AUR=$(sanitize_variable "$PACKAGES_AUR")
    SYSTEMD_UNITS=$(sanitize_variable "$SYSTEMD_UNITS")
}

function check_variables() {
    check_variables_boolean "PACKAGES_PACMAN_INSTALL" "$PACKAGES_PACMAN_INSTALL"
    check_variables_boolean "PACKAGES_PACMAN_INSTALL_PIPEWIRE" "$PACKAGES_PACMAN_INSTALL_PIPEWIRE"
    check_variables_boolean "PACKAGES_FLATPAK_INSTALL" "$PACKAGES_FLATPAK_INSTALL"
    check_variables_boolean "PACKAGES_SDKMAN_INSTALL" "$PACKAGES_SDKMAN_INSTALL"
    check_variables_boolean "PACKAGES_AUR_INSTALL" "$PACKAGES_AUR_INSTALL"
    check_variables_list "PACKAGES_AUR_COMMAND" "$PACKAGES_AUR_COMMAND" "paru-bin yay-bin paru yay aurman" "true" "false"
}

function init() {
    if [ "$PACKAGES_STANDALONE" == "true" ]; then
        init_log_trace "$LOG_TRACE"
        init_log_file "$LOG_FILE" "$PACKAGES_LOG_FILE"
    fi
}

function facts() {
    print_step "facts()"

    facts_commons

    if [ -z "$USER_NAME" ]; then
        USER_NAME="$(whoami)"
    fi
}

function checks() {
    print_step "checks()"

    check_variables_value "USER_NAME" "$USER_NAME"

    if [ -n "$PACKAGES_PACMAN" ]; then
        execute_sudo "pacman -Syi $PACKAGES_PACMAN"
    fi

    if [ "$SYSTEM_INSTALLATION" == "false" ]; then
        ask_sudo
    fi
}

function ask_sudo() {
    sudo pwd >> /dev/null
}

function prepare() {
    print_step "prepare()"
}

function packages() {
    print_step "packages()"

    packages_pacman
    packages_flatpak
    packages_sdkman
    packages_aur
}

function packages_pacman() {
    print_step "packages_pacman()"

    if [ "$PACKAGES_PACMAN_INSTALL" == "true" ]; then
        local CUSTOM_REPOSITORIES="$(echo "$PACKAGES_PACMAN_CUSTOM_REPOSITORIES" | grep -E "^[^#]|\n^$"; exit 0)"
        if [ -n "$CUSTOM_REPOSITORIES" ]; then
            execute_sudo "echo -e \"# alis\n$CUSTOM_REPOSITORIES\" >> /etc/pacman.conf"
        fi

        if [ -n "$PACKAGES_PACMAN" ]; then
            pacman_install "$PACKAGES_PACMAN"
        fi

        if [[ ("$PACKAGES_PIPEWIRE" == "true" || "$PACKAGES_PACMAN_INSTALL_PIPEWIRE" == "true") && -n "$PACKAGES_PACMAN_PIPEWIRE" ]]; then
            if echo "$PACKAGES_PACMAN_PIPEWIRE" | grep -F -qw "pipewire-pulse"; then
                pacman_uninstall "pulseaudio pulseaudio-bluetooth"
            fi
            if echo "$PACKAGES_PACMAN_PIPEWIRE" | grep -F -qw "pipewire-alsa"; then
                pacman_uninstall "pulseaudio pulseaudio-alsa"
            fi
            if echo "$PACKAGES_PACMAN_PIPEWIRE" | grep -F -qw "wireplumber"; then
                pacman_uninstall "pipewire-media-session"
            fi
            if echo "$PACKAGES_PACMAN_PIPEWIRE" | grep -F -qw "pipewire-jack"; then
                pacman_uninstall "jack2"
            fi
            pacman_install "$PACKAGES_PACMAN_PIPEWIRE"
            #if [ -n "$(echo "$PACKAGES_PACMAN_PIPEWIRE" | grep -F -w "pipewire-pulse")" ]; then
            #    execute_user "$USER_NAME" "systemctl enable --user pipewire-pulse.service"
            #fi
        fi
    fi
}

function packages_flatpak() {
    print_step "packages_flatpak()"

    if [ "$PACKAGES_FLATPAK_INSTALL" == "true" ]; then
        pacman_install "flatpak"

        if [ -n "$PACKAGES_FLATPAK" ]; then
            execute_flatpak "flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo"

            flatpak_install "$PACKAGES_FLATPAK"
        fi
    fi
}

function packages_sdkman() {
    print_step "packages_sdkman()"

    if [ "$PACKAGES_SDKMAN_INSTALL" == "true" ]; then
        pacman_install "zip unzip"
        execute_user "$USER_NAME" "curl -s https://get.sdkman.io | bash"

        if [ -n "$PACKAGES_SDKMAN" ]; then
            execute_user "$USER_NAME" "sed -i 's/sdkman_auto_answer=.*/sdkman_auto_answer=true/g' /home/$USER_NAME/.sdkman/etc/config"
            sdkman_install "$PACKAGES_SDKMAN"
            execute_user "$USER_NAME" "sed -i 's/sdkman_auto_answer=.*/sdkman_auto_answer=false/g' /home/$USER_NAME/.sdkman/etc/config"
        fi
    fi
}

function packages_aur() {
    print_step "packages_aur()"

    if [ "$PACKAGES_AUR_INSTALL" == "true" ]; then
        local COMMANDS=()
        IFS=' ' read -ra COMMANDS <<< "$PACKAGES_AUR_COMMAND"
        for COMMAND in "${COMMANDS[@]}"
        do
            aur_command_install "$USER_NAME" "$COMMAND"
        done

        AUR_PACKAGE="${COMMANDS[0]}"

        case "${AUR_PACKAGE}" in
            "aurman" )
                AUR_COMMAND="aurman"
                ;;
            "yay" )
                AUR_COMMAND="yay"
                ;;
            "paru" )
                AUR_COMMAND="paru"
                ;;
            "yay-bin" )
                AUR_COMMAND="yay"
                ;;
            "paru-bin" | *)
                AUR_COMMAND="paru"
                ;;
        esac

        if [ -n "$PACKAGES_AUR" ]; then
            aur_install "$PACKAGES_AUR"
        fi
    fi
}

function flatpak_install() {
    local OPTIONS=""
    if [ "$SYSTEM_INSTALLATION" == "true" ]; then
        local OPTIONS="--system"
    fi

    local ERROR="true"
    local PACKAGES=()
    set +e
    IFS=' ' read -ra PACKAGES <<< "$1"
    for VARIABLE in {1..5}
    do
        local COMMAND="flatpak install $OPTIONS -y flathub ${PACKAGES[*]}"
        if ! execute_flatpak "$COMMAND"; then
            local ERROR="false"
            break
        else
            sleep 10
        fi
    done
    set -e
    if [ "$ERROR" == "true" ]; then
        return
    fi
}

function sdkman_install() {
    local ERROR="true"
    local PACKAGES=()
    local PACKAGE=""
    local I=()
    set +e
    IFS=' ' read -ra PACKAGES <<< "$1"
    for PACKAGE in "${PACKAGES[@]}"
    do
        IFS=':' read -ra I <<< "$PACKAGE"
        for VARIABLE in {1..5}
        do
            local COMMAND="source /home/$USER_NAME/.sdkman/bin/sdkman-init.sh && sdk install ${I[*]}"
            if ! execute_user "$USER_NAME" "$COMMAND"; then
                local ERROR="false"
                break
            else
                sleep 10
            fi
        done
    done
    set -e
    if [ "$ERROR" == "true" ]; then
        return
    fi
}

function end() {
    echo ""
    echo -e "${GREEN}Arch Linux packages installed successfully"'!'"${NC}"
    echo ""
}

function main() {
    local START_TIMESTAMP=$(date -u +"%F %T")
    set +u
    if [ "$COMMOMS_LOADED" != "true" ]; then
        PACKAGES_STANDALONE="true"
    fi
    set -u

    init_config
    execute_step "sanitize_variables"
    execute_step "check_variables"
    execute_step "init"
    execute_step "facts"
    execute_step "checks"
    execute_step "prepare"
    execute_step "packages"
    execute_step "systemd_units"
    local END_TIMESTAMP=$(date -u +"%F %T")
    local INSTALLATION_TIME=$(date -u -d @$(($(date -d "$END_TIMESTAMP" '+%s') - $(date -d "$START_TIMESTAMP" '+%s'))) '+%T')
    echo -e "Installation packages start ${WHITE}$START_TIMESTAMP${NC}, end ${WHITE}$END_TIMESTAMP${NC}, time ${WHITE}$INSTALLATION_TIME${NC}"
    execute_step "end"
}

main

"$@"


code:
#!/usr/bin/env bash
set -eu

# Arch Linux Install Script (alis) installs unattended, automated
# and customized Arch Linux system.
# Copyright (C) 2022 picodotdev

CONFIG_FILE="alis-packer.json"
BRANCH="master"
BRANCH_QUALIFIER=""
CONFIG_FILE_SH="alis-config-efi-ext4-systemd.sh"

while getopts "b:c:" arg; do
  case $arg in
    b)
      BRANCH="$OPTARG"
      ;;
    c)
      CONFIG_FILE_SH="$OPTARG"
      ;;
    *)
      echo "Unknown option: $arg"
      exit 1
      ;;
  esac
done

if [ "$BRANCH" == "sid" ]; then
  BRANCH_QUALIFIER="-sid"
fi

packer validate "packer/$CONFIG_FILE"
packer build -force -on-error=ask -var "branch=$BRANCH branch_qualifier=$BRANCH_QUALIFIER config_file_sh=$CONFIG_FILE_SH" "configs/$CONFIG_FILE"

repo_name: supersonicsataa/alis

license: mit


code:
#!/usr/bin/env bash
#shellcheck disable=SC1091
#SC1091: Can't follow non-constant source. Use a directive to specify location.
set -eu

# Arch Linux Install Script (alis) installs unattended, automated
# and customized Arch Linux system.
# Copyright (C) 2022 picodotdev

source "alis-commons.sh"

do_reboot


code:
#!/usr/bin/env bash
set -eu

# Arch Linux Install Script (alis) installs unattended, automated
# and customized Arch Linux system.
# Copyright (C) 2022 picodotdev

#curl -L -o asciinema-2.0.2.zip https://github.com/asciinema/asciinema/archive/v2.0.2.zip
#bsdtar xvf asciinema-2.0.2.zip
#rm -f alis.asciinema
#(cd asciinema-2.0.2 && python3 -m asciinema rec --stdin -i 5 ~/alis.asciinema)

rm -f alis-recovery.asciinema

pacman -Sy
pacman -S --noconfirm asciinema

clear
asciinema rec --stdin -i 5 ~/alis-recovery.asciinema


code:
#!/usr/bin/env bash
set -eu

# Arch Linux Install Script (alis) installs unattended, automated
# and customized Arch Linux system.
# Copyright (C) 2022 picodotdev

LOG_FILE="alis-recovery.log"
ASCIINEMA_FILE="alis-recovery.asciinema"

function copy_logs() {
    if [ -f "$LOG_FILE" ]; then
        SOURCE_FILE="$LOG_FILE"
        FILE="${MNT_DIR}/var/log/alis/$LOG_FILE"

        mkdir -p "${MNT_DIR}/var/log/alis"
        cp "$SOURCE_FILE" "$FILE"
        chown root:root "$FILE"
        chmod 600 "$FILE"
    fi
    if [ -f "$ASCIINEMA_FILE" ]; then
        SOURCE_FILE="$ASCIINEMA_FILE"
        FILE="${MNT_DIR}/var/log/alis/$ASCIINEMA_FILE"

        mkdir -p "${MNT_DIR}/var/log/alis"
        cp "$SOURCE_FILE" "$FILE"
        chown root:root "$FILE"
        chmod 600 "$FILE"
    fi
}

function do_reboot() {
    umount -R "${MNT_DIR}"/boot
    umount -R "${MNT_DIR}"
    reboot
}

copy_logs
do_reboot


code:
# Arch Linux Install Script (alis) configuration file
#
# Some variables values are preceded by a ! character, this means that the value is ignored.
# Some variables accept a single value others accept multiple values as annotated in the comments.
# Some variables are boolean with a value of true or false.
#
# Read the Arch Linux wiki pages to learn more about the variables values.
# https://github.com/picodotdev/alis/blob/master/README.md

# init
## KEYS sets keyboard layout.
## LOG_TRACE outputs the comands executed.
## LOG_FILE generates a log file with the commands executed and output generated during installation.
### The log file is saved to /var/log/alis-recovery.log.
KEYS="us"
LOG_TRACE="true"
LOG_FILE="false"

# partition
## DEVICE sets which is the device for the installation. auto autodetects the device.
## DEVICE_TRIM sets if the DEVICE device supports TRIM feature.
## LVM sets if the DEVICE is partitioned with LVM partition scheme.
## LUKS_PASSWORD and LUKS_PASSWORD_RETYPE if set is the password for encrypt the device. With LVM, LVM on LUKS is used. If "ask" password alis asks for a secure password.
## FILE_SYSTEM_TYPE root device is formatted with this file system type.
## BTRFS_SUBVOLUMES_MOUNTPOINTS allows to customize btrfs file system subvolumes mountpoints. swap sobvolume is created only if swap file is created (only if there is SWAP_SIZE value).
### Format ("name,subvolume,mount_point")
## FILE_SYSTEM_TYPE root device is formatted with this file system type.
## PARTITION_MODE how partition is performed on DEVICE.
## PARTITION_MOUNT_POINTS mount points, partition number and directory, to mount from DEVICE.
DEVICE="/dev/sda"
DEVICE_TRIM="false"
LVM="false"
LUKS_PASSWORD=""
LUKS_PASSWORD_RETYPE=""
FILE_SYSTEM_TYPE="btrfs" # (single)
BTRFS_SUBVOLUMES_MOUNTPOINTS=("root,root,/" "home,home,/home" "var,var,/var" "snapshots,snapshots,/snapshots" "swap,swap,/swap")
#BTRFS_SUBVOLUMES_MOUNTPOINTS=("root,@,/" "home,@home,/home" "var,@var_log,/var/log" "snapshots,@snapshots,/.snapshots" "swap,@swap,/swap")
SWAP_SIZE="4096" # (single)
PARTITION_MODE="auto"
PARTITION_MOUNT_POINTS=("1=/boot" "2=/" "!3=/home")

# network_install
## Variables to setup the WIFI connection to internet.
## The WIFI interface, WIFI ESSID identifier and WIFI password must be specified. If "ask" password alis asks for a secure password.
## PING_HOSTNAME is the host to check the internet connection.
WIFI_INTERFACE="wlan0"
WIFI_ESSID="LinksysB"
WIFI_KEY="ask"
WIFI_HIDDEN="false"
PING_HOSTNAME="mirrors.kernel.org"

# chroot
## CHROOT sets if arch-chroot ${MNT_DIR} command is executed after partitions mounted to start recovery
CHROOT="false"


code:
#!/usr/bin/env bash
# shellcheck disable=SC1090,SC2153,SC2155,SC2034
#SC1090: Can't follow non-constant source. Use a directive to specify location.
#SC2153: Possible Misspelling: MYVARIABLE may not be assigned. Did you mean MY_VARIABLE?
#SC2155 Declare and assign separately to avoid masking return values
#SC2034: foo appears unused. Verify it or export it.
set -eu

# Arch Linux Install Script Recovery (alis-recovery) start a recovery for an
# failed installation or broken system.
# Copyright (C) 2022 picodotdev

# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.

# This script is hosted at https://github.com/picodotdev/alis. For new features,
# improvements and bugs fill an issue in GitHub or make a pull request.
# Pull Request are welcome!
#
# If you test it in real hardware please send me an email to pico.dev@gmail.com with
# the machine description and tell me if somethig goes wrong or all works fine.
#
# Please, don't ask for support for this script in Arch Linux forums, first read
# the Arch Linux wiki [1], the Installation Guide [2] and the General
# Recomendations [3], later compare the commands with those of this script.
#
# [1] https://wiki.archlinux.org
# [2] https://wiki.archlinux.org/index.php/Installation_guide
# [3] https://wiki.archlinux.org/index.php/General_recommendations

# Starts the reccovery of a Arch Linux system installed with alis.
#
# Usage:
# # loadkeys es
# # curl -sL https://raw.githubusercontent.com/picodotdev/alis/master/download.sh | bash
# # vim alis-recovery.conf
# # ./alis-recovery.sh

function init_config() {
    local COMMONS_FILE="alis-commons.sh"

    source "$COMMONS_FILE"
    source "$COMMONS_CONF_FILE"
    source "$RECOVERY_CONF_FILE"
}

function sanitize_variables() {
    DEVICE=$(sanitize_variable "$DEVICE")
    FILE_SYSTEM_TYPE=$(sanitize_variable "$FILE_SYSTEM_TYPE")
    PARTITION_MODE=$(sanitize_variable "$PARTITION_MODE")
    SWAP_SIZE=$(sanitize_variable "$SWAP_SIZE")
    PARTITION_CUSTOMMANUAL_BOOT=$(sanitize_variable "$PARTITION_CUSTOMMANUAL_BOOT")
    PARTITION_CUSTOMMANUAL_ROOT=$(sanitize_variable "$PARTITION_CUSTOMMANUAL_ROOT")

    for I in "${BTRFS_SUBVOLUMES_MOUNTPOINTS[@]}"; do
        IFS=',' read -ra SUBVOLUME <<< "$I"
        if [ "${SUBVOLUME[0]}" == "root" ]; then
            BTRFS_SUBVOLUME_ROOT=("${SUBVOLUME[@]}")
        elif [ "${SUBVOLUME[0]}" == "swap" ]; then
            BTRFS_SUBVOLUME_SWAP=("${SUBVOLUME[@]}")
        fi
    done

    for I in "${PARTITION_MOUNT_POINTS[@]}"; do
        IFS='=' read -ra PARTITION_MOUNT_POINT <<< "$I"
        if [ "${PARTITION_MOUNT_POINT[1]}" == "/boot" ]; then
            PARTITION_BOOT_NUMBER="${PARTITION_MOUNT_POINT[0]}"
        elif [ "${PARTITION_MOUNT_POINT[1]}" == "/" ]; then
            PARTITION_ROOT_NUMBER="${PARTITION_MOUNT_POINT[0]}"
        fi
    done
}

function check_variables() {
    check_variables_value "KEYS" "$KEYS"
    check_variables_boolean "LOG_TRACE" "$LOG_TRACE"
    check_variables_boolean "LOG_FILE" "$LOG_FILE"
    check_variables_value "DEVICE" "$DEVICE"
    if [ "$DEVICE" == "auto" ]; then
        local DEVICE_BOOT=$(lsblk -oMOUNTPOINT,PKNAME -P -M | grep 'MOUNTPOINT="/run/archiso/bootmnt"' | sed 's/.*PKNAME="\(.*\)".*/\1/')
        if [ -n "$DEVICE_BOOT" ]; then
            local DEVICE_BOOT="/dev/$DEVICE_BOOT"
        fi
        local DEVICE_DETECTED="false"
        if [ -e "/dev/sda" ] && [ "$DEVICE_BOOT" != "/dev/sda" ]; then
            if [ "$DEVICE_DETECTED" == "true" ]; then
                echo "Auto device is ambigous, detected $DEVICE and /dev/sda."
                exit 1
            fi
            DEVICE_DETECTED="true"
            DEVICE_SDA="true"
            DEVICE="/dev/sda"
        fi
        if [ -e "/dev/nvme0n1" ] && [ "$DEVICE_BOOT" != "/dev/nvme0n1" ]; then
            if [ "$DEVICE_DETECTED" == "true" ]; then
                echo "Auto device is ambigous, detected $DEVICE and /dev/nvme0n1."
                exit 1
            fi
            DEVICE_DETECTED="true"
            DEVICE_NVME="true"
            DEVICE="/dev/nvme0n1"
        fi
        if [ -e "/dev/vda" ] && [ "$DEVICE_BOOT" != "/dev/vda" ]; then
            if [ "$DEVICE_DETECTED" == "true" ]; then
                echo "Auto device is ambigous, detected $DEVICE and /dev/vda."
                exit 1
            fi
            DEVICE_DETECTED="true"
            DEVICE_VDA="true"
            DEVICE="/dev/vda"
        fi
        if [ -e "/dev/mmcblk0" ] && [ "$DEVICE_BOOT" != "/dev/mmcblk0" ]; then
            if [ "$DEVICE_DETECTED" == "true" ]; then
                echo "Auto device is ambigous, detected $DEVICE and /dev/mmcblk0."
                exit 1
            fi
            DEVICE_DETECTED="true"
            DEVICE_MMC="true"
            DEVICE="/dev/mmcblk0"
        fi
    fi
    check_variables_boolean "DEVICE_TRIM" "$DEVICE_TRIM"
    check_variables_boolean "LVM" "$LVM"
    check_variables_equals "LUKS_PASSWORD" "LUKS_PASSWORD_RETYPE" "$LUKS_PASSWORD" "$LUKS_PASSWORD_RETYPE"
    check_variables_list "FILE_SYSTEM_TYPE" "$FILE_SYSTEM_TYPE" "ext4 btrfs xfs f2fs reiserfs" "true" "true"
    check_variables_size "BTRFS_SUBVOLUME_ROOT" ${#BTRFS_SUBVOLUME_ROOT[@]} 3
    check_variables_list "BTRFS_SUBVOLUME_ROOT" "${BTRFS_SUBVOLUME_ROOT[2]}" "/" "true" "true"
    if [ -n "$SWAP_SIZE" ]; then
        check_variables_size "BTRFS_SUBVOLUME_SWAP" ${#BTRFS_SUBVOLUME_SWAP[@]} 3
    fi
    for I in "${BTRFS_SUBVOLUMES_MOUNTPOINTS[@]}"; do
        IFS=',' read -ra SUBVOLUME <<< "$I"
        check_variables_size "SUBVOLUME" ${#SUBVOLUME[@]} 3
    done
    check_variables_list "PARTITION_MODE" "$PARTITION_MODE" "auto custom manual" "true" "true"
    check_variables_value "PARTITION_BOOT_NUMBER" "$PARTITION_BOOT_NUMBER"
    check_variables_value "PARTITION_ROOT_NUMBER" "$PARTITION_ROOT_NUMBER"
    check_variables_boolean "CHROOT" "$CHROOT"
}

function warning() {
    echo -e "${BLUE}Welcome to Arch Linux Install Script Recovery${NC}"
    echo ""
    read -r -p "Do you want to continue? [y/N] " yn
    case $yn in
        [Yy]* )
            ;;
        [Nn]* )
            exit
            ;;
        * )
            exit
            ;;
    esac
}

function init() {
    print_step "init()"

    init_log_trace "$LOG_TRACE"
    init_log_file "$LOG_FILE" "$RECOVERY_LOG_FILE"
    loadkeys "$KEYS"
}

function facts() {
    print_step "facts()"

    facts_commons

    if echo "$DEVICE" | grep -q "^/dev/sd[a-z]"; then
        DEVICE_SDA="true"
    elif echo "$DEVICE" | grep -q "^/dev/nvme"; then
        DEVICE_NVME="true"
    elif echo "$DEVICE" | grep -q "^/dev/vd[a-z]"; then
        DEVICE_VDA="true"
    elif echo "$DEVICE" | grep -q "^/dev/mmc"; then
        DEVICE_MMC="true"
    fi
}

function prepare() {
    print_step "prepare()"

    prepare_partition
    configure_network
    ask_passwords
}

function prepare_partition() {
    if [ -d "${MNT_DIR}"/boot ]; then
        umount "${MNT_DIR}"/boot
        umount "${MNT_DIR}"
    fi
    if [ -e "/dev/mapper/$LVM_VOLUME_GROUP-$LVM_VOLUME_LOGICAL" ]; then
        umount "/dev/mapper/$LVM_VOLUME_GROUP-$LVM_VOLUME_LOGICAL"
    fi
    if [ -e "/dev/mapper/$LUKS_DEVICE_NAME" ]; then
        cryptsetup close "$LUKS_DEVICE_NAME"
    fi
    partprobe $DEVICE
}

function ask_passwords() {
    if [ "$LUKS_PASSWORD" == "ask" ]; then
        PASSWORD_TYPED="false"
        while [ "$PASSWORD_TYPED" != "true" ]; do
            read -r -sp 'Type LUKS password: ' LUKS_PASSWORD
            echo ""
            read -r -sp 'Retype LUKS password: ' LUKS_PASSWORD_RETYPE
            echo ""
            if [ "$LUKS_PASSWORD" == "$LUKS_PASSWORD_RETYPE" ]; then
                PASSWORD_TYPED="true"
            else
                echo "LUKS password don't match. Please, type again."
            fi
        done
    fi
}

function partition() {
    print_step "partition()"

    # setup
    partition_setup

    # luks and lvm
    if [ -n "$LUKS_PASSWORD" ]; then
        echo -n "$LUKS_PASSWORD" | cryptsetup --key-file=- open "$PARTITION_ROOT" "$LUKS_DEVICE_NAME"
        sleep 5
    fi

    if [ -n "$LUKS_PASSWORD" ]; then
        DEVICE_ROOT="/dev/mapper/$LUKS_DEVICE_NAME"
    fi
    if [ "$LVM" == "true" ]; then
        DEVICE_ROOT="/dev/mapper/$LVM_VOLUME_GROUP-$LVM_VOLUME_LOGICAL"
    fi

    # options
    partition_options

    # mount
    partition_mount
}

function recovery() {
    arch-chroot "${MNT_DIR}"
}

function end() {
    echo ""
    if [ "$CHROOT" == "false" ]; then
        echo -e "${GREEN}Recovery started.${NC}"
    else
        echo -e "${GREEN}Recovery ended.${NC}"
    fi
    echo "You must do an explicit reboot after finalize recovery (exit if in arch-chroot, ./alis-reboot.sh)."
    echo ""
}

function main() {
    init_config
    sanitize_variables
    check_variables
    warning
    init
    facts
    prepare
    partition
    if [ "$CHROOT" == "true" ]; then
        recovery
    fi
    end
}

main


code:
# Arch Linux Install Script (alis) configuration file
#
# Some variables values are preceded by a ! character, this means that the value is ignored.
# Some variables accept a single value others accept multiple values as annotated in the comments.
# Some variables are boolean with a value of true or false.
#
# Read the Arch Linux wiki pages to learn more about the variables values.
# https://github.com/picodotdev/alis/blob/master/README.md

# init
## KEYS sets keyboard layout.
## LOG_TRACE outputs the comands executed.
## LOG_FILE generates a log file with the commands executed and output generated during installation.
### The log file is saved to /var/log/alis.log.
KEYS="us"
LOG_TRACE="true"
LOG_FILE="false"

# partition
## DEVICE sets which is the device for the installation. auto autodetects the device.
## DEVICE_TRIM sets if the DEVICE device supports TRIM feature.
## LVM sets if the DEVICE is partitioned with LVM partition scheme.
## LUKS_PASSWORD and LUKS_PASSWORD_RETYPE if set is the password for encrypt the device. With LVM, LVM on LUKS is used. If "ask" password alis asks for a secure password.
## FILE_SYSTEM_TYPE root device is formatted with this file system type.
## BTRFS_SUBVOLUMES_MOUNTPOINTS allows to customize btrfs file system subvolumes mountpoints. swap sobvolume is created only if swap file is created (only if there is SWAP_SIZE value).
### Format ("name,subvolume,mount_point")
## SWAP_SIZE swap file size with a size of the value in megabytes. If no value no swap file is created.
## PARTITION_MODE how partition is performed on DEVICE.
### "auto" value deletes all existing partitions and creates a boot partition and a root partition using disk full size.
### Warning! all disk data will be lost, so backup existing data before.
### "custom" value allows to use a custom parted partition script.
### "manual" allows to specify which existing partitions are used for boot partition and root partition.
## PARTITION_MOUNT_POINTS mount points, partition number and directory, to mount from DEVICE.
DEVICE="/dev/sda" # sata nvme mmc (single)
DEVICE_TRIM="false"
LVM="false"
LUKS_PASSWORD=""
LUKS_PASSWORD_RETYPE=""
FILE_SYSTEM_TYPE="btrfs" # (single)
BTRFS_SUBVOLUMES_MOUNTPOINTS=("root,root,/" "home,home,/home" "var,var,/var" "snapshots,snapshots,/snapshots" "swap,swap,/swap")
#BTRFS_SUBVOLUMES_MOUNTPOINTS=("root,@,/" "home,@home,/home" "var,@var_log,/var/log" "snapshots,@snapshots,/.snapshots" "swap,@swap,/swap")
SWAP_SIZE="4096" # (single)
PARTITION_MODE="auto"
PARTITION_MOUNT_POINTS=("1=/boot" "2=/" "!3=/home")
PARTITION_CUSTOM_PARTED_UEFI="mklabel gpt mkpart ESP fat32 1MiB 512MiB mkpart root $FILE_SYSTEM_TYPE 512MiB 100% set 1 esp on"
PARTITION_CUSTOM_PARTED_BIOS="mklabel msdos mkpart primary ext4 4MiB 512MiB mkpart primary $FILE_SYSTEM_TYPE 512MiB 100% set 1 boot on"

# network_install
## Variables to setup the WIFI connection to internet.
## The WIFI interface, WIFI ESSID identifier and WIFI password must be specified. If "ask" password alis asks for a secure password.
## PING_HOSTNAME is the host to check the internet connection.
WIFI_INTERFACE="wlan0"
WIFI_ESSID="LinksysB"
WIFI_KEY="ask"
WIFI_KEY_RETYPE="ask"
PING_HOSTNAME="mirrors.kernel.org"

# install
## REFLECTOR allows to use reflector utility to use the best mirrors for packages download.
## REFLECTOR_COUNTRIES is an array of countries to select mirrors from.
## PACMAN_MIRROR if reflector is not used this specific mirror is used.
## PACMAN_PARALLEL_DOWNLOADS configures pacman to use parallel downloads, set to false on slow internet connections and disable timeouts.
## KERNELS additional kernels and headers to install.
## KERNELS_COMPRESSION selects the algorithm for kernel compression.
## KERNELS_PARAMETERS specific kernel parameters to set on boot. eg. iommu=soft
REFLECTOR="true"
REFLECTOR_COUNTRIES=("United States")
PACMAN_MIRROR="https://mirrors.kernel.org/archlinux/\$repo/os/\$arch"
PACMAN_PARALLEL_DOWNLOADS="true"
KERNELS="linux-zen linux-zen-headers" # (multiple)
KERNELS_COMPRESSION="zstd"
KERNELS_PARAMETERS="!iommu=soft !nvme_load=YES"

# aur
## AUR_PACKAGE the AUR command to install in case some package requires it, only is installed if necessary.
AUR_PACKAGE="yay" # (single)

# display driver
## DISPLAY_DRIVER installs a specific display driver, you must know which brand is the graphics hardware.
### With auto value intel driver is used for Intel brand, amdgpu driver for AMD brand and nvidia driver for NVIDIA brand.
### Other variables activates some features if are supported for the DISPLAY_DRIVER.
## KMS add support for kernel mode setting
## FASTBOOT, FRAMEBUFFER_COMPRESSION for intel graphics.
## DISPLAY_DRIVER_DDX add DDX driver which provides 2D acceleration in Xorg.
## VULKAN add support for Vulkan.
## DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION, DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION_INTEL add support for hardware video acceleration
DISPLAY_DRIVER="intel" # (single)
KMS="true"
FASTBOOT="true"
FRAMEBUFFER_COMPRESSION="true"
DISPLAY_DRIVER_DDX="false"
VULKAN="true"
DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION="true"
DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION_INTEL="intel-media-driver" # (single)

# config
## Some variables for system configuration, from timezone, locale and keyboard to the root password.
## KEYLAYOUT, KEYMODEL, KEYVARIANT, KEYOPTIONS see https://wiki.archlinux.org/title/X_keyboard_extension#Preset_configuration
## KEYMAP, FONT, FONT_MAP see https://man.archlinux.org/man/vconsole.conf.5
## ROOT_PASSWORD root user password. If "ask" password alis asks for a secure password.
TIMEZONE="/usr/share/zoneinfo/Europe/Madrid"
LOCALES=("en_US.UTF-8 UTF-8")
LOCALE_CONF=("LANG=en_US.UTF-8" "LANGUAGE=en_US:en")
KEYLAYOUT="qwerty"
KEYMODEL=""
KEYVARIANT=""
KEYOPTIONS=""
KEYMAP="us"
FONT=""
FONT_MAP=""
HOSTNAME="SusBook G4"
ROOT_PASSWORD="ask"
ROOT_PASSWORD_RETYPE="ask"

# user
## USER_NAME, USER_PASSWORD Regular user to create in the system. A password must be specified, if "ask" password alis asks for a secure password.
## ADDITIONAL_USERS is an array of additional users to create in the system, if "ask" password alis asks for a secure password.
USER_NAME="sparks"
USER_PASSWORD="ask"
USER_PASSWORD_RETYPE="ask"
ADDITIONAL_USERS=() # eg. ("user1=password1" "user2=password2")

## systemd-homed
### SYSTEMD_HOMED "true" value requires interactivity to set user password
SYSTEMD_HOMED="false"
SYSTEMD_HOMED_STORAGE="!auto !luks !subvolume directory !fscrypt !cifs"
SYSTEMD_HOMED_STORAGE_LUKS_TYPE="auto !ext4 !btrfs !xfs"
SYSTEMD_HOMED_STORAGE_CIFS_DOMAIN=""
SYSTEMD_HOMED_STORAGE_CIFS_SERVICE=""

# mkinitcpio
## HOOKS are the system hooks to execute to build the initial ramdisk.
## MODULES are used to specify the modules to load before anything to execute to build the initial ramdisk.
### Generally, it is not necessary to modify, alis enables or disables some hooks
### taking in account other variables values like bootloader or device encryption.
HOOKS="base !udev !usr !resume !systemd !btrfs autodetect keyboard !keymap !consolefont !sd-vconsole modconf block !net !dmraid !mdadm !mdadm_udev !encrypt !sd-encrypt !lvm2 fsck filesystems"
MODULES="!vmd !tpm"

# bootloader
## BOOTLOADER system boot loader.
### With auto value grub is used for BIOS system, systemd for UEFI system.
BOOTLOADER="systemd" # (single)

# shell
## CUSTOM_SHELL configures an alternative custom shell interpreter.
CUSTOM_SHELL="fish" # (single)

# desktop
## DESKTOP_ENVIRONMENT desktop environment to install.
## DISPLAY_MANAGER display manager to install and enable. With auto a default DM will be choosed based on the selected DE.
DESKTOP_ENVIRONMENT="kde" # (single)
DISPLAY_MANAGER="sddm" # (single)

# packages
## PACKAGES_MULTILIB configures multilib repository for pacman and install multilib packages for display driver.
## PACKAGES_INSTALL installs packages on system installation, edit alis-packages.conf to select packages.
## PACKAGES_PIPEWIRE installs PipeWire replacing PulseAudio, requires PACKAGES_INSTALL="true".
### It is recommended to install packages after base installation and reboot.
PACKAGES_MULTILIB="true"
PACKAGES_INSTALL="true"
PACKAGES_PIPEWIRE="true"

# provision
## PROVISION provisions the files placed in files directory on the installed system (preserving directory structure). This is useful to copy some configuration files.
PROVISION="false"

# misc
## VAGRANT for build a VirtualBox OVA with Packer
VAGRANT="false"

# systemd
## SYSTEMD_UNITS systemd units to enable or disable.
### If preceded with a "+" unit is enabled, if preceded with "-" unit is disabled, if preceded with "!" unit is ignored (no action is performed).
### eg. "+ufw.service" to enable, "-ufw.service" to disable, "!ufw.service" to ignore
SYSTEMD_UNITS=""

# reboot
## REBOOT on installation end reboots the system automatically. If "false" no reboot is performed and the user must do it explicitly.
REBOOT="true"