linux.bash

#!/usr/bin/env bash

import core/linux-helper

## Setup, configure, backup my personal linux systems
#
# Aims to have a single folder to contain all backup-able items


## 
# Set up a new system from my setup source files. Do this AFTER a restore
#
#
function linux_setup(){
# - prompt for system/user home dir
# - prompt for system files directory  (source of truth)
#     - prompt for Documents parent directory
#         - Contains 'Documents', 'Pictures', and so on. We will make symlinks
#     - prompt for home_symlinks directory where each immediate child is directly symlinked into home dir
#     - prompt for scripts directory of scripts to execute after built-in system setup
#         - copy my firefox profile
#         - copy spacevim's init.toml file
# - prompt if old home dirs ('documents', etc) should be deleted or moved
# - backup home dir (for symlinking)
# - target home directory (on the system we're setting up)
# - Execution
#     - execute pre-setup scripts
#     - create symlinks to each file in `home_symlinks` dir
#     - remove existing `Documents` & other dirs if empty. Move otherwise
#     - symlink to own documents & pictures directories
#     - execute post-setup scripts

    homeDir=""
    rootDir=""
    if [[ -f ~/.tlfsetup ]];then
        source ~/.tlfsetup
    fi

    while [[ ! -d "$homeDir" ]]; do
        prompt "Absolute path to your home directory:" homeDir
    done

    while [[ ! -d "$rootDir" ]]; do
        prompt "Absolute path to all your files:" rootDir
    done



    echo "# Enter paths relative to '$rootDir'"
    echo ""

    ## Where 'Documents' and 'Pictures' & the like go
    filesDir="$rootDir/Files/"
    while [[ ! -d "$filesDir" ]]; do
        prompt "Relative path to Files dir (contains Documents/, Pictures/, etc):" filesDir 
        filesDir="$rootDir/$filesDir"
    done

    ## System Dir, where setup files are located
    systemDir="$rootDir/Linux"
    while [[ ! -d "$systemDir" ]]; do
        prompt "Relative path to system dir" systemDir 
	systemDir="$rootDir/$systemDir"
    done


    echo "Root Paths Found"
    echo ""
    echo "----"
    echo "# Enter paths relative to '$systemDir'"
    echo ""

    ## Home Symlinks. link ~/FILE to $homelinkDir/* (including directories)
    homeLinkDir="$systemDir/homelink"
    while [[ ! -d "$homeLinkDir" ]]; do
        prompt "Relative path to homelinks dir:" homeLinkDir
        homeLinkDir="$systemDir/$homeLinkDir"
    done

    ## Home Symlinks. link ~/FILE to $homelinkDir/* (including directories)
    systemFilesDir="$systemDir/files"
    while [[ ! -d "$systemFilesDir" ]]; do
	prompt "Relative path to system files dir (requires special setup by scripts):" homeLinkDir
        systemFilesDir="$systemDir/$systemFilesDir"
    done

    ## Where to put files that we (re)move during setup
    trashDir="$systemDir/setup_trash/"
    while [[ ! -d "$trashDir" ]]; do
        prompt "Relative path to setup trash dir:" trashDir
        trashDir="$systemDir/$trashDir"
    done
    trashDir="$trashDir/$(date +%d-%m-%Y-%H:%M)/"
    mkdir "$trashDir"

    ## Setup Dir, to load scripts & packages to install & such
    setupDir="$systemDir/setup/"
    while [[ ! -d "$setupDir" ]]; do
        prompt "Relative path to setup dir, to load scripts & info from: " setupDir
        postSetupScriptsDir="$systemDir/$setupDir"
    done

    ## Source directory for scripts & things
    sourceDir="$systemDir/src/"
    while [[ ! -d "$sourceDir" ]]; do
        prompt "Relative path to source dir, where your scripts will load from:" sourceDir
        sourceDir="$systemDir/$sourceDir"
    done

    echo "System Paths Found"
    echo ""

    ###
    ##
    #
    ##### done getting paths
    ##### start doing actual setup
    #
    ##
    ###



    preSetupScript="$setupDir/pre-setup.bash"
    if [[ -f "$preSetupScript" ]];then
        step "Run pre Setup Script?" source "$setupDir/pre-setup.bash"
    fi


    step "Write symlinks to files. " write_home_symlinks_to "$homeLinkDir" "$homeDir" "$trashDir"

    step "Write symlinks to Documents, Pictures, etc" write_home_symlinks_to "$filesDir" "$homeDir" "$trashDir"

    if [[ -f "$setupDir/dnf-remove" ]];then
        dnfRemoveList="$(cat "$setupDir/dnf-remove")"
        prompt=$(echo -e "\nRemove ${dnfRemoveList[@]}")
        step "$prompt" sudo dnf remove ${dnfRemoveList[@]}
    fi

    if [[ -f "$setupDir/dnf-install" ]];then
        dnfInstallList="$(cat "$setupDir/dnf-install")"
        prompt=$(echo -e "\nInstall ${dnfInstallList[@]}")
        step "$prompt" sudo dnf install ${dnfInstallList[@]}
    fi

    postSetupScript="$setupDir/post-setup.bash"
    if [[ -f "$postSetupScript" ]];then
        step "Run Post Setup Script?" source "$setupDir/post-setup.bash"
    fi

    step_run
}

