#!/bin/sh # ArchDistrobox - Craig Jennings # License: GNU GPLv3 # Commentary # # This script sets up an Arch Linux distrobox setup for software development. # # There are two levels of errors: # * CRASH: Issues that will halt forward progress, aborting this script. # * ERROR: Issues not serious enough to halt the script. # Both are printed on screen and in the $logfile. # Stderr is also printed to the $logfile for all relevant info. # # # Code # uncomment to stop on any error # set -e ### Constants username=cjennings dotfiles_repo="https://git.cjennings.net/dotfiles" dotemacs_repo="https://git.cjennings.net/dotemacs.git" dotfiles_home="/home/$username/.dotfiles" # aur/git source directories go here, logs go in base directiory source_dir="/home/$username/.local/src" logfile="$source_dir/archdistrobox-$(date +'%Y-%m-%d-%H-%M-%S').log" packages_before="$source_dir/archdistrobox-preexisting-package-list.txt" packages_after="/$source_dir/archdistrobox-post-install-package-list.txt" archdistrobox_packages="$source_dir/archdistrobox-installed-packages.txt" ### Intro intro() { printf "\n\nArchDistrobox launched @ %s\n" "$(date +'%D %T')"| tee -a "$logfile" STARTTIME=$(date +%s) errors_encountered=0 # Check that we're not root; error and exit if we are if [ $(id -u) -eq 0 ]; then echo "Please do not run this script as root or using sudo!" exit 1 fi # on fresh distrobox, $source_dir may not exist yet [ -d "$source_dir" ] || mkdir "$source_dir" ] # 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") # $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: %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 ! (sudo pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then action="retrying $1" && display "task" "$action" if ! (sudo pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then action="retrying $1 once more" && display "task" "$action" (sudo pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1) || error "error" "$action" "$?" fi fi } # AUR Install aur_install() { action="installing $1 via the AUR" && display "task" "$action" if ! (yay -S --noconfirm "$1" >> "$logfile" 2>&1); then action="retrying $1" && display "task" "$action" if ! (yay -S --noconfirm "$1" >> "$logfile" 2>&1); then action="retrying $1 once more" && display "task" "$action" (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 | pip install "$1" >> "$logfile" 2>&1) || \ error "error" "$action" "$?" } ### Prerequisites prerequisites() { # why these software packages are 'required' # base_devel - required tools to compile # 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 # python - required for python pip installs # stow - places dotfiles (see: https://bit.ly/41GmysO) # tar - extract unix archives # vi - should things go wrong, we'll need an editor # zsh - we need a shell interpreter for yay; this one's mine display "title" "Prerequisites" # display "subtitle" "Bootstrapping" # 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 coreutils curl git go python \ stow tar vi zsh; do pacman_install "$software" done } ### User Customizations # user_customizations() { # Change cjennings's shell to zsh chsh -s $(which zsh) # Pull relevant dotfiles and put them in their proper place # ----------------------------------------------------- # 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 --no-folding --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" "$?" # } ### AUR Installer aur_installer () { display "title" "AUR Installer" yay_repo="https://aur.archlinux.org/yay.git" build_dir="$source_dir/yay" display "task" "creating yay build directory" if ! (mkdir -p "$build_dir" >> "$logfile" 2>&1); then error "crash" "creating yay build directory" fi display "task" "fetching source code for yay" if ! (git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1); then error "error" "cloning source code for yay" (cd "$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" && makepkg --noconfirm -si >> "$logfile" 2>&1) || \ error "crash" "$action" "$?" } ### Desktop Environment environment_tools() { display "title" "Environment Tools" # System Utilities action="System Utilities" && display "subtitle" "$action" pacman_install dmidecode pacman_install dosfstools pacman_install exfat-utils pacman_install lshw pacman_install ntfs-3g pacman_install sshfs pacman_install testdisk pacman_install udisks2 aur_install downgrade aur_install inxi # File Associations action="File/Application Associations" && display "subtitle" "$action" pacman_install perl-file-mimeinfo pacman_install xdg-utils # Authentication Tools 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 {} \; # 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 moreutils; do pacman_install "$software" done; for software in task-spooler speedtest-go gotop-bin rar; do aur_install "$software" done; # Help And Documentation action="Help and Documentation" && display "subtitle" "$action" pacman_install man pacman_install arch-wiki-docs pacman_install tealdeer aur_install cht.sh-git } ### Developer Workstation developer_workstation () { action="Developer Workstation" && display "title" "$action" action="Programming Languages and Utilities" && display "subtitle" "$action" # C pacman_install clang # C/C++ compiler pacman_install cmake # make system pacman_install gdb # the GNU debugger pacman_install splint # C programming static analysis pacman_install valgrind # memory management utility # java pacman_install jdk-openjdk # Java Development Kit pacman_install openjdk-doc # ...and the documentation # Lisps pacman_install guile # GNU Scheme pacman_install sbcl # Steel Bank Common Lisp pacman_install racket # Racket + SICP mit-scheme emulation # Rust pacman_install rust # Rust programming language # Python pacman_install pyright # Python language server pacman_install pyenv # Python environment manager # Shell pacman_install shellcheck # Shell script linter pacman_install shfmt # Shell script formatter # Go pacman_install delve # Go programming language debugger pacman_install go-tools # Go language utilities pacman_install gopls # Go language server pacman_install staticcheck # Go programming language linter # Typescript pacman_install jq # JSON processor pacman_install typescript # Typescript programming language pacman_install nodejs # Node-js JavaScript runtime environment pacman_install npm # Node-js package manager aur_install nvm # Node-js version manager # HTML pacman_install tidy # HTML formatter pacman_install prettier # Multi-language formatter # General Utilities pacman_install meld # Visual diff pacman_install ripgrep # Fast grep utility aur_install the_silver_searcher # Another fast grep utility action="Programming Editors" && display "subtitle" "$action" pacman_install mg pacman_install neovim } emacs_install() { action="Emacs Dependencies" && display "subtitle" "$action" pacman_install emacs # supporting utilities used by my emacs configuration aur_install exercism-bin # command line tool for exercism.io aur_install isync # email sync aur_install mu # email indexer and utilities aur_install multimarkdown # markdown conversion aur_install proselint # grammar checker aur_install gist # command-line gist poster pacman_install aspell # spell check system pacman_install aspell-en # spell check english files pacman_install fd # a faster find for dired/dirvish pacman_install ffmpegthumbnailer # video previews in dired/dirvish pacman_install imagemagick # image previews for dired/dirvish pacman_install libgccjit # native compilation for Emacs pacman_install mediainfo # generating media info in dired/dirvish pacman_install mpv # video viewer pacman_install mailutils # Emacs' IMAP mail support backend pacman_install msmtp # mail transport for Mu4e pacman_install msmtp-mta # mail transport for Mu4e pacman_install python-lsp-server # python language support pacman_install rlwrap # adds readline support to programs (SBCL-related) pacman_install sdcv # stardict dictionary system pacman_install yt-dlp # video download action="setting up emacs configuration files" && display "task" "$action" (git clone --recurse-submodules $dotemacs_repo "/home/$username/.emacs.d" >> \ "$logfile" 2>&1) || error "error" "$action" "$?" action="Android Utilities" && display "subtitle" "$action" pacman_install android-file-transfer pacman_install android-tools action="DevOps Utilities" && display "subtitle" "$action" action="installing devops virtualization and automation tools" && display "task" "$action" pacman_install vagrant pacman_install ansible # Docker within Podman! 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" "$?" } ### Supplemental Software supplemental_software() { display "title" "Supplemental Software" # pacman installs pacman_install aria2 # fast downloader pacman_install code # visual studio code pacman_install dash # posix compliant /bin/sh pacman_install dfc # better display of available space on mounted filesystems pacman_install docx2txt # recovers text from docx files pacman_install entr # run arbitrary commands when files change pacman_install figlet # words into ascii art pacman_install filezilla # ftp gui pacman_install gparted # disk partition utility pacman_install gucharmap # gui display of character maps pacman_install gzip # compression tool pacman_install libconfig # library for processing structured config files pacman_install mosh # alt SSH terminal with roaming and responsiveness support 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 poppler-glib # poppler-glib document viewer library pacman_install pv # monitor progress of data through pipeline pacman_install ranger # terminal file manager pacman_install rclone # syncs files from gdrive, s3, dropbox, etc. pacman_install texlive-meta # latex pacman_install w3m # text based browser 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 zlib # compression library # aur installs aur_install dtrx # extraction tool aur_install figlet-fonts # fonts for figlet aur_install hfsprogs # file system tools for Mac OS aur_install mcomix # image viewer for comic books aur_install nsxiv # image viewer aur_install shell-gpt # gpt in your terminal aur_install snore-git # sleep with feedback aur_install tageditor # metadata editor for mkv, webm and related video files aur_install zsh-fast-syntax-highlighting-git # Optimized and extended zsh-syntax-highlighting # git installs git_install https://github.com/clamiax/snore.git # sleep with feedback } ### Distrobox Exports distrobox_exports() { for software in emacs \ filezilla \ gparted \ meld \ code ; do distrobox-export --app "$software" done } ### Outro outro() { display "subtitle" "Statistics" action="identifying newly installed packages" && display "task" "$action" pacman -Q > "$packages_after" || error "error" "$action" "$?" (comm -13 --nocheck-order "$packages_before" "$packages_after" > "$archdistrobox_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 $archdistrobox_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 prerequisites # user_customizations aur_installer environment_tools developer_workstation emacs_install supplemental_software distrobox_exports outro exit 0