#!/usr/bin/env bash set -euo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TMP_ERR="$(mktemp)" trap 'rm -f "$TMP_ERR"' EXIT # The .config tree is stowed into $HOME/.config CONFIG_PKG=".config" # Remaining home-dotfile packages (stowed into $HOME) HOME_PKGS=( zshrc ) # Empty portage dirs, recreated because git does not track empty directories PORTAGE_EMPTY_DIRS=( package.mask postsync.d profile/package.use.force ) log() { printf '\033[1;32m[install]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[fatal]\033[0m %s\n' "$*" >&2; exit 1; } run_root() { if [[ $EUID -eq 0 ]]; then "$@" elif command -v sudo >/dev/null 2>&1; then sudo "$@" else die "need root (use: $0 as root, or install sudo)" fi } need_stow() { if command -v stow >/dev/null 2>&1; then log "GNU Stow found: $(stow --version 2>/dev/null | head -n1 || true)" return fi warn "GNU Stow not installed — installing app-admin/stow" run_root emerge --ask app-admin/stow } stow_dotfiles() { cd "$REPO_DIR" local ok=0 fail=0 # .config package -> ~/.config if stow -R -v -t "$HOME/.config" "$CONFIG_PKG" >"$TMP_ERR" 2>&1; then printf ' %s\n' "$(grep '^LINK' "$TMP_ERR" || true)" ok=$((ok + 1)) else warn "stow '$CONFIG_PKG' (-> \$HOME/.config) failed — resolve manually:" sed 's/^/ /' "$TMP_ERR" || true fail=$((fail + 1)) fi # remaining home-dotfile packages -> ~ for pkg in "${HOME_PKGS[@]}"; do if [[ ! -d "$pkg" ]]; then warn "package dir '$pkg' missing — skipped" continue fi if stow -R -v "$pkg" >"$TMP_ERR" 2>&1; then printf ' %s\n' "$(grep '^LINK' "$TMP_ERR" || true)" ok=$((ok + 1)) else warn "stow '$pkg' failed — resolve manually:" sed 's/^/ /' "$TMP_ERR" || true fail=$((fail + 1)) fi done log "stowed: $ok ok, $fail with conflicts" } restore_portage() { log "copying /etc/portage config from repo" run_root cp -a "$REPO_DIR/portage/etc/portage/." /etc/portage/ log "copying /var/lib/portage/world from repo" run_root cp -a "$REPO_DIR/portage/var/lib/portage/world" /var/lib/portage/world run_root find /etc/portage -type f -name .gitkeep -delete for d in "${PORTAGE_EMPTY_DIRS[@]}"; do run_root mkdir -p "/etc/portage/$d" done if [[ -f "$REPO_DIR/portage/PROFILE" ]]; then local prof prof="$(cat "$REPO_DIR/portage/PROFILE")" log "linking /etc/portage/make.profile -> $prof" run_root ln -snf "$prof" /etc/portage/make.profile fi } restore_system_configs() { log "installing /etc/fstab from repo" run_root cp -a "$REPO_DIR/fstab/etc/fstab" /etc/fstab if [[ -f "$REPO_DIR/config.toml" ]]; then log "installing /etc/greetd/config.toml from repo" run_root mkdir -p /etc/greetd run_root cp -a "$REPO_DIR/config.toml" /etc/greetd/config.toml fi } check_notes() { if [[ ! -x "$HOME/.local/bin/start-niri.sh" ]]; then warn "~/.local/bin/start-niri.sh not found; greetd (config.toml) and PATH reference it." warn " create it manually or place it in a stowed package before the session is usable." fi if grep -q '/home/seraphim' "$REPO_DIR/config.toml" 2>/dev/null; then warn "config.toml hardcodes /home/seraphim paths — adjust for your username if different." fi if grep -q '/march=znver3' "$REPO_DIR/portage/etc/portage/make.conf"; then warn "make.conf targets Zen 3 (znver3) and CPU_FLAGS_X86 — review if other hardware." fi } emerge_world() { local ans read -r -p "Run 'emerge --sync && emerge -uDN @world' now? [y/N] " ans if [[ "${ans,,}" =~ ^y ]]; then run_root emerge --sync run_root emerge -uDN @world else log "skip — run manually: emerge --sync && emerge -uDN @world" fi } main() { need_stow stow_dotfiles restore_portage restore_system_configs check_notes emerge_world log "done." } main "$@"