##
# Restore backup files from backup drive onto system drive
#
function linux_restore(){
    echo "Being run from '$(pwd)'"
    echo "Use absolute paths"
    # Executing it for backup would
    # - prompt for backup path
    # - prompt for target restore path
    # - Ask if we should do a dry run
    # - ask if we should --delete on restore
    # - The backup
    #     - Delete files that don't exist in source of truth
    #     - overrwrite existing files unless they're the same (how do I do that with rsync?)
    #     - execute 'pre-restore' scripts
    #     - rsync everything
    #     - execute 'post-backup' scripts
    #         - decompress git folders
    # - Write a .last_backup file that shows when the backup was performed

    backupDir=""
    restoreDir=""

    # backupDir="/path/to/test/backup/dir/"
    # restoreDir="/path/to/test/source/dir"

    # backupDir="/mnt/BackupDrive/a/"
    # restoreDir="/home/reed/.disk"

    while [[ ! -d "$backupDir" ]]; do
        prompt "The directory to restore your files from" backupDir
    done
    backupDir="$backupDir/"

    # Location to restore to
    while [[ ! -d "$restoreDir" ]]; do
        prompt "Enter path to restore files into" restoreDir
    done
    restoreDir="${restoreDir%/}"

    prompt_yes_or_no "Delete files in target directory, if they're not found in the backup?" doDelete
    prompt_yes_or_no "Overwrite files in target directory?" doOverwrite
    prompt_yes_or_no "Do dry run?" doDryRun

    echo "Restoring from '$backupDir' into '$restoreDir'"


    ## --archive equals -rlptgoD    or:
        # --recursive # recurse into directories
        # --links # copy symlinks as symlinks
        # --perms # preserve permissions
        # --times # preserve modification times
        # --group # preserve group
        # --owner # preserve owner
        # -D is --devices --specials # "preserve device files" & "preserve special files" respectively
    ## Others:
        # --hard-links preserve hard links (probably not needed)
        # --executability preserve executability
        # --acls preserve ACLs (implies --perms) (see `info ACL`. I think this is needed for sticky bits to work? idk)
    rsync_args=(--verbose --archive --hard-links --executability --acls --progress)
    if [[ $doDelete ]];then
        rsync_args+=(--delete)
        echo "Delete files not in backup!"
    fi
    if [[ ! $doOverwrite ]];then
        rsync_args+=(--ignore-existing)
        echo "Overwrite files!"
    fi


    if [[ $doDryRun ]]; then
        rsync_args+=(--dry-run)
        echo "Do dry run!"
    fi

    echo "Restore into dir: $restoreDir"
    echo "Backup Dir: $backupDir"

    read -p "[enter] continue "

    rsync "${rsync_args[@]}" "$backupDir" "$restoreDir"

    run_decompress_git "$restoreDir"

    postRestoreScript="$restoreDir/post-restore.bash"
    if [[ -f "$postRestoreScript" ]];then
        source "$postRestoreScript"
    fi

    echo -e "\nShould be all done!!\n"
}

