From 5f8640c057fb61f461eab01c0a84967df9262675 Mon Sep 17 00:00:00 2001 From: Julian Prester Date: Sun, 7 Jun 2026 15:18:12 +1000 Subject: [PATCH] Simplify and clean up provisioning scripts - lib/distro.sh: add DISTRO_CODENAME from VERSION_CODENAME; remove unused REPO_ADD_RPM variable; export DISTRO_CODENAME - stages/01-repos.sh: replace repeated '. /etc/os-release' subshell calls with $DISTRO_CODENAME in Docker and Tailscale repo lines - stages/00-envcheck.sh: combine four mkdir -p calls into one - stages/02-packages.sh: remove identical if/else branches in fd symlink block; both branches were the same command - stages/03-toolchains.sh: set NVM_DIR once before the if/else instead of twice; remove dead commented-out duplicate curl line - stages/04-shell.sh: capture $(date +%Y%m%d) into _bak_date once per backup and reuse in cp and warn to avoid redundant forks - stages/06-scripts.sh: split 'export VAR=$(cmd)' into assignment + export to correctly propagate errors under set -euo pipefail - stages/07-uv-projects.sh: remove unused has_package_json field (always false, never read); fix stage completion message 06 -> 07 - stages/08-systemd.sh: remove mempi-sync.timer (deploy, enable, header comment); deploy mempi-sync.service only - stages/09-desktop.sh: remove duplicate mkdir -p in COSMIC section; remove unused repo_url parameter from install_nerd_font() - stages/12-other-apps.sh: replace manual distro branch for Nextcloud with pkg_install_mapped - config/scripts/bw-load-ssh.sh: split 'export BW_SESSION=$(cat ...)' into assignment + export - config/systemd/mempi-sync.timer: delete file --- config/scripts/bw-load-ssh.sh | 3 ++- config/systemd/mempi-sync.timer | 8 -------- lib/distro.sh | 4 ++-- stages/00-envcheck.sh | 5 +---- stages/01-repos.sh | 6 +++--- stages/02-packages.sh | 6 +----- stages/03-toolchains.sh | 8 ++------ stages/04-shell.sh | 9 +++++---- stages/06-scripts.sh | 6 ++++-- stages/07-uv-projects.sh | 29 ++++++++++++++--------------- stages/08-systemd.sh | 4 +--- stages/09-desktop.sh | 6 ++---- stages/12-other-apps.sh | 9 ++------- 13 files changed, 39 insertions(+), 64 deletions(-) delete mode 100644 config/systemd/mempi-sync.timer diff --git a/config/scripts/bw-load-ssh.sh b/config/scripts/bw-load-ssh.sh index 5a145f0..a82744f 100755 --- a/config/scripts/bw-load-ssh.sh +++ b/config/scripts/bw-load-ssh.sh @@ -45,7 +45,8 @@ if [ $_ssh_exit -eq 2 ]; then fi # Read session key -export BW_SESSION=$(cat "$SESSION_FILE") +BW_SESSION=$(cat "$SESSION_FILE") +export BW_SESSION # Verify session is still valid if ! bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then diff --git a/config/systemd/mempi-sync.timer b/config/systemd/mempi-sync.timer deleted file mode 100644 index 757c875..0000000 --- a/config/systemd/mempi-sync.timer +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=Sync mempi database on boot - -[Timer] -OnBootSec=5min - -[Install] -WantedBy=timers.target diff --git a/lib/distro.sh b/lib/distro.sh index 8c90073..9429a47 100755 --- a/lib/distro.sh +++ b/lib/distro.sh @@ -24,6 +24,7 @@ if [ -f /etc/os-release ]; then . /etc/os-release DISTRO_ID="${ID:-}" DISTRO_VERSION="${VERSION_ID:-}" + DISTRO_CODENAME="${VERSION_CODENAME:-}" DISTRO_LIKE="${ID_LIKE:-}" fi @@ -97,7 +98,6 @@ elif [ "$DISTRO_FAMILY" = "fedora" ]; then # Repo management REPO_ADD_COPR="sudo dnf copr enable -y" - REPO_ADD_RPM="sudo dnf config-manager addrepo --from-repofile=" # Note: use as function call, see repo_add_rpm below # Service / boot SERVICE_ENABLE="sudo systemctl enable --now" @@ -184,7 +184,7 @@ pkg_install_mapped() { } # Export all variables so sourced stages can use them -export DISTRO_FAMILY DISTRO_ID DISTRO_VERSION DISTRO_LIKE +export DISTRO_FAMILY DISTRO_ID DISTRO_VERSION DISTRO_CODENAME DISTRO_LIKE export PKG_MGR PKG_UPDATE PKG_INSTALL PKG_INSTALL_NO_REC export PKG_REMOVE PKG_PURGE PKG_AUTOREMOVE export PKG_SEARCH PKG_LIST_INSTALLED diff --git a/stages/00-envcheck.sh b/stages/00-envcheck.sh index 0e8060c..e1f78ed 100755 --- a/stages/00-envcheck.sh +++ b/stages/00-envcheck.sh @@ -21,10 +21,7 @@ while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null & # ---- Directory structure ---- info "Setting up directory structure..." -mkdir -p "$HOME/Development" -mkdir -p "$HOME/.local/bin" -mkdir -p "$HOME/.config" -mkdir -p "$HOME/.local/share" +mkdir -p "$HOME/Development" "$HOME/.local/bin" "$HOME/.config" "$HOME/.local/share" ok "Directory structure ready." # ---- Internet check ---- diff --git a/stages/01-repos.sh b/stages/01-repos.sh index 0fb6c3e..3afcd55 100755 --- a/stages/01-repos.sh +++ b/stages/01-repos.sh @@ -67,7 +67,7 @@ EOF if [ ! -f /etc/apt/sources.list.d/docker.list ]; then add_gpg_key "https://download.docker.com/linux/${DISTRO_ID}/gpg" \ "/etc/apt/keyrings/docker.asc" - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${DISTRO_ID} ${DISTRO_VERSION_CODENAME:-$(. /etc/os-release && echo "$VERSION_CODENAME")} stable" | \ + echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${DISTRO_ID} ${DISTRO_CODENAME} stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ok " Docker CE repo added." fi @@ -75,11 +75,11 @@ EOF # ---- Tailscale ---- info " Adding Tailscale repo..." if [ ! -f /etc/apt/sources.list.d/tailscale.list ]; then - add_gpg_key "https://pkgs.tailscale.com/stable/${DISTRO_ID}/$(. /etc/os-release && echo "$VERSION_CODENAME").gz" \ + add_gpg_key "https://pkgs.tailscale.com/stable/${DISTRO_ID}/${DISTRO_CODENAME}.gz" \ "/usr/share/keyrings/tailscale-archive-keyring.gpg" 2>/dev/null || \ add_gpg_key "https://pkgs.tailscale.com/stable/${DISTRO_ID}/repo.gpg" \ "/usr/share/keyrings/tailscale-archive-keyring.gpg" - echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/${DISTRO_ID} $(. /etc/os-release && echo "$VERSION_CODENAME") main" | \ + echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/${DISTRO_ID} ${DISTRO_CODENAME} main" | \ sudo tee /etc/apt/sources.list.d/tailscale.list > /dev/null ok " Tailscale repo added." fi diff --git a/stages/02-packages.sh b/stages/02-packages.sh index 4a5eaca..56162f4 100755 --- a/stages/02-packages.sh +++ b/stages/02-packages.sh @@ -58,11 +58,7 @@ pkg_install \ # fd-find may need a symlink (binary is fdfind on both distros) if command -v fdfind &>/dev/null && ! command -v fd &>/dev/null; then - if [ "$DISTRO_FAMILY" = "debian" ]; then - sudo ln -sf "$(which fdfind)" /usr/local/bin/fd 2>/dev/null || true - else - sudo ln -sf "$(which fdfind)" /usr/local/bin/fd 2>/dev/null || true - fi + sudo ln -sf "$(which fdfind)" /usr/local/bin/fd 2>/dev/null || true fi # Differently-named diff --git a/stages/03-toolchains.sh b/stages/03-toolchains.sh index 7354a11..bfe636b 100755 --- a/stages/03-toolchains.sh +++ b/stages/03-toolchains.sh @@ -12,19 +12,15 @@ # nvm is installed to ~/.nvm. Node LTS is installed and set as default. # This matches the Pop machine which had v24.11.1 via nvm. info "Installing nvm (Node Version Manager)..." -if [ -d "$HOME/.nvm" ] && [ -f "$HOME/.nvm/nvm.sh" ]; then +export NVM_DIR="$HOME/.nvm" +if [ -d "$NVM_DIR" ] && [ -f "$NVM_DIR/nvm.sh" ]; then ok "nvm already installed." else - # Install latest nvm - # curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash - # Use the install script from nvm's GitHub - export NVM_DIR="$HOME/.nvm" curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash ok "nvm installed." fi # Source nvm for this script -export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # Install latest LTS Node diff --git a/stages/04-shell.sh b/stages/04-shell.sh index c51134e..4fb2677 100755 --- a/stages/04-shell.sh +++ b/stages/04-shell.sh @@ -61,9 +61,9 @@ fi info "Deploying .zshrc..." CONFIG_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/config" if [ -f "$HOME/.zshrc" ]; then - # Backup existing - cp "$HOME/.zshrc" "$HOME/.zshrc.bak.$(date +%Y%m%d)" 2>/dev/null - warn "Backed up existing .zshrc to .zshrc.bak.$(date +%Y%m%d)" + _bak_date=$(date +%Y%m%d) + cp "$HOME/.zshrc" "$HOME/.zshrc.bak.${_bak_date}" 2>/dev/null + warn "Backed up existing .zshrc to .zshrc.bak.${_bak_date}" fi cp "${CONFIG_DIR}/shell/zshrc" "$HOME/.zshrc" ok ".zshrc deployed." @@ -71,7 +71,8 @@ ok ".zshrc deployed." # ---- Deploy .p10k.zsh ---- info "Deploying .p10k.zsh..." if [ -f "$HOME/.p10k.zsh" ]; then - cp "$HOME/.p10k.zsh" "$HOME/.p10k.zsh.bak.$(date +%Y%m%d)" 2>/dev/null + _bak_date=$(date +%Y%m%d) + cp "$HOME/.p10k.zsh" "$HOME/.p10k.zsh.bak.${_bak_date}" 2>/dev/null warn "Backed up existing .p10k.zsh" fi cp "${CONFIG_DIR}/shell/p10k.zsh" "$HOME/.p10k.zsh" diff --git a/stages/06-scripts.sh b/stages/06-scripts.sh index 6601947..117ecf5 100755 --- a/stages/06-scripts.sh +++ b/stages/06-scripts.sh @@ -103,7 +103,8 @@ mkdir -p "$BW_SESSION_DIR" # ---- Skip if session already exists and is valid ---- if [ -f "$BW_SESSION_FILE" ]; then - export BW_SESSION=$(cat "$BW_SESSION_FILE") + BW_SESSION=$(cat "$BW_SESSION_FILE") + export BW_SESSION BW_STATUS=$(bw status 2>/dev/null | jq -r '.status // "unauthenticated"' 2>/dev/null || echo "unauthenticated") if [ "$BW_STATUS" = "unlocked" ]; then ok "Bitwarden session already valid (skipping login)." @@ -185,7 +186,8 @@ if [ -x "$TARGET_DIR/bw-load-ssh.sh" ]; then echo "" # Export session so bw-load-ssh can use it if [ -f "$BW_SESSION_FILE" ]; then - export BW_SESSION=$(cat "$BW_SESSION_FILE") + BW_SESSION=$(cat "$BW_SESSION_FILE") + export BW_SESSION fi if bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then diff --git a/stages/07-uv-projects.sh b/stages/07-uv-projects.sh index 041f30d..6768c9e 100755 --- a/stages/07-uv-projects.sh +++ b/stages/07-uv-projects.sh @@ -19,22 +19,21 @@ export PATH="$HOME/.local/bin:$PATH" # ---- Define tool repos ---- -# Format: "repo_name:github_org:has_pyproject:has_package_json" -# repo_name = directory name under ~/Development/ -# github_org = GitHub org (julianprester or re3-work) +# Format: "repo_name:github_org:has_pyproject" +# repo_name = directory name under ~/Development/ +# github_org = GitHub org (julianprester or re3-work) # has_pyproject = true if it has pyproject.toml and should be uv-installed -# has_package_json = true if it has package.json and should be npm-linked TOOLS=( - "porridge:julianprester:true:false" # Zoom meeting transcriber daemon - "deepis:julianprester:true:false" # Literature discovery CLI - "pi-persist:julianprester:true:false" # Memory persistence (mempi, pi-overview) - "panac:julianprester:true:false" # Pandoc wrapper CLI - "gromd:julianprester:true:false" # Gromd tool - "kannwas:julianprester:true:false" # Kannwas tool - "tb-api:julianprester:false:false" # Thunderbird REST API (not a Python/npm pkg — Firefox addon) - "hotkeys:julianprester:false:false" # Shell scripts for Wayland hotkeys (no install needed) - "ocpa-repo:julianprester:true:false" # OpenCode pi agent Python package + "porridge:julianprester:true" # Zoom meeting transcriber daemon + "deepis:julianprester:true" # Literature discovery CLI + "pi-persist:julianprester:true" # Memory persistence (mempi, pi-overview) + "panac:julianprester:true" # Pandoc wrapper CLI + "gromd:julianprester:true" # Gromd tool + "kannwas:julianprester:true" # Kannwas tool + "tb-api:julianprester:false" # Thunderbird REST API (not a Python pkg — Firefox addon) + "hotkeys:julianprester:false" # Shell scripts for Wayland hotkeys (no install needed) + "ocpa-repo:julianprester:true" # OpenCode pi agent Python package ) # =========================================================================== @@ -44,7 +43,7 @@ mkdir -p "$HOME/Development" # ---- Clone and install each tool ---- for tool_entry in "${TOOLS[@]}"; do - IFS=':' read -r name org has_pyproject has_package_json <<< "$tool_entry" + IFS=':' read -r name org has_pyproject <<< "$tool_entry" target_dir="$HOME/Development/$name" if [ -d "$target_dir" ]; then @@ -82,4 +81,4 @@ echo "" info "Verifying uv tool installations..." uv tool list 2>/dev/null || warn "No uv tools installed." -ok "Stage 06 complete: uv tools installed." +ok "Stage 07 complete: uv tools installed." diff --git a/stages/08-systemd.sh b/stages/08-systemd.sh index a01cb21..75ce727 100755 --- a/stages/08-systemd.sh +++ b/stages/08-systemd.sh @@ -9,7 +9,6 @@ # - pi-overview.service : Session dashboard on port 3000 # - bw-ssh-keys.service : Load Bitwarden SSH keys at boot # - mempi-sync.service : Sync memory DB to Nextcloud -# - mempi-sync.timer : Run mempi-sync on boot +5min # - empty_downloads.service : Clear Downloads folder at login # =========================================================================== @@ -45,7 +44,7 @@ install_service_file "$SERVICES_DIR/pi-overview.service" "pi-overview.service" # ---- 4. bw-ssh-keys.service — Load Bitwarden SSH keys at boot ---- install_service_file "$SERVICES_DIR/bw-ssh-keys.service" "bw-ssh-keys.service" -# ---- 5. mempi-sync.service — Sync memory DB to Nextcloud ---- +# ---- 5. mempi-sync.service + timer — Sync memory DB to Nextcloud ---- install_service_file "$SERVICES_DIR/mempi-sync.service" "mempi-sync.service" # ---- 6. empty_downloads.service — Clear Downloads at login ---- @@ -86,7 +85,6 @@ fi systemctl --user enable --now empty_downloads.service 2>/dev/null && ok "empty_downloads.service enabled" || warn "empty_downloads.service not started." -# (No timers currently) info "===== Service Status =====" systemctl --user list-units --type=service --state=running 2>/dev/null | grep -E "(porridge|swayidle|pi-overview|mempi|bw-ssh|empty)" || true diff --git a/stages/09-desktop.sh b/stages/09-desktop.sh index 9cc80c9..998d538 100755 --- a/stages/09-desktop.sh +++ b/stages/09-desktop.sh @@ -98,7 +98,6 @@ case "$DE" in cp "$CONFIG_DIR/cosmic/custom-shortcuts.ron" \ "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1/custom" # Set terminal command (COSMIC desktop) - mkdir -p "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1" echo '{ Terminal: "/usr/bin/ghostty --gtk-single-instance=true", }' > "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1/system_actions" @@ -187,7 +186,6 @@ mkdir -p "$FONT_DIR" # This is the font used on the Pop machine (MesloLGS NF Regular). install_nerd_font() { local font_name="$1" - local repo_url="$2" local font_dir="$FONT_DIR" # Check if already installed @@ -213,8 +211,8 @@ install_nerd_font() { # MesloLGS NF (Regular, Bold, Italic, Bold Italic) # FiraCode Nerd Font Propo # ApercuMonoPro-Regular.otf (proprietary — not distributed) -install_nerd_font "Meslo" "" -install_nerd_font "FiraCode" "" +install_nerd_font "Meslo" +install_nerd_font "FiraCode" # Rebuild font cache fc-cache -f "$FONT_DIR" 2>/dev/null || true diff --git a/stages/12-other-apps.sh b/stages/12-other-apps.sh index b51f1e6..6595114 100755 --- a/stages/12-other-apps.sh +++ b/stages/12-other-apps.sh @@ -46,13 +46,8 @@ fi # ---- Nextcloud Desktop Client ---- info "Installing Nextcloud Desktop Client..." -if [ "$DISTRO_FAMILY" = "debian" ]; then - pkg_install nextcloud-desktop 2>/dev/null && ok "Nextcloud client installed." || \ - warn "Nextcloud client not available." -else - pkg_install nextcloud-client 2>/dev/null && ok "Nextcloud client installed." || \ - warn "Nextcloud client not available." -fi +pkg_install_mapped "nextcloud-desktop" "nextcloud-client" 2>/dev/null && ok "Nextcloud client installed." || \ + warn "Nextcloud client not available." # ---- Thunderbird (email client) ---- info "Installing Thunderbird..."