@ 260802.2
current
#!/bin/bash

# BREADCRUMBS:
#
# Audit this whole thing and use it as a forcing function to do clean-up.

# TIP: For configuring wifi from the boot disk, these commands are useful:
#
#   iwctl station wlan0 scan
#   iwctl station wlan0 get-networks
#   iwctl station wlan0 connect <SSID>
#
# The last command will prompt for a password.

# TIP: This command will write out a nice mirror list. Do this before
# bootstrap.
#
#   reflector \
#     --country 'United States' \
#     --age 12 \
#     --protocol https \
#     --sort rate \
#     --save /etc/pacman.d/mirrorlist
#
# This command can take a while and will sometimes emit errors. That's OK.
# Running this can sometimes significantly improve download speeds.

# The script below doesn't handle disk partitioning since that can vary
# depending on the hardware. But the standard thing I do (for non-encrypted
# devices) is:
#
#   cfdisk /dev/sda
#
# N.B. /dev/sda is just an example. These days, it's probably /dev/nvme0n1.
#
# Use a GPT partition table. Then create a 2GB boot EFI System Partition.
# And then a Linux system partition using the rest of the space. No swap
# partition. Write it. Then format the partitions:
#
#   mkfs.fat -F32 /dev/sda1
#   mkfs.ext4 /dev/sda2
#
# Finally, mount the latter above to `/mnt` and the former to `/mnt/boot`:
#
#   mount /dev/sda2 /mnt
#   mkdir /mnt/boot
#   mount /dev/sda1 /mnt/boot
#
# Then you can start the steps below.

# Recommended steps before entering chroot:
#
#   encrypt (if encrypting disk, recommended for laptop)
#   bootstrap before entering chroot
#   installinit
#
# Now enter the chroot:
#
#   arch-chroot /mnt
#
# And continue installation using `/arch-install`:
#
#   rootinit after entering chroot
#   x (if installing graphics)
#   pkgs
#   xpkgs (if installing graphics)
#   bluetoothinit
#   andrewinit
#   kaitinit
#   wifiinit (optional)
#   grubinit
#
# At this point, log in as the user created above.
#
#   yayinit
#   aurpkgs
#   aurxpkgs (if installing graphics)
#   dhcpcdinit
#
# At this point, reboot to disk, as dealing with GPG off the
# live disk seems to have issues.
#
#   gpginit
#   homeinit
#
# Now log out and log back in on tty2, then:
#
#   xenvinit (if installing graphics)
#   pywingoinit (if installing graphics)
#   sshinit
#   scannerinit
#   autologin (for media PCs)
#   nasinit (for PCs wanting automatic NAS connection via sshfs)
#
# Time for some manual steps:
#
#   Run setup-home-links and add appropriate configs.
#   Then run it again.
#
#   Then add hostname to relevant scripts in ~/.config and ~/bin. Then add
#   ~/.config/ag/startup/wingo-HOST.xinitrc and make it executable.
#
#   Then `setup-system-links --dry-run`. Check the output and then run
#   `sudo -E setup-system-links`. (Somewhat recently, "secure path" has
#   been enabled in sudoers, which makes this annoyingly not work. I've just
#   been disabling it.)

INSTALL_DIR=/mnt

