Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 169 additions & 14 deletions .config/dotfiles/playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@
# Update tools: uvx --from ansible-core ansible-playbook playbook.yml
# Check mode: uvx --from ansible-core ansible-playbook playbook.yml --check
# Dev tools: uvx --from ansible-core ansible-playbook playbook.yml --extra-vars "dev_mode=true"
# Force server mode: uvx --from ansible-core ansible-playbook playbook.yml --extra-vars "is_desktop=false"
# Specific category: uvx --from ansible-core ansible-playbook playbook.yml --tags homebrew
#
# Variables:
# dev_mode: Install additional development tools (default: false)
# is_desktop: Install desktop apps vs CLI-only tools (auto-detected, override with true/false)
#
# Desktop detection:
# - macOS: Always treated as desktop
# - Linux: Checks systemd default target (graphical.target = desktop)
# - Override with --extra-vars "is_desktop=true" or "is_desktop=false"

- name: Manage development environment
hosts: localhost
Expand All @@ -17,6 +27,26 @@
vars:
dev_mode: false
force: false
# Desktop detection: macOS is always desktop, Linux checks systemd target
# Override with --extra-vars "is_desktop=true" or "is_desktop=false"
_linux_desktop: "{{ ansible_service_mgr == 'systemd' and (ansible_facts['default_target'] | default('multi-user.target')) == 'graphical.target' }}"
is_desktop: "{{ is_desktop | default(true if ansible_os_family == 'Darwin' else _linux_desktop) }}"

pre_tasks:
- name: Gather systemd default target (Linux only)
command: systemctl get-default
register: systemd_target
changed_when: false
failed_when: false
when: ansible_system == "Linux" and ansible_service_mgr == "systemd"

- name: Set desktop fact from systemd target
set_fact:
is_desktop: "{{ is_desktop | default(true if ansible_os_family == 'Darwin' else (systemd_target.stdout | default('multi-user.target')) == 'graphical.target') }}"

- name: Display system type
debug:
msg: "System type: {{ 'Desktop' if is_desktop else 'Server' }} ({{ ansible_os_family }})"

tasks:
# ========================================
Expand Down Expand Up @@ -44,28 +74,56 @@
register: brew_update
changed_when: "'Already up-to-date' not in brew_update.stdout"

- name: Install/upgrade essential Homebrew packages
# Essential CLI tools - installed on all macOS systems
- name: Install/upgrade essential Homebrew formulae
shell: brew install {{ item }} || brew upgrade {{ item }} || true
loop:
- fzf
- bat
- eza
- fd
- ripgrep
- mise
- fzf
- jq
- bat
- mise
- ripgrep
- starship
- atuin
- zsh-autosuggestions
- zsh-syntax-highlighting
register: brew_install
changed_when: "'Upgrading' in brew_install.stdout or 'Installing' in brew_install.stdout"

- name: Install/upgrade dev Homebrew packages
# Dev tools - only in dev mode
- name: Install/upgrade dev Homebrew formulae
shell: brew install {{ item }} || brew upgrade {{ item }} || true
loop:
- bat-extras
- gh
- yq
- bat-extras
register: brew_dev_install
changed_when: "'Upgrading' in brew_dev_install.stdout or 'Installing' in brew_dev_install.stdout"
when: dev_mode | bool

# 1Password CLI - requires special tap
- name: Tap 1Password CLI
shell: brew tap 1password/tap
changed_when: false
failed_when: false

- name: Install 1Password CLI
shell: brew install 1password-cli || brew upgrade 1password-cli || true
register: op_install
changed_when: "'Upgrading' in op_install.stdout or 'Installing' in op_install.stdout"

# Desktop-only casks
- name: Install desktop Homebrew casks
shell: brew install --cask {{ item }} || brew upgrade --cask {{ item }} || true
loop:
- visual-studio-code
- 1password
register: brew_cask_install
changed_when: "'Upgrading' in brew_cask_install.stdout or 'Installing' in brew_cask_install.stdout"
when: is_desktop | bool

