diff options
| author | Craig Jennings <craigmartinjennings@gmail.com> | 2023-04-16 10:05:01 -0500 | 
|---|---|---|
| committer | Craig Jennings <craigmartinjennings@gmail.com> | 2023-04-16 10:05:01 -0500 | 
| commit | a9a804d293695710e6edf25cfe4b2c36fa21fe52 (patch) | |
| tree | 18394b21c2319819354bf5bc46a67a9bc61f4de8 /archsetup.sh | |
moving from sr.ht
Diffstat (limited to 'archsetup.sh')
| -rwxr-xr-x | archsetup.sh | 891 | 
1 files changed, 891 insertions, 0 deletions
| diff --git a/archsetup.sh b/archsetup.sh new file mode 100755 index 0000000..73a4f73 --- /dev/null +++ b/archsetup.sh @@ -0,0 +1,891 @@ +#!/bin/sh +# ArchSetup - Craig Jennings <craigmartinjennings@gmail.com> +# License: GNU GPLv3 + +# Commentary +: ' + +This script assumes the following of the base install +* btrfs for the root and home file system +  I use the snapshot/recover feature of btrfs and install related tools. +* grub as the boot manager +  required for grub-btrfs to display the rollback-to-snapshot menu. +* a network connection +  though network-manager will be installed regardless + +This first installs and configures what I feel is essential +software for running my system. After essential software is +complete, it installs all non-essential applications within +an install loop. Essential software is hard-coded in this +script. Non-essential software is listed in a software.csv +text file. If the software.csv file is inaccessible, I can still +build a working (though less functional) desktop. + +Notes: +This script creates a tmpfs RAM disk for all compilation. + +I define two levels of errors: +* STOP: Issues that will halt forward progress, aborting this script. +* ERROR: Issues not serious enough to prevent the script from continuing. +Both are printed on screen and in the $logfile. +Stderr is also printed to the $logfile for all relevant info. + +Outstanding Tasks: + +' +# Code + +# uncomment to stop on any error +# set -e + +### Constants + +username="cjennings" +password="welcome"  # change on first login. :) + +dwm_repo="https://git.cjennings.net/dwm.git" +dmenu_repo="https://git.cjennings.net/dmenu.git" +st_repo="https://git.cjennings.net/st.git" +dotfiles_repo="https://git.cjennings.net/dotfiles" +dotemacs_repo="https://git.cjennings.net/dotemacs.git" +dotfiles_home="/home/$username/.dotfiles" + +logfile="/var/log/archsetup-$(date +'%Y-%m-%d-%H-%M-%S').log"   # logfile location +source_dir="/home/$username/.local/src"                         # aur/git source goes here +packages_before="/var/log/archsetup-preexisting-package-list.txt" +packages_after="/var/log/archsetup-post-install-package-list.txt" +archsetup_packages="/var/log/archsetup-installed-packages.txt" + +### Intro + +intro() { +    printf "\n\nArchSetup launched @ %s\n" "$(date +'%D %T')"| tee -a "$logfile" +    STARTTIME=$(date +%s) +    errors_encountered=0 + +    # begin with a clean logfile +    [ -f "$logfile" ] && rm -f "$logfile" +    touch "$logfile" + +    # count the arch packages before install +    pacman -Q > "$packages_before" || \ +        error "crash" "generating pre-install package list" "$?" +} + +### General Functions +# Error +error () { +    # $1 = type ERROR, noted but the script will continue to run. +    #      anything else will produce CRASH, which halts the script +    # $2 = what was happening (e.g., "adding $username to group $groupname", etc.) +    # $3 = the error code (i.e., "$?") + +    errors_encountered=$((errors_encountered+1)) +    case "$1" in +        "error") +            printf "ERROR: %s failed with error code %s @ %s\n" \ +                   "$2" "$3"  "$(date +'%T')"  | tee -a "$logfile" +            return 1; +            ;; +        *) +            printf "CRASH: %s failed with error code: %s @ %s. Script halted.\n" \ +                   "$2" "$3"  "$(date +'%T')"  | tee -a "$logfile" +            exit 1; +            ;; +    esac +} + +#  Display +display () { +    # $1 = type (TITLE, ACTION) +    # $2 = description (answers: "what are you trying to do?") + +    case "$1" in +        "title") +            printf "\n##### %s\n" "$2" | tee -a "$logfile" +            return 1; +            ;; +        "subtitle") +            printf "\n%s\n" "$2"  | tee -a "$logfile" +            ;; +        "task") +            printf "...%s @ %s\n" "$2" "$(date +'%T')" | tee -a "$logfile" +            return 1; +            ;; +        *) +            printf "CRASH: display () called with incorrect arguments.\n" +            printf "...called %s type, %s action @ %s\n" \ +                   "$1" "$2"  "$(date +'%T')"   | tee -a "$logfile" +            exit 1; +            ;; +    esac + +} + +# Pacman Install + +pacman_install() { +    action="installing $1 via pacman" && display "task" "$action" +    if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then +        action="retrying $1" && display "task" "$action" +        if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then +            action="retrying $1 once more" && display "task" "$action" +            (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1) || +                error "error" "$action" "$?" +        fi +    fi + +} + +# Git Install +git_install() { +    prog_name="$(basename "$1" .git)" +    build_dir="$source_dir/$prog_name" +    action="building & installing $prog_name from source" +    display "task" "$action" + +    if ! (sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1); then +        error "error" "cloning source code for $prog_name" "$?" +        (cd "$build_dir" && sudo -u "$username" git pull --force origin master >> "$logfile" 2>&1) || \ +            error "error" "pulling source code for $prog_name" "$?" +    fi + +    (cd "$build_dir" && make install >> "$logfile" 2>&1) || \ +        error "error" "building $prog_name from source code" "$?" +} + +# Aur Install +aur_install() { +    action="installing $1 via the AUR" && display "task" "$action" +    if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then +        action="retrying $1" && display "task" "$action" +        if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then +            action="retrying $1 once more" && display "task" "$action" +            (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1) || +                error "error" "$action" "$?" +        fi +    fi +} + +# Pip Install +pip_install() { +    [ -x "$(command -v "pip")" ] || pacman_install python-pip +    action="installing $1 via PIP" && display "task" "$action" +    (yes | sudo -u "$username" pip install "$1" >> "$logfile" 2>&1)  || \ +        error "error" "$action" "$?" +} + +### Prerequisites + +prerequisites() { +    # why these software packages are 'required' +    # base_devel        - required tools to compile +    # ca_certificates   - for validation of keyrings, etc. +    # coreutils         - comparing package lists +    # curl              - to transfer source code +    # git               - tools required to work with git source respositories +    # go                - required to build yay, the aur installer +    # ntp               - must communicate with other servers in ordered manner +    # python            - required for python pip installs +    # stow              - for placing the dotfiles +    # tar               - extract unix archives +    # vi                - should things go wrong, we'll need an editor +    # zsh               - we'll need a shell interpreter for yay; this is mine + +    display "title" "Prerequisites" + +    display "subtitle" "Bootstrapping" + +    action="ensuring current Arch Linux keyring" && display "task" "$action" +    (pacman -S --noconfirm archlinux-keyring) >> $logfile 2>&1  || \ +        error "crash" "$action" "$?" + +    display "task" "verifying Arch Linux keys" +    (pacman-key --populate archlinux >> "$logfile" 2>&1) || \ +        error "crash" "verifying Arch Linux keys" "$?" + +    action="refreshing the package cache" && display "task" "$action" +    (pacman -Syu --noconfirm >> "$logfile" 2>&1)  || error "crash" "$action" "$?" + +    display "subtitle" "Required Software" + +    for software in base-devel ca-certificates coreutils curl git go ntp openssh \ +                    python stow tar vi zsh; do +        pacman_install "$software" +    done + +    display "subtitle" "Environment Configuration" + +    # sync the time on this machine +    action="synchronizing system time" && display "task" "$action" +    (ntpdate 0.us.pool.ntp.org >> "$logfile" 2>&1) || error "error" "$action" "$?" + +    action="configuring compiler to use all processor cores" && display "task" "$action" +    sed -i "s/-j2/-j$(nproc)/;s/^#MAKEFLAGS/MAKEFLAGS/" /etc/makepkg.conf >> "$logfile" 2>&1 + +    # enable pacman concurrent downloads and color +    action="enabling concurrent downloads" && display "task" "$action" +    sed -i "s/^#ParallelDownloads.*$/ParallelDownloads = 5/;s/^#Color$/Color/" /etc/pacman.conf + +    action="Package Mirrors" && display "subtitle" "$action" +    pacman_install reflector + +    action="configuring reflector" && display "task" "$action" +    (printf ' +          --connection-timeout 3 \ +          --download-timeout 3 \ +          --protocol https \ +          --age 12 \ +          --latest 20 \ +          --score 10 \ +          --fastest 5 \ +          --sort score \ +          --save /etc/pacman.d/mirrorlist +    ' > /etc/xdg/reflector/reflector.conf >> "$logfile" 2>&1) || \ +        error "error" "$action" "$?" + +    action="updating repository mirrors" && display "task" "$action" +    (reflector --connection-timeout 3 \ +               --download-timeout 3 \ +               --protocol https \ +               --age 12 \ +               --latest 20 \ +               --score 10 \ +               --fastest 5 \ +               --sort score \ +               --save /etc/pacman.d/mirrorlist > /dev/null 2>&1) + +    action="enabling the reflector timer" && display "task" "$action" +    (systemctl enable reflector.timer >> "$logfile" 2>&1) || \ +        error "error" "$action" "$?" + +    action="replacing sudoers file if new package version exists" && display "task" "$action" +    [ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers >> "$logfile" 2>&1 + +    action="creating a directory to build/install software from git/AUR." +    (mkdir -p $source_dir) || error "crash" "creating the directory $source_dir" + +} + +### Create User +create_user () { +    display "title" "User Creation" + +    display "task" "checking if user exists" +    # halt if $username exists +    ( id -u "$username" >/dev/null 2>&1; ) && \ +        error "crash" "user '$username' already exists!" + +    # create $username with home, group, shell, password +    action="creating user and home directory" && display "task" "$action" +    (useradd -m -G wheel -s /bin/zsh "$username" >> "$logfile" 2>&1) || \ +        error "crash" "adding user '$username" "$?" + +    display "task" "assigning the password" +    echo "$username:$password" | chpasswd  # any text is allowable! be careful! + +    display "task" "configuring shell" +    # zsh cache required: $username will install via yay; zsh will run those commands +    mkdir -p "/home/$username/.cache/zsh/" | tee -a "$logfile" + +    # give $username sudo nopasswd rights (required for aur installs) +    display "task" "granting permissions" +    (echo "%$username ALL=(ALL) NOPASSWD: ALL #ArchSetup" >> /etc/sudoers) \ +        || error "error" "$action" "$?" + +    # # mount as ramdisk to speed aur/git build/installs +    # (sudo mount -t tmpfs -o size=4G archsetup $source_dir >> "$logfile" 2>&1) || \ +        #     error "crash" "mounting the RAM disk for archsetup" "$?" + +    (chown -R "$username":wheel "$(dirname "$source_dir")" >> "$logfile" 2>&1) || \ +        error "crash" "changing ownership of $source_dir" "$?" +} + +### User Customizations + +user_customizations() { +    action="User Customizations" && display "title" "$action" + +    action="cloning dotfiles" && display "task" "$action" +    (git clone --depth 1 $dotfiles_repo "$dotfiles_home" \ +          >> "$logfile" 2>&1)  ||  error "error" "$action" "$?" + +    action="moving dotfiles into place" && display "task" "$action" +    (cd "$dotfiles_home" &&  stow --adopt * \ +          >> "$logfile" 2>&1 )  || error "error" "$action" "$?" + +    action="restoring dotfile versions" && display "task" "$action" +    (cd "$dotfiles_home" &&  git restore . \ +          >> "$logfile" 2>&1 )  || error "error" "$action" "$?" + +    action="creating common directories" && display "task" "$action" +    # Create default directories and grant permissions +    { +        mkdir -p -m 751 /home/$username/code +        mkdir -p -m 751 /home/$username/documents +        mkdir -p -m 751 /home/$username/downloads/torrents/complete +        mkdir -p -m 751 /home/$username/downloads/torrents/incomplete +        mkdir -p -m 751 /home/$username/downloads/torrents/files +        mkdir -p -m 751 /home/$username/downloads/ebooks +        mkdir -p -m 751 /home/$username/music +        mkdir -p -m 751 /home/$username/projects +        mkdir -p -m 751 /home/$username/pictures/screenshots +        mkdir -p -m 751 /home/$username/videos +        mkdir -p -m 751 /home/$username/vms +        chown -R $username: /home/$username + +        mkdir -p -m 751 /media/backup +        mkdir -p -m 751 /media/remote0 +        mkdir -p -m 751 /media/remote1 +        mkdir -p -m 751 /media/remote2 +        chown -R $username: /media +    }  >> "$logfile" 2>&1 + +} + +### AUR Installer +aur_installer () { +    display "title" "AUR Installer" + +    yay_repo="https://aur.archlinux.org/yay.git" +    build_dir="$source_dir/yay" + +    display "task" "fetching source code for yay" +    if ! (sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1); then +        error "error" "cloning source code for Yay" +        (sudo -u "$username" -D "$build_dir" git pull --force origin master >> "$logfile" 2>&1) || \ +            error "crash" "changing directories to $build_dir and pulling source code" "$?" +    fi + +    action="packaging and installing yay"; display "task" "$action" +    (cd "$build_dir" && sudo -u "$username" makepkg --noconfirm -si >> "$logfile" 2>&1) || \ +        error "crash" "$action" "$?" +} + +### Essential Services +essential_services() { +    display "title" "Essential Services" + +    # Networking + +    display "subtitle" "Networking" +    pacman_install networkmanager + +    # Secure Shell + +    display "subtitle" "Secure Shell" +    pacman_install openssh +    action="enabling the openssh service to run at boot" && display "task" "$action" +    systemctl enable sshd >> "$logfile" 2>&1  || error "error" "$action" "$?" +    action="starting the openssh service" && display "task" "$action" +    systemctl start sshd >> "$logfile" 2>&1   || error "error" "$action" "$?" + +    # Firewall + +    # deny by default, then allow the following: +    # http/s                    : 80/tcp, 443/tcp +    # tor                       : 9040,9050,9051,9053,9119/tcp +    # email                     : IMAP, IMAPS +    # mDNS printer discovery    : 5353/udp +    # ssh                       : ssh +    # syncthing                 : 22000/tcp, 22000/udp, 21027/udp +    # torrents                  : transmission +    # calibre content server    : 8080/tcp + +    display "subtitle" "Firewall" +    pacman_install ufw + +    action="configuring ufw to deny by default" && display "task" "$action" +    ufw default deny incoming >> "$logfile" 2>&1 || error "error" "$action" + +    for protocol in \ +        "80/tcp" "443/tcp" "9040,9050,9051,9053,9119/tcp" "IMAP" "IMAPS" "55353/udp" \ +                 "ssh" "22000/tcp" "22000/udp" "21027/udp" "transmission" "8080/tcp"; do +        action="adding ufw rule to allow $protocol" && display "task" "$action" +        (ufw allow $protocol  >> "$logfile" 2>&1) || error "error" "$action" "$?" +    done + +    action="adding limits to protect from brute force attacks" && display "task" "$action" +    (ufw limit 22/tcp  >> "$logfile" 2>&1 && \ +         ufw limit 443/tcp >> "$logfile" 2>&1) || \ +        error "error" "action" + +    action="enabling firewall service to launch on boot" && display "task" "$action" +    systemctl enable ufw.service >> "$logfile" 2>&1  || error "error" "$action" "$?" + +    action="starting firewall service" && display "task" "$action" +    systemctl start ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?" + +    # Service Discovery + +    display "subtitle" "Network Service Discovery" +    pacman_install avahi + +    action="configuring avahi" && display "task" "$action" +    systemctl disable systemd-resolved.service >> "$logfile" 2>&1 || error "error" "$action" "$?" +    systemctl enable avahi-daemon.service >> "$logfile" 2>&1 || error "error" "$action" "$?" + +    # Job Scheduling + +    display "subtitle" "Job Scheduling" +    pacman_install cronie +    action="enabling cronie to launch at boot" && display "task" "$action" +    systemctl enable cronie  >> "$logfile" 2>&1  || error "error" "$action" "$?" +} + +### Desktop Environment +desktop_environment() { +    display "title" "Desktop Environment" + +    # Display Server + +    action="Display Server Dependencies" && display "subtitle" "$action" +    pacman_install libglvnd + +    action="Display Server" && display "subtitle" "$action" +    for software in xorg-server xorg-xinit xorg-xsetroot xf86-video-intel \ +                                xsel xorg-xbacklight xf86-input-libinput \ +                                xorg-xdpyinfo xorg-xprop xorg-xwininfo \ +                                xorg-xinput xorg-xkill ; do +        pacman_install $software +    done + +    # Window Managers + +    action="Window Manager Dependencies" && display "subtitle" "$action" +    for software in coreutils fontconfig freetype2 glibc libx11 libxft libxinerama; do +        pacman_install $software +    done; + +    action="Window Managers" && display "subtitle" "$action" +    pacman_install hyprland +    aur_install waybar-hyprland-fix +    pacman_install xdg-desktop-portal-hyprland +    aur_install foot + +    git_install $dwm_repo +    git_install $dmenu_repo +    git_install $st_repo +    pacman_install alacritty    # my dwm's default terminal +    aur_install pinentry-dmenu  # password entry works with dmenu + +    # Core Fonts + +    action="Core Fonts" && display "subtitle" "$action" +    pacman_install ttf-firacode-nerd +    pacman_install ttf-hack-nerd +    pacman_install noto-fonts-emoji +    aur_install ttf-all-the-icons + +    # File System Utilities + +    action="File System Utilities" && display "subtitle" "$action" +    pacman_install sshfs +    pacman_install dosfstools +    pacman_install exfat-utils +    pacman_install testdisk +    pacman_install ntfs-3g +    pacman_install udisks2 +    aur_install inxi + +    # File Associations + +    action="File/Application Associations" && display "subtitle" "$action" +    pacman_install perl-file-mimeinfo +    pacman_install xdg-utils + +    # File Associations + +    action="Authentication Tools" && display "subtitle" "$action" +    pacman_install gnupg +    pacman_install polkit +    pacman_install gnome-keyring + +    # ensure correct permissions on .gpg directory +    # the colon means the user's group will have perms +    [ -d /home/"$username"/.gnupg ] || mkdir /home/"$username"/.gnupg +    chown -R "$username": /home/"$username"/.gnupg +    find /home/"$username"/.gnupg -type f -exec chmod 600 {} \; +    find /home/"$username"/.gnupg -type d -exec chmod 700 {} \; + +    #  Power Management + +    action="Power Management" && display "subtitle" "$action" +    pacman_install acpi +    pacman_install powertop + +    #  Audio System + +    action="Audio System" && display "subtitle" "$action" +    for software in alsa-utils pipewire wireplumber pipewire-pulse \ +                               pipewire-docs pamixer pulsemixer ffmpeg; do +        pacman_install $software +    done; +    # disable the pc speaker beep +    rmmod pcspkr >> "$logfile" 2>&1 +    echo "blacklist pcspkr" >/etc/modprobe.d/nobeep.conf  >> "$logfile" 2>&1 + +    # Keyboard Shortcut Manager + +    action="Keyboard Shortcut Manager" && display "subtitle" "$action" +    pacman_install sxhkd + +    # Notifications + +    action="Notification System" && display "subtitle" "$action" +    pacman_install libnotify +    pacman_install dunst + +    # Bluetooth Devices + +    action="Bluetooth System" && display "subtitle" "$action" +    for software in bluez bluez-utils blueman; do +        pacman_install $software +    done +    action="enabling bluetooth to launch at boot" && display "task" "$action" +    systemctl enable bluetooth.service  >> "$logfile" 2>&1 ||e || error "error" "$action" "$?" + +    # Command Line Utilities + +    action="Command Line Utilities" && display "subtitle" "$action" +    for software in htop mc ncdu tmux fzf zip unzip atool wget detox \ +                         lsof usbutils speedtest-cli moreutils; do +        pacman_install "$software" +    done; + +    for software in lf-git task-spooler rar; do +        aur_install "$software" +    done; + +    pip_install glances + +    # Help And Documentation + +    action="Help and Documentation" && display "subtitle" "$action" +    for software in man arch-wiki-docs arch-wiki-lite; do +        pacman_install $software +    done; + +    aur_install cht.sh-git +    pip_install tldr + +    # Desktop Environment Utilities + +    action="Desktop Environment Utilities" && display "subtitle" "$action" + +    for software in brightnessctl network-manager-applet xclip bc nitrogen; do +        pacman_install $software +    done; + +    aur_install colorpicker + +    # Browser + +    action="Browsers" && display "subtitle" "$action" +    pacman_install firefox +    # aur_install tor-browser +    # currently getting errors with the key validation + +    # Install Printing + +    action="Print System" && display "subtitle" "$action" +    for software in cups cups-pdf foomatic-db-engine foomatic-db-ppds foomatic-db-nonfree-ppds \ +                         gutenprint foomatic-db-gutenprint-ppds nss-mdns; do +        pacman_install "$software" +    done +    action="enabling printing service to launch at boot" && display "task" "$action" +    (systemctl enable cups.service  >> "$logfile" 2>&1) || error "error" "$action" "$?" +} + +### Developer Workstation +developer_workstation () { + +    action="Developer Workstation" && display "title" "$action" + +    action="Programming Languages and Utilities" && display "subtitle" "$action" +    pacman_install clang       # C/C++ compiler +    pacman_install cmake       # make system +    pacman_install gdb         # the gnu debuffer +    pacman_install splint      # C programming static analysis +    pacman_install valgrind    # memory management utility + +    pacman_install rust        # Rust programming language + +    pacman_install pyright     # Python language server + +    pacman_install shellcheck  # Shell script linter +    pacman_install shfmt       # Shell script formatter + +    pacman_install go-tools    # Go language utilities +    pacman_install gopls       # Go language server +    pacman_install delve       # Go programming language debugger +    pacman_install staticcheck # Go programming language linter + +    pacman_install typescript  # Typescript programming language +    pacman_install npm         # Node-js package manager +    aur_install nvm            # Node-js version manager +    pacman_install jq          # JSON processor + +    pacman_install meld        # Visual diff +    pacman_install ripgrep     # Fast grep utility + +    action="Programming Editors" && display "subtitle" "$action" +    pacman_install mg +    pacman_install neovim + +    action="Emacs and Dependencies" && display "subtitle" "$action" +    pacman_install emacs + +    # supporting utilities used by my emacs configuration +    pacman_install aspell            # spell check system +    pacman_install aspell-en         # spell check english files +    aur_install multimarkdown        # markdown conversion +    pacman_install sdcv              # stardict dictionary system +    pacman_install fd                # a faster find for dired/dirvish +    pacman_install imagemagick       # image previews for dired/dirvish +    pacman_install mediainfo         # generating media info in dired/dirvish +    pacman_install ffmpegthumbnailer # video previews in dired/dirvish +    aur_install mu                   # email indexer and utilities +    aur_install isync                # email sync +    pip_install yt-dlp               # video download +    pacman_install mpv               # video viewer +    pip_install proselint            # grammar checker +    aur_install exercism             # command line tool for exercism.io + + +    action="setting up emacs configuration files" && display "task" "$action" +    (sudo -u "$username" git clone $dotemacs_repo /home/$username/.emacs.d  >> "$logfile" 2>&1) || \ +        error "error" "$action" "$?" + +    # DevOps Utilities + +    action="installing devops virtualization and automation tools" && display "task" "$action" +    pacman_install virtualbox >> "$logfile" 2>&1 || error "error" "$action" "$?" +    pacman_install virtualbox-guest-iso >> "$logfile" 2>&1 || error "error" "$action" "$?" +    pacman_install virtualbox-host-modules-arch >> "$logfile" 2>&1 || error "error" "$action" "$?" +    pacman_install linux-headers >> "$logfile" 2>&1 || error "error" "$action" "$?" +    action="adding user to vboxusers group" && display "task" "$action" +    (gpasswd -a $username vboxusers >> "$logfile" 2>&1)  || error "error" "$action" "$?" +    pacman_install docker +    pacman_install docker-compose +    action="adding user to docker group" && display "task" "$action" +    (gpasswd -a $username docker >> "$logfile" 2>&1)  || error "error" "$action" "$?" +    action="enabling docker service to launch on boot" && display "task" "$action" +    systemctl enable docker.service >> "$logfile" 2>&1  || error "error" "$action" "$?" +    pacman_install vagrant  >> "$logfile" 2>&1 || error "error" "$action" "$?" +    pip_install ansible >> "$logfile" 2>&1 || error "error" "$action" "$?" + +} + +### Supplemental Software + +supplemental_software() { + +    display "title" "Supplemental Software" + +    # pacman installs +    pacman_install arandr                            # xrandr gui for monitor settings +    pacman_install arch-install-scripts              # for making arch installers +    pacman_install archinstall                       # the archinstall python program +    pacman_install aria2                             # fast downloader +    pacman_install dash                              # posix compliant /bin/sh +    pacman_install docx2txt                          # recovers text from docx files +    pacman_install entr                              # run arbitrary commands when files change +    pacman_install faac                              # open source mpeg 3 and aac encoder +    pacman_install faad2                             # processes an aac stream +    pacman_install filezilla                         # ftp gui +    pacman_install gparted                           # disk partition utility +    pacman_install gst-plugin-pipewire               # gstreamer audio plugin for pipewire +    pacman_install gst-plugins-base                  # gstreamer base audio plugins +    pacman_install gst-plugins-good                  # gstreamer extra audio plugins +    pacman_install gstreamer                         # pipeline based multimedia framework +    pacman_install gucharmap                         # gui display of character maps +    pacman_install gzip                              # compression tool +    pacman_install handbrake                         # video transcoder +    pacman_install libconfig                         # library for processing structured config files +    pacman_install libmad                            # mpeg audio decoder +    pacman_install libmpeg2                          # library for decoding mpeg video streams +    pacman_install maim                              # screenshot utility +    pacman_install mediainfo                         # technical and tag information about media files +    pacman_install mosh                              # alt SSH terminal with roaming and responsiveness support +    pacman_install mpc                               # command line interface to mpd +    pacman_install mpd                               # the music player daemon +    pacman_install ncmpcpp                           # and mpd client to play music +    pacman_install neofetch                          # cli system information tool +    pacman_install odt2txt                           # converts from open document to text +    pacman_install p7zip                             # p7zip compression tool +    pacman_install pandoc                            # universal document converter +    pacman_install perl-image-exiftool               # reads/writes exif info for raw photo files +    pacman_install pv                                # monitor progress of data through pipeline +    pacman_install rclone                            # syncs files from gdrive, s3, dropbox, etc. +    pacman_install smartmontools                     # monitors hard drives +    pacman_install syncthing                         # sync utility +    pacman_install texlive-most                      # latex +    pacman_install transmission-cli                  # bittorrent client +    pacman_install transmission-remote-gtk           # bittorrent client +    pacman_install unclutter                         # hides mouse cursor when not being used +    pacman_install w3m                               # text based browser +    pacman_install wavpack                           # audio compression format +    pacman_install webkit2gtk                        # web content engine for GTK +    pacman_install xdotool                           # command line xorg automation tool +    pacman_install xz                                # general purpose data compression tool +    pacman_install zathura                           # document viewer +    pacman_install zathura-cb                        # zathura plugin for comics +    pacman_install zathura-djvu                      # zathura plugin for djvu books +    pacman_install zathura-pdf-mupdf                 # zathura plugin for pdf +    pacman_install poppler-glib                      # poppler-glib document viewer library +    pacman_install zlib                              # compression library +    aur_install authy                                # two-factor authenticator +    pip_install dtrx                                 # extraction tool +    aur_install hfsprogs                             # file system tools for Mac OS +    aur_install mcomix                               # image viewer for comic books +    aur_install nsxiv                                # image viewer +    aur_install picom-jonaburg-git                   # xorg compositor with enhancements +    aur_install plexamp-appimage                     # music player +    aur_install topgrade                             # invokes upgrade procedures of various package maangers +    aur_install tremc                                # curses interface for transmission +    aur_install zsh-fast-syntax-highlighting-git     # Optimized and extended zsh-syntax-highlighting +    git_install https://github.com/clamiax/snore.git # sleep with feedback +    pip_install ranger                               # terminal file manager +    pip_install pydf                                 # better display of available space on mounted filesystems +    pip_install tidal-dl                             # tidal-dl: tidal as yt-dlp:youtube +    pacman_install lxappearance # GTK+ theme switcher + +    # nice fonts +    pacman_install ttf-crimson-pro +    pacman_install ttf-crimson-pro-variable +    pacman_install ttf-sourcecodepro-nerd +    pacman_install otf-cascadia-code-nerd +    pacman_install ttf-go-nerd +    pacman_install ttf-jetbrains-mono-nerd +    pacman_install ttf-meslo-nerd +    aur_install ttf-lato + + +} + +### Silent Boot + +silent_boot() { + +    action="Silent Boot" && display "title" "$action" + +    action="removing distro and date/time from initial screen" && display "task" "$action" +    (cat /dev/null >/etc/issue)  || error "error" "$action" "$?" + +    action="preventing kernel messages on the console" && display "task" "$action" +    (echo "kernel.printk = 3 3 3 3" >/etc/sysctl.d/20-quiet-printk.conf)  || \ +        error "error" "$action" "$?" + +    action="delegating fsck messages from udev to systemd" && display "task" "$action" +    sed -i "s/.*HOOKS=(base udev autodetect keyboard keymap modconf block filesystems fsck).*/HOOKS=(base systemd autodetect keyboard keymap modconf block filesystems fsck)/" /etc/mkinitcpio.conf  || error "error" "running sed on mkinitcpio.conf to hide fsck messages" "$?" +    mkinitcpio -P  >> "$logfile" 2>&1  || error "error" "running mkinitcpio -P to silence fsck messages" "$?" + +    action="instructing systemd to check filesystems" && display "task" "$action" +    servicefile=/usr/lib/systemd/system/systemd-fsck-root.service +    [ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \ +        echo "StandardError=journal+console" >>$servicefile + +    servicefile=/usr/lib/systemd/system/systemd-fsck@.service +    [ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \ +        echo "StandardError=journal+console" >>$servicefile + +    action="removing hostname from login prompt" && display "task" "$action" +    sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/getty@.service  \ +        || error "error" "$action" "$?" + +    action="silencing the unneeded and chatty watchdog module" && display "task" "$action" +    echo "blacklist iTCO_wdt" >/etc/modprobe.d/nowatchdog.conf  || error "error" "$action" "$?" + +    # on systemd boot, eliminate timeout and silence boot text +    if [ -f /boot/loader/loader.conf ]; then +        action="eliminating timeout and silencing boot test on systemd boot" && display "task" "$action" +        echo "timeout=0" >/boot/loader/loader.conf + +        # the file in this location was named based on the time of the install, so we must use find to identify it. +        kernelfile=$(find /boot/loader/entries/ -name "*.conf") +        # hush boot output via kernel parameters +        sed -i "/.*options root=PARTUUID.*/ s/$/quiet rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog/" "$kernelfile" +    fi + +    # if grub, reset timeouts and adjust log levels +    if [ -f /etc/default/grub ]; then +        action="resetting timeouts and adjusting log levels on grub boot" && display "task" "$action" +        sed -i "s/.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=2/g" /etc/default/grub +        sed -i "s/.*GRUB_DEFAULT=.*/GRUB_DEFAULT=0/g" /etc/default/grub +        sed -i "s/.*GRUB_RECORDFAIL_TIMEOUT=.*/GRUB_RECORDFAIL_TIMEOUT=$GRUB_TIMEOUT/g" /etc/default/grub +        sed -i "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"rw quiet loglevel=2 rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog\"/g" /etc/default/grub +        grub-mkconfig -o /boot/grub/grub.cfg  >> "$logfile" 2>&1  || error "error" "" "$?" +    fi +} + +### Configure Snapshots + +configure_snapshots() { + +    # note that the order of these commands are important +    action="Snapshots and Recovery" && display "title" "$action" +    aur_install grub-btrfs + +    action="configuring boot menu to display snapshots" && display "task" "$action" +    (grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1)  || error "error" "$action" "$?" + +    # install timeshift + autosnap +    aur_install timeshift +    aur_install timeshift-autosnap + +    action="taking initial btrfs snapshot" && display "task" "$action" +    (timeshift --btrfs --create --comments "ArchSetup initial snapshot on $(date +'%D %T')"  >> \ +               "$logfile" 2>&1) || error "error" "$action" "$?" + +    action="enabling automatic snapshots in the boot menu" && display "task" "$action" +    (systemctl enable --now grub-btrfs.path  >> "$logfile" 2>&1)  || error "error" "$action" "$?" + +} + +### Outro + +outro() { + +    display "title" "Generating Statistics" +    action="identifying newly installed packages" && display "task" "$action" +    pacman -Q > "$packages_after"  || error "error" "$action" "$?" +    (comm -13 --nocheck-order "$packages_before" "$packages_after" > "$archsetup_packages")  || \ +        error "error" "$action" "$?" + +    action="comparing timestamps" && display "task" "$action" +    ENDTIME=$(date +%s) +    totalsecs=$(($ENDTIME - $STARTTIME)) +    mins=$(($totalsecs / 60)) +    secs=$(($totalsecs % 60)) + +    new_packages=$(cat $archsetup_packages | wc -l) + +    printf "\n" +    printf "Completion time    : %s\n" "$(date +'%D %T')"  | tee -a "$logfile" +    printf "Elapsed time       : %s minutes, %s seconds\n" $mins $secs | tee -a "$logfile" +    printf "Errors encountered : %s\n" $errors_encountered | tee -a "$logfile" +    printf "Log file location  : %s\n" "$logfile" +    printf "Packages installed : %s\n" "$new_packages" +    printf "\n" +    printf "Please reboot before working with your new workstation.\n\n" +} + +### Installation Steps + +intro                   # take start stats + +prerequisites           # install software required to install software +create_user             # create user in wheel with :nopasswd sudo +user_customizations     # dotfiles +aur_installer           # install yay +essential_services +desktop_environment +developer_workstation +supplemental_software +silent_boot             # make booting less noisy +configure_snapshots     # automatic snapshots added to grub menu for restoration + +outro                   # take end stats; show summary + +exit 0 | 
