diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d8931083..1da32528 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,7 +2,6 @@ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" - labels: [] schedule: interval: "daily" groups: @@ -12,7 +11,6 @@ updates: update-types: - "minor" - "patch" - open-pull-requests-limit: 10 - package-ecosystem: "gitsubmodule" directory: "/" schedule: @@ -37,6 +35,8 @@ updates: update-types: - "minor" - "patch" + allow: + - dependency-type: "all" - package-ecosystem: "uv" directory: "/" schedule: @@ -50,6 +50,8 @@ updates: update-types: - "minor" - "patch" + allow: + - dependency-type: "all" - package-ecosystem: "npm" directory: "/" schedule: diff --git a/Home/.config/yadm/bootstrap b/Home/.config/yadm/bootstrap index a027d581..79564ed8 100755 --- a/Home/.config/yadm/bootstrap +++ b/Home/.config/yadm/bootstrap @@ -29,7 +29,11 @@ install_base_deps(){ local pac_cmd="sudo pacman" has paru && pac_cmd="paru" has yay && pac_cmd="yay" - $pac_cmd -Sq --needed --noconfirm git gitoxide aria2 curl zsh fd sd ripgrep bat jq zoxide starship fzf stow tuckr rsync konsave || warn "Some packages may have failed to install" + # Try tuckr first, fall back to stow if unavailable + if ! $pac_cmd -Sq --needed --noconfirm git gitoxide aria2 curl zsh fd sd ripgrep bat jq zoxide starship fzf tuckr rsync konsave; then + warn "tuckr install failed, installing stow as fallback" + $pac_cmd -Sq --needed --noconfirm git gitoxide aria2 curl zsh fd sd ripgrep bat jq zoxide starship fzf stow rsync konsave || warn "Some packages may have failed to install" + fi elif has apt-get; then sudo apt-get update -y sudo apt-get install -y git curl zsh fd-find ripgrep bat jq fzf stow rsync || warn "Some packages may have failed" @@ -64,20 +68,34 @@ configure_shell(){ fi } deploy_system_configs(){ - if ! has tuckr; then - warn "tuckr not installed; skipping etc/usr." - warn "Install tuckr then run: sudo tuckr link -d $REPO_DIR -t / etc usr" + local pkg + if has tuckr; then + info "Using tuckr for system config deployment" + local hooks_file="${REPO_DIR}/hooks.toml" + for pkg in etc usr; do + local src="${REPO_DIR}/${pkg}" + [[ -d $src ]] || { warn "Missing dir: $src"; continue; } + info "Linking ${pkg}/ → / (tuckr)" + local cmd=(sudo tuckr link -d "$REPO_DIR" -t / "$pkg") + [[ -f $hooks_file ]] && cmd+=(-H "$hooks_file") + "${cmd[@]}" || warn "Failed to link $pkg" + done + elif has stow; then + info "tuckr not found, using stow as fallback" + for pkg in etc usr; do + local src="${REPO_DIR}/${pkg}" + [[ -d $src ]] || { warn "Missing dir: $src"; continue; } + info "Linking ${pkg}/ → / (stow)" + (cd "$REPO_DIR" && sudo stow -t / -d . "$pkg") || warn "Failed to stow $pkg" + done + else + warn "Neither tuckr nor stow installed; skipping etc/usr deployment." + warn "Install tuckr: paru -S tuckr" + warn " OR stow: paru -S stow" + warn "Then run: sudo tuckr link -d $REPO_DIR -t / etc usr" + warn " OR: cd $REPO_DIR && sudo stow -t / etc usr" return 0 fi - local hooks_file="${REPO_DIR}/hooks.toml" pkg - for pkg in etc usr; do - local src="${REPO_DIR}/${pkg}" - [[ -d $src ]] || { warn "Missing dir: $src"; continue; } - info "Linking ${pkg}/ → /" - local cmd=(sudo tuckr link -d "$REPO_DIR" -t / "$pkg") - [[ -f $hooks_file ]] && cmd+=(-H "$hooks_file") - "${cmd[@]}" || warn "Failed to link $pkg" - done } setup_alternates(){ info "Processing yadm alternates..." diff --git a/Home/.local/bin/deploy-system-configs.sh b/Home/.local/bin/deploy-system-configs.sh new file mode 100755 index 00000000..51ebb745 --- /dev/null +++ b/Home/.local/bin/deploy-system-configs.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# shellcheck enable=all shell=bash source-path=SCRIPTDIR +set -euo pipefail; shopt -s nullglob globstar +export LC_ALL=C; IFS=$'\n\t' +has(){ command -v -- "$1" &>/dev/null; } +info(){ printf '==> %s\n' "$*"; } +warn(){ printf '==> WARNING: %s\n' "$*"; } +die(){ printf '==> ERROR: %s\n' "$*" >&2; exit 1; } + +# Get repository directory +get_repo_dir(){ + if yadm rev-parse --show-toplevel &>/dev/null; then + yadm rev-parse --show-toplevel + elif [[ -d "${HOME}/.local/share/yadm/repo.git" ]]; then + echo "${HOME}" + elif git rev-parse --show-toplevel &>/dev/null; then + git rev-parse --show-toplevel + else + die "Cannot determine repository location" + fi +} + +usage(){ + cat <<'EOF' +deploy-system-configs - Deploy system configs using tuckr or stow + +Usage: deploy-system-configs [OPTIONS] [PACKAGES...] + +Options: + -h, --help Show this help + -d, --dir DIR Repository directory (auto-detected if omitted) + -u, --unlink Unlink/unstow packages instead of linking + +Packages: + etc Deploy /etc configs + usr Deploy /usr configs + (default: etc usr) + +This script automatically uses tuckr if available, otherwise falls back to stow. + +Examples: + sudo deploy-system-configs # Deploy both etc and usr + sudo deploy-system-configs etc # Deploy only etc + sudo deploy-system-configs --unlink # Unlink all packages +EOF +} + +REPO_DIR="" +UNLINK=false +PACKAGES=() + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) usage; exit 0 ;; + -d|--dir) + if [[ -z ${2:-} ]]; then die "Option '$1' requires an argument."; fi + REPO_DIR="$2"; shift + ;; + -u|--unlink) UNLINK=true ;; + -*) die "Unknown option: $1" ;; + *) PACKAGES+=("$1") ;; + esac + shift +done + +# Auto-detect repo dir if not provided +[[ -z $REPO_DIR ]] && REPO_DIR="$(get_repo_dir)" +[[ -d $REPO_DIR ]] || die "Repository not found: $REPO_DIR" + +# Default to etc and usr if no packages specified +((${#PACKAGES[@]} == 0)) && PACKAGES=(etc usr) + +# Check if running as root +[[ $EUID -eq 0 ]] || die "This script must be run as root (use sudo)" + +# Deploy using tuckr or stow +if has tuckr; then + info "Using tuckr for deployment" + local hooks_file="${REPO_DIR}/hooks.toml" + for pkg in "${PACKAGES[@]}"; do + local src="${REPO_DIR}/${pkg}" + [[ -d $src ]] || { warn "Directory not found: $src"; continue; } + + if [[ $UNLINK == true ]]; then + info "Unlinking ${pkg}/" + tuckr unlink -d "$REPO_DIR" -t / "$pkg" || warn "Failed to unlink $pkg" + else + info "Linking ${pkg}/ → / (tuckr)" + local cmd=(tuckr link -d "$REPO_DIR" -t / "$pkg") + [[ -f $hooks_file ]] && cmd+=(-H "$hooks_file") + "${cmd[@]}" || warn "Failed to link $pkg" + fi + done +elif has stow; then + info "Using stow for deployment (tuckr not available)" + for pkg in "${PACKAGES[@]}"; do + local src="${REPO_DIR}/${pkg}" + [[ -d $src ]] || { warn "Directory not found: $src"; continue; } + + if [[ $UNLINK == true ]]; then + info "Unstowing ${pkg}/" + (cd "$REPO_DIR" && stow -t / -d . -D "$pkg") || warn "Failed to unstow $pkg" + else + info "Stowing ${pkg}/ → / (stow)" + (cd "$REPO_DIR" && stow -t / -d . "$pkg") || warn "Failed to stow $pkg" + fi + done +else + die "Neither tuckr nor stow is installed. Install one of them: + Arch: paru -S tuckr OR paru -S stow + Debian: apt install stow" +fi + +info "Deployment complete" diff --git a/YADM.md b/YADM.md index 5e3eeaff..d567226f 100644 --- a/YADM.md +++ b/YADM.md @@ -8,8 +8,8 @@ clean, hierarchical folder structure. ``` dotfiles/ ├── Home/ # User-level dotfiles (~/.*) [Managed by yadm] -├── etc/ # System configs (/etc/*) [Managed by tuckr] -├── usr/ # System configs (/usr/*) [Managed by tuckr] +├── etc/ # System configs (/etc/*) [Managed by tuckr/stow] +├── usr/ # System configs (/usr/*) [Managed by tuckr/stow] ├── .yadm/ # YADM configuration │ ├── bootstrap # Main bootstrap script │ └── config # Repository-wide yadm config @@ -20,9 +20,10 @@ dotfiles/ - **Separation of concerns**: User configs vs. system configs - **Easy to understand**: Mirrors Linux filesystem structure -- **Flexible deployment**: yadm for user files, tuckr for system files +- **Flexible deployment**: yadm for user files, tuckr/stow for system files - **Git-friendly**: Clean repository with minimal clutter - **Portable**: Works across different systems +- **Fallback support**: Automatically uses stow if tuckr is unavailable --- @@ -169,7 +170,7 @@ yadm push ### Update System Configs (etc/, usr/) -System configs are managed separately with **tuckr**: +System configs are managed separately with **tuckr** (or **stow** as fallback): ```bash # Navigate to repository @@ -184,8 +185,14 @@ git commit -m "Update pacman configuration" git push # Re-link system configs (creates symlinks) -sudo tuckr link -d $(yadm rev-parse --show-toplevel) -t / etc -sudo tuckr link -d $(yadm rev-parse --show-toplevel) -t / usr +# Option 1: Using tuckr (preferred) +sudo tuckr link -d $(yadm rev-parse --show-toplevel) -t / etc usr + +# Option 2: Using stow (fallback) +cd $(yadm rev-parse --show-toplevel) && sudo stow -t / etc usr + +# Option 3: Using helper script (auto-detects tuckr/stow) +sudo deploy-system-configs ``` ### Check Repository Status @@ -256,15 +263,25 @@ Unlike traditional yadm setups where dotfiles are at the repository root, this r The `.yadm/bootstrap` script handles this deployment automatically using rsync. -### System Configs with Tuckr +### System Configs with Tuckr or Stow -System-level configs (`/etc`, `/usr`) require root permissions and are managed with **tuckr**: +System-level configs (`/etc`, `/usr`) require root permissions and are managed with **tuckr** or **stow**: ```bash +# Using tuckr (preferred - supports hooks) sudo tuckr link -d /path/to/repo -t / etc # Creates: /etc/pacman.conf → /path/to/repo/etc/pacman.conf + +# Using stow (fallback - widely available) +cd /path/to/repo && sudo stow -t / etc +# Creates: /etc/pacman.conf → /path/to/repo/etc/pacman.conf + +# Using helper script (auto-detects best tool) +sudo deploy-system-configs etc usr ``` +The bootstrap script automatically detects which tool is available and uses it accordingly. + --- ## 🔧 Advanced Usage @@ -366,13 +383,24 @@ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc ### System configs not applying ```bash -# Install tuckr +# Option 1: Install tuckr (preferred) paru -S tuckr # Arch/AUR +# Option 2: Install stow (fallback, widely available) +paru -S stow # Arch +sudo apt install stow # Debian/Ubuntu + # Re-link system configs with sudo cd $(yadm rev-parse --show-toplevel) -sudo tuckr link -d "$PWD" -t / etc -sudo tuckr link -d "$PWD" -t / usr + +# Using tuckr: +sudo tuckr link -d "$PWD" -t / etc usr + +# OR using stow: +sudo stow -t / etc usr + +# OR using helper script (auto-detects): +sudo deploy-system-configs ``` --- diff --git a/setup.sh b/setup.sh index 7d124348..21986af9 100755 --- a/setup.sh +++ b/setup.sh @@ -48,15 +48,19 @@ main(){ install_packages(){ info "Installing packages..." local paru_opts=(--needed --noconfirm --skipreview --sudoloop --batchinstall --combinedupgrade) - local pkgs=(git gitoxide aria2 curl zsh fd sd ripgrep bat jq zoxide starship fzf yadm tuckr konsave) + local pkgs=(git gitoxide aria2 curl zsh fd sd ripgrep bat jq zoxide starship fzf yadm konsave) if ! has paru; then die "paru not found." fi if [[ $DRY_RUN == true ]]; then - info "[DRY-RUN] Would install: ${pkgs[*]}" + info "[DRY-RUN] Would install: ${pkgs[*]} tuckr (or stow)" return 0 fi - paru -Syuq "${paru_opts[@]}" "${pkgs[@]}" || die "Failed to install packages" + # Try installing with tuckr first + if ! paru -Syuq "${paru_opts[@]}" "${pkgs[@]}" tuckr; then + warn "tuckr install failed, using stow as fallback" + paru -Syuq "${paru_opts[@]}" "${pkgs[@]}" stow || die "Failed to install packages" + fi } setup_dotfiles(){ if ! has yadm; then @@ -83,23 +87,39 @@ deploy_home(){ fi } link_system_configs(){ - if ! has tuckr; then - warn "tuckr not found; skipping etc/usr deploy" + local pkg + if has tuckr; then + info "Using tuckr for system config deployment" + local hooks_file="${WORKTREE}/hooks.toml" + for pkg in etc usr; do + local src="${WORKTREE}/${pkg}" + [[ -d $src ]] || { warn "Directory not found: $src"; continue; } + info "Linking ${pkg}/ → / (tuckr)" + local cmd=(sudo tuckr link -d "$WORKTREE" -t / "$pkg") + [[ -f $hooks_file ]] && cmd+=(-H "$hooks_file") + "${cmd[@]}" || warn "Failed to link ${pkg}" + done + elif has stow; then + info "tuckr not found, using stow as fallback" + for pkg in etc usr; do + local src="${WORKTREE}/${pkg}" + [[ -d $src ]] || { warn "Directory not found: $src"; continue; } + info "Linking ${pkg}/ → / (stow)" + (cd "$WORKTREE" && sudo stow -t / -d . "$pkg") || warn "Failed to stow ${pkg}" + done + else + warn "Neither tuckr nor stow found; skipping etc/usr deploy" + warn "Install with: paru -S tuckr OR paru -S stow" return 0 fi - local hooks_file="${WORKTREE}/hooks.toml" pkg - for pkg in etc usr; do - local src="${WORKTREE}/${pkg}" - [[ -d $src ]] || { warn "Directory not found: $src"; continue; } - info "Linking ${pkg}/ → /" - local cmd=(sudo tuckr link -d "$WORKTREE" -t / "$pkg") - [[ -f $hooks_file ]] && cmd+=(-H "$hooks_file") - "${cmd[@]}" || warn "Failed to link ${pkg}" - done } final_steps(){ info "Run 'yadm status' to review." - info "For system configs: sudo tuckr link -d $WORKTREE -t / etc usr" + if has tuckr; then + info "For system configs: sudo tuckr link -d $WORKTREE -t / etc usr" + elif has stow; then + info "For system configs: cd $WORKTREE && sudo stow -t / etc usr" + fi info "Validate /etc/fstab with: sudo systemd-analyze verify /etc/fstab" info "Setup complete." } diff --git a/usr/.gitkeep b/usr/.gitkeep new file mode 100644 index 00000000..8b412b79 --- /dev/null +++ b/usr/.gitkeep @@ -0,0 +1 @@ +# This directory is managed by tuckr and deployed to /usr diff --git a/usr/README.md b/usr/README.md new file mode 100644 index 00000000..aede11cf --- /dev/null +++ b/usr/README.md @@ -0,0 +1,33 @@ +# usr/ - System-Wide User Programs + +This directory contains system-wide binaries and libraries deployed to `/usr` using `tuckr` or `stow`. + +## Structure + +``` +usr/ +├── local/ +│ ├── bin/ # Custom system-wide binaries +│ └── lib/ # Custom system-wide libraries +└── share/ # System-wide data files +``` + +## Deployment + +These files are symlinked to `/usr` using `tuckr` or `stow`: + +```bash +sudo tuckr link -d $(yadm rev-parse --show-toplevel) -t / usr +``` + +## What Goes Here + +- System-wide scripts that all users should access +- Custom binaries installed for the entire system +- Shared libraries and data files + +## What Does NOT Go Here + +- User-specific binaries → Use `Home/.local/bin/` +- Configuration files → Use `etc/` instead +- Package manager-installed files → Managed by pacman/apt