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
This commit is contained in:
2026-06-07 15:18:12 +10:00
parent 2ca9a2bdef
commit 5f8640c057
13 changed files with 39 additions and 64 deletions

View File

@@ -45,7 +45,8 @@ if [ $_ssh_exit -eq 2 ]; then
fi fi
# Read session key # Read session key
export BW_SESSION=$(cat "$SESSION_FILE") BW_SESSION=$(cat "$SESSION_FILE")
export BW_SESSION
# Verify session is still valid # Verify session is still valid
if ! bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then if ! bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then

View File

@@ -1,8 +0,0 @@
[Unit]
Description=Sync mempi database on boot
[Timer]
OnBootSec=5min
[Install]
WantedBy=timers.target

View File

@@ -24,6 +24,7 @@ if [ -f /etc/os-release ]; then
. /etc/os-release . /etc/os-release
DISTRO_ID="${ID:-}" DISTRO_ID="${ID:-}"
DISTRO_VERSION="${VERSION_ID:-}" DISTRO_VERSION="${VERSION_ID:-}"
DISTRO_CODENAME="${VERSION_CODENAME:-}"
DISTRO_LIKE="${ID_LIKE:-}" DISTRO_LIKE="${ID_LIKE:-}"
fi fi
@@ -97,7 +98,6 @@ elif [ "$DISTRO_FAMILY" = "fedora" ]; then
# Repo management # Repo management
REPO_ADD_COPR="sudo dnf copr enable -y" 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 / boot
SERVICE_ENABLE="sudo systemctl enable --now" SERVICE_ENABLE="sudo systemctl enable --now"
@@ -184,7 +184,7 @@ pkg_install_mapped() {
} }
# Export all variables so sourced stages can use them # 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_MGR PKG_UPDATE PKG_INSTALL PKG_INSTALL_NO_REC
export PKG_REMOVE PKG_PURGE PKG_AUTOREMOVE export PKG_REMOVE PKG_PURGE PKG_AUTOREMOVE
export PKG_SEARCH PKG_LIST_INSTALLED export PKG_SEARCH PKG_LIST_INSTALLED

View File

@@ -21,10 +21,7 @@ while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &
# ---- Directory structure ---- # ---- Directory structure ----
info "Setting up directory structure..." info "Setting up directory structure..."
mkdir -p "$HOME/Development" mkdir -p "$HOME/Development" "$HOME/.local/bin" "$HOME/.config" "$HOME/.local/share"
mkdir -p "$HOME/.local/bin"
mkdir -p "$HOME/.config"
mkdir -p "$HOME/.local/share"
ok "Directory structure ready." ok "Directory structure ready."
# ---- Internet check ---- # ---- Internet check ----

View File

@@ -67,7 +67,7 @@ EOF
if [ ! -f /etc/apt/sources.list.d/docker.list ]; then if [ ! -f /etc/apt/sources.list.d/docker.list ]; then
add_gpg_key "https://download.docker.com/linux/${DISTRO_ID}/gpg" \ add_gpg_key "https://download.docker.com/linux/${DISTRO_ID}/gpg" \
"/etc/apt/keyrings/docker.asc" "/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 sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
ok " Docker CE repo added." ok " Docker CE repo added."
fi fi
@@ -75,11 +75,11 @@ EOF
# ---- Tailscale ---- # ---- Tailscale ----
info " Adding Tailscale repo..." info " Adding Tailscale repo..."
if [ ! -f /etc/apt/sources.list.d/tailscale.list ]; then 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 || \ "/usr/share/keyrings/tailscale-archive-keyring.gpg" 2>/dev/null || \
add_gpg_key "https://pkgs.tailscale.com/stable/${DISTRO_ID}/repo.gpg" \ add_gpg_key "https://pkgs.tailscale.com/stable/${DISTRO_ID}/repo.gpg" \
"/usr/share/keyrings/tailscale-archive-keyring.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 sudo tee /etc/apt/sources.list.d/tailscale.list > /dev/null
ok " Tailscale repo added." ok " Tailscale repo added."
fi fi

View File

@@ -58,11 +58,7 @@ pkg_install \
# fd-find may need a symlink (binary is fdfind on both distros) # 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 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
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
fi fi
# Differently-named # Differently-named

View File

@@ -12,19 +12,15 @@
# nvm is installed to ~/.nvm. Node LTS is installed and set as default. # 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. # This matches the Pop machine which had v24.11.1 via nvm.
info "Installing nvm (Node Version Manager)..." 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." ok "nvm already installed."
else 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 curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash
ok "nvm installed." ok "nvm installed."
fi fi
# Source nvm for this script # Source nvm for this script
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
# Install latest LTS Node # Install latest LTS Node