- name: Clean up Homebrew
shell: brew cleanup
register: brew_cleanup
Expand All @@ -90,29 +148,83 @@
become: yes
register: apt_upgrade

# Essential CLI tools for all Linux systems
- name: Install essential apt packages
apt:
name:
- fzf
- fd-find
- fzf
- jq
- ripgrep
- zsh-autosuggestions
- zsh-syntax-highlighting
state: latest
become: yes

# Dev tools - only in dev mode
- name: Install dev apt packages
apt:
name:
- jq
- gh
state: latest
become: yes
when: dev_mode | bool

# Desktop-only packages
- name: Install desktop apt packages
apt:
name:
- code
state: latest
become: yes
when: is_desktop | bool
failed_when: false

# ========================================
# 1PASSWORD CLI (Linux)
# ========================================
- name: Install 1Password CLI on Linux
tags: [setup, tools]
when: ansible_pkg_mgr == "apt"
block:
- name: Check if 1Password CLI is installed
command: which op
register: op_check
changed_when: false
failed_when: false

- name: Add 1Password apt repository key
shell: |
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg
args:
creates: /usr/share/keyrings/1password-archive-keyring.gpg
become: yes
when: op_check.rc != 0

- name: Add 1Password apt repository
shell: |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | \
tee /etc/apt/sources.list.d/1password.list
args:
creates: /etc/apt/sources.list.d/1password.list
become: yes
when: op_check.rc != 0

- name: Install 1Password CLI via apt
apt:
name: 1password-cli
state: latest
update_cache: yes
become: yes

# ========================================
# MISE
# ========================================
- name: Install and update mise
# On macOS, mise is installed via Homebrew. On Linux, use the installer script.
- name: Install mise (Linux only)
tags: [mise, setup]
when: ansible_os_family != "Darwin"
block:
- name: Check if mise is installed
stat:
Expand Down Expand Up @@ -177,8 +289,10 @@
changed_when: "'Updating' in cargo_updates.stdout"
failed_when: false

- name: Install essential Rust tools
# On Linux, install eza and bat via cargo (on macOS these come from Homebrew)
- name: Install essential Rust tools (Linux only)
tags: [setup, rust]
when: ansible_os_family != "Darwin"
shell: "{{ ansible_env.HOME }}/.cargo/bin/cargo install {{ item }}"
args:
creates: "{{ ansible_env.HOME }}/.cargo/bin/{{ item }}"
Expand All @@ -188,8 +302,9 @@

- name: Build bat cache
tags: [setup, rust]
shell: "{{ ansible_env.HOME }}/.cargo/bin/bat cache --build"
shell: bat cache --build
changed_when: false
failed_when: false

- name: Install Rust dev tools
tags: [setup, rust, dev]
Expand Down Expand Up @@ -289,8 +404,10 @@
creates: "{{ ansible_env.HOME }}/.local/bin/claude"
when: not claude_check.stat.exists

- name: Install Starship prompt
# On macOS, starship is installed via Homebrew. On Linux, use the installer script.
- name: Install Starship prompt (Linux only)
tags: [setup, tools]
when: ansible_os_family != "Darwin"
block:
- name: Check if Starship is installed
stat:
Expand All @@ -303,8 +420,10 @@
creates: "{{ ansible_env.HOME }}/.local/bin/starship"
when: not starship_check.stat.exists

- name: Install/update Atuin
# On macOS, atuin is installed via Homebrew. On Linux, use the installer script.
- name: Install/update Atuin (Linux only)
tags: [setup, tools]
when: ansible_os_family != "Darwin"
block:
- name: Check if Atuin is installed
command: which atuin
Expand All @@ -323,6 +442,42 @@
changed_when: "'Updated' in atuin_update.stdout or 'updated' in atuin_update.stdout"
failed_when: false

# pnpm - installed via corepack (comes with Node.js via mise)
- name: Enable pnpm via corepack
tags: [setup, tools]
block:
- name: Check if corepack is available
command: which corepack
register: corepack_check
changed_when: false
failed_when: false

