From 845567d1f5a40a6e179cb14592e2ae1e8304cb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Martin=20J=C3=A4ckel?= Date: Fri, 17 Jul 2026 20:02:49 +0200 Subject: [PATCH] update --- .gitignore | 3 + README.md | 24 +++- applications/.gitkeep | 1 + backup.sh | 103 ++++++++++++-- bash/.gitkeep | 1 + bootstrap.sh | 31 ++++ flatpaks.txt | 1 + fonts/.gitkeep | 1 + install.sh | 205 +++++++++++++++++++-------- smb-setup.md | 283 +++++++++++++++++++++++++++++++++++++ smb/README.md | 10 ++ smb/fstab.fragment.example | 2 + smb/install.sh | 32 +++++ tracked-configs.txt | 16 +++ version.txt | 1 + 15 files changed, 635 insertions(+), 79 deletions(-) create mode 100644 applications/.gitkeep mode change 100644 => 100755 backup.sh create mode 100644 bash/.gitkeep create mode 100755 bootstrap.sh create mode 100644 flatpaks.txt create mode 100644 fonts/.gitkeep mode change 100644 => 100755 install.sh create mode 100644 smb-setup.md create mode 100644 smb/README.md create mode 100644 smb/fstab.fragment.example create mode 100755 smb/install.sh create mode 100644 tracked-configs.txt create mode 100644 version.txt diff --git a/.gitignore b/.gitignore index 263cc87..e54c5c6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ Thumbs.db node_modules/ __pycache__/ + +# Local machine secrets and filled-in templates +smb/fstab.fragment diff --git a/README.md b/README.md index f3b829b..0de0947 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,21 @@ # Milan's Omarchy Config -## Install +This repository is the source of truth for Milan's Omarchy workstation. +Configs are restored with symlinks so future edits should happen here. + +## Fresh install ```bash git clone https://git.ta52.dk/milan/omarchy-config.git cd omarchy-config -chmod +x install.sh +./bootstrap.sh +``` +## Restore on an existing install + +```bash ./install.sh ``` @@ -25,3 +32,16 @@ git commit -m "Update" git push ``` + +## Structure + +- `tracked-configs.txt` lists every managed config symlink. +- `configs/` stores files that restore into `~/.config`. +- `bash/` can store `.bashrc` and `.bash_aliases` when enabled in `tracked-configs.txt`. +- `scripts/` restores executable helpers into `~/.local/bin`. +- `applications/` restores custom launchers into `~/.local/share/applications`. +- `fonts/` restores into `~/.local/share/fonts/omarchy-config`. +- `system/` stores exported service and system package metadata. +- `smb/` stores SMB automount templates without credentials. + +Set `ENABLE_SYSTEM_SERVICES=1` to restore system services and `INSTALL_SMB=1` to run the SMB installer. diff --git a/applications/.gitkeep b/applications/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/applications/.gitkeep @@ -0,0 +1 @@ + diff --git a/backup.sh b/backup.sh old mode 100644 new mode 100755 index 8c6b724..35184f5 --- a/backup.sh +++ b/backup.sh @@ -2,36 +2,109 @@ set -euo pipefail +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TRACKED_CONFIGS="$REPO_DIR/tracked-configs.txt" + +copy_path() { + local source="$1" + local destination="$2" + + if [[ ! -e "$source" && ! -L "$source" ]]; then + echo "Skipping missing source: $source" + return 0 + fi + + if [[ -e "$destination" || -L "$destination" ]]; then + if [[ "$(readlink -f "$source")" == "$(readlink -f "$destination")" ]]; then + echo "Already tracked: ${destination#$REPO_DIR/}" + return 0 + fi + rm -rf "$destination" + fi + + mkdir -p "$(dirname "$destination")" + cp -a "$source" "$destination" + echo "Copied $source -> ${destination#$REPO_DIR/}" +} + +read_list() { + local file="$1" + + [[ -f "$file" ]] || return 0 + + sed 's/#.*//' "$file" | awk 'NF {print $1}' +} + +write_version_file() { + { + echo "Generated: $(date -Is)" + echo "Kernel: $(uname -r)" + if command -v hyprctl >/dev/null 2>&1; then + hyprctl version | sed -n '1p' | sed 's/^/Hyprland: /' + fi + if command -v omarchy >/dev/null 2>&1; then + omarchy version 2>/dev/null | sed 's/^/Omarchy: /' || true + fi + } > "$REPO_DIR/version.txt" +} + +cd "$REPO_DIR" + echo "Updating package lists..." pacman -Qqe > packages.txt pacman -Qqem > aur-packages.txt pacman -Qe > installed-packages-full.txt -echo "Updating configs..." +if command -v flatpak >/dev/null 2>&1; then + flatpak list --app --columns=application > flatpaks.txt +fi -rm -rf configs +echo "Updating version info..." +write_version_file -mkdir configs +echo "Updating tracked configs..." -cp -r ~/.config/omarchy configs/ -cp -r ~/.config/hypr configs/ -cp -r ~/.config/waybar configs/ -cp -r ~/.config/walker configs/ -cp -r ~/.config/ghostty configs/ -cp -r ~/.config/kitty configs/ -cp -r ~/.config/mako configs/ -cp -r ~/.config/nvim configs/ -cp -r ~/.config/fastfetch configs/ +if [[ ! -f "$TRACKED_CONFIGS" ]]; then + echo "Missing tracked-configs.txt" + exit 1 +fi -cp ~/.config/starship.toml configs/ -cp ~/.config/mimeapps.list configs/ +while read -r destination source; do + [[ -n "${destination:-}" ]] || continue + [[ "$destination" != \#* ]] || continue + [[ -n "${source:-}" ]] || source="$destination" + + destination="${destination/#\~/$HOME}" + source="${source/#\~/$HOME}" + + [[ "$destination" = /* ]] || destination="$REPO_DIR/$destination" + [[ "$source" = /* ]] || source="$HOME/$source" + + copy_path "$source" "$destination" +done < "$TRACKED_CONFIGS" + +echo "Updating scripts, launchers, and fonts..." + +if [[ -d "$HOME/.local/bin" ]]; then + mkdir -p scripts +fi + +if [[ -d "$HOME/.local/share/applications" ]]; then + mkdir -p applications +fi + +if [[ -d "$HOME/.local/share/fonts/omarchy-config" ]]; then + copy_path "$HOME/.local/share/fonts/omarchy-config" "$REPO_DIR/fonts" +fi echo "Updating services..." systemctl --user list-unit-files --state=enabled > system/user-services.txt -sudo systemctl list-unit-files --state=enabled > system/system-services.txt +if command -v sudo >/dev/null 2>&1; then + sudo -n systemctl list-unit-files --state=enabled > system/system-services.txt 2>/dev/null || true +fi echo echo "Done!" diff --git a/bash/.gitkeep b/bash/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/bash/.gitkeep @@ -0,0 +1 @@ + diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..cbd5fb4 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +require_command() { + local command_name="$1" + + if ! command -v "$command_name" >/dev/null 2>&1; then + echo "Missing required command: $command_name" + exit 1 + fi +} + +echo "========================================" +echo " Milan's Omarchy Bootstrap" +echo "========================================" +echo + +require_command yay +require_command systemctl +require_command fc-cache + +if [[ ! -f "$REPO_DIR/tracked-configs.txt" ]]; then + echo "Missing tracked-configs.txt" + exit 1 +fi + +chmod +x "$REPO_DIR/install.sh" +"$REPO_DIR/install.sh" diff --git a/flatpaks.txt b/flatpaks.txt new file mode 100644 index 0000000..e75eb14 --- /dev/null +++ b/flatpaks.txt @@ -0,0 +1 @@ +# Add one Flatpak application ID per line. diff --git a/fonts/.gitkeep b/fonts/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/fonts/.gitkeep @@ -0,0 +1 @@ + diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 1736673..29b495d --- a/install.sh +++ b/install.sh @@ -3,98 +3,179 @@ set -euo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONFIGS_DIR="$REPO_DIR/configs" +TRACKED_CONFIGS="$REPO_DIR/tracked-configs.txt" +BACKUP_DIR="$HOME/.local/state/omarchy-config/backups/$(date +%Y%m%d-%H%M%S)" echo "========================================" echo " Milan's Omarchy Setup Installer" echo "========================================" echo -# -# Update system -# -echo "[1/5] Updating system..." +ensure_dir() { + mkdir -p "$1" +} + +read_list() { + local file="$1" + + [[ -f "$file" ]] || return 0 + + sed 's/#.*//' "$file" | awk 'NF {print $1}' +} + +backup_target() { + local target="$1" + local backup + + [[ -e "$target" || -L "$target" ]] || return 0 + + ensure_dir "$BACKUP_DIR" + backup="$BACKUP_DIR/${target#$HOME/}" + ensure_dir "$(dirname "$backup")" + + echo "Backing up $target" + mv "$target" "$backup" +} + +link_path() { + local source="$1" + local target="$2" + + if [[ ! -e "$source" ]]; then + echo "Skipping missing source: ${source#$REPO_DIR/}" + return 0 + fi + + ensure_dir "$(dirname "$target")" + + if [[ -L "$target" && "$(readlink -f "$target")" == "$(readlink -f "$source")" ]]; then + echo "Already linked: $target" + return 0 + fi + + backup_target "$target" + ln -s "$source" "$target" + echo "Linked $target -> ${source#$REPO_DIR/}" +} + +install_packages() { + local file="$1" + + [[ -s "$file" ]] || return 0 + mapfile -t packages < <(read_list "$file") + ((${#packages[@]} > 0)) || return 0 + + yay -S --needed --noconfirm "${packages[@]}" +} + +echo "[1/8] Updating system..." yay -Syu --noconfirm -# -# Install packages -# echo -echo "[2/5] Installing packages..." +echo "[2/8] Installing packages..." +install_packages "$REPO_DIR/packages.txt" +install_packages "$REPO_DIR/aur-packages.txt" -if [[ -f "$REPO_DIR/packages.txt" ]]; then - yay -S --needed --noconfirm $(<"$REPO_DIR/packages.txt") +if [[ -s "$REPO_DIR/flatpaks.txt" ]] && command -v flatpak >/dev/null 2>&1; then + while read -r app; do + [[ -n "$app" ]] || continue + flatpak install --user --noninteractive flathub "$app" || true + done < <(read_list "$REPO_DIR/flatpaks.txt") fi -if [[ -s "$REPO_DIR/aur-packages.txt" ]]; then - yay -S --needed --noconfirm $(<"$REPO_DIR/aur-packages.txt") +echo +echo "[3/8] Linking tracked configs..." + +if [[ ! -f "$TRACKED_CONFIGS" ]]; then + echo "Missing tracked-configs.txt" + exit 1 fi -# -# Symlink configs -# +while read -r source target; do + [[ -n "${source:-}" ]] || continue + [[ "$source" != \#* ]] || continue + [[ -n "${target:-}" ]] || target="$source" + + source="${source/#\~/$HOME}" + target="${target/#\~/$HOME}" + + [[ "$source" = /* ]] || source="$REPO_DIR/$source" + [[ "$target" = /* ]] || target="$HOME/$target" + + link_path "$source" "$target" +done < "$TRACKED_CONFIGS" + echo -echo "[3/5] Linking configs..." +echo "[4/8] Linking scripts..." -mkdir -p "$HOME/.config" +if [[ -d "$REPO_DIR/scripts" ]]; then + ensure_dir "$HOME/.local/bin" + find "$REPO_DIR/scripts" -maxdepth 1 -type f -executable | sort | + while read -r script; do + link_path "$script" "$HOME/.local/bin/$(basename "$script")" + done +fi -for item in "$CONFIGS_DIR"/*; do - - name="$(basename "$item")" - - target="$HOME/.config/$name" - - # Skip if already linked correctly - if [[ -L "$target" ]]; then - if [[ "$(readlink -f "$target")" == "$(readlink -f "$item")" ]]; then - echo "✓ $name already linked" - continue - fi - fi - - # Backup existing config - if [[ -e "$target" && ! -L "$target" ]]; then - backup="${target}.backup.$(date +%Y%m%d-%H%M%S)" - echo "Backing up $name -> $(basename "$backup")" - mv "$target" "$backup" - fi - - rm -rf "$target" - - ln -s "$item" "$target" - - echo "Linked $name" - -done - -# -# Enable user services -# echo -echo "[4/5] Enabling user services..." +echo "[5/8] Linking desktop launchers..." + +if [[ -d "$REPO_DIR/applications" ]]; then + ensure_dir "$HOME/.local/share/applications" + find "$REPO_DIR/applications" -maxdepth 1 -type f -name '*.desktop' | sort | + while read -r launcher; do + link_path "$launcher" "$HOME/.local/share/applications/$(basename "$launcher")" + done +fi + +echo +echo "[6/8] Linking fonts..." + +if [[ -d "$REPO_DIR/fonts" ]]; then + ensure_dir "$HOME/.local/share/fonts" + link_path "$REPO_DIR/fonts" "$HOME/.local/share/fonts/omarchy-config" + fc-cache -fv >/dev/null 2>&1 || true +fi + +echo +echo "[7/8] Enabling user services..." if [[ -f "$REPO_DIR/system/user-services.txt" ]]; then - awk '{print $1}' "$REPO_DIR/system/user-services.txt" | + read_list "$REPO_DIR/system/user-services.txt" | while read -r service; do - [[ -z "$service" ]] && continue systemctl --user enable "$service" >/dev/null 2>&1 || true done fi -# -# Font cache -# +if [[ -f "$REPO_DIR/system/system-services.txt" ]]; then + if [[ "${ENABLE_SYSTEM_SERVICES:-0}" == "1" ]]; then + read_list "$REPO_DIR/system/system-services.txt" | + while read -r service; do + if systemctl list-unit-files "$service" >/dev/null 2>&1; then + sudo systemctl enable "$service" >/dev/null 2>&1 || true + fi + done + else + echo "Skipping system services. Run with ENABLE_SYSTEM_SERVICES=1 to enable them." + fi +fi + echo -echo "[5/5] Refreshing font cache..." -fc-cache -fv >/dev/null 2>&1 || true +echo "[8/8] Running optional installers..." + +if [[ -x "$REPO_DIR/smb/install.sh" ]]; then + if [[ "${INSTALL_SMB:-0}" == "1" ]]; then + "$REPO_DIR/smb/install.sh" + else + echo "Skipping SMB installer. Run with INSTALL_SMB=1 to enable it." + fi +fi echo echo "========================================" echo " Finished!" echo "========================================" echo -echo "You may want to:" -echo " • Log out and back in" -echo " • Run: omarchy-theme (if needed)" -echo " • Restart Waybar/Hyprland if configs changed" +echo "Backups were written to: $BACKUP_DIR" +echo +echo "You may want to log out and back in, or restart Waybar/Hyprland if configs changed." echo diff --git a/smb-setup.md b/smb-setup.md new file mode 100644 index 0000000..722019b --- /dev/null +++ b/smb-setup.md @@ -0,0 +1,283 @@ +# SVR52 Samba Client Setup (Omarchy / Arch Linux) + +## Purpose + +This document describes the complete client-side configuration for automatically connecting to the Samba share hosted on **svr52** (a Raspberry Pi server) from another Linux machine running Omarchy/Arch. + +The server is accessed primarily over **Tailscale**, meaning the machine may not be on the same LAN. + +The goal is: + +* Automatically access the Samba share after boot. +* Do **not** fail boot if the server is unavailable. +* Wait until the share is actually accessed before attempting to connect. +* Work reliably with Tailscale's startup delay. + +--- + +# Server Information + +Hostname: + +```text +svr52 +``` + +Samba user: + +```text +ta52 +``` + +Primary share: + +```text +smb +``` + +Mount point on client: + +```text +/home/milan/svr52 +``` + +--- + +# Required packages + +Arch: + +```bash +sudo pacman -S cifs-utils smbclient +``` + +--- + +# Verify connectivity + +List available shares: + +```bash +smbclient -L //svr52 -U ta52 +``` + +Expected shares: + +``` +smb +ta52 +print$ +IPC$ +``` + +--- + +# Credentials file + +Create: + +```bash +mkdir -p ~/.smb +nano ~/.smb/svr52 +``` + +Contents: + +```text +username=ta52 +password=costarica +``` + +Protect it: + +```bash +chmod 600 ~/.smb/svr52 +``` + +--- + +# Create mountpoint + +```bash +mkdir -p ~/svr52 +``` + +--- + +# /etc/fstab + +Append: + +```fstab +//svr52/smb /home/milan/svr52 cifs credentials=/home/milan/.smb/svr52,uid=1000,gid=1000,_netdev,nofail,x-systemd.automount,x-systemd.idle-timeout=10min 0 0 +``` + +### Explanation + +* `credentials=...` + Uses the credentials file. + +* `uid=1000,gid=1000` + Files appear owned by the normal user. + +* `_netdev` + Marks this as a network filesystem. + +* `nofail` + Boot continues even if the server is unreachable. + +* `x-systemd.automount` + Do **not** mount during boot. + Mount only when the directory is first accessed. + +* `x-systemd.idle-timeout=10min` + Automatically unmount after 10 minutes of inactivity. + +--- + +# Reload systemd + +```bash +sudo systemctl daemon-reload +``` + +--- + +# Test + +Unmount if currently mounted: + +```bash +sudo umount ~/svr52 +``` + +Start automount: + +```bash +sudo systemctl start home-milan-svr52.automount +``` + +Status should show: + +``` +Active: active (waiting) +``` + +--- + +# Verify automount + +Before accessing: + +```bash +findmnt ~/svr52 +``` + +Expected: + +``` +autofs +``` + +Access the folder: + +```bash +ls ~/svr52 +``` + +Then verify: + +```bash +findmnt ~/svr52 +``` + +Expected: + +``` +autofs +└── cifs //svr52/smb +``` + +This confirms the automount triggered successfully. + +--- + +# Why automount is required + +A normal fstab mount fails because: + +1. systemd processes `/etc/fstab` +2. Tailscale has **not yet connected** +3. `svr52` cannot be reached +4. Samba mount fails + +Automount fixes this because: + +1. Boot finishes normally. +2. Tailscale connects. +3. User later opens: + +``` +~/svr52 +``` + +4. systemd performs the mount only then. + +This completely avoids boot-time race conditions. + +--- + +# Useful commands + +List shares: + +```bash +smbclient -L //svr52 -U ta52 +``` + +Manual mount: + +```bash +sudo mount -a +``` + +Unmount: + +```bash +sudo umount ~/svr52 +``` + +Status: + +```bash +systemctl status home-milan-svr52.automount +``` + +Verify mount: + +```bash +findmnt ~/svr52 +``` + +Reload systemd after editing fstab: + +```bash +sudo systemctl daemon-reload +``` + +--- + +# Current Working Configuration + +* Client OS: Omarchy (Arch Linux) +* Transport: Tailscale +* Hostname: `svr52` +* Share: `smb` +* Credentials file: `~/.smb/svr52` +* Mount point: `/home/milan/svr52` +* Mount type: CIFS +* Mount strategy: `systemd` automount +* Idle timeout: 10 minutes + +This configuration has been tested and confirmed working. The Samba share mounts automatically on first access after Tailscale is connected, eliminating boot-time failures caused by network startup timing. + diff --git a/smb/README.md b/smb/README.md new file mode 100644 index 0000000..603466e --- /dev/null +++ b/smb/README.md @@ -0,0 +1,10 @@ +# SMB Automount + +This directory stores the non-secret pieces needed to restore SMB mounts. + +1. Copy `fstab.fragment.example` to `fstab.fragment`. +2. Edit the server, share, mountpoint, and credentials path. +3. Store credentials outside this repository. +4. Run `INSTALL_SMB=1 ./install.sh` from the repository root. + +Never commit Samba credentials. diff --git a/smb/fstab.fragment.example b/smb/fstab.fragment.example new file mode 100644 index 0000000..2f9ec55 --- /dev/null +++ b/smb/fstab.fragment.example @@ -0,0 +1,2 @@ +# Example only. Copy to smb/fstab.fragment and edit locally. +# //server/share /mnt/share cifs credentials=/home/milan/.smbcredentials,uid=1000,gid=1000,iocharset=utf8,nofail,x-systemd.automount 0 0 diff --git a/smb/install.sh b/smb/install.sh new file mode 100755 index 0000000..d235d29 --- /dev/null +++ b/smb/install.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +FSTAB_FRAGMENT="$REPO_DIR/smb/fstab.fragment" + +echo "Installing SMB support..." +yay -S --needed --noconfirm cifs-utils smbclient + +if [[ ! -f "$FSTAB_FRAGMENT" ]]; then + echo "No smb/fstab.fragment found. Copy smb/fstab.fragment.example and edit it first." + exit 0 +fi + +while read -r device mountpoint rest; do + [[ -n "${device:-}" ]] || continue + [[ "$device" != \#* ]] || continue + [[ -n "${mountpoint:-}" ]] || continue + + sudo mkdir -p "$mountpoint" + + if ! grep -Fq "$device $mountpoint " /etc/fstab; then + echo "$device $mountpoint $rest" | sudo tee -a /etc/fstab >/dev/null + echo "Added fstab entry for $mountpoint" + else + echo "fstab already contains $mountpoint" + fi +done < "$FSTAB_FRAGMENT" + +sudo systemctl daemon-reload +echo "SMB setup complete." diff --git a/tracked-configs.txt b/tracked-configs.txt new file mode 100644 index 0000000..879c33a --- /dev/null +++ b/tracked-configs.txt @@ -0,0 +1,16 @@ +# Repository path Home path +configs/omarchy .config/omarchy +configs/hypr .config/hypr +configs/waybar .config/waybar +configs/walker .config/walker +configs/ghostty .config/ghostty +configs/kitty .config/kitty +configs/mako .config/mako +configs/nvim .config/nvim +configs/fastfetch .config/fastfetch +configs/starship.toml .config/starship.toml +configs/mimeapps.list .config/mimeapps.list + +# Uncomment after adding the matching files: +# bash/.bashrc .bashrc +# bash/.bash_aliases .bash_aliases diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..c723171 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +# Generated by ./backup.sh