View File

@@ -61,9 +61,9 @@ fi
info "Deploying .zshrc..." info "Deploying .zshrc..."
CONFIG_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/config" CONFIG_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/config"
if [ -f "$HOME/.zshrc" ]; then if [ -f "$HOME/.zshrc" ]; then
# Backup existing _bak_date=$(date +%Y%m%d)
cp "$HOME/.zshrc" "$HOME/.zshrc.bak.$(date +%Y%m%d)" 2>/dev/null cp "$HOME/.zshrc" "$HOME/.zshrc.bak.${_bak_date}" 2>/dev/null
warn "Backed up existing .zshrc to .zshrc.bak.$(date +%Y%m%d)" warn "Backed up existing .zshrc to .zshrc.bak.${_bak_date}"
fi fi
cp "${CONFIG_DIR}/shell/zshrc" "$HOME/.zshrc" cp "${CONFIG_DIR}/shell/zshrc" "$HOME/.zshrc"
ok ".zshrc deployed." ok ".zshrc deployed."
@@ -71,7 +71,8 @@ ok ".zshrc deployed."
# ---- Deploy .p10k.zsh ---- # ---- Deploy .p10k.zsh ----
info "Deploying .p10k.zsh..." info "Deploying .p10k.zsh..."
if [ -f "$HOME/.p10k.zsh" ]; then 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" warn "Backed up existing .p10k.zsh"
fi fi
cp "${CONFIG_DIR}/shell/p10k.zsh" "$HOME/.p10k.zsh" cp "${CONFIG_DIR}/shell/p10k.zsh" "$HOME/.p10k.zsh"

View File

@@ -103,7 +103,8 @@ mkdir -p "$BW_SESSION_DIR"
# ---- Skip if session already exists and is valid ---- # ---- Skip if session already exists and is valid ----
if [ -f "$BW_SESSION_FILE" ]; then 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") BW_STATUS=$(bw status 2>/dev/null | jq -r '.status // "unauthenticated"' 2>/dev/null || echo "unauthenticated")
if [ "$BW_STATUS" = "unlocked" ]; then if [ "$BW_STATUS" = "unlocked" ]; then
ok "Bitwarden session already valid (skipping login)." ok "Bitwarden session already valid (skipping login)."
@@ -185,7 +186,8 @@ if [ -x "$TARGET_DIR/bw-load-ssh.sh" ]; then
echo "" echo ""
# Export session so bw-load-ssh can use it # Export session so bw-load-ssh can use it
if [ -f "$BW_SESSION_FILE" ]; then if [ -f "$BW_SESSION_FILE" ]; then
export BW_SESSION=$(cat "$BW_SESSION_FILE") BW_SESSION=$(cat "$BW_SESSION_FILE")
export BW_SESSION
fi fi
if bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then if bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then

View File

@@ -19,22 +19,21 @@
export PATH="$HOME/.local/bin:$PATH" export PATH="$HOME/.local/bin:$PATH"
# ---- Define tool repos ---- # ---- Define tool repos ----
# Format: "repo_name:github_org:has_pyproject:has_package_json" # Format: "repo_name:github_org:has_pyproject"
# repo_name = directory name under ~/Development/ # repo_name = directory name under ~/Development/
# github_org = GitHub org (julianprester or re3-work) # github_org = GitHub org (julianprester or re3-work)
# has_pyproject = true if it has pyproject.toml and should be uv-installed # 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=( TOOLS=(
"porridge:julianprester:true:false" # Zoom meeting transcriber daemon "porridge:julianprester:true" # Zoom meeting transcriber daemon
"deepis:julianprester:true:false" # Literature discovery CLI "deepis:julianprester:true" # Literature discovery CLI
"pi-persist:julianprester:true:false" # Memory persistence (mempi, pi-overview) "pi-persist:julianprester:true" # Memory persistence (mempi, pi-overview)
"panac:julianprester:true:false" # Pandoc wrapper CLI "panac:julianprester:true" # Pandoc wrapper CLI
"gromd:julianprester:true:false" # Gromd tool "gromd:julianprester:true" # Gromd tool
"kannwas:julianprester:true:false" # Kannwas tool "kannwas:julianprester:true" # Kannwas tool
"tb-api:julianprester:false:false" # Thunderbird REST API (not a Python/npm pkg — Firefox addon) "tb-api:julianprester:false" # Thunderbird REST API (not a Python pkg — Firefox addon)
"hotkeys:julianprester:false:false" # Shell scripts for Wayland hotkeys (no install needed) "hotkeys:julianprester:false" # Shell scripts for Wayland hotkeys (no install needed)
"ocpa-repo:julianprester:true:false" # OpenCode pi agent Python package "ocpa-repo:julianprester:true" # OpenCode pi agent Python package
) )
# =========================================================================== # ===========================================================================
@@ -44,7 +43,7 @@ mkdir -p "$HOME/Development"
# ---- Clone and install each tool ---- # ---- Clone and install each tool ----
for tool_entry in "${TOOLS[@]}"; do 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" target_dir="$HOME/Development/$name"
if [ -d "$target_dir" ]; then if [ -d "$target_dir" ]; then
@@ -82,4 +81,4 @@ echo ""
info "Verifying uv tool installations..." info "Verifying uv tool installations..."
uv tool list 2>/dev/null || warn "No uv tools installed." 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."

