From 62f364ed911bff31aa1abc307322f7270aa0aff0 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Fri, 13 Feb 2026 14:40:51 -0500 Subject: Migrate Jakoolit to Linuxbeginnings repo references --- config/fastfetch/config-compact.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config/fastfetch/config-compact.jsonc') diff --git a/config/fastfetch/config-compact.jsonc b/config/fastfetch/config-compact.jsonc index 358efcc5..156cb6df 100644 --- a/config/fastfetch/config-compact.jsonc +++ b/config/fastfetch/config-compact.jsonc @@ -1,4 +1,4 @@ -/* ----------- đŸ’Ģ https://github.com/JaKooLit đŸ’Ģ -------- */ +/* ----------- đŸ’Ģ https://github.com/LinuxBeginnings đŸ’Ģ -------- */ { "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", -- cgit v1.2.3 From 3e39cb4b1902875c2649febb756b3dc748f65652 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Wed, 18 Feb 2026 17:59:17 -0500 Subject: Updated config-compact.jsonc fastfetch --- config/fastfetch/config-compact-legacy.jsonc | 86 ++ config/fastfetch/config-compact.jsonc | 1106 ++++++++++++++++++++++++-- 2 files changed, 1107 insertions(+), 85 deletions(-) create mode 100644 config/fastfetch/config-compact-legacy.jsonc mode change 100644 => 100755 config/fastfetch/config-compact.jsonc (limited to 'config/fastfetch/config-compact.jsonc') diff --git a/config/fastfetch/config-compact-legacy.jsonc b/config/fastfetch/config-compact-legacy.jsonc new file mode 100644 index 00000000..156cb6df --- /dev/null +++ b/config/fastfetch/config-compact-legacy.jsonc @@ -0,0 +1,86 @@ +/* ----------- đŸ’Ģ https://github.com/LinuxBeginnings đŸ’Ģ -------- */ + +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "logo": { + "padding": { + "top": 2 + }, + "type": "small" + }, + "display": { + "separator": " -> " + }, + "modules": [ + "break", + { + "type": "title", + "keyWidth": 10, + "format": " {6}{7}{8}" + }, + { + "type": "custom", + "format": " â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ī†’â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ " + }, + { + "type": "kernel", + "key": " ", + "keyColor": "yellow" + }, + { + "keyColor": "blue", + "key": "ī™ ", + "text": "echo Jakoolit: v${DOTS_VERSION}", + "type": "command" + }, + { + "type": "wm", + "key": "ī’ˆ ", + "keyColor": "magenta" + }, + { + "type": "shell", + "key": "ī’‰ ", + "keyColor": "yellow" + }, + { + "type": "terminal", + "key": " ", + "keyColor": "blue" + }, + /* + { + "type": "packages", + "key": "ķ°– ", + "keyColor": "yellow" + }, + */ + { + "type": "memory", + "key": "ķ°› ", + "keyColor": "magenta", + // format: used / total + "format": "{1} / {2}" + }, + { + "type": "uptime", + "key": "ķ°”› ", + "keyColor": "green" + }, + { + "type": "command", + "key": "ķąĻŸ ", + "keyColor": "magenta", + "text": "echo $(( ($(date +%s) - $(stat -c %W /)) / 86400 )) days" + }, + { + "type": "custom", + "format": " â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ī†’â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ " + }, + { + "type": "custom", + "format": " \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[90m " + }, + "break" + ] +} diff --git a/config/fastfetch/config-compact.jsonc b/config/fastfetch/config-compact.jsonc old mode 100644 new mode 100755 index 156cb6df..b6431de9 --- a/config/fastfetch/config-compact.jsonc +++ b/config/fastfetch/config-compact.jsonc @@ -1,86 +1,1022 @@ -/* ----------- đŸ’Ģ https://github.com/LinuxBeginnings đŸ’Ģ -------- */ - -{ - "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "padding": { - "top": 2 - }, - "type": "small" - }, - "display": { - "separator": " -> " - }, - "modules": [ - "break", - { - "type": "title", - "keyWidth": 10, - "format": " {6}{7}{8}" - }, - { - "type": "custom", - "format": " â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ī†’â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ " - }, - { - "type": "kernel", - "key": " ", - "keyColor": "yellow" - }, - { - "keyColor": "blue", - "key": "ī™ ", - "text": "echo Jakoolit: v${DOTS_VERSION}", - "type": "command" - }, - { - "type": "wm", - "key": "ī’ˆ ", - "keyColor": "magenta" - }, - { - "type": "shell", - "key": "ī’‰ ", - "keyColor": "yellow" - }, - { - "type": "terminal", - "key": " ", - "keyColor": "blue" - }, - /* - { - "type": "packages", - "key": "ķ°– ", - "keyColor": "yellow" - }, - */ - { - "type": "memory", - "key": "ķ°› ", - "keyColor": "magenta", - // format: used / total - "format": "{1} / {2}" - }, - { - "type": "uptime", - "key": "ķ°”› ", - "keyColor": "green" - }, - { - "type": "command", - "key": "ķąĻŸ ", - "keyColor": "magenta", - "text": "echo $(( ($(date +%s) - $(stat -c %W /)) / 86400 )) days" - }, - { - "type": "custom", - "format": " â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ī†’â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ " - }, - { - "type": "custom", - "format": " \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[90m " - }, - "break" - ] +#!/usr/bin/env bash +set -Eeuo pipefail + +# Ubuntu setup of common apps and configuration (based on debian-setup.sh) +# - Colors, iconography, robust error handling +# - Checks /mnt/nas and copies configs if available +# - Optional modes: --config-only, --apps-only, --dry-run +# - Uses nala when available, falls back to apt +# - Prompts to run apt update/upgrade before and after + +# ------------- Config ------------- +NAS_MOUNT="/mnt/nas" +NAS_CONFIG_DIR="$NAS_MOUNT/config.files" +DRY_RUN=0 +CONFIG_ONLY=0 +APPS_ONLY=0 +SKIP_ALL=0 +INSTALL_DMS=0 +DMS_ONLY=0 +DMS_SRC="" +DMS_WORKDIR="$HOME/.local/src/dms" +APT_ONLY=0 + +# Selective install toggles +WEZTERM_ONLY=0 +FONTS_ONLY=0 +THEMES_ONLY=0 + +# ------------- Colors & Icons ------------- +RESET="\033[0m" +BOLD="\033[1m" +RED="\033[31m" +GREEN="\033[32m" +YELLOW="\033[33m" +BLUE="\033[34m" +CYAN="\033[36m" +GRAY="\033[90m" +ICON_INFO="â„šī¸" +ICON_OK="✅" +ICON_WARN="âš ī¸" +ICON_ERR="❌" +ICON_STEP="â–ļī¸" + +info() { printf "%b%s%b %b%s%b\n" "$BLUE" "$ICON_INFO" "$RESET" "$BOLD" "$*" "$RESET"; } +success() { printf "%b%s%b %s\n" "$GREEN" "$ICON_OK" "$RESET" "$*"; } +warn() { printf "%b%s%b %s\n" "$YELLOW" "$ICON_WARN" "$RESET" "$*"; } +error() { printf "%b%s%b %s\n" "$RED" "$ICON_ERR" "$RESET" "$*" 1>&2; } +step() { printf "%b%s%b %s\n" "$CYAN" "$ICON_STEP" "$RESET" "$*"; } + +run() { + if ((DRY_RUN)); then + printf "%b+ %s%b\n" "$GRAY" "$(printf '%q ' "$@")" "$RESET" + else + "$@" + fi +} + +usage() { + cat <<'USAGE' +Usage: ubuntu-setup.sh [options] + +Options: + --config-only Only copy/apply configuration (no package installs) + --apps-only Only install/upgrade packages and apps (no config copy) + --dry-run Show what would be done without making changes + --install-dms Install Dank Material Shell: fonts + dependencies + build Quickshell and required sources; also installs the dms wrapper + --dms-only Only install DMS (skip general apps/config); implies --install-dms + --dms-src PATH Use existing source tree at PATH for building (auto-detects Meson/CMake/Autotools) + --wezterm-only Only install and configure WezTerm (nightly) + --fonts-only Only install Nerd Fonts + --themes-only Only install GTK and icon themes + --apt-only Force using apt (disable nala detection/installation) + -h, --help Show this help +USAGE +} + +# ------------- Arg parsing ------------- +while [[ $# -gt 0 ]]; do + case "${1}" in + --config-only) + CONFIG_ONLY=1 + shift + ;; + --apps-only) + APPS_ONLY=1 + shift + ;; + --dry-run) + DRY_RUN=1 + shift + ;; + --install-dms) + INSTALL_DMS=1 + shift + ;; + --dms-only) + DMS_ONLY=1 + INSTALL_DMS=1 + shift + ;; + --dms-src) + DMS_SRC="${2:-}" + if [[ -z "$DMS_SRC" ]]; then + error "--dms-src requires a path" + exit 2 + fi + shift 2 + ;; + --wezterm-only) + WEZTERM_ONLY=1 + shift + ;; + --fonts-only) + FONTS_ONLY=1 + shift + ;; + --themes-only) + THEMES_ONLY=1 + shift + ;; + --apt-only) + APT_ONLY=1 + shift + ;; + -h | --help) + usage + exit 0 + ;; + *) + error "Unknown option: $1" + usage + exit 2 + ;; + esac +done + +confirm() { + local msg=${1:-"Are you sure?"} + local def=${2:-"y"} + local prompt="[y/N]" + [[ "$def" =~ ^[Yy]$ ]] && prompt="[Y/n]" + local reply + read -r -p "$msg $prompt " reply || true + reply=${reply:-$def} + [[ "$reply" =~ ^[Yy]$ ]] +} + +ask_backup_or_skip() { + local path="$1" + local reply + if ((SKIP_ALL)); then + warn "Skip-All enabled; skipping '$path'" + return 1 + fi + while true; do + read -r -p "'$path' exists. (B)ackup, (S)kip, Skip (A)ll? [B/s/a] " reply || reply="B" + reply=${reply:-B} + case "${reply}" in + B | b) return 0 ;; + S | s) return 1 ;; + A | a) + SKIP_ALL=1 + warn "Skip-All enabled; skipping '$path' and all subsequent conflicts" + return 1 + ;; + *) printf "Please answer B, S, or A.\n" ;; + esac + done +} + +# ------------- /mnt/nas helpers ------------- +ensure_nas_available() { + if [[ -d "$NAS_CONFIG_DIR" ]]; then + return 0 + fi + if mountpoint -q "$NAS_MOUNT"; then + if [[ -d "$NAS_CONFIG_DIR" ]]; then + return 0 + fi + warn "$NAS_MOUNT is mounted but $NAS_CONFIG_DIR not found" + else + if grep -Eq '^[^#].*\s/mnt/nas\s' /etc/fstab; then + step "Attempting to mount $NAS_MOUNT from /etc/fstab" + if run sudo mount "$NAS_MOUNT"; then + [[ -d "$NAS_CONFIG_DIR" ]] && return 0 || warn "Mounted $NAS_MOUNT but $NAS_CONFIG_DIR not found" + else + warn "Failed to mount $NAS_MOUNT" + fi + else + warn "$NAS_MOUNT not mounted and no /etc/fstab entry found" + fi + fi + return 1 +} + +# ------------- Shell rc helpers ------------- +ensure_rc_sources() { + local bashrc="$HOME/.bashrc" bashrc_personal="$HOME/.bashrc-personal" + local zshrc="$HOME/.zshrc" zshrc_personal="$HOME/.zshrc-personal" + + if [[ -f "$bashrc_personal" ]]; then + local line_bash='[ -f "$HOME/.bashrc-personal" ] && source "$HOME/.bashrc-personal"' + if ! grep -Fq ".bashrc-personal" "$bashrc" 2>/dev/null; then + step "Adding source of .bashrc-personal to $bashrc" + if ((DRY_RUN)); then + printf "Would append to %s: %s\n" "$bashrc" "$line_bash" + else + mkdir -p "$(dirname "$bashrc")" + printf "%s\n" "$line_bash" >>"$bashrc" + fi + else + info "$bashrc already sources .bashrc-personal" + fi + fi + + if [[ -f "$zshrc_personal" ]]; then + local line_zsh='[ -f "$HOME/.zshrc-personal" ] && source "$HOME/.zshrc-personal"' + if ! grep -Fq ".zshrc-personal" "$zshrc" 2>/dev/null; then + step "Adding source of .zshrc-personal to $zshrc" + if ((DRY_RUN)); then + printf "Would append to %s: %s\n" "$zshrc" "$line_zsh" + else + mkdir -p "$(dirname "$zshrc")" + printf "%s\n" "$line_zsh" >>"$zshrc" + fi + else + info "$zshrc already sources .zshrc-personal" + fi + fi +} + +backup_then_copy_file() { + local src="$1" dest="$2" + if [[ -e "$dest" ]]; then + if ask_backup_or_skip "$dest"; then + local ts backup + ts=$(date +%Y%m%d-%H%M%S) + backup="${dest}.bak.${ts}" + step "Backing up $dest -> $backup" + run mv -v "$dest" "$backup" + else + warn "Skipped $dest" + return 0 + fi + fi + run cp -v "$src" "$dest" +} + +backup_then_copy_dir() { + local src="$1" dest="$2" + if [[ -e "$dest" ]]; then + if ask_backup_or_skip "$dest"; then + local ts backup + ts=$(date +%Y%m%d-%H%M%S) + backup="${dest}.bak.${ts}" + step "Backing up $dest -> $backup" + run mv -v "$dest" "$backup" + else + warn "Skipped $dest" + return 0 + fi + fi + run cp -rv "$src" "$dest" +} + +copy_config_files() { + if ! ensure_nas_available; then + if confirm "Could not access $NAS_CONFIG_DIR. Continue without copying standard config files?" y; then + warn "Skipping config copy" + return 0 + else + error "Aborting per user decision" + return 1 + fi + fi + + step "Copying configuration files from $NAS_CONFIG_DIR" + + # Starship + run mkdir -p "$HOME/.config" + if [[ -f "$NAS_CONFIG_DIR/Shells/starship/garuda-mokka.starship.toml" ]]; then + backup_then_copy_file "$NAS_CONFIG_DIR/Shells/starship/garuda-mokka.starship.toml" "$HOME/.config/starship.toml" + fi + + # Ghostty + run mkdir -p "$HOME/.config/ghostty" + if [[ -f "$NAS_CONFIG_DIR/skel/ghostty.config.xerolinux" ]]; then + backup_then_copy_file "$NAS_CONFIG_DIR/skel/ghostty.config.xerolinux" "$HOME/.config/ghostty/config" + fi + + # Yazi + if [[ -d "$NAS_CONFIG_DIR/yazi" ]]; then + backup_then_copy_dir "$NAS_CONFIG_DIR/yazi" "$HOME/.config/yazi" + if command -v ya >/dev/null 2>&1; then + step "Updating Yazi plugins via 'ya pkg upgrade'" + run ya pkg upgrade || warn "'ya pkg upgrade' failed" + else + info "'ya' not found; skipping Yazi plugin upgrade" + fi + fi + + # Tmux + run mkdir -p "$HOME/.config/tmux" + if [[ -d "$NAS_CONFIG_DIR/skel/tmux/tmux.no.git.folders" ]]; then + backup_then_copy_dir "$NAS_CONFIG_DIR/skel/tmux/tmux.no.git.folders" "$HOME/.config/tmux" + elif [[ -f "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" ]]; then + step "Extracting tmux config tar" + if ((DRY_RUN)); then + printf "Would extract %s to %s\n" "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" "$HOME/.config/tmux" + else + tar -xvf "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" -C "$HOME/.config/tmux" + fi + fi + + # Personal shells + [[ -f "$NAS_CONFIG_DIR/.bashrc-personal" ]] && backup_then_copy_file "$NAS_CONFIG_DIR/.bashrc-personal" "$HOME/.bashrc-personal" + [[ -f "$NAS_CONFIG_DIR/.zshrc-personal" ]] && backup_then_copy_file "$NAS_CONFIG_DIR/.zshrc-personal" "$HOME/.zshrc-personal" + + ensure_rc_sources + success "Config copy complete" +} + +# ------------- Fonts (DMS) ------------- +ensure_dms_fonts() { + step "Ensuring fonts required by Dank Material Shell (DMS)" + run sudo install -d -m 0755 /usr/share/fonts + local changed=0 + local IFS='|' + local font + local FONTS=( + "Material Symbols Rounded|https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsRounded%5BFILL%2CGRAD%2Copsz%2Cwght%5D.ttf|/usr/share/fonts/MaterialSymbolsRounded.ttf|Material Symbols Rounded" + "Inter Variable|https://github.com/rsms/inter/raw/refs/tags/v4.1/docs/font-files/InterVariable.ttf|/usr/share/fonts/InterVariable.ttf|Inter" + "Fira Code|https://raw.githubusercontent.com/tonsky/FiraCode/main/distr/ttf/FiraCode-Regular.ttf|/usr/share/fonts/FiraCode-Regular.ttf|Fira Code" + ) + for font in "${FONTS[@]}"; do + read -r LABEL URL DEST CHECK <<<"$font" + if fc-list | grep -qi -- "$CHECK"; then + info "Font '$LABEL' already available" + continue + fi + if [[ -f "$DEST" ]]; then + info "Font file for '$LABEL' already present at $DEST" + continue + fi + step "Downloading font: $LABEL" + if run sudo curl -fL "$URL" -o "$DEST"; then + changed=1 + else + warn "Failed to download $LABEL" + if [[ "$LABEL" == "Fira Code" ]]; then + step "Attempting to install Fira Code via package manager" + if pkg_install fonts-firacode; then + changed=1 + else + warn "fonts-firacode package not available" + fi + fi + fi + done + if ((changed)); then + step "Rebuilding font cache" + run sudo fc-cache -fv + else info "No font changes needed"; fi +} + +# ------------- DMS install/build (same as debian script) ------------- +install_dms_deps() { + step "Installing DMS build/runtime dependencies" + pkg_install build-essential gcc make cmake ninja-build git autoconf automake libtool pkg-config + pkg_install qt6-base-dev qt6-base-dev-tools qt6-declarative-dev qt6-shadertools-dev qt6-declarative-private-dev + pkg_install qt6-tools-dev qt6-tools-dev-tools qttools5-dev-tools qt6-wayland + pkg_install libwayland-dev wayland-protocols libxkbcommon-dev libegl1-mesa-dev + pkg_install libcli11-dev libjemalloc-dev libdbus-1-dev +} + +install_dms_binary() { + step "Installing DMS (prebuilt binary)" + local arch cmd + arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + cmd="curl -L https://github.com/AvengeMedia/danklinux/releases/latest/download/dms-${arch}.gz | gunzip | tee /usr/local/bin/dms >/dev/null && chmod +x /usr/local/bin/dms" + if ((DRY_RUN)); then + printf "Would run (as root): %s\n" "$cmd" + else + sudo sh -c "$cmd" + fi +} + +qs_detect_version() { + local v + if command -v quickshell >/dev/null 2>&1; then + v=$(quickshell --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) + if [[ -z "$v" ]]; then + v=$(quickshell -v 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) + fi + printf "%s" "${v}" + fi +} + +version_ge() { dpkg --compare-versions "$1" ge "$2"; } + +build_quickshell() { + local workdir="$DMS_WORKDIR" + local qs_dir="$workdir/quickshell" + local qs_url="https://git.outfoxxed.me/quickshell/quickshell.git" + run mkdir -p "$workdir" + if [[ -d "$qs_dir/.git" ]]; then + step "Updating Quickshell in $qs_dir" + (cd "$qs_dir" && run git fetch --all --prune && run git pull --ff-only) + else + step "Cloning Quickshell" + run git clone "$qs_url" "$qs_dir" + fi + step "Configuring Quickshell (CMake + Ninja)" + run mkdir -p "$qs_dir/build" + (cd "$qs_dir/build" && run cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DINSTALL_QMLDIR="$(qtpaths6 -query QT_INSTALL_QML 2>/dev/null || echo /usr/lib/qt6/qml)" ..) + step "Building Quickshell" + (cd "$qs_dir/build" && run cmake --build .) + step "Installing Quickshell" + (cd "$qs_dir/build" && run sudo cmake --install .) +} + +ensure_quickshell_min_version() { + local min_ver="$1" + local cur + cur=$(qs_detect_version || true) + if [[ -n "$cur" ]] && version_ge "$cur" "$min_ver"; then + info "Quickshell $cur present (>= $min_ver); skipping build" + return 0 + fi + warn "Quickshell not present or < $min_ver; building from source" + build_quickshell +} + +ensure_quickshell_config_dms() { + local cfg="$HOME/.config/quickshell" + local dms_dir="$cfg/dms" + run mkdir -p "$cfg" + if [[ -d "$dms_dir/.git" ]]; then + step "Updating DankMaterialShell in $dms_dir" + (cd "$dms_dir" && run git fetch --all --prune && run git pull --ff-only) + else + step "Cloning DankMaterialShell to $dms_dir" + run git clone https://github.com/AvengeMedia/DankMaterialShell.git "$dms_dir" + fi +} + +ensure_dgop_installed() { + if command -v dgop >/dev/null 2>&1; then + info "dgop already installed" + return 0 + fi + step "Installing dgop" + local arch + arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + local cmd="curl -L https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-${arch}.gz | gunzip | tee /usr/local/bin/dgop > /dev/null && chmod +x /usr/local/bin/dgop" + if ((DRY_RUN)); then + printf "Would run (as root): %s\n" "$cmd" + else + sudo sh -c "$cmd" + fi +} + +ensure_rustc_cargo() { + if command -v cargo >/dev/null 2>&1 && command -v rustc >/dev/null 2>&1; then + return 0 + fi + step "Installing rust toolchain (rustc, cargo)" + pkg_install rustc cargo +} + +matugen_version() { + local v + if command -v matugen >/dev/null 2>&1; then + v=$(matugen --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) + printf "%s" "$v" + fi +} + +ensure_matugen_min_version() { + local min_ver="$1" + local cur + cur=$(matugen_version || true) + if [[ -n "$cur" ]] && version_ge "$cur" "$min_ver"; then + info "matugen $cur present (>= $min_ver)" + return 0 + fi + step "Installing matugen via cargo (requires rustc/cargo)" + ensure_rustc_cargo + run cargo install matugen + if [[ -x "$HOME/.cargo/bin/matugen" ]]; then + if ((DRY_RUN)); then + printf "Would copy %s to /usr/local/bin\n" "$HOME/.cargo/bin/matugen" + else + sudo cp "$HOME/.cargo/bin/matugen" /usr/local/bin/ + fi + fi +} + +build_from_source_generic() { + local src="$1" + if [[ -z "$src" || ! -d "$src" ]]; then + error "Invalid source directory: $src" + return 1 + fi + step "Building from source at $src" + if [[ -f "$src/meson.build" ]]; then + run meson setup "$src/build" "$src" --buildtype=release + run meson compile -C "$src/build" + run sudo meson install -C "$src/build" + elif [[ -f "$src/CMakeLists.txt" ]]; then + run cmake -S "$src" -B "$src/build" -DCMAKE_BUILD_TYPE=Release + run cmake --build "$src/build" -j"$(nproc)" + run sudo cmake --install "$src/build" + elif [[ -x "$src/configure" || -f "$src/configure.ac" ]]; then + (cd "$src" && run ./configure && run make -j"$(nproc)" && run sudo make install) + else + warn "Unknown build system in $src; skipping build" + return 1 + fi +} + +git_clone_or_update() { + local url="$1" dest="$2" + if [[ -d "$dest/.git" ]]; then + step "Updating repo $(basename "$dest")" + (cd "$dest" && run git fetch --all --prune && run git pull --ff-only) + else + step "Cloning $(basename "$dest")" + run git clone "$url" "$dest" + fi + if [[ -f "$dest/.gitmodules" ]]; then + step "Updating submodules for $(basename "$dest")" + (cd "$dest" && run git submodule update --init --recursive) + fi +} + +build_breakpad() { + local workdir="$DMS_WORKDIR" + local bp_dir="$workdir/breakpad" + run mkdir -p "$workdir" + git_clone_or_update https://chromium.googlesource.com/breakpad/breakpad "$bp_dir" + run mkdir -p "$bp_dir/src/third_party" + if [[ ! -d "$bp_dir/src/third_party/lss/.git" ]]; then + run git clone https://chromium.googlesource.com/linux-syscall-support "$bp_dir/src/third_party/lss" + else + (cd "$bp_dir/src/third_party/lss" && run git pull --ff-only) + fi + (cd "$bp_dir" && run autoreconf -fi && run ./configure && run make -j"$(nproc)") + run sudo make -C "$bp_dir" install + run sudo ldconfig || true +} + +ensure_breakpad() { + if pkg-config --exists breakpad 2>/dev/null; then + info "breakpad already available (pkg-config)" + return 0 + fi + step "Installing breakpad development package" + if pkg_install libbreakpad-dev; then + if pkg-config --exists breakpad 2>/dev/null; then + success "breakpad detected via pkg-config after install" + return 0 + fi + warn "libbreakpad-dev installed but pkg-config 'breakpad' still not found" + else + warn "libbreakpad-dev not available via $PKG_MGR" + fi + warn "Falling back to building breakpad from source" + build_breakpad + if pkg-config --exists breakpad 2>/dev/null; then + success "breakpad available after source build" + return 0 + fi + error "breakpad still missing; Quickshell build will fail" + return 1 +} + +install_dms_sources() { + ensure_breakpad || true + ensure_quickshell_min_version "0.2.1" +} + +install_dms() { + install_dms_deps + install_dms_sources + ensure_quickshell_config_dms + ensure_dgop_installed + ensure_matugen_min_version "2.4.1" + install_dms_binary || true + if command -v dms >/dev/null 2>&1; then success "DMS wrapper installed: $(command -v dms)"; fi +} + +# ------------- Polkit agent management ------------- +ensure_polkit_agent() { + step "Ensuring a working Polkit authentication agent" + local gnome_pkg="policykit-1-gnome" mate_pkg="mate-polkit" + local gnome_paths=( + "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1" + ) + local mate_paths=( + "/usr/libexec/polkit-mate-authentication-agent-1" + "/usr/lib/mate-polkit/polkit-mate-authentication-agent-1" + "/usr/lib/policykit-1-mate/polkit-mate-authentication-agent-1" + ) + run sudo apt purge -y hyprpolkit hyprpolkit-agent hyprpolkit-git || true + if pgrep -u "$USER" -f 'hypr.*polkit' >/dev/null 2>&1; then + warn "Found running hyprpolkit agent; stopping to avoid conflicts" + run pkill -u "$USER" -f 'hypr.*polkit' || true + fi + pkg_install pkexec || true + local agent="" + if pkg_install "$gnome_pkg"; then + for p in "${gnome_paths[@]}"; do + if [[ -x "$p" ]]; then + agent="$p" + break + fi + done + fi + if [[ -z "$agent" ]]; then + if pkg_install "$mate_pkg"; then + for p in "${mate_paths[@]}"; do + if [[ -x "$p" ]]; then + agent="$p" + break + fi + done + fi + fi + if [[ -z "$agent" ]]; then + warn "No polkit authentication agent found after install attempts" + return 0 + fi + local autostart="$HOME/.config/autostart/polkit-agent.desktop" + run mkdir -p "$HOME/.config/autostart" + if ((DRY_RUN)); then + printf "Would write autostart for agent: %s -> %s\n" "$agent" "$autostart" + else + cat >"$autostart" </dev/null 2>&1; then + step "Starting polkit agent: $agent" + if ((DRY_RUN)); then + printf "Would start: %s\n" "$agent" + else + nohup "$agent" >/dev/null 2>&1 & + disown || true + fi + else + info "Polkit agent already running" + fi +} + +# ------------- Package manager (nala/apt) ------------- +PKG_MGR="apt" +PKG_INSTALL_CMD=(sudo apt install -y) +PKG_UPDATE_CMD=(sudo apt update) +PKG_UPGRADE_CMD=(sudo apt upgrade -y) + +use_nala_if_available() { + if command -v nala >/dev/null 2>&1; then + PKG_MGR="nala" + PKG_INSTALL_CMD=(sudo nala install -y) + PKG_UPDATE_CMD=(sudo nala update) + PKG_UPGRADE_CMD=(sudo nala upgrade -y) + info "Using nala for package operations" + return 0 + fi + return 1 +} + +try_install_nala() { + if command -v nala >/dev/null 2>&1; then return 0; fi + step "Attempting to install nala" + if run sudo apt update && run sudo apt install -y nala; then + use_nala_if_available + else + warn "nala installation failed; falling back to apt" + fi +} + +pkg_install() { run "${PKG_INSTALL_CMD[@]}" "$@"; } +pkg_update() { run "${PKG_UPDATE_CMD[@]}"; } +pkg_upgrade() { run "${PKG_UPGRADE_CMD[@]}"; } + +# ------------- Docker (Ubuntu packages) ------------- +install_docker() { + step "Installing Docker (Ubuntu packages)" + run sudo apt-get update + pkg_install ca-certificates curl gnupg || true + pkg_install docker.io docker-compose-v2 + run sudo usermod -aG docker "$USER" + run sudo systemctl enable --now docker || run sudo systemctl enable --now dockerd || true + success "Docker installation complete" +} + +# ------------- Flatpak ------------- +configure_flatpak() { + step "Configuring Flatpak" + run sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo +} + +install_flatpak_apps() { + step "Installing Flatpak apps (flathub)" + local apps=( + com.github.tchx84.Flatseal + com.visualstudio.code + io.github.dvlv.boxbuddyrs + io.github.flattool.Warehouse + ) + run flatpak install -y flathub "${apps[@]}" } + +# ------------- Local .deb installs from NAS ------------- +install_deb_if_exists() { + local deb_path="$1" + if [[ -f "$deb_path" ]]; then + step "Installing $(basename "$deb_path")" + pkg_install "$deb_path" || { + warn "Install via $PKG_MGR failed for $deb_path; attempting dpkg -i + fix" + run sudo dpkg -i "$deb_path" || run sudo apt-get -f install -y + } + else + warn "Missing .deb: $deb_path" + fi +} + +install_nas_local_bins() { + local bin_dir="$NAS_CONFIG_DIR/OS/debian/bin" + if ! ensure_nas_available; then + warn "NAS not available; skipping local bin installs" + return 0 + fi + if [[ ! -d "$bin_dir" ]]; then + info "No local bin dir at $bin_dir; skipping" + return 0 + fi + step "Installing local binaries from $bin_dir to /usr/local/bin" + local f base + for f in "$bin_dir"/*; do + [[ -f "$f" ]] || continue + base=$(basename "$f") + if ((DRY_RUN)); then + printf "Would install %s -> /usr/local/bin/%s with mode 0755\n" "$f" "$base" + else + sudo install -m 0755 -D "$f" "/usr/local/bin/$base" + fi + done +} + +install_apps() { + step "Installing standard packages" + pkg_install git wget curl rsync tmux flatpak sshfs mpv gcc remmina vlc ugrep ripgrep bat fzf ncdu time flex + pkg_install btop glances zoxide tree ranger cava cmatrix virt-viewer arandr variety feh nitrogen fastfetch + pkg_install rustc cargo wlr-randr htop ncdu kitty alacritty starship + + configure_flatpak + install_flatpak_apps + + step "Installing Docker and related components" + install_docker + + step "Installing additional utilities (distrobox)" + pkg_install distrobox || warn "distrobox not available in current repositories" + + step "Optional installs from NAS (if present)" + step "Removing distro Neovim before installing NAS package (avoids conflicts)" + run sudo apt remove -y neovim neovim-runtime || true + install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/nvim-linux-x86_64.deb" + install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/onefetch_2.25.0_amd64.deb" + install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/discord.deb" + install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/discord-canary.deb" + install_nas_local_bins + + success "Package installation complete" +} + +# ------------- WezTerm / Nerd Fonts / Themes ------------- +install_wezterm() { + step "Installing WezTerm (nightly) from official repository" + if command -v wezterm >/dev/null 2>&1; then + info "WezTerm already installed; skipping package install" + else + run sudo install -d -m 0755 /usr/share/keyrings /etc/apt/sources.list.d + local cmd + cmd="curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg" + if ((DRY_RUN)); then + printf "Would run: %s\n" "$cmd" + else + sh -c "$cmd" + fi + if ((DRY_RUN)); then + printf "Would write WezTerm APT source to /etc/apt/sources.list.d/wezterm.list\n" + else + echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list >/dev/null || true + fi + run sudo chmod 644 /usr/share/keyrings/wezterm-fury.gpg + step "Refreshing package metadata for WezTerm" + pkg_update || run sudo apt update + step "Installing wezterm-nightly" + pkg_install wezterm-nightly || warn "Failed to install wezterm-nightly" + fi + + step "Configuring WezTerm" + run mkdir -p "$HOME/.config/wezterm" + local cfg_url="https://codeberg.org/justaguylinux/butterscripts/raw/branch/main/wezterm/wezterm.lua" + if ((DRY_RUN)); then + printf "Would download %s -> %s\n" "$cfg_url" "$HOME/.config/wezterm/wezterm.lua" + else + curl -fsSL "$cfg_url" -o "$HOME/.config/wezterm/wezterm.lua" || warn "Failed to download WezTerm config" + fi + + if command -v update-alternatives >/dev/null 2>&1 && command -v wezterm >/dev/null 2>&1; then + step "Setting wezterm as default terminal emulator" + run sudo update-alternatives --install /usr/bin/x-terminal-emulator x-terminal-emulator /usr/bin/wezterm 50 + run sudo update-alternatives --set x-terminal-emulator /usr/bin/wezterm + fi + success "WezTerm installation/configuration complete" +} + +install_nerd_fonts() { + step "Installing Nerd Fonts" + pkg_install wget unzip || true + local FONTS_DIR="$HOME/.local/share/fonts" + local TEMP_DIR + TEMP_DIR=$(mktemp -d -t nerdfonts.XXXXXX) + run mkdir -p "$FONTS_DIR" + local FONT_VERSION="v3.4.0" + local fonts=( + JetBrainsMono FiraCode Hack CascadiaCode SourceCodePro RobotoMono Meslo UbuntuMono Inconsolata VictorMono Mononoki Terminus Lilex + ) + local font + for font in "${fonts[@]}"; do + step "Processing $font" + if [[ -d "$FONTS_DIR/$font" ]] && [[ -n "$(ls -A "$FONTS_DIR/$font" 2>/dev/null)" ]]; then + info "$font already installed; skipping" + continue + fi + local zip="$TEMP_DIR/${font}.zip" + local url="https://github.com/ryanoasis/nerd-fonts/releases/download/${FONT_VERSION}/${font}.zip" + if ((DRY_RUN)); then + printf "Would download %s -> %s\n" "$url" "$zip" + printf "Would extract %s into %s/%s\n" "$zip" "$FONTS_DIR" "$font" + else + curl -fL "$url" -o "$zip" || { + warn "Download failed for $font" + continue + } + run mkdir -p "$FONTS_DIR/$font" + if unzip -q "$zip" -d "$FONTS_DIR/$font/"; then :; else + warn "Extraction failed for $font" + rm -rf "$FONTS_DIR/$font" + fi + rm -f "$zip" + fi + done + step "Rebuilding font cache" + run fc-cache -f + if ((DRY_RUN)); then + printf "Would remove temp dir %s\n" "$TEMP_DIR" + else + rm -rf "$TEMP_DIR" + fi + success "Nerd Fonts installation complete" +} + +install_themes() { + step "Installing GTK and icon themes" + pkg_install git || true + local TEMP_DIR + TEMP_DIR=$(mktemp -d -t themes.XXXXXX) + if ((DRY_RUN)); then + printf "Would clone and run theme installers in %s\n" "$TEMP_DIR" + else + mkdir -p "$TEMP_DIR" + (cd "$TEMP_DIR" && git clone -q https://github.com/vinceliuice/Orchis-theme) || { error "Failed to clone GTK theme"; } + (cd "$TEMP_DIR/Orchis-theme" && yes | ./install.sh -l -c dark -t grey --tweaks black >/dev/null 2>&1) || warn "GTK theme install failed" + (cd "$TEMP_DIR" && git clone -q https://github.com/vinceliuice/Colloid-icon-theme) || { error "Failed to clone icon theme"; } + (cd "$TEMP_DIR/Colloid-icon-theme" && ./install.sh -t grey -s dracula >/dev/null 2>&1 || true) + local ICON_THEME="Colloid-Grey-Dracula-Dark" + if [[ ! -d "$HOME/.local/share/icons/$ICON_THEME" ]] && [[ ! -d "$HOME/.icons/$ICON_THEME" ]]; then + warn "Icon theme installation verification failed" + fi + fi + + local GTK_THEME="Orchis-Grey-Dark" + run mkdir -p "$HOME/.config/gtk-3.0" + if ((DRY_RUN)); then + printf "Would write GTK settings files and apply via gsettings if available\n" + else + cat >"$HOME/.config/gtk-3.0/settings.ini" <"$HOME/.gtkrc-2.0" </dev/null 2>&1; then + gsettings set org.gnome.desktop.interface gtk-theme "$GTK_THEME" || true + gsettings set org.gnome.desktop.interface icon-theme "Colloid-Grey-Dracula-Dark" || true + fi + fi + + if ((DRY_RUN)); then + printf "Would remove temp dir %s\n" "$TEMP_DIR" + else + rm -rf "$TEMP_DIR" + fi + success "Themes installed and applied" +} + +preflight_updates() { + if confirm "Recommended: run 'sudo apt update && sudo apt upgrade -y' now before proceeding?" y; then + step "Updating package metadata" + pkg_update || run sudo apt update + step "Upgrading packages" + pkg_upgrade || run sudo apt upgrade -y + else + warn "Proceeding without initial apt update/upgrade" + fi +} + +postflight_updates() { + if confirm "Run 'sudo apt update && sudo apt upgrade -y' again to pick up any new updates (e.g., from newly added repos)?" y; then + step "Updating package metadata" + run sudo apt update + step "Upgrading packages" + run sudo apt upgrade -y + else + warn "Skipping final apt update/upgrade" + fi +} + +main() { + info "Starting Ubuntu setup" + + if ((APT_ONLY)); then + info "Using apt (forced)" + else + info "Using apt" + fi + + preflight_updates + + if ((DMS_ONLY)); then + info "DMS-only mode" + ensure_dms_fonts + install_dms + ensure_polkit_agent + success "Done (dms-only)" + postflight_updates + return 0 + fi + + if ((WEZTERM_ONLY || FONTS_ONLY || THEMES_ONLY)); then + info "Selective install mode" + if ((WEZTERM_ONLY)); then install_wezterm; fi + if ((FONTS_ONLY)); then install_nerd_fonts; fi + if ((THEMES_ONLY)); then install_themes; fi + success "Done (selective installs)" + postflight_updates + return 0 + fi + + if ((CONFIG_ONLY)); then + info "Config-only mode" + ensure_dms_fonts + if ((INSTALL_DMS)); then + install_dms + fi + ensure_polkit_agent + copy_config_files + success "Done (config-only)" + postflight_updates + return 0 + fi + + if ((APPS_ONLY)); then + info "Apps-only mode" + install_apps + if ((INSTALL_DMS)); then + ensure_dms_fonts + install_dms + fi + ensure_polkit_agent + success "Done (apps-only)" + postflight_updates + return 0 + fi + + install_apps + ensure_dms_fonts + if ((INSTALL_DMS)); then + install_dms + fi + ensure_polkit_agent + copy_config_files + + success "All tasks complete" + postflight_updates +} + +main "$@" -- cgit v1.2.3 From efae693feae00b9439ab2a62eb964a0f31303aff Mon Sep 17 00:00:00 2001 From: Don Williams Date: Wed, 18 Feb 2026 22:10:00 -0500 Subject: Fixed config-compact.jsonc --- config/fastfetch/config-compact.jsonc | 1086 ++------------------------------- 1 file changed, 65 insertions(+), 1021 deletions(-) mode change 100755 => 100644 config/fastfetch/config-compact.jsonc (limited to 'config/fastfetch/config-compact.jsonc') diff --git a/config/fastfetch/config-compact.jsonc b/config/fastfetch/config-compact.jsonc old mode 100755 new mode 100644 index b6431de9..d88e1d32 --- a/config/fastfetch/config-compact.jsonc +++ b/config/fastfetch/config-compact.jsonc @@ -1,1022 +1,66 @@ -#!/usr/bin/env bash -set -Eeuo pipefail - -# Ubuntu setup of common apps and configuration (based on debian-setup.sh) -# - Colors, iconography, robust error handling -# - Checks /mnt/nas and copies configs if available -# - Optional modes: --config-only, --apps-only, --dry-run -# - Uses nala when available, falls back to apt -# - Prompts to run apt update/upgrade before and after - -# ------------- Config ------------- -NAS_MOUNT="/mnt/nas" -NAS_CONFIG_DIR="$NAS_MOUNT/config.files" -DRY_RUN=0 -CONFIG_ONLY=0 -APPS_ONLY=0 -SKIP_ALL=0 -INSTALL_DMS=0 -DMS_ONLY=0 -DMS_SRC="" -DMS_WORKDIR="$HOME/.local/src/dms" -APT_ONLY=0 - -# Selective install toggles -WEZTERM_ONLY=0 -FONTS_ONLY=0 -THEMES_ONLY=0 - -# ------------- Colors & Icons ------------- -RESET="\033[0m" -BOLD="\033[1m" -RED="\033[31m" -GREEN="\033[32m" -YELLOW="\033[33m" -BLUE="\033[34m" -CYAN="\033[36m" -GRAY="\033[90m" -ICON_INFO="â„šī¸" -ICON_OK="✅" -ICON_WARN="âš ī¸" -ICON_ERR="❌" -ICON_STEP="â–ļī¸" - -info() { printf "%b%s%b %b%s%b\n" "$BLUE" "$ICON_INFO" "$RESET" "$BOLD" "$*" "$RESET"; } -success() { printf "%b%s%b %s\n" "$GREEN" "$ICON_OK" "$RESET" "$*"; } -warn() { printf "%b%s%b %s\n" "$YELLOW" "$ICON_WARN" "$RESET" "$*"; } -error() { printf "%b%s%b %s\n" "$RED" "$ICON_ERR" "$RESET" "$*" 1>&2; } -step() { printf "%b%s%b %s\n" "$CYAN" "$ICON_STEP" "$RESET" "$*"; } - -run() { - if ((DRY_RUN)); then - printf "%b+ %s%b\n" "$GRAY" "$(printf '%q ' "$@")" "$RESET" - else - "$@" - fi +/** + * â”â”“â”â”“â”â”“â”â”ŗâ”“â”â”“â”â”“â”â”ŗâ”“â”â”“â”“â” + * â”Ŗ â”Ŗâ”Ģ┗┓ ┃ â”Ŗ â”Ŗ ┃ ┃ â”Ŗâ”Ģ + * â”ģ ┛┗┗┛ â”ģ â”ģ ┗┛ â”ģ ┗┛┛┗ + * + */ +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "logo": { + // "type": "auto", + // x."source": "~/.config/fastfetch/logo.png", + // "height": 10, + "padding": { + "top": 3, + "right": 2 + }, + "type": "small" + }, + "display": { + "separator": " " + }, + "modules": [ + "break", + "break", + "break", + "break", + { + "type": "os", + "key": " ", + "keyColor": "31" + }, + { + "type": "kernel", + "key": " ", + "keyColor": "32" + }, + { + "type": "shell", + "key": "ī„  ", + "keyColor": "34" + }, + { + "type": "terminal", + "key": "ī’‰ ", + "keyColor": "35" + }, + { + "type": "wm", + "key": "ī’ˆ ", + "keyColor": "36" + }, + { + "type": "uptime", + "key": " ", + "keyColor": "31" + }, + { + "type": "command", + "key": "ī™ ", + "keyColor": "36", + "shell": "/bin/bash", + "text": "echo \"Jak's dotfiles: v$DOTS_VERSION\"" + }, + "break" + ] } - -usage() { - cat <<'USAGE' -Usage: ubuntu-setup.sh [options] - -Options: - --config-only Only copy/apply configuration (no package installs) - --apps-only Only install/upgrade packages and apps (no config copy) - --dry-run Show what would be done without making changes - --install-dms Install Dank Material Shell: fonts + dependencies + build Quickshell and required sources; also installs the dms wrapper - --dms-only Only install DMS (skip general apps/config); implies --install-dms - --dms-src PATH Use existing source tree at PATH for building (auto-detects Meson/CMake/Autotools) - --wezterm-only Only install and configure WezTerm (nightly) - --fonts-only Only install Nerd Fonts - --themes-only Only install GTK and icon themes - --apt-only Force using apt (disable nala detection/installation) - -h, --help Show this help -USAGE -} - -# ------------- Arg parsing ------------- -while [[ $# -gt 0 ]]; do - case "${1}" in - --config-only) - CONFIG_ONLY=1 - shift - ;; - --apps-only) - APPS_ONLY=1 - shift - ;; - --dry-run) - DRY_RUN=1 - shift - ;; - --install-dms) - INSTALL_DMS=1 - shift - ;; - --dms-only) - DMS_ONLY=1 - INSTALL_DMS=1 - shift - ;; - --dms-src) - DMS_SRC="${2:-}" - if [[ -z "$DMS_SRC" ]]; then - error "--dms-src requires a path" - exit 2 - fi - shift 2 - ;; - --wezterm-only) - WEZTERM_ONLY=1 - shift - ;; - --fonts-only) - FONTS_ONLY=1 - shift - ;; - --themes-only) - THEMES_ONLY=1 - shift - ;; - --apt-only) - APT_ONLY=1 - shift - ;; - -h | --help) - usage - exit 0 - ;; - *) - error "Unknown option: $1" - usage - exit 2 - ;; - esac -done - -confirm() { - local msg=${1:-"Are you sure?"} - local def=${2:-"y"} - local prompt="[y/N]" - [[ "$def" =~ ^[Yy]$ ]] && prompt="[Y/n]" - local reply - read -r -p "$msg $prompt " reply || true - reply=${reply:-$def} - [[ "$reply" =~ ^[Yy]$ ]] -} - -ask_backup_or_skip() { - local path="$1" - local reply - if ((SKIP_ALL)); then - warn "Skip-All enabled; skipping '$path'" - return 1 - fi - while true; do - read -r -p "'$path' exists. (B)ackup, (S)kip, Skip (A)ll? [B/s/a] " reply || reply="B" - reply=${reply:-B} - case "${reply}" in - B | b) return 0 ;; - S | s) return 1 ;; - A | a) - SKIP_ALL=1 - warn "Skip-All enabled; skipping '$path' and all subsequent conflicts" - return 1 - ;; - *) printf "Please answer B, S, or A.\n" ;; - esac - done -} - -# ------------- /mnt/nas helpers ------------- -ensure_nas_available() { - if [[ -d "$NAS_CONFIG_DIR" ]]; then - return 0 - fi - if mountpoint -q "$NAS_MOUNT"; then - if [[ -d "$NAS_CONFIG_DIR" ]]; then - return 0 - fi - warn "$NAS_MOUNT is mounted but $NAS_CONFIG_DIR not found" - else - if grep -Eq '^[^#].*\s/mnt/nas\s' /etc/fstab; then - step "Attempting to mount $NAS_MOUNT from /etc/fstab" - if run sudo mount "$NAS_MOUNT"; then - [[ -d "$NAS_CONFIG_DIR" ]] && return 0 || warn "Mounted $NAS_MOUNT but $NAS_CONFIG_DIR not found" - else - warn "Failed to mount $NAS_MOUNT" - fi - else - warn "$NAS_MOUNT not mounted and no /etc/fstab entry found" - fi - fi - return 1 -} - -# ------------- Shell rc helpers ------------- -ensure_rc_sources() { - local bashrc="$HOME/.bashrc" bashrc_personal="$HOME/.bashrc-personal" - local zshrc="$HOME/.zshrc" zshrc_personal="$HOME/.zshrc-personal" - - if [[ -f "$bashrc_personal" ]]; then - local line_bash='[ -f "$HOME/.bashrc-personal" ] && source "$HOME/.bashrc-personal"' - if ! grep -Fq ".bashrc-personal" "$bashrc" 2>/dev/null; then - step "Adding source of .bashrc-personal to $bashrc" - if ((DRY_RUN)); then - printf "Would append to %s: %s\n" "$bashrc" "$line_bash" - else - mkdir -p "$(dirname "$bashrc")" - printf "%s\n" "$line_bash" >>"$bashrc" - fi - else - info "$bashrc already sources .bashrc-personal" - fi - fi - - if [[ -f "$zshrc_personal" ]]; then - local line_zsh='[ -f "$HOME/.zshrc-personal" ] && source "$HOME/.zshrc-personal"' - if ! grep -Fq ".zshrc-personal" "$zshrc" 2>/dev/null; then - step "Adding source of .zshrc-personal to $zshrc" - if ((DRY_RUN)); then - printf "Would append to %s: %s\n" "$zshrc" "$line_zsh" - else - mkdir -p "$(dirname "$zshrc")" - printf "%s\n" "$line_zsh" >>"$zshrc" - fi - else - info "$zshrc already sources .zshrc-personal" - fi - fi -} - -backup_then_copy_file() { - local src="$1" dest="$2" - if [[ -e "$dest" ]]; then - if ask_backup_or_skip "$dest"; then - local ts backup - ts=$(date +%Y%m%d-%H%M%S) - backup="${dest}.bak.${ts}" - step "Backing up $dest -> $backup" - run mv -v "$dest" "$backup" - else - warn "Skipped $dest" - return 0 - fi - fi - run cp -v "$src" "$dest" -} - -backup_then_copy_dir() { - local src="$1" dest="$2" - if [[ -e "$dest" ]]; then - if ask_backup_or_skip "$dest"; then - local ts backup - ts=$(date +%Y%m%d-%H%M%S) - backup="${dest}.bak.${ts}" - step "Backing up $dest -> $backup" - run mv -v "$dest" "$backup" - else - warn "Skipped $dest" - return 0 - fi - fi - run cp -rv "$src" "$dest" -} - -copy_config_files() { - if ! ensure_nas_available; then - if confirm "Could not access $NAS_CONFIG_DIR. Continue without copying standard config files?" y; then - warn "Skipping config copy" - return 0 - else - error "Aborting per user decision" - return 1 - fi - fi - - step "Copying configuration files from $NAS_CONFIG_DIR" - - # Starship - run mkdir -p "$HOME/.config" - if [[ -f "$NAS_CONFIG_DIR/Shells/starship/garuda-mokka.starship.toml" ]]; then - backup_then_copy_file "$NAS_CONFIG_DIR/Shells/starship/garuda-mokka.starship.toml" "$HOME/.config/starship.toml" - fi - - # Ghostty - run mkdir -p "$HOME/.config/ghostty" - if [[ -f "$NAS_CONFIG_DIR/skel/ghostty.config.xerolinux" ]]; then - backup_then_copy_file "$NAS_CONFIG_DIR/skel/ghostty.config.xerolinux" "$HOME/.config/ghostty/config" - fi - - # Yazi - if [[ -d "$NAS_CONFIG_DIR/yazi" ]]; then - backup_then_copy_dir "$NAS_CONFIG_DIR/yazi" "$HOME/.config/yazi" - if command -v ya >/dev/null 2>&1; then - step "Updating Yazi plugins via 'ya pkg upgrade'" - run ya pkg upgrade || warn "'ya pkg upgrade' failed" - else - info "'ya' not found; skipping Yazi plugin upgrade" - fi - fi - - # Tmux - run mkdir -p "$HOME/.config/tmux" - if [[ -d "$NAS_CONFIG_DIR/skel/tmux/tmux.no.git.folders" ]]; then - backup_then_copy_dir "$NAS_CONFIG_DIR/skel/tmux/tmux.no.git.folders" "$HOME/.config/tmux" - elif [[ -f "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" ]]; then - step "Extracting tmux config tar" - if ((DRY_RUN)); then - printf "Would extract %s to %s\n" "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" "$HOME/.config/tmux" - else - tar -xvf "$NAS_CONFIG_DIR/skel/tmux/tmux.conf.update.tar" -C "$HOME/.config/tmux" - fi - fi - - # Personal shells - [[ -f "$NAS_CONFIG_DIR/.bashrc-personal" ]] && backup_then_copy_file "$NAS_CONFIG_DIR/.bashrc-personal" "$HOME/.bashrc-personal" - [[ -f "$NAS_CONFIG_DIR/.zshrc-personal" ]] && backup_then_copy_file "$NAS_CONFIG_DIR/.zshrc-personal" "$HOME/.zshrc-personal" - - ensure_rc_sources - success "Config copy complete" -} - -# ------------- Fonts (DMS) ------------- -ensure_dms_fonts() { - step "Ensuring fonts required by Dank Material Shell (DMS)" - run sudo install -d -m 0755 /usr/share/fonts - local changed=0 - local IFS='|' - local font - local FONTS=( - "Material Symbols Rounded|https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsRounded%5BFILL%2CGRAD%2Copsz%2Cwght%5D.ttf|/usr/share/fonts/MaterialSymbolsRounded.ttf|Material Symbols Rounded" - "Inter Variable|https://github.com/rsms/inter/raw/refs/tags/v4.1/docs/font-files/InterVariable.ttf|/usr/share/fonts/InterVariable.ttf|Inter" - "Fira Code|https://raw.githubusercontent.com/tonsky/FiraCode/main/distr/ttf/FiraCode-Regular.ttf|/usr/share/fonts/FiraCode-Regular.ttf|Fira Code" - ) - for font in "${FONTS[@]}"; do - read -r LABEL URL DEST CHECK <<<"$font" - if fc-list | grep -qi -- "$CHECK"; then - info "Font '$LABEL' already available" - continue - fi - if [[ -f "$DEST" ]]; then - info "Font file for '$LABEL' already present at $DEST" - continue - fi - step "Downloading font: $LABEL" - if run sudo curl -fL "$URL" -o "$DEST"; then - changed=1 - else - warn "Failed to download $LABEL" - if [[ "$LABEL" == "Fira Code" ]]; then - step "Attempting to install Fira Code via package manager" - if pkg_install fonts-firacode; then - changed=1 - else - warn "fonts-firacode package not available" - fi - fi - fi - done - if ((changed)); then - step "Rebuilding font cache" - run sudo fc-cache -fv - else info "No font changes needed"; fi -} - -# ------------- DMS install/build (same as debian script) ------------- -install_dms_deps() { - step "Installing DMS build/runtime dependencies" - pkg_install build-essential gcc make cmake ninja-build git autoconf automake libtool pkg-config - pkg_install qt6-base-dev qt6-base-dev-tools qt6-declarative-dev qt6-shadertools-dev qt6-declarative-private-dev - pkg_install qt6-tools-dev qt6-tools-dev-tools qttools5-dev-tools qt6-wayland - pkg_install libwayland-dev wayland-protocols libxkbcommon-dev libegl1-mesa-dev - pkg_install libcli11-dev libjemalloc-dev libdbus-1-dev -} - -install_dms_binary() { - step "Installing DMS (prebuilt binary)" - local arch cmd - arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') - cmd="curl -L https://github.com/AvengeMedia/danklinux/releases/latest/download/dms-${arch}.gz | gunzip | tee /usr/local/bin/dms >/dev/null && chmod +x /usr/local/bin/dms" - if ((DRY_RUN)); then - printf "Would run (as root): %s\n" "$cmd" - else - sudo sh -c "$cmd" - fi -} - -qs_detect_version() { - local v - if command -v quickshell >/dev/null 2>&1; then - v=$(quickshell --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) - if [[ -z "$v" ]]; then - v=$(quickshell -v 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) - fi - printf "%s" "${v}" - fi -} - -version_ge() { dpkg --compare-versions "$1" ge "$2"; } - -build_quickshell() { - local workdir="$DMS_WORKDIR" - local qs_dir="$workdir/quickshell" - local qs_url="https://git.outfoxxed.me/quickshell/quickshell.git" - run mkdir -p "$workdir" - if [[ -d "$qs_dir/.git" ]]; then - step "Updating Quickshell in $qs_dir" - (cd "$qs_dir" && run git fetch --all --prune && run git pull --ff-only) - else - step "Cloning Quickshell" - run git clone "$qs_url" "$qs_dir" - fi - step "Configuring Quickshell (CMake + Ninja)" - run mkdir -p "$qs_dir/build" - (cd "$qs_dir/build" && run cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DINSTALL_QMLDIR="$(qtpaths6 -query QT_INSTALL_QML 2>/dev/null || echo /usr/lib/qt6/qml)" ..) - step "Building Quickshell" - (cd "$qs_dir/build" && run cmake --build .) - step "Installing Quickshell" - (cd "$qs_dir/build" && run sudo cmake --install .) -} - -ensure_quickshell_min_version() { - local min_ver="$1" - local cur - cur=$(qs_detect_version || true) - if [[ -n "$cur" ]] && version_ge "$cur" "$min_ver"; then - info "Quickshell $cur present (>= $min_ver); skipping build" - return 0 - fi - warn "Quickshell not present or < $min_ver; building from source" - build_quickshell -} - -ensure_quickshell_config_dms() { - local cfg="$HOME/.config/quickshell" - local dms_dir="$cfg/dms" - run mkdir -p "$cfg" - if [[ -d "$dms_dir/.git" ]]; then - step "Updating DankMaterialShell in $dms_dir" - (cd "$dms_dir" && run git fetch --all --prune && run git pull --ff-only) - else - step "Cloning DankMaterialShell to $dms_dir" - run git clone https://github.com/AvengeMedia/DankMaterialShell.git "$dms_dir" - fi -} - -ensure_dgop_installed() { - if command -v dgop >/dev/null 2>&1; then - info "dgop already installed" - return 0 - fi - step "Installing dgop" - local arch - arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') - local cmd="curl -L https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-${arch}.gz | gunzip | tee /usr/local/bin/dgop > /dev/null && chmod +x /usr/local/bin/dgop" - if ((DRY_RUN)); then - printf "Would run (as root): %s\n" "$cmd" - else - sudo sh -c "$cmd" - fi -} - -ensure_rustc_cargo() { - if command -v cargo >/dev/null 2>&1 && command -v rustc >/dev/null 2>&1; then - return 0 - fi - step "Installing rust toolchain (rustc, cargo)" - pkg_install rustc cargo -} - -matugen_version() { - local v - if command -v matugen >/dev/null 2>&1; then - v=$(matugen --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1 || true) - printf "%s" "$v" - fi -} - -ensure_matugen_min_version() { - local min_ver="$1" - local cur - cur=$(matugen_version || true) - if [[ -n "$cur" ]] && version_ge "$cur" "$min_ver"; then - info "matugen $cur present (>= $min_ver)" - return 0 - fi - step "Installing matugen via cargo (requires rustc/cargo)" - ensure_rustc_cargo - run cargo install matugen - if [[ -x "$HOME/.cargo/bin/matugen" ]]; then - if ((DRY_RUN)); then - printf "Would copy %s to /usr/local/bin\n" "$HOME/.cargo/bin/matugen" - else - sudo cp "$HOME/.cargo/bin/matugen" /usr/local/bin/ - fi - fi -} - -build_from_source_generic() { - local src="$1" - if [[ -z "$src" || ! -d "$src" ]]; then - error "Invalid source directory: $src" - return 1 - fi - step "Building from source at $src" - if [[ -f "$src/meson.build" ]]; then - run meson setup "$src/build" "$src" --buildtype=release - run meson compile -C "$src/build" - run sudo meson install -C "$src/build" - elif [[ -f "$src/CMakeLists.txt" ]]; then - run cmake -S "$src" -B "$src/build" -DCMAKE_BUILD_TYPE=Release - run cmake --build "$src/build" -j"$(nproc)" - run sudo cmake --install "$src/build" - elif [[ -x "$src/configure" || -f "$src/configure.ac" ]]; then - (cd "$src" && run ./configure && run make -j"$(nproc)" && run sudo make install) - else - warn "Unknown build system in $src; skipping build" - return 1 - fi -} - -git_clone_or_update() { - local url="$1" dest="$2" - if [[ -d "$dest/.git" ]]; then - step "Updating repo $(basename "$dest")" - (cd "$dest" && run git fetch --all --prune && run git pull --ff-only) - else - step "Cloning $(basename "$dest")" - run git clone "$url" "$dest" - fi - if [[ -f "$dest/.gitmodules" ]]; then - step "Updating submodules for $(basename "$dest")" - (cd "$dest" && run git submodule update --init --recursive) - fi -} - -build_breakpad() { - local workdir="$DMS_WORKDIR" - local bp_dir="$workdir/breakpad" - run mkdir -p "$workdir" - git_clone_or_update https://chromium.googlesource.com/breakpad/breakpad "$bp_dir" - run mkdir -p "$bp_dir/src/third_party" - if [[ ! -d "$bp_dir/src/third_party/lss/.git" ]]; then - run git clone https://chromium.googlesource.com/linux-syscall-support "$bp_dir/src/third_party/lss" - else - (cd "$bp_dir/src/third_party/lss" && run git pull --ff-only) - fi - (cd "$bp_dir" && run autoreconf -fi && run ./configure && run make -j"$(nproc)") - run sudo make -C "$bp_dir" install - run sudo ldconfig || true -} - -ensure_breakpad() { - if pkg-config --exists breakpad 2>/dev/null; then - info "breakpad already available (pkg-config)" - return 0 - fi - step "Installing breakpad development package" - if pkg_install libbreakpad-dev; then - if pkg-config --exists breakpad 2>/dev/null; then - success "breakpad detected via pkg-config after install" - return 0 - fi - warn "libbreakpad-dev installed but pkg-config 'breakpad' still not found" - else - warn "libbreakpad-dev not available via $PKG_MGR" - fi - warn "Falling back to building breakpad from source" - build_breakpad - if pkg-config --exists breakpad 2>/dev/null; then - success "breakpad available after source build" - return 0 - fi - error "breakpad still missing; Quickshell build will fail" - return 1 -} - -install_dms_sources() { - ensure_breakpad || true - ensure_quickshell_min_version "0.2.1" -} - -install_dms() { - install_dms_deps - install_dms_sources - ensure_quickshell_config_dms - ensure_dgop_installed - ensure_matugen_min_version "2.4.1" - install_dms_binary || true - if command -v dms >/dev/null 2>&1; then success "DMS wrapper installed: $(command -v dms)"; fi -} - -# ------------- Polkit agent management ------------- -ensure_polkit_agent() { - step "Ensuring a working Polkit authentication agent" - local gnome_pkg="policykit-1-gnome" mate_pkg="mate-polkit" - local gnome_paths=( - "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1" - ) - local mate_paths=( - "/usr/libexec/polkit-mate-authentication-agent-1" - "/usr/lib/mate-polkit/polkit-mate-authentication-agent-1" - "/usr/lib/policykit-1-mate/polkit-mate-authentication-agent-1" - ) - run sudo apt purge -y hyprpolkit hyprpolkit-agent hyprpolkit-git || true - if pgrep -u "$USER" -f 'hypr.*polkit' >/dev/null 2>&1; then - warn "Found running hyprpolkit agent; stopping to avoid conflicts" - run pkill -u "$USER" -f 'hypr.*polkit' || true - fi - pkg_install pkexec || true - local agent="" - if pkg_install "$gnome_pkg"; then - for p in "${gnome_paths[@]}"; do - if [[ -x "$p" ]]; then - agent="$p" - break - fi - done - fi - if [[ -z "$agent" ]]; then - if pkg_install "$mate_pkg"; then - for p in "${mate_paths[@]}"; do - if [[ -x "$p" ]]; then - agent="$p" - break - fi - done - fi - fi - if [[ -z "$agent" ]]; then - warn "No polkit authentication agent found after install attempts" - return 0 - fi - local autostart="$HOME/.config/autostart/polkit-agent.desktop" - run mkdir -p "$HOME/.config/autostart" - if ((DRY_RUN)); then - printf "Would write autostart for agent: %s -> %s\n" "$agent" "$autostart" - else - cat >"$autostart" </dev/null 2>&1; then - step "Starting polkit agent: $agent" - if ((DRY_RUN)); then - printf "Would start: %s\n" "$agent" - else - nohup "$agent" >/dev/null 2>&1 & - disown || true - fi - else - info "Polkit agent already running" - fi -} - -# ------------- Package manager (nala/apt) ------------- -PKG_MGR="apt" -PKG_INSTALL_CMD=(sudo apt install -y) -PKG_UPDATE_CMD=(sudo apt update) -PKG_UPGRADE_CMD=(sudo apt upgrade -y) - -use_nala_if_available() { - if command -v nala >/dev/null 2>&1; then - PKG_MGR="nala" - PKG_INSTALL_CMD=(sudo nala install -y) - PKG_UPDATE_CMD=(sudo nala update) - PKG_UPGRADE_CMD=(sudo nala upgrade -y) - info "Using nala for package operations" - return 0 - fi - return 1 -} - -try_install_nala() { - if command -v nala >/dev/null 2>&1; then return 0; fi - step "Attempting to install nala" - if run sudo apt update && run sudo apt install -y nala; then - use_nala_if_available - else - warn "nala installation failed; falling back to apt" - fi -} - -pkg_install() { run "${PKG_INSTALL_CMD[@]}" "$@"; } -pkg_update() { run "${PKG_UPDATE_CMD[@]}"; } -pkg_upgrade() { run "${PKG_UPGRADE_CMD[@]}"; } - -# ------------- Docker (Ubuntu packages) ------------- -install_docker() { - step "Installing Docker (Ubuntu packages)" - run sudo apt-get update - pkg_install ca-certificates curl gnupg || true - pkg_install docker.io docker-compose-v2 - run sudo usermod -aG docker "$USER" - run sudo systemctl enable --now docker || run sudo systemctl enable --now dockerd || true - success "Docker installation complete" -} - -# ------------- Flatpak ------------- -configure_flatpak() { - step "Configuring Flatpak" - run sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -} - -install_flatpak_apps() { - step "Installing Flatpak apps (flathub)" - local apps=( - com.github.tchx84.Flatseal - com.visualstudio.code - io.github.dvlv.boxbuddyrs - io.github.flattool.Warehouse - ) - run flatpak install -y flathub "${apps[@]}" -} - -# ------------- Local .deb installs from NAS ------------- -install_deb_if_exists() { - local deb_path="$1" - if [[ -f "$deb_path" ]]; then - step "Installing $(basename "$deb_path")" - pkg_install "$deb_path" || { - warn "Install via $PKG_MGR failed for $deb_path; attempting dpkg -i + fix" - run sudo dpkg -i "$deb_path" || run sudo apt-get -f install -y - } - else - warn "Missing .deb: $deb_path" - fi -} - -install_nas_local_bins() { - local bin_dir="$NAS_CONFIG_DIR/OS/debian/bin" - if ! ensure_nas_available; then - warn "NAS not available; skipping local bin installs" - return 0 - fi - if [[ ! -d "$bin_dir" ]]; then - info "No local bin dir at $bin_dir; skipping" - return 0 - fi - step "Installing local binaries from $bin_dir to /usr/local/bin" - local f base - for f in "$bin_dir"/*; do - [[ -f "$f" ]] || continue - base=$(basename "$f") - if ((DRY_RUN)); then - printf "Would install %s -> /usr/local/bin/%s with mode 0755\n" "$f" "$base" - else - sudo install -m 0755 -D "$f" "/usr/local/bin/$base" - fi - done -} - -install_apps() { - step "Installing standard packages" - pkg_install git wget curl rsync tmux flatpak sshfs mpv gcc remmina vlc ugrep ripgrep bat fzf ncdu time flex - pkg_install btop glances zoxide tree ranger cava cmatrix virt-viewer arandr variety feh nitrogen fastfetch - pkg_install rustc cargo wlr-randr htop ncdu kitty alacritty starship - - configure_flatpak - install_flatpak_apps - - step "Installing Docker and related components" - install_docker - - step "Installing additional utilities (distrobox)" - pkg_install distrobox || warn "distrobox not available in current repositories" - - step "Optional installs from NAS (if present)" - step "Removing distro Neovim before installing NAS package (avoids conflicts)" - run sudo apt remove -y neovim neovim-runtime || true - install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/nvim-linux-x86_64.deb" - install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/onefetch_2.25.0_amd64.deb" - install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/discord.deb" - install_deb_if_exists "$NAS_CONFIG_DIR/OS/debian/Packages/discord-canary.deb" - install_nas_local_bins - - success "Package installation complete" -} - -# ------------- WezTerm / Nerd Fonts / Themes ------------- -install_wezterm() { - step "Installing WezTerm (nightly) from official repository" - if command -v wezterm >/dev/null 2>&1; then - info "WezTerm already installed; skipping package install" - else - run sudo install -d -m 0755 /usr/share/keyrings /etc/apt/sources.list.d - local cmd - cmd="curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg" - if ((DRY_RUN)); then - printf "Would run: %s\n" "$cmd" - else - sh -c "$cmd" - fi - if ((DRY_RUN)); then - printf "Would write WezTerm APT source to /etc/apt/sources.list.d/wezterm.list\n" - else - echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list >/dev/null || true - fi - run sudo chmod 644 /usr/share/keyrings/wezterm-fury.gpg - step "Refreshing package metadata for WezTerm" - pkg_update || run sudo apt update - step "Installing wezterm-nightly" - pkg_install wezterm-nightly || warn "Failed to install wezterm-nightly" - fi - - step "Configuring WezTerm" - run mkdir -p "$HOME/.config/wezterm" - local cfg_url="https://codeberg.org/justaguylinux/butterscripts/raw/branch/main/wezterm/wezterm.lua" - if ((DRY_RUN)); then - printf "Would download %s -> %s\n" "$cfg_url" "$HOME/.config/wezterm/wezterm.lua" - else - curl -fsSL "$cfg_url" -o "$HOME/.config/wezterm/wezterm.lua" || warn "Failed to download WezTerm config" - fi - - if command -v update-alternatives >/dev/null 2>&1 && command -v wezterm >/dev/null 2>&1; then - step "Setting wezterm as default terminal emulator" - run sudo update-alternatives --install /usr/bin/x-terminal-emulator x-terminal-emulator /usr/bin/wezterm 50 - run sudo update-alternatives --set x-terminal-emulator /usr/bin/wezterm - fi - success "WezTerm installation/configuration complete" -} - -install_nerd_fonts() { - step "Installing Nerd Fonts" - pkg_install wget unzip || true - local FONTS_DIR="$HOME/.local/share/fonts" - local TEMP_DIR - TEMP_DIR=$(mktemp -d -t nerdfonts.XXXXXX) - run mkdir -p "$FONTS_DIR" - local FONT_VERSION="v3.4.0" - local fonts=( - JetBrainsMono FiraCode Hack CascadiaCode SourceCodePro RobotoMono Meslo UbuntuMono Inconsolata VictorMono Mononoki Terminus Lilex - ) - local font - for font in "${fonts[@]}"; do - step "Processing $font" - if [[ -d "$FONTS_DIR/$font" ]] && [[ -n "$(ls -A "$FONTS_DIR/$font" 2>/dev/null)" ]]; then - info "$font already installed; skipping" - continue - fi - local zip="$TEMP_DIR/${font}.zip" - local url="https://github.com/ryanoasis/nerd-fonts/releases/download/${FONT_VERSION}/${font}.zip" - if ((DRY_RUN)); then - printf "Would download %s -> %s\n" "$url" "$zip" - printf "Would extract %s into %s/%s\n" "$zip" "$FONTS_DIR" "$font" - else - curl -fL "$url" -o "$zip" || { - warn "Download failed for $font" - continue - } - run mkdir -p "$FONTS_DIR/$font" - if unzip -q "$zip" -d "$FONTS_DIR/$font/"; then :; else - warn "Extraction failed for $font" - rm -rf "$FONTS_DIR/$font" - fi - rm -f "$zip" - fi - done - step "Rebuilding font cache" - run fc-cache -f - if ((DRY_RUN)); then - printf "Would remove temp dir %s\n" "$TEMP_DIR" - else - rm -rf "$TEMP_DIR" - fi - success "Nerd Fonts installation complete" -} - -install_themes() { - step "Installing GTK and icon themes" - pkg_install git || true - local TEMP_DIR - TEMP_DIR=$(mktemp -d -t themes.XXXXXX) - if ((DRY_RUN)); then - printf "Would clone and run theme installers in %s\n" "$TEMP_DIR" - else - mkdir -p "$TEMP_DIR" - (cd "$TEMP_DIR" && git clone -q https://github.com/vinceliuice/Orchis-theme) || { error "Failed to clone GTK theme"; } - (cd "$TEMP_DIR/Orchis-theme" && yes | ./install.sh -l -c dark -t grey --tweaks black >/dev/null 2>&1) || warn "GTK theme install failed" - (cd "$TEMP_DIR" && git clone -q https://github.com/vinceliuice/Colloid-icon-theme) || { error "Failed to clone icon theme"; } - (cd "$TEMP_DIR/Colloid-icon-theme" && ./install.sh -t grey -s dracula >/dev/null 2>&1 || true) - local ICON_THEME="Colloid-Grey-Dracula-Dark" - if [[ ! -d "$HOME/.local/share/icons/$ICON_THEME" ]] && [[ ! -d "$HOME/.icons/$ICON_THEME" ]]; then - warn "Icon theme installation verification failed" - fi - fi - - local GTK_THEME="Orchis-Grey-Dark" - run mkdir -p "$HOME/.config/gtk-3.0" - if ((DRY_RUN)); then - printf "Would write GTK settings files and apply via gsettings if available\n" - else - cat >"$HOME/.config/gtk-3.0/settings.ini" <"$HOME/.gtkrc-2.0" </dev/null 2>&1; then - gsettings set org.gnome.desktop.interface gtk-theme "$GTK_THEME" || true - gsettings set org.gnome.desktop.interface icon-theme "Colloid-Grey-Dracula-Dark" || true - fi - fi - - if ((DRY_RUN)); then - printf "Would remove temp dir %s\n" "$TEMP_DIR" - else - rm -rf "$TEMP_DIR" - fi - success "Themes installed and applied" -} - -preflight_updates() { - if confirm "Recommended: run 'sudo apt update && sudo apt upgrade -y' now before proceeding?" y; then - step "Updating package metadata" - pkg_update || run sudo apt update - step "Upgrading packages" - pkg_upgrade || run sudo apt upgrade -y - else - warn "Proceeding without initial apt update/upgrade" - fi -} - -postflight_updates() { - if confirm "Run 'sudo apt update && sudo apt upgrade -y' again to pick up any new updates (e.g., from newly added repos)?" y; then - step "Updating package metadata" - run sudo apt update - step "Upgrading packages" - run sudo apt upgrade -y - else - warn "Skipping final apt update/upgrade" - fi -} - -main() { - info "Starting Ubuntu setup" - - if ((APT_ONLY)); then - info "Using apt (forced)" - else - info "Using apt" - fi - - preflight_updates - - if ((DMS_ONLY)); then - info "DMS-only mode" - ensure_dms_fonts - install_dms - ensure_polkit_agent - success "Done (dms-only)" - postflight_updates - return 0 - fi - - if ((WEZTERM_ONLY || FONTS_ONLY || THEMES_ONLY)); then - info "Selective install mode" - if ((WEZTERM_ONLY)); then install_wezterm; fi - if ((FONTS_ONLY)); then install_nerd_fonts; fi - if ((THEMES_ONLY)); then install_themes; fi - success "Done (selective installs)" - postflight_updates - return 0 - fi - - if ((CONFIG_ONLY)); then - info "Config-only mode" - ensure_dms_fonts - if ((INSTALL_DMS)); then - install_dms - fi - ensure_polkit_agent - copy_config_files - success "Done (config-only)" - postflight_updates - return 0 - fi - - if ((APPS_ONLY)); then - info "Apps-only mode" - install_apps - if ((INSTALL_DMS)); then - ensure_dms_fonts - install_dms - fi - ensure_polkit_agent - success "Done (apps-only)" - postflight_updates - return 0 - fi - - install_apps - ensure_dms_fonts - if ((INSTALL_DMS)); then - install_dms - fi - ensure_polkit_agent - copy_config_files - - success "All tasks complete" - postflight_updates -} - -main "$@" -- cgit v1.2.3