From b51f2e0b09a1886703d390ec8a889bc1afb7b2d0 Mon Sep 17 00:00:00 2001 From: Andrejus Date: Wed, 24 Dec 2025 02:34:10 +0200 Subject: [PATCH] feat: mise, brew and fastfetch perf --- files/home/.profile | 9 +-- files/home/.zshrc | 46 +---------- script/install | 14 ++-- script/install.d/00-os.sh | 18 +---- script/install.d/23-stow.sh | 3 + script/install.d/30-mise.sh | 41 ++++++++++ script/install.d/30-pyenv.sh | 57 ------------- script/install.d/31-python.sh | 80 +++++-------------- script/install.d/32-node.sh | 37 ++------- script/install.d/33-terraform.sh | 16 ++++ script/install.d/34-firebase.sh | 16 ++++ script/install.d/40-gh.sh | 1 + script/install.d/43-copilot.sh | 20 +++++ script/install.d/43-terraform.sh | 37 --------- script/install.d/60-iterm2.sh | 2 +- script/install.d/61-nerdfont.sh | 17 +++- script/install.d/70-cca.sh | 2 +- script/install.d/71-rectangle.sh | 2 +- script/install.d/72-meetingbar.sh | 2 +- script/install.d/73-betterdisplay.sh | 2 +- script/install.d/74-dockutil.sh | 2 +- .../{80-neofetch.sh => 80-fastfetch.sh} | 14 ++-- script/install.d/90-macos.sh | 20 ++--- script/install.d/98-clean.sh | 33 -------- .../{99-screenfetch.sh => 99-fastfetch.sh} | 4 +- tests/test_binaries.py | 7 +- 26 files changed, 178 insertions(+), 324 deletions(-) create mode 100644 script/install.d/30-mise.sh delete mode 100644 script/install.d/30-pyenv.sh create mode 100644 script/install.d/33-terraform.sh create mode 100644 script/install.d/34-firebase.sh create mode 100644 script/install.d/43-copilot.sh delete mode 100644 script/install.d/43-terraform.sh rename script/install.d/{80-neofetch.sh => 80-fastfetch.sh} (50%) delete mode 100644 script/install.d/98-clean.sh rename script/install.d/{99-screenfetch.sh => 99-fastfetch.sh} (77%) diff --git a/files/home/.profile b/files/home/.profile index b9d4b3e..128ed6f 100644 --- a/files/home/.profile +++ b/files/home/.profile @@ -4,10 +4,7 @@ export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" export WORKSPACE="${WORKSPACE:-$HOME/Workspace}" export DOTFILES="${DOTFILES:-$HOME/.dotfiles}" -# Tool roots -export NVM_DIR="${NVM_DIR:-$HOME/.config/nvm}" -export PYENV_ROOT="${PYENV_ROOT:-$HOME/.pyenv}" -export POETRY_ROOT="${POETRY_ROOT:-$HOME/.poetry}" +# Homebrew export HOMEBREW_NO_ANALYTICS=1 # PATH setup with caching @@ -16,11 +13,7 @@ if [[ -f "$_dots_path_cache" && "$_dots_path_cache" -nt ~/.profile ]]; then export PATH="$(cat "$_dots_path_cache")" else [[ ":$PATH:" != *":$HOME/.local/bin:"* ]] && export PATH="$HOME/.local/bin:$PATH" - [[ ":$PATH:" != *":$PYENV_ROOT/shims:"* ]] && export PATH="$PYENV_ROOT/shims:$PATH" - [[ ":$PATH:" != *":$PYENV_ROOT/bin:"* ]] && export PATH="$PYENV_ROOT/bin:$PATH" - [[ ":$PATH:" != *":$POETRY_ROOT/bin:"* ]] && export PATH="$POETRY_ROOT/bin:$PATH" [[ -x "/opt/homebrew/bin/brew" && ":$PATH:" != *":/opt/homebrew/bin:"* ]] && export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH" - [ -f "$NVM_DIR/alias/lts/jod" ] && export PATH="$NVM_DIR/versions/node/$(cat "$NVM_DIR/alias/lts/jod")/bin:$PATH" # Cache the result mkdir -p "$(dirname "$_dots_path_cache")" diff --git a/files/home/.zshrc b/files/home/.zshrc index 9a7be45..bb7a7be 100644 --- a/files/home/.zshrc +++ b/files/home/.zshrc @@ -7,7 +7,7 @@ _dots_load_profile() { source "$HOME/.profile" } _dots_load_profile _dots_setup_dirs() { - mkdir -p "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" "$HOME/.local/bin" "$WORKSPACE" "$NVM_DIR" "$_dots_cache_dir" + mkdir -p "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" "$HOME/.local/bin" "$WORKSPACE" "$_dots_cache_dir" } _dots_setup_dirs @@ -333,47 +333,9 @@ _dots_prompt_init() { } _dots_prompt_init -# Lazy loading -_dots_init_nvm() { - unfunction nvm node npm npx yarn pnpm corepack 2>/dev/null - [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" - [[ -s "$NVM_DIR/bash_completion" ]] && source "$NVM_DIR/bash_completion" +_dots_load_mise() { + command -v mise &>/dev/null && eval "$(mise activate zsh)" } - -_dots_load_nvm_lazy() { - local -a nvm_cmds=(nvm node npm npx yarn pnpm corepack) - for cmd in "${nvm_cmds[@]}"; do - eval "${cmd}() { _dots_init_nvm; ${cmd} \"\$@\" }" - done -} - -_dots_init_pyenv() { - unfunction pyenv python python3 pip pip3 poetry pipx 2>/dev/null - if command -v pyenv &>/dev/null; then - eval "$(pyenv init -)" - eval "$(pyenv virtualenv-init -)" 2>/dev/null - fi -} - -_dots_load_pyenv_lazy() { - local -a pyenv_cmds=(pyenv python python3 pip pip3 poetry pipx) - for cmd in "${pyenv_cmds[@]}"; do - eval "${cmd}() { _dots_init_pyenv; ${cmd} \"\$@\" }" - done -} - -_dots_setup_lazy_completions() { - compdef '_dots_init_nvm; _npm' npm 2>/dev/null - compdef '_dots_init_nvm; _node' node 2>/dev/null - compdef '_dots_init_pyenv; _pip' pip 2>/dev/null - compdef '_dots_init_pyenv; _python' python 2>/dev/null -} - -_dots_lazy_init() { - _dots_load_nvm_lazy - _dots_load_pyenv_lazy - _dots_setup_lazy_completions -} -_dots_lazy_init +_dots_load_mise [[ -n "$ZSH_BENCH" ]] && zprof || true diff --git a/script/install b/script/install index 3967692..5e32830 100755 --- a/script/install +++ b/script/install @@ -80,12 +80,14 @@ esac # Set up Homebrew environment if [[ "$DOTS_PKG" == "brew" ]]; then - NONINTERACTIVE=1 - HOMEBREW_NO_ANALYTICS=1 - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 - HOMEBREW_NO_ENV_HINTS=1 - HOMEBREW_NO_AUTO_UPDATE=1 - HOMEBREW_NO_INSTALL_CLEANUP=1 + export NONINTERACTIVE=1 + export HOMEBREW_NO_ANALYTICS=1 + export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 + export HOMEBREW_NO_ENV_HINTS=1 + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + export BREW_CASKS=$(brew list --cask 2>/dev/null || true) + export BREW_FORMULAE=$(brew list 2>/dev/null || true) fi # Set up directory variables diff --git a/script/install.d/00-os.sh b/script/install.d/00-os.sh index 772e07b..b628650 100644 --- a/script/install.d/00-os.sh +++ b/script/install.d/00-os.sh @@ -8,29 +8,17 @@ log_info "Environment: DOTS_OS=$DOTS_OS, DOTS_PKG=$DOTS_PKG, DOTS_ENV=$DOTS_ENV" if [[ "$DOTS_OS" == "macos" ]]; then - # macOS info sw_vers - log_info "Detected macOS (OSTYPE=$OSTYPE)" - log_info "Package manager: Homebrew (brew)" - log_info "Code path: macOS-only brew scripts will run; Linux package scripts are skipped." - elif [[ "$DOTS_OS" == "linux" ]]; then - # Linux info if [[ -r /etc/os-release ]]; then cat /etc/os-release - # shellcheck source=/dev/null - . /etc/os-release fi - - log_info "Detected Linux (OSTYPE=$OSTYPE, ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-n/a}, NAME=${NAME:-n/a}, VERSION_ID=${VERSION_ID:-n/a})" - log_info "Package manager detected: ${DOTS_PKG:-none}" - + if [[ -z "$DOTS_PKG" ]]; then - log_warn "No known package manager (apt-get/pacman/dnf) found on Linux." + log_warn "No known package manager found on Linux" fi - else - log_error "Unknown OS: $OSTYPE" + log_error "Unknown OS: $DOTS_OS" fi if [[ "$DOTS_ENV" == "codespaces" ]]; then diff --git a/script/install.d/23-stow.sh b/script/install.d/23-stow.sh index fcb852f..7268614 100644 --- a/script/install.d/23-stow.sh +++ b/script/install.d/23-stow.sh @@ -41,3 +41,6 @@ mkdir -p "$HOME/.ssh" stow --dir="$root_dir/files" --target="$HOME" home stow --dir="$root_dir/files" --target="$HOME/.config" dot-config stow --dir="$root_dir/files" --target="$HOME/.ssh" dot-ssh + +# Bust PATH cache to force regeneration with new profile +rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/dots/path" diff --git a/script/install.d/30-mise.sh b/script/install.d/30-mise.sh new file mode 100644 index 0000000..d0d8bec --- /dev/null +++ b/script/install.d/30-mise.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# ----------------------------------------------------------------------------- +# Description: +# Install mise runtime manager (base installation only). +# Individual tools are installed in separate scripts (31-python, 32-node, etc.) +# + +# Skip in Codespaces (use pre-installed versions) +[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } + +# Install mise +if ! command -v mise &>/dev/null; then + log_info "Installing mise..." + case "$DOTS_PKG" in + brew) + brew install mise + ;; + apt) + # https://mise.jdx.dev/getting-started.html#apt-debian-ubuntu + wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | \ + sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null + echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=amd64] https://mise.jdx.dev/deb stable main" | \ + sudo tee /etc/apt/sources.list.d/mise.list + sudo apt-get update -qq + sudo apt-get install -qq mise + ;; + pacman) + yay -S --noconfirm mise + ;; + *) + # Fallback: curl install + log_info "Using curl installer..." + curl https://mise.jdx.dev/install.sh | sh + # Add to PATH for current session + export PATH="$HOME/.local/bin:$PATH" + ;; + esac +fi + +mise --version diff --git a/script/install.d/30-pyenv.sh b/script/install.d/30-pyenv.sh deleted file mode 100644 index 2b4ca36..0000000 --- a/script/install.d/30-pyenv.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -# ----------------------------------------------------------------------------- -# Description: -# Configure pyenv. -# - -# Skip in Codespaces (use pre-installed Python) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } - -export PYENV_ROOT="$HOME/.pyenv" -if ! echo "$PATH" | grep -q "$PYENV_ROOT"; then - export PATH="$PYENV_ROOT/bin:$PATH" -fi -if ! command -v pyenv &>/dev/null; then - case "$DOTS_PKG" in - apt) - # https://github.com/pyenv/pyenv/wiki#suggested-build-environment - sudo apt-get install -qq build-essential libssl-dev zlib1g-dev \ - libbz2-dev libreadline-dev libsqlite3-dev curl \ - libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev - - # see https://github.com/pyenv/pyenv-installer - bash -c "$(curl -fsSL https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer)" - ;; - pacman) - # Prefer native packages if available; otherwise install build deps then use installer - if ! sudo pacman -Qi pyenv >/dev/null 2>&1; then - sudo pacman -S --noconfirm --needed base-devel openssl zlib-ng-compat bzip2 readline sqlite xz tk libffi curl - bash -c "$(curl -fsSL https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer)" - else - sudo pacman -S --noconfirm --needed pyenv pyenv-virtualenv - fi - ;; - brew) - brew install pyenv - brew install pyenv-virtualenv - ;; - *) - log_warn "Skipping pyenv install: no supported package manager found" - ;; - esac -fi - -if [[ "$DOTS_OS" == "linux" ]]; then - virtualenv_path="$(pyenv root)/plugins/pyenv-virtualenv" - if [ ! -d "$virtualenv_path" ]; then - git clone \ - https://github.com/pyenv/pyenv-virtualenv.git \ - "$virtualenv_path" - fi - unset virtualenv_path -fi - -eval "$(pyenv init --path)" - -pyenv --version diff --git a/script/install.d/31-python.sh b/script/install.d/31-python.sh index 72cbabd..78f586c 100644 --- a/script/install.d/31-python.sh +++ b/script/install.d/31-python.sh @@ -2,74 +2,30 @@ # ----------------------------------------------------------------------------- # Description: -# Configure Python. +# Install Python via mise and configure poetry. # -# Skip in Codespaces (use pre-installed Python) +# Skip in Codespaces (use pre-installed versions) [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } -export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring +log_info "Installing Python..." +mise install python@3 +mise use -g python@3 -local version="3.14.2" +log_info "Installing Poetry..." +mise install poetry@latest +mise use -g poetry@latest -if ! pyenv versions --bare | grep -q "$version"; then - pyenv install "$version" -fi -pyenv global "$version" - -pip3 install --quiet --upgrade --user pip -python3 --version -pip3 --version - -pip_dependencies=( - # docker-compose - # neovim - # "python-language-server[all]" - # pyvim -) -installed_packages=$(pip3 list --format=freeze | awk -F'==' '{print $1}') -pip_dependencies=($(comm -13 <(printf "%s\n" "${installed_packages[@]}" | sort) <(printf "%s\n" "${pip_dependencies[@]}" | sort))) - -if [ ${#pip_dependencies[@]} -gt 0 ]; then - pip3 install --quiet --upgrade --user "${pip_dependencies[@]}" -fi - -unset installed_packages pip_dependencies PYTHON_KEYRING_BACKEND - -local_bin_path="$HOME/.local/bin" -if [[ ":$PATH:" != *":$local_bin_path:"* ]]; then - export PATH="$local_bin_path:$PATH" -fi -mkdir -p ~/.local/bin -unset local_bin_path - -if ! command -v pipx &>/dev/null; then - case "$DOTS_PKG" in - apt) - sudo apt-get install -qq pipx - ;; - pacman) - sudo pacman -S --noconfirm python-pipx - ;; - brew) - brew install pipx - ;; - *) - log_warn "Skipping pipx install: no supported package manager found" - ;; - esac -fi - -echo "pipx $(pipx --version)" - -if ! command -v poetry &>/dev/null; then - pipx install poetry +# Setup Poetry ZSH completions +ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" +if [[ -d "$ZSH_CUSTOM/plugins" ]]; then + POETRY_PLUGIN="$ZSH_CUSTOM/plugins/poetry" + if [ ! -d "$POETRY_PLUGIN" ]; then + mkdir -p "$POETRY_PLUGIN" + poetry completions zsh > "$POETRY_PLUGIN/_poetry" + fi fi +# Verify installations +python --version poetry --version - -POETRY_PLUGIN="$ZSH/custom/plugins/poetry" -if [ ! -d "$POETRY_PLUGIN" ]; then - mkdir -p "$POETRY_PLUGIN" - poetry completions zsh > "$POETRY_PLUGIN/_poetry" -fi diff --git a/script/install.d/32-node.sh b/script/install.d/32-node.sh index e458161..d69a954 100644 --- a/script/install.d/32-node.sh +++ b/script/install.d/32-node.sh @@ -2,39 +2,16 @@ # ----------------------------------------------------------------------------- # Description: -# Configure Node.js. +# Install Node.js via mise. # -# Skip in Codespaces (use pre-installed Node.js) +# Skip in Codespaces (use pre-installed versions) [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } -NVM_DIR=${NVM_DIR:-"$HOME/.nvm"} -[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" - -nvm_version="0.40.3" -if ! command -v nvm &>/dev/null; then - bash -c "$(curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${nvm_version}/install.sh)" - [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" -fi - -nvm --version -nvm alias default lts/jod -nvm install lts/jod -nvm use lts/jod - -echo "Node.js $(node --version)" +log_info "Installing Node.js..." +mise install node@lts +mise use -g node@lts +# Verify installations +echo "node $(node --version)" echo "npm $(npm --version)" - -npm_dependencies=( - "firebase-tools" - "@github/copilot" -) - -npm_dependencies=($(comm -23 <(printf "%s\n" "${npm_dependencies[@]}" | sort) <(npm list -g --depth=0 --parseable | awk -F'/' '{print $NF}' | sort))) - -if [ ${#npm_dependencies[@]} -gt 0 ]; then - npm install -g "${npm_dependencies[@]}" -fi - -unset nvm_version npm_dependencies diff --git a/script/install.d/33-terraform.sh b/script/install.d/33-terraform.sh new file mode 100644 index 0000000..7b1d999 --- /dev/null +++ b/script/install.d/33-terraform.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# ----------------------------------------------------------------------------- +# Description: +# Install Terraform via mise. +# + +# Skip in Codespaces (not needed) +[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } + +log_info "Installing Terraform..." +mise install terraform@latest +mise use -g terraform@latest + +# Verify installation +terraform --version diff --git a/script/install.d/34-firebase.sh b/script/install.d/34-firebase.sh new file mode 100644 index 0000000..2f67f31 --- /dev/null +++ b/script/install.d/34-firebase.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# ----------------------------------------------------------------------------- +# Description: +# Install Firebase CLI via mise. +# + +# Skip in Codespaces (not needed) +[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } + +log_info "Installing Firebase CLI..." +mise install firebase@latest +mise use -g firebase@latest + +# Verify installation +echo "firebase: $(firebase --version)" diff --git a/script/install.d/40-gh.sh b/script/install.d/40-gh.sh index 8d7888a..774db81 100644 --- a/script/install.d/40-gh.sh +++ b/script/install.d/40-gh.sh @@ -31,3 +31,4 @@ if ! command -v gh &>/dev/null; then fi gh --version + diff --git a/script/install.d/43-copilot.sh b/script/install.d/43-copilot.sh new file mode 100644 index 0000000..c296cf3 --- /dev/null +++ b/script/install.d/43-copilot.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# ----------------------------------------------------------------------------- +# Description: +# Install GitHub Copilot CLI (globally via npm). +# + +if ! command -v npm &>/dev/null; then + log_warn "npm not found, skipping" + return 0 +fi + +# Install if not present +if ! command -v copilot &>/dev/null; then + log_info "Installing GitHub Copilot CLI..." + npm install -g @github/copilot --silent +fi + +# Verify installation +log_info "GitHub Copilot CLI: $(copilot --version 2>&1 | head -1)" diff --git a/script/install.d/43-terraform.sh b/script/install.d/43-terraform.sh deleted file mode 100644 index 1a1bf4c..0000000 --- a/script/install.d/43-terraform.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -# ----------------------------------------------------------------------------- -# Description: -# Install terraform. -# - -# Skip in Codespaces (project-specific tool) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } - -if ! command -v terraform &>/dev/null; then - case "$DOTS_PKG" in - apt) - terraform_keyring_path="/usr/share/keyrings/hashicorp-archive-keyring.gpg" - if [[ ! -f "$terraform_keyring_path" ]]; then - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o "$terraform_keyring_path" - fi - echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ - https://apt.releases.hashicorp.com $(lsb_release -cs) main" | - sudo tee /etc/apt/sources.list.d/hashicorp.list - sudo apt-get update -qq && - sudo apt-get install -qq terraform - ;; - pacman) - sudo pacman -S --noconfirm terraform - ;; - brew) - brew tap hashicorp/tap - brew install hashicorp/tap/terraform - ;; - *) - log_warn "Skipping Terraform install: no supported package manager found" - ;; - esac -fi - -terraform --version diff --git a/script/install.d/60-iterm2.sh b/script/install.d/60-iterm2.sh index 0e3147c..43eae73 100644 --- a/script/install.d/60-iterm2.sh +++ b/script/install.d/60-iterm2.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list --cask iterm2 &>/dev/null; then +if ! echo "$BREW_CASKS" | grep -q "^iterm2$"; then brew install --cask iterm2 fi log_pass "iTerm2 installed successfully!" diff --git a/script/install.d/61-nerdfont.sh b/script/install.d/61-nerdfont.sh index a4c460b..9567caf 100644 --- a/script/install.d/61-nerdfont.sh +++ b/script/install.d/61-nerdfont.sh @@ -13,11 +13,22 @@ fonts_list=( font-fira-code-nerd-font ) -if ! brew list "${fonts_list[@]}" &> /dev/null; then +# Check if any fonts are missing +fonts_missing=false +for font in "${fonts_list[@]}"; do + if ! echo "$BREW_CASKS" | grep -q "^$font$"; then + fonts_missing=true + break + fi +done + +if [[ "$fonts_missing" == "true" ]]; then brew tap homebrew/cask-fonts for font in "${fonts_list[@]}"; do - brew install --cask "$font" + if ! echo "$BREW_CASKS" | grep -q "^$font$"; then + brew install --cask "$font" + fi done fi -unset fonts_list +unset fonts_list fonts_missing diff --git a/script/install.d/70-cca.sh b/script/install.d/70-cca.sh index a6f79d0..53723f9 100644 --- a/script/install.d/70-cca.sh +++ b/script/install.d/70-cca.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list --cask colour-contrast-analyser &> /dev/null; then +if ! echo "$BREW_CASKS" | grep -q "^colour-contrast-analyser$"; then brew install --cask colour-contrast-analyser else echo "Colour Contrast Analyser (CCA) is already installed." diff --git a/script/install.d/71-rectangle.sh b/script/install.d/71-rectangle.sh index 26b4a92..ec259a1 100644 --- a/script/install.d/71-rectangle.sh +++ b/script/install.d/71-rectangle.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list --cask rectangle &> /dev/null; then +if ! echo "$BREW_CASKS" | grep -q "^rectangle$"; then brew install --cask rectangle else echo "Rectangle is already installed." diff --git a/script/install.d/72-meetingbar.sh b/script/install.d/72-meetingbar.sh index 4c74f24..ad76488 100644 --- a/script/install.d/72-meetingbar.sh +++ b/script/install.d/72-meetingbar.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list --cask meetingbar &> /dev/null; then +if ! echo "$BREW_CASKS" | grep -q "^meetingbar$"; then brew install --cask meetingbar else echo "MeetingBar is already installed." diff --git a/script/install.d/73-betterdisplay.sh b/script/install.d/73-betterdisplay.sh index 8b0544c..579c9f8 100644 --- a/script/install.d/73-betterdisplay.sh +++ b/script/install.d/73-betterdisplay.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list --cask betterdisplay &> /dev/null; then +if ! echo "$BREW_CASKS" | grep -q "^betterdisplay$"; then brew install --cask betterdisplay else echo "BetterDisplay is already installed." diff --git a/script/install.d/74-dockutil.sh b/script/install.d/74-dockutil.sh index 180e77b..8bedbf3 100644 --- a/script/install.d/74-dockutil.sh +++ b/script/install.d/74-dockutil.sh @@ -8,7 +8,7 @@ # macOS only [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } -if ! brew list dockutil &> /dev/null; then +if ! echo "$BREW_FORMULAE" | grep -q "^dockutil$"; then brew install dockutil else echo "dockutil is already installed." diff --git a/script/install.d/80-neofetch.sh b/script/install.d/80-fastfetch.sh similarity index 50% rename from script/install.d/80-neofetch.sh rename to script/install.d/80-fastfetch.sh index 131cd5f..c4542dd 100644 --- a/script/install.d/80-neofetch.sh +++ b/script/install.d/80-fastfetch.sh @@ -2,27 +2,27 @@ # ----------------------------------------------------------------------------- # Description: -# Install neofetch. +# Install fastfetch (fast system information tool). # # Skip in Codespaces (cosmetic tool) [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } -if ! command -v neofetch &>/dev/null; then +if ! command -v fastfetch &>/dev/null; then case "$DOTS_PKG" in apt) - sudo apt-get install -qq neofetch &>/dev/null + sudo apt-get install -qq fastfetch &>/dev/null ;; pacman) - yay -S --noconfirm neofetch &>/dev/null + yay -S --noconfirm fastfetch &>/dev/null ;; brew) - brew install neofetch + brew install fastfetch ;; *) - log_warn "Skipping neofetch install: no supported package manager found" + log_warn "Skipping fastfetch install: no supported package manager found" ;; esac fi -echo "$(neofetch --version)" +echo "fastfetch: $(fastfetch --version 2>&1 | head -1)" diff --git a/script/install.d/90-macos.sh b/script/install.d/90-macos.sh index a5226d9..a38f13c 100644 --- a/script/install.d/90-macos.sh +++ b/script/install.d/90-macos.sh @@ -37,8 +37,6 @@ defaults write -globalDomain AppleInterfaceStyle -string "Dark" # #2CB494 -- Highlight color defaults write -globalDomain AppleHighlightColor -string "0.172549 0.705882 0.580392" -killall SystemUIServer 2>/dev/null || true - # Control Center # -------------- # off -- Control Center: Show Bluetooth icon in menu bar @@ -65,8 +63,6 @@ defaults write \ Battery \ -int 24 -killall ControlCenter 2>/dev/null || true - # Finder # ------ # on -- Finder: Add quit option @@ -121,15 +117,11 @@ defaults write com.apple.finder NewWindowTargetPath -string "file://${HOME}/" # list -- Finder: Preferred view style defaults write com.apple.finder FXPreferredViewStyle -string "nlsv" -killall Finder 2>/dev/null || true - # Spotlight # --------- # on -- Spotlight: Hide menu bar icon defaults write com.apple.Spotlight MenuItemHidden -int 1 -killall Spotlight 2>/dev/null || true - # Dock # ---- # off -- Dock: Show recent applications @@ -156,7 +148,7 @@ default_apps=( "Numbers" "Pages" ) -for default_app in default_apps; do +for default_app in "${default_apps[@]}"; do dockutil --remove "$default_app" --no-restart 1>/dev/null 2>&1 || true done @@ -169,20 +161,20 @@ dock_order=( "/System/Applications/Utilities/Activity Monitor.app" "/Applications/iTerm.app" ) -dock_state=$(defaults read com.apple.dock persistent-apps) +dock_state=$(defaults read com.apple.dock persistent-apps 2>/dev/null || echo "") for i in "${!dock_order[@]}"; do if [[ $i -ne 0 ]]; then path="${dock_order[$i]}" name=$(basename "$path" | sed 's/\.app$//') if [[ $dock_state == *"$name"* ]]; then - dockutil --move "${path}" --position "$i" --no-restart + dockutil --move "${path}" --position "$i" --no-restart 2>/dev/null || true else - dockutil --add "${path}" --position "$i" --no-restart + dockutil --add "${path}" --position "$i" --no-restart 2>/dev/null || true fi fi done if [[ ! $dock_state == *"spacer"* ]]; then - dockutil --add '' --type spacer --section apps --position "${#dock_order[@]}" --no-restart + dockutil --add '' --type spacer --section apps --position "${#dock_order[@]}" --no-restart 2>/dev/null || true fi -killall Dock 2>/dev/null || true +log_info "macOS settings configured. Restart Finder/Dock to apply: osascript -e 'quit app \"Finder\"'" diff --git a/script/install.d/98-clean.sh b/script/install.d/98-clean.sh deleted file mode 100644 index 141f4bb..0000000 --- a/script/install.d/98-clean.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -# ----------------------------------------------------------------------------- -# Description: -# Clean up after installation. -# - -# Skip in Codespaces (minimal benefit in ephemeral environment) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } - -case "$DOTS_PKG" in - brew) - brew cleanup - ;; - apt) - sudo apt-get autoremove -qq - sudo apt-get clean -qq - ;; - pacman) - # Remove orphans if any (ignore error if none) - if pacman -Qtdq >/dev/null 2>&1; then - sudo pacman -Rns --noconfirm $(pacman -Qtdq) || true - fi - # Clear package cache without interactive prompt - yes | sudo pacman -Scc >/dev/null 2>&1 || true - ;; - *) - log_warn "Skipping cleanup: no supported package manager found" - return 0 - ;; -esac - -log_pass "Cleanup completed successfully!" diff --git a/script/install.d/99-screenfetch.sh b/script/install.d/99-fastfetch.sh similarity index 77% rename from script/install.d/99-screenfetch.sh rename to script/install.d/99-fastfetch.sh index a3bef8c..bb9a12a 100644 --- a/script/install.d/99-screenfetch.sh +++ b/script/install.d/99-fastfetch.sh @@ -2,10 +2,10 @@ # ----------------------------------------------------------------------------- # Description: -# Print system information. +# Display system information with fastfetch. # # Skip in Codespaces (cosmetic only) [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } -neofetch +fastfetch --pipe false diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 50f4319..2c9645d 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -46,18 +46,21 @@ binaries: List[Text] = [ # tools "git", "gh", + "copilot", "terraform", "docker" if not os.environ.get("SKIP_DOCKER_CONFIG") else None, + "mise", "neofetch", + "cmatrix", + "az", + "firebase", "redis-cli", "redis-server", # language: python - "pyenv", "python", "python3", "pip", "pip3", - "pipx", "poetry", # langauge: js "node",