View File

@@ -9,7 +9,6 @@
# - pi-overview.service : Session dashboard on port 3000 # - pi-overview.service : Session dashboard on port 3000
# - bw-ssh-keys.service : Load Bitwarden SSH keys at boot # - bw-ssh-keys.service : Load Bitwarden SSH keys at boot
# - mempi-sync.service : Sync memory DB to Nextcloud # - 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 # - 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 ---- # ---- 4. bw-ssh-keys.service — Load Bitwarden SSH keys at boot ----
install_service_file "$SERVICES_DIR/bw-ssh-keys.service" "bw-ssh-keys.service" 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" install_service_file "$SERVICES_DIR/mempi-sync.service" "mempi-sync.service"
# ---- 6. empty_downloads.service — Clear Downloads at login ---- # ---- 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." 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 =====" 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 systemctl --user list-units --type=service --state=running 2>/dev/null | grep -E "(porridge|swayidle|pi-overview|mempi|bw-ssh|empty)" || true

View File

@@ -98,7 +98,6 @@ case "$DE" in
cp "$CONFIG_DIR/cosmic/custom-shortcuts.ron" \ cp "$CONFIG_DIR/cosmic/custom-shortcuts.ron" \
"$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1/custom" "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1/custom"
# Set terminal command (COSMIC desktop) # Set terminal command (COSMIC desktop)
mkdir -p "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1"
echo '{ echo '{
Terminal: "/usr/bin/ghostty --gtk-single-instance=true", Terminal: "/usr/bin/ghostty --gtk-single-instance=true",
}' > "$HOME/.config/cosmic/com.system76.CosmicSettings.Shortcuts/v1/system_actions" }' > "$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). # This is the font used on the Pop machine (MesloLGS NF Regular).
install_nerd_font() { install_nerd_font() {
local font_name="$1" local font_name="$1"
local repo_url="$2"
local font_dir="$FONT_DIR" local font_dir="$FONT_DIR"
# Check if already installed # Check if already installed
@@ -213,8 +211,8 @@ install_nerd_font() {
# MesloLGS NF (Regular, Bold, Italic, Bold Italic) # MesloLGS NF (Regular, Bold, Italic, Bold Italic)
# FiraCode Nerd Font Propo # FiraCode Nerd Font Propo
# ApercuMonoPro-Regular.otf (proprietary — not distributed) # ApercuMonoPro-Regular.otf (proprietary — not distributed)
install_nerd_font "Meslo" "" install_nerd_font "Meslo"
install_nerd_font "FiraCode" "" install_nerd_font "FiraCode"
# Rebuild font cache # Rebuild font cache
fc-cache -f "$FONT_DIR" 2>/dev/null || true fc-cache -f "$FONT_DIR" 2>/dev/null || true

View File

@@ -46,13 +46,8 @@ fi
# ---- Nextcloud Desktop Client ---- # ---- Nextcloud Desktop Client ----
info "Installing Nextcloud Desktop Client..." info "Installing Nextcloud Desktop Client..."
if [ "$DISTRO_FAMILY" = "debian" ]; then pkg_install_mapped "nextcloud-desktop" "nextcloud-client" 2>/dev/null && ok "Nextcloud client installed." || \
pkg_install nextcloud-desktop 2>/dev/null && ok "Nextcloud client installed." || \ warn "Nextcloud client not available."
warn "Nextcloud client not available."
else
pkg_install nextcloud-client 2>/dev/null && ok "Nextcloud client installed." || \
warn "Nextcloud client not available."
fi
# ---- Thunderbird (email client) ---- # ---- Thunderbird (email client) ----
info "Installing Thunderbird..." info "Installing Thunderbird..."