diff --git a/README.md b/README.md index a7cca06..32eac7f 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,21 @@ rm -f file.txt # Falls through to standard rm -f | `upgrade` | Full system upgrade: `paru -Syu --noconfirm` | | `cleanup` | Log and remove orphaned packages | +### Dependency Management + +`fish-deps` is a unified command for checking, installing, and updating all tools this config depends on. + +| Command | Description | +|---|---| +| `fish-deps` / `fish-deps status` | Show installed/missing status for all deps, grouped by tier | +| `fish-deps install` | Interactively install each missing dep (prompts per-dep, prompts method when multiple exist) | +| `fish-deps update` | Update all installed deps using their preferred install method | +| `fish-deps sync` | Install missing deps then update installed ones | +| `fzf-update` | Install or upgrade fzf from git HEAD into `~/.fzf` (guarantees the latest build) | +| `check_fish_deps` | Legacy alias — delegates to `fish-deps status` | + +Install method priority: **cargo** (for Rust tools, gets latest crate) → **system PM** (paru/apt/brew/etc.) → **git clone** (fzf) → **curl installer** (starship, fisher) → **pipx** (Python tools). When multiple methods are available for a tool, you are prompted to choose. + ### Docker | Function | Description | diff --git a/functions/_fish_deps_catalog.fish b/functions/_fish_deps_catalog.fish new file mode 100644 index 0000000..ca644f8 --- /dev/null +++ b/functions/_fish_deps_catalog.fish @@ -0,0 +1,52 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Populates parallel arrays describing every managed dependency. +# Callers must invoke this function before accessing _fdc_* variables. +# +# Array layout (same index across all sets): +# _fdc_bins — binary name (what `type -q` checks) +# _fdc_tiers — req | int | rec +# _fdc_cargo — cargo crate name, or "" if not on crates.io +# _fdc_pm — system PM package name, or "" if not in repos +# _fdc_special — special install key: fisher-bootstrap | fzf-update | +# paru-build | pipx | curl-installer | "" (none) +function _fish_deps_catalog + set -g _fdc_bins \ + fish fisher starship fzf zoxide direnv paru \ + wakatime tailscale \ + eza lsd bat btop dust duf prettyping most rg lazygit lazydocker trash kitty wezterm + + set -g _fdc_tiers \ + req req req req req req req \ + int int \ + rec rec rec rec rec rec rec rec rec rec rec rec rec rec + + set -g _fdc_cargo \ + "" "" starship "" zoxide "" "" \ + "" "" \ + eza lsd bat "" du-dust "" "" "" ripgrep "" "" trash-cli "" "" + + set -g _fdc_pm \ + fish "" starship fzf zoxide direnv paru \ + wakatime tailscale \ + eza lsd bat btop dust duf prettyping most ripgrep lazygit lazydocker trash kitty wezterm + + set -g _fdc_special \ + "" fisher-bootstrap curl-installer fzf-update "" "" paru-build \ + pipx "" \ + "" "" "" "" "" "" "" "" "" "" "" "" "" "" +end + +# Returns the index (1-based) of $argv[1] in the catalog, or "" if not found. +function _fish_deps_catalog_idx --argument-names bin + _fish_deps_catalog + set -l i 1 + for b in $_fdc_bins + if test "$b" = "$bin" + echo $i + return + end + set i (math $i + 1) + end +end diff --git a/functions/_fish_deps_install.fish b/functions/_fish_deps_install.fish new file mode 100644 index 0000000..96843c8 --- /dev/null +++ b/functions/_fish_deps_install.fish @@ -0,0 +1,135 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Interactively install missing deps. +# For each missing dep: prompts yes/no, then prompts install method when multiple exist. +function _fish_deps_install + _fish_deps_catalog + + set -l pm (_fish_deps_detect_pm) + set -l installed_any 0 + + set -l i 1 + for bin in $_fdc_bins + if not type -q $bin + set -l cargo_crate $_fdc_cargo[$i] + set -l pm_pkg $_fdc_pm[$i] + set -l special $_fdc_special[$i] + + # Build list of available install methods + set -l methods + set -l method_labels + + # Cargo — only if cargo is present and the tool has a crate + if test -n "$cargo_crate" -a (type -q cargo) + set -a methods cargo + set -a method_labels "cargo ($cargo_crate)" + end + + # System PM — only if a PM is detected and the tool is in repos + if test -n "$pm_pkg" -a -n "$pm" + set -a methods pm + set -a method_labels "$pm ($pm_pkg)" + end + + # Special methods + switch $special + case fzf-update + set -a methods special-fzf + set -a method_labels "git clone (~/.fzf)" + case fisher-bootstrap + set -a methods special-fisher + set -a method_labels "curl bootstrap (fisher)" + case curl-installer + set -a methods special-curl + set -a method_labels "curl installer" + case paru-build + # Only useful on Arch; skip if pacman not present + if type -q pacman + set -a methods special-paru + set -a method_labels "build from AUR (paru)" + end + case pipx + if type -q pipx + set -a methods special-pipx + set -a method_labels "pipx ($bin)" + else if type -q pip + set -a methods special-pip + set -a method_labels "pip install --user ($bin)" + end + end + + if test (count $methods) -eq 0 + set_color yellow + echo " $bin: no install method available on this system — skipping" + set_color normal + set i (math $i + 1) + continue + end + + # Prompt: install this dep? + set_color cyan; echo -n "Install $bin? "; set_color normal + read -l -P "[Y/n] " _reply + if test "$_reply" = n -o "$_reply" = N + set i (math $i + 1) + continue + end + + # Choose install method + set -l chosen_method $methods[1] + if test (count $methods) -gt 1 + echo " Available methods:" + set -l m 1 + for lbl in $method_labels + echo " $m) $lbl" + set m (math $m + 1) + end + read -l -P " Choose [1-"(count $methods)"] (default 1): " _choice + if test -n "$_choice" -a "$_choice" -ge 1 -a "$_choice" -le (count $methods) 2>/dev/null + set chosen_method $methods[$_choice] + end + end + + # Execute chosen method + switch $chosen_method + case cargo + cargo install $cargo_crate + case pm + _fish_deps_pm_install $pm_pkg + case special-fzf + fzf-update + case special-fisher + curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source + fisher update + case special-curl + # Currently used for starship + if test "$bin" = starship + curl -sS https://starship.rs/install.sh | sh + end + case special-paru + set -l _build_dir (mktemp -d) + git clone https://aur.archlinux.org/paru.git $_build_dir + and pushd $_build_dir + and makepkg -si --noconfirm + and popd + rm -rf $_build_dir + case special-pipx + pipx install $bin + case special-pip + pip install --user $bin + end + + if test $status -eq 0 + set installed_any 1 + set_color green; echo " $bin installed."; set_color normal + else + set_color red; echo " $bin install failed."; set_color normal + end + end + set i (math $i + 1) + end + + if test $installed_any -eq 0 + echo "Nothing to install." + end +end diff --git a/functions/_fish_deps_pm.fish b/functions/_fish_deps_pm.fish new file mode 100644 index 0000000..d7314ee --- /dev/null +++ b/functions/_fish_deps_pm.fish @@ -0,0 +1,65 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Detect the first available system package manager. +function _fish_deps_detect_pm + for pm in paru pacman apt brew pkg dnf yum + if type -q $pm + echo $pm + return + end + end + echo "" +end + +# Install a package via the system PM. +# Usage: _fish_deps_pm_install +function _fish_deps_pm_install --argument-names pkg + set -l pm (_fish_deps_detect_pm) + if test -z "$pm" + echo "No supported package manager found." >&2 + return 1 + end + switch $pm + case paru + paru -S --noconfirm $pkg + case pacman + sudo pacman -S --noconfirm $pkg + case apt + sudo apt install -y $pkg + case brew + brew install $pkg + case pkg + sudo pkg install -y $pkg + case dnf + sudo dnf install -y $pkg + case yum + sudo yum install -y $pkg + end +end + +# Upgrade an already-installed package via the system PM. +# Usage: _fish_deps_pm_upgrade +function _fish_deps_pm_upgrade --argument-names pkg + set -l pm (_fish_deps_detect_pm) + if test -z "$pm" + echo "No supported package manager found." >&2 + return 1 + end + switch $pm + case paru + paru -S --noconfirm $pkg + case pacman + sudo pacman -S --noconfirm $pkg + case apt + sudo apt install --only-upgrade -y $pkg + case brew + brew upgrade $pkg + case pkg + sudo pkg upgrade -y $pkg + case dnf + sudo dnf upgrade -y $pkg + case yum + sudo yum update -y $pkg + end +end diff --git a/functions/_fish_deps_status.fish b/functions/_fish_deps_status.fish new file mode 100644 index 0000000..8997122 --- /dev/null +++ b/functions/_fish_deps_status.fish @@ -0,0 +1,35 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Print colored installed/missing status for all deps, grouped by tier. +function _fish_deps_status + _fish_deps_catalog + + function __fds_print_dep --argument-names bin + if type -q $bin + set_color green; echo -n " "; set_color normal + echo -n "$bin " + set_color brblack; echo "(Found at "(type -p $bin)")"; set_color normal + else + set_color red; echo -n " "; set_color normal + echo -n "$bin " + set_color brblack; echo "(Not installed)"; set_color normal + end + end + + for tier_label in "Required Dependencies:req" "Integrations:int" "Recommended Dependencies:rec" + set -l label (string split : $tier_label)[1] + set -l tier (string split : $tier_label)[2] + set_color cyan; echo $label; set_color normal + set -l i 1 + for bin in $_fdc_bins + if test "$_fdc_tiers[$i]" = $tier + __fds_print_dep $bin + end + set i (math $i + 1) + end + echo "" + end + + functions -e __fds_print_dep +end diff --git a/functions/_fish_deps_update.fish b/functions/_fish_deps_update.fish new file mode 100644 index 0000000..e40bcaf --- /dev/null +++ b/functions/_fish_deps_update.fish @@ -0,0 +1,84 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Update all installed deps using their known install method. +# Priority: cargo > system PM > special (fzf-update, fisher, pipx). +function _fish_deps_update + _fish_deps_catalog + + set -l pm (_fish_deps_detect_pm) + set -l updated_any 0 + + # Fisher plugins — always update if fisher is present + if type -q fisher + echo "Updating fisher plugins..." + fisher update + set updated_any 1 + end + + set -l i 1 + for bin in $_fdc_bins + # Skip fisher itself (handled above) and tools that aren't installed + if test "$bin" = fisher -o not (type -q $bin) + set i (math $i + 1) + continue + end + + set -l cargo_crate $_fdc_cargo[$i] + set -l pm_pkg $_fdc_pm[$i] + set -l special $_fdc_special[$i] + + # fzf: always use fzf-update (git-based) + if test "$special" = fzf-update + echo "Updating $bin..." + fzf-update + set updated_any 1 + set i (math $i + 1) + continue + end + + # pipx tools + if test "$special" = pipx + if type -q pipx + echo "Updating $bin..." + pipx upgrade $bin + set updated_any 1 + end + set i (math $i + 1) + continue + end + + # curl-installer tools (starship etc.): re-run install script, which upgrades in place + if test "$special" = curl-installer + if test "$bin" = starship + echo "Updating $bin..." + curl -sS https://starship.rs/install.sh | sh -- --yes + set updated_any 1 + end + set i (math $i + 1) + continue + end + + # Cargo: prefer for Rust tools + if test -n "$cargo_crate" -a (type -q cargo) + echo "Updating $bin..." + cargo install --force $cargo_crate + set updated_any 1 + set i (math $i + 1) + continue + end + + # System PM fallback + if test -n "$pm_pkg" -a -n "$pm" + echo "Updating $bin..." + _fish_deps_pm_upgrade $pm_pkg + set updated_any 1 + end + + set i (math $i + 1) + end + + if test $updated_any -eq 0 + echo "Nothing to update." + end +end diff --git a/functions/check_fish_deps.fish b/functions/check_fish_deps.fish index 4ca9b4b..04470c5 100644 --- a/functions/check_fish_deps.fish +++ b/functions/check_fish_deps.fish @@ -1,50 +1,7 @@ # Copyright (C) 2026 Rootiest # SPDX-License-Identifier: AGPL-3.0-or-later -# Check all fish-related dependencies +# Thin wrapper kept for backwards compatibility. function check_fish_deps --description 'Check all fish-related dependencies' - set -l required fish fisher starship fzf zoxide direnv paru - set -l integrations wakatime tailscale - set -l recommended eza lsd bat btop dust duf prettyping most rg lazygit lazydocker trash kitty wezterm - - function __print_dep - set -l dep $argv[1] - if type -q $dep - set_color green - echo -n "  " - set_color normal - echo -n "$dep " - set_color brblack - echo "(Found at "(type -p $dep)")" - set_color normal - else - set_color red - echo -n "  " - set_color normal - echo -n "$dep " - set_color brblack - echo "(Not installed)" - set_color normal - end - end - - set_color cyan; echo "Required Dependencies:"; set_color normal - for dep in $required - __print_dep $dep - end - echo "" - - set_color cyan; echo "Integrations:"; set_color normal - for dep in $integrations - __print_dep $dep - end - echo "" - - set_color cyan; echo "Recommended Dependencies:"; set_color normal - for dep in $recommended - __print_dep $dep - end - echo "" - - functions -e __print_dep + fish-deps status end diff --git a/functions/fish-deps.fish b/functions/fish-deps.fish new file mode 100644 index 0000000..47099e5 --- /dev/null +++ b/functions/fish-deps.fish @@ -0,0 +1,41 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +function fish-deps --description 'Manage fish shell dependencies' + set -l subcmd $argv[1] + + switch $subcmd + case status '' + _fish_deps_status + case install + _fish_deps_install + case update + _fish_deps_update + case sync + echo "=== Installing missing deps ===" + _fish_deps_install + echo "" + echo "=== Updating installed deps ===" + _fish_deps_update + case '*' + set_color red + echo "Unknown subcommand: $subcmd" + set_color normal + echo "" + __fish_deps_help + return 1 + end +end + +function __fish_deps_help + set_color cyan; echo "fish-deps — manage fish shell dependencies"; set_color normal + echo "" + echo "Usage:" + echo " fish-deps [status] Check installed/missing deps (default)" + echo " fish-deps install Install missing deps interactively" + echo " fish-deps update Update all installed deps" + echo " fish-deps sync Install missing, then update all" + echo "" + echo "Install method priority: cargo > system PM > git/curl/pipx" + echo "When multiple methods are available, you will be prompted to choose." +end