encrypt() {
  if [ $# != 1 ]; then
    echo "Usage: $(basename "$0") encrypt <device>" >&2
    exit 1
  fi
  device="$1"

  cryptsetup -y -v luksFormat "$device"
  cryptsetup open "$device" cryptroot
  echo "partition should be at /dev/mapper/cryptroot"
}

bootstrap() {
  pacstrap "$INSTALL_DIR" base base-devel linux linux-firmware
  genfstab -U "$INSTALL_DIR" >> "$INSTALL_DIR"/etc/fstab
}

installinit() {
  run='curl -fsSL https://burntsushi.net/stuff/arch-install | bash -s -- "$@"'
  dest="$INSTALL_DIR"/archlinux-install

  echo '#!/usr/bin/env bash' > "$dest"
  echo "$run" >> "$INSTALL_DIR"/archlinux-install
  chmod +x "$dest"
}

rootinit() {
  if [ $# != 1 ]; then
    echo "Usage: $(basename "$0") rootinit <hostname>" >&2
    exit 1
  fi
  hostname="$1"

  ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime
  hwclock --systohc
  sed -i 's/^#\(en_US\.UTF-8 .*\)$/\1/g' /etc/locale.gen
  locale-gen
  echo 'LANG=en_US.UTF-8' > /etc/locale.conf

  echo "$hostname" > /etc/hostname
  {
    echo "127.0.0.1  localhost"
    echo "::1  localhost"
    echo "127.0.1.1  $hostname.localdomain $hostname"
  } >> /etc/hosts

  echo 'COMPRESSXZ=(xz -c -z -0 -)' >> /etc/makepkg.conf

  echo "set root password:"
  passwd
}

x() {
  pacman --noconfirm -S xorg xorg-xinit
}

pkgs() {
  pacman --noconfirm -S \
    zsh \
    sudo \
    vi \
    pkgfile \
    alsa-utils vorbis-tools \
    aspell aspell-en hunspell hunspell-en_US \
    uv python python-pip python-setuptools python-virtualenv bpython \
    flake8 \
    go go-tools \
    rustup rust-analyzer \
    grub efibootmgr \
    iputils inetutils whois bind-tools dhcpcd \
    cups \
    shellcheck \
    asciidoc \
    pdftk \
    unzip \
    iwd \
    cronie openssh openssl sshfs sshuttle gnupg tmux nfs-utils enscript \
    docker ffmpeg jq ripgrep yt-dlp fzf \
    iotop htop linux-tools pkgfile pwgen pv strace tig time tree valgrind \
    vim \
    git git-crypt git-absorb tk \
    aws-cli s3cmd colordiff curl wget ctags darkhttpd pass rsync \
    nodejs yarn \
    terminus-font \
    words \
    keyd \
    bash-language-server lua-language-server typescript-language-server
  pkgfile --update
  systemctl enable keyd
}

xpkgs() {
  pacman --noconfirm -Rdd vim
  pacman --noconfirm -S \
    xterm \
    alacritty \
    k3b konversation konsole dolphin okular ffmpegthumbs \
    qt6ct oxygen oxygen-icons kde-cli-tools \
    xbindkeys \
    libnotify \
    kmix \
    dunst \
    i3lock \
    mpv \
    numlockx \
    xclip \
    xsel \
    xdotool \
    wmctrl \
    scrot \
    freerdp \
    gvim \
    vorbis-tools \
    noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra \
    pipewire-audio pipewire-pulse pipewire-alsa wireplumber \
    pamixer pavucontrol \
    recordmydesktop \
    feh variety \
    stalonetray \
    firefox
  systemctl --user enable wireplumber
}

bluetoothinit() {
  pacman --noconfirm -S blueman bluez bluez-utils
  systemctl enable bluetooth
}

andrewinit() {
  # Use the same group ID on all machines.
  sudo groupmod -n users-old users
  sudo groupadd -g 100 users

  sudo useradd -g users -u 1000 -m -s /bin/zsh \
    -G disk,lp,wheel,log,dbus,network,video,audio,optical,storage,scanner,power \
    andrew
  echo "set andrew password"
  sudo passwd andrew
  echo "make sure '%wheel ALL=(ALL) NOPASSWD: ALL' is in sudoers"
}

kaitinit() {
  sudo useradd -g users -u 1002 -m -s /bin/bash \
    -G disk,lp,wheel,log,dbus,network,video,audio,optical,storage,scanner,power \
    kait
  echo "set kait password"
  sudo passwd kait
  echo "make sure '%wheel ALL=(ALL) NOPASSWD: ALL' is in sudoers"
}

wifiinit() {
  pacman --noconfirm -S networkmanager network-manager-applet
  systemctl enable NetworkManager
}

grubinit() {
  grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
  grub-mkconfig -o /boot/grub/grub.cfg
}

yayinit() {
  cd /tmp || exit 1
  if [ ! -d yay ]; then
    git clone https://aur.archlinux.org/yay
  fi
  cd yay || exit 1
  makepkg -fsi --noconfirm
}

aurpkgs() {
  # It looks like these need to be manually installed:
  #
  #   brother-mfc-l3770cdw
  #
  # The AUR packages appear borked.
  yay --noconfirm -S \
    neovim neovim-plug-git python-pynvim \
    brscan4 \
    vim-plug-git \
    zsh-autosuggestions \
    zsh-completions \
    zsh-syntax-highlighting \
    zsh-fast-syntax-highlighting-git \
    dict-wn \
    par
}

aurxpkgs() {
  yay --noconfirm -S \
    dzen2-xft-xpm-xinerama-git \
    google-chrome \
    1password 1password-cli \
    idesk \
    gmrun \
    naps2-bin \
    ttf-hack-nerd \
    ttf-dejavu \
    ttf-fira-mono \
    ttf-mononoki-git \
    ttf-roboto \
    ttf-ubuntu-font-family
}

dhcpcdinit() {
  sudo systemctl enable dhcpcd
}

gpginit() {
  import() {
    private_key="$1"
    fingerprint=$(
      gpg \
        --pinentry-mode loopback \
        --with-colons \
        --import-options show-only \
        --import "$private_key" \
        | awk -F: '$1 == "fpr" {print $10; exit}'
    )
    # We could consider using `gpg --export-ownertrust` and then
    # `gpg --import-ownertrust`. But this way works too.
    echo "$fingerprint:6:" | gpg --import-ownertrust
  }

  rsync \
    --archive --recursive --human-readable --partial --inplace --progress \
    -e 'ssh -p 7704' \
    andrew@home.burntsushi.net:/m/data/andrew/keys/*.key.* /tmp/
  import /tmp/jamslam@gmail.com.key.priv
  import /tmp/kbrady39@gmail.com.key.priv
}

homeinit() {
  cd "$HOME" || exit 1

  rustup toolchain install stable
  rustup default stable

  curl https://burntsushi.net/stuff/setup-home > /tmp/setup-home.sh
  sh /tmp/setup-home.sh
  if ! [ -d .password-store ]; then
    git clone ssh://andrew@home.burntsushi.net:7704/m/git/password-store .password-store
  fi
  (cd .password-store && "$HOME/bin/configure-git")

  mkdir -p .gnupg
  {
    echo 'default-cache-ttl 86400'
    echo 'max-cache-ttl 86400'
  } > .gnupg/gpg-agent.conf
}

xenvinit() {
  cd "$HOME" || exit 1

  # shellcheck disable=SC1091
  . "$HOME/bin/x11-go"
  go install -v github.com/BurntSushi/wingo/...@latest
  go install -v github.com/BurntSushi/gohead/...@latest
  git clone https://github.com/BurntSushi/wingo /tmp/wingo
  mkdir -p ~/.local/share
  cp -a /tmp/wingo/data ~/.local/share/wingo

  # Someone seems to have fucked up the KDE/qt6 packages
  # on Archlinux, so we need to download this magical file
  # in order to make file associations in Dolphin work. WTF.
  #
  # See: https://old.reddit.com/r/kde/comments/1bd313p/dolphin_not_recognizing_file_associations/l26i3m2/
  mkdir -p "$HOME/.config/menus"
  url="https://github.com/KDE/plasma-workspace/raw/11e7f5306fa013ec5c2b894a28457dabf5c42bad/menu/desktop/plasma-applications.menu"
  curl -L "$url" -o "$HOME/.config/menus/applications.menu"
}

# Split into its own step so that it can be run on its own. When major Python
# upgrades occur, the venv can get fucked up. Unless, I think, when uv does
# installation. :-)
pywingoinit() {
  cd "$HOME" || exit 1

  rm -rfv "$HOME/.pyx11"
  uv venv "$HOME/.pyx11"
  # shellcheck disable=SC1091
  . "$HOME/.pyx11/bin/activate"
  uv pip install git+https://github.com/wingowm/pywingo
}

sshinit() {
  sudo systemctl enable sshd
  sudo systemctl start sshd
  ssh-extract-key burntsushi
}

scannerinit() {
  # New color printer.
  sudo brsaneconfig4 -a name=BrotherColor model=MFC-L3770CDW ip=192.168.1.151
}

autologin() {
  sudo mkdir -p /etc/systemd/system/getty@tty1.service.d
  sudo tee /etc/systemd/system/getty@tty1.service.d/override.conf > /dev/null <<EOF
[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin andrew --noclear %I $TERM
EOF
}

nasinit() {
  sudo mkdir /m
  sudo chown andrew:users /m
  systemctl --user enable mount-nas
  systemctl --user start mount-nas
  cd ~/system/etc/NetworkManager/dispatcher.d/50-mount-nas || exit 1
  ln -s run copy:$(myhostname)
}

case "$1" in
  encrypt) shift ; encrypt "$@" ;;
  bootstrap) shift ; bootstrap "$@" ;;
  installinit) shift ; installinit "$@" ;;
  rootinit) shift ; rootinit "$@" ;;
  x) shift ; x "$@" ;;
  pkgs) shift ; pkgs "$@" ;;
  xpkgs) shift ; xpkgs "$@" ;;
  bluetoothinit) shift ; bluetoothinit "$@" ;;
  andrewinit) shift ; andrewinit "$@" ;;
  kaitinit) shift ; kaitinit "$@" ;;
  wifiinit) shift ; wifiinit "$@" ;;
  grubinit) shift ; grubinit "$@" ;;
  yayinit) shift ; yayinit "$@" ;;
  aurpkgs) shift ; aurpkgs "$@" ;;
  aurxpkgs) shift ; aurxpkgs "$@" ;;
  homeinit) shift ; homeinit "$@" ;;
  xenvinit) shift ; xenvinit "$@" ;;
  pywingoinit) shift ; pywingoinit "$@" ;;
  dhcpcdinit) shift ; dhcpcdinit "$@" ;;
  gpginit) shift ; gpginit "$@" ;;
  sshinit) shift ; sshinit "$@" ;;
  scannerinit) shift ; scannerinit "$@" ;;
  autologin) shift ; autologin "$@" ;;
  nasinit) shift ; nasinit "$@" ;;
  *)
    echo "unrecognized command" >&2
    exit 1
    ;;
esac