scripts/bash/pt_pwnbox.sh
#!/usr/bin/env bash

### BEGIN SCRIPT HEADER
SCRIPT_PATH=$(readlink -f "${BASH_SOURCE[0]}")
SCRIPT_NAME=$(basename "${SCRIPT_PATH}")
DIR_SCRIPT=$(dirname "${SCRIPT_PATH}")
COMMON="${DIR_SCRIPT}/common.sh"
source "$COMMON" || exit
### END SCRIPT HEADER

ACTION_INSTALL="install"
ACTION_DELETE="delete"
ACTION_LIST="list"
ACTION_UPDATE="update"
ACTION_UPGRADE="upgrade"
ACTION_REBUILD="rebuild"

### BEGIN COMMON
function print_usage_and_exit() {
    print_info "Usage: ${SCRIPT_NAME} <${ACTION_INSTALL}|${ACTION_UPDATE}|${ACTION_REBUILD}|${ACTION_LIST}|${ACTION_DELETE}>"
    exit
}

check_argc $# 1 || print_usage_and_exit
### END COMMON

NIXOS_UNSTABLE_CHANNEL_URL="https://nixos.org/channels/nixos-unstable"
HOME_MANAGER_CHANNEL_URL="https://github.com/nix-community/home-manager/archive/master.tar.gz"

DIR_SCRIPTS_PATH=$(dirname "${DIR_SCRIPT}")
DIR_ROOT_PATH=$(dirname "${DIR_SCRIPTS_PATH}")
CONFIG_FILE="pwnbox.nix"
CONFIG_PATH="${DIR_ROOT_PATH}/install/${CONFIG_FILE}"

function helper_add_channels() {
    print_info "Adding channels..."
    nix-channel --add $NIXOS_UNSTABLE_CHANNEL_URL nixos
    nix-channel --add $HOME_MANAGER_CHANNEL_URL home-manager || return 1
    return 0
}

function helper_update_channels() {
    test_command_exists nix-channel || return 1
    print_info "Updating channels..."
    nix-channel --update || return 2
    return 0
}

function helper_update_pipx() {
    test_command_exists pipx || return 0 # Return if pipx is not installed
    current_user=$(whoami)
    if [ $SUDO_USER ]; then current_user=$SUDO_USER; fi
    sudo -u "${current_user}" pipx list >/dev/null 2>&1
    if [ $? -eq 0 ]
    then
        print_info "Updating pipx packages as user '${current_user}'..."
        sudo -u "${current_user}" pipx upgrade-all || return 1
    else
        # Python interpreter path is probably broken, so reinstall
        print_warning "One or more packages seem to be broken."
        print_info "Reinstalling pipx packages as user '${current_user}'..."
        sudo -u "${current_user}" rm -rf "/home/${current_user}/.local/pipx/shared"
        sudo -u "${current_user}" pipx reinstall-all || return 1
    fi
    return 0
}

function helper_rebuild() {
    test_command_exists nixos-rebuild || return 1
    print_info "Applying new configuration..."
    nixos-rebuild switch -I nixos-config="${1}" || return 2
    return 0
}

function helper_delete_old() {
    test_command_exists nix-collect-garbage || return 1
    if [ $# -ge 1 ];
    then
        print_info "Deleting old configurations..."
        nb_days_arg="${1}d"
    else
        print_info "Deleting configurations older than 30 days..."
        nb_days_arg="30d" # older than 30 days by default
    fi
    nix-collect-garbage --delete-older-than "${nb_days_arg}" || return 2
    return 0
}

function helper_list() {
    nixos-rebuild list-generations || return 1
    return 0
}

function action_install() {
    helper_add_channels || return 1
    helper_update_channels || return 2
    helper_rebuild "${1}" || return 3
    return 0
}

function action_update() {
    helper_rebuild "${1}" || return 1
    helper_update_channels || return 2
    helper_rebuild "${1}" || return 3
    helper_delete_old || return 4
    helper_update_pipx || return 5
    return 0
}

function action_rebuild() {
    helper_rebuild "${1}" || return 1
    return 0
}

function action_list() {
    helper_list || return 1
    return 0
}

function action_delete() {
    if [ -z "${1}" ];
    then
        helper_delete_old || return 1
    else
        helper_delete_old "${1}" || return 1
    fi
    return 0
}

test_is_root || exit 1
test_file_exists $CONFIG_PATH || exit 2

case $1 in

    $ACTION_INSTALL)
        action_install "${CONFIG_PATH}" || exit 3
        ;;

    $ACTION_UPDATE)
        action_update "${CONFIG_PATH}" || exit 3
        ;;

    $ACTION_UPGRADE)
        action_update "${CONFIG_PATH}" || exit 3
        ;;

    $ACTION_REBUILD)
        action_rebuild "${CONFIG_PATH}" || exit 3
        ;;

    $ACTION_LIST)
        action_list
        ;;

    $ACTION_DELETE)
        action_delete "${2}"
        ;;

    *)
        print_error "Unknown command: ${1}"
        print_usage_and_exit
        ;;
esac

print_success "All done!"