##
# Run a backup from system drive to external drive
#
function linux_backup(){

    echo "Being run from '$(pwd)'"
    echo "Use absolute paths"
    # Executing it for backup would
    # - prompt for target backup path
    # - prompt for source of truth
    # - ask if git folders should be backed up
    # - Ask if we should do a dry run
    # - The backup
    #     - Delete files that don't exist in source of truth
    #     - overrwrite existing files unless they're the same (how do I do that with rsync?)
    #     - execute 'pre-backup' scripts
    #         - compress git folders
    #     - rsync compressed git folders
    #     - rsync everything else except ignored directories (ignore git folders)
    #     - execute 'post-backup' scripts
    #         - decompress git folders
    # - Write a .last_backup file that shows when the backup was performed

    sourceDir=""
    backupDir=""

    # sourceDir="/path/to/test/source/dir/"
    # backupDir="/path/to/test/backup/dir"

    while [[ ! -d "$sourceDir" ]]; do
        prompt "The directory to backup" sourceDir
        sourceDir="$sourceDir/"
    done

    excludesListFile=""
    useExcludesFile=true
    while [[ ! -f "$excludesListFile" ]]; do
        prompt "Enter relative path to your rsync excludes file (within '$sourceDir') or 's' to skip" excludesListRelFile
        if [[ "$excludesListRelFile" == "s" ]];then
            useExcludesFile=false
            break;
        fi
        excludesListFile="$sourceDir/$excludesListRelFile"
    done

    # Location to backup sourcedir to
    while [[ ! -d "$backupDir" ]]; do
        prompt "Enter path to backup dir" backupDir
        backupDir="${backupDir%/}"
    done

    prompt_yes_or_no "Backup .git folders?" doBackupGit
    prompt_yes_or_no "Do dry run?" doDryRun

    echo "Backing up from '$sourceDir' into '$backupDir'"



    preBackupScript="$sourceDir/pre-backup.bash"
    if [[ -f "$preBackupScript" ]];then
        step "Run pre backup Script?" source "$preBackupScript"
    fi


    
    if [[ $doBackupGit ]];then
        msg_notice "compressing git dirs"

        run_compress_git "$sourceDir"

        echo -e "\n\n-------- .git folders compressed: \n"
        find "$sourceDir" | grep ".git.tar.gz"
        echo -e "\n----------------\n"

        read -p "(enter) to continue"
    else
        msg_notice "git not backed up"
    fi


    ## --archive equals -rlptgoD    or:
        # --recursive # recurse into directories
        # --links # copy symlinks as symlinks
        # --perms # preserve permissions
        # --times # preserve modification times
        # --group # preserve group
        # --owner # preserve owner
        # -D is --devices --specials # "preserve device files" & "preserve special files" respectively
    ## Others:
    # --hard-links preserve hard links (probably not needed)
    # --executability preserve executability
    # --acls preserve ACLs (implies --perms) (see `info ACL`. I think this is needed for sticky bits to work? idk)
    rsync_args=(--verbose --archive --hard-links --executability --acls --progress)
    if [[ $doDryRun ]]; then
        rsync_args+=(--dry-run)
        msg_notice "Do dry run!"
    fi

    rsync_end_args=()
    if $useExcludesFile;then
        rsync_end_args+=("--exclude-from=$excludesListFile")
    fi

    echo "Source Dir: $sourceDir"
    echo "Backup Dir: $backupDir"

    rsync "${rsync_args[@]}" --delete --delete-before --delete-excluded --exclude=".git/" --exclude="vendor/" "${rsync_end_args[@]}"  "$sourceDir" "$backupDir"

    if [[ $doBackupGit ]];then
        msg_notice "Decompressing git dirs"
        run_decompress_git "$sourceDir"
    fi

    echo -e "\nShould be all done!!\n"
}