- name: Enable pnpm via corepack
shell: corepack enable pnpm
when: corepack_check.rc == 0
changed_when: false
failed_when: false

# VS Code CLI for server environments (desktop gets full VS Code via package manager)
- name: Install VS Code CLI (server only)
tags: [setup, tools]
when: not is_desktop | bool
block:
- name: Check if code CLI is installed
command: which code
register: code_cli_check
changed_when: false
failed_when: false

- name: Download and install VS Code CLI
shell: |
curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-x64' -o /tmp/vscode_cli.tar.gz
tar -xf /tmp/vscode_cli.tar.gz -C {{ ansible_env.HOME }}/.local/bin
rm /tmp/vscode_cli.tar.gz
args:
creates: "{{ ansible_env.HOME }}/.local/bin/code"
when: code_cli_check.rc != 0

- name: Setup tmux plugin manager
tags: [setup, tools]
block:
Expand Down
8 changes: 6 additions & 2 deletions .config/zsh/tools.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ ZSH_AUTO_SCRIPT="zsh-autosuggestions/zsh-autosuggestions.zsh"
[[ -e /usr/share/$ZSH_AUTO_SCRIPT ]] && source /usr/share/$ZSH_AUTO_SCRIPT

# Zsh syntax highlighting
[[ -d "$BREW_PREFIX/share/zsh-syntax-highlighting" ]] && {
source "$BREW_PREFIX/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
ZSH_HL_SCRIPT="zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
ZSH_HL_PATH=""
[[ -e "$BREW_PREFIX/share/$ZSH_HL_SCRIPT" ]] && ZSH_HL_PATH="$BREW_PREFIX/share/$ZSH_HL_SCRIPT"
[[ -z "$ZSH_HL_PATH" && -e "/usr/share/$ZSH_HL_SCRIPT" ]] && ZSH_HL_PATH="/usr/share/$ZSH_HL_SCRIPT"
[[ -n "$ZSH_HL_PATH" ]] && {
source "$ZSH_HL_PATH"
# Disable underline
(( ${+ZSH_HIGHLIGHT_STYLES} )) || typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[path]=none
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,18 @@ tool-update --tags mise

# Include dev tools in update
tool-update --dev

# Force server mode (CLI-only tools, no desktop apps)
tool-update --extra-vars "is_desktop=false"
```

**Desktop vs Server Detection:**
- macOS is always treated as a desktop system
- Linux auto-detects based on systemd target (`graphical.target` = desktop)
- Desktop systems get full GUI apps (VS Code, 1Password app)
- Server systems get CLI-only tools (VS Code CLI, 1Password CLI)
- Override with `--extra-vars "is_desktop=true"` or `"is_desktop=false"`

To add new tools, edit `.config/dotfiles/playbook.yml`. To change runtime versions (node, python, etc.), edit `.mise.toml`.

### Shell Script Linting
Expand Down
12 changes: 11 additions & 1 deletion bin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@ This directory contains personal utility scripts that are part of my dotfiles se

- `--check`: Show what would be updated (dry-run)
- `--diff`: Show changes that would be made
- `--tags <tag>`: Update only specific tools (e.g., `homebrew`, `mise`)
- `--tags <tag>`: Update only specific tools (e.g., `homebrew`, `mise`, `rust`, `uv`)
- `--dev`: Include dev tools in updates
- `--no-sudo`: Skip sudo password prompt (for passwordless sudo)
- `--extra-vars "key=value"`: Pass variables to Ansible (e.g., `is_desktop=false`)
- `-v`: Verbose output

**Desktop vs Server Mode:**

The playbook auto-detects desktop vs server environments:
- macOS: Always treated as desktop
- Linux: Detects via systemd target (`graphical.target` = desktop)

Desktop systems install full GUI apps (VS Code, 1Password). Server systems install CLI-only versions. Override with `--extra-vars "is_desktop=false"`.

**Description:** Wrapper around Ansible playbook for convenient daily/weekly tool updates.

## File and System Utilities
Expand Down
Loading