-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathjustfile
More file actions
410 lines (328 loc) · 14.3 KB
/
Copy pathjustfile
File metadata and controls
410 lines (328 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# Dotfiles — https://github.com/snics/dotfiles
# Usage: just <target>
# List all targets: just --list
set shell := ["bash", "-cu"]
DOTFILES := env_var("HOME") / ".dotfiles"
# Stow package lists (CLI = universal, GUI = macOS only)
CLI_PACKAGES := "zsh git nvim tmux lazygit k9s herdr opencode claude"
GUI_PACKAGES := "ghostty zed cursor obsidian"
ALL_PACKAGES := CLI_PACKAGES + " " + GUI_PACKAGES
# ── Full Setup ──────────────────────────────────────────
# Full setup: brew + link + macos (macOS settings skipped on Linux)
all: install link
@if [[ "$(uname -s)" == "Darwin" && "${CI:-}" != "true" ]]; then \
echo "==> Applying macOS settings..."; \
source {{ DOTFILES }}/_macOS/settings.sh; \
source {{ DOTFILES }}/_macOS/dock.sh; \
elif [[ "$(uname -s)" != "Darwin" ]]; then \
echo "==> Skipping macOS settings (not macOS)"; \
else \
echo "==> Skipping macOS settings (CI mode)"; \
fi
@echo "Done! Open a new shell to apply changes."
# ── Install ─────────────────────────────────────────────
# Install Homebrew and all packages from Brewfile
install:
@echo "==> Installing Homebrew packages..."
@if ! command -v brew &>/dev/null; then \
/bin/bash -c "$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; \
if [[ -f "/opt/homebrew/bin/brew" ]]; then \
eval "$$(/opt/homebrew/bin/brew shellenv)"; \
elif [[ -f "/home/linuxbrew/.linuxbrew/bin/brew" ]]; then \
eval "$$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"; \
fi; \
fi
cat {{ DOTFILES }}/brew/Brewfile.* | brew bundle --file=-
# ── Link / Unlink ──────────────────────────────────────
# Symlink all stow packages (CLI on all platforms, GUI on macOS only)
link: link-cli link-gui
# Symlink CLI packages (universal — works on macOS, Linux, containers)
link-cli:
@echo "==> Linking CLI dotfiles..."
@cd {{ DOTFILES }} && stow --restow -t "$HOME" {{ CLI_PACKAGES }}
# Symlink GUI packages (macOS only — no-op on Linux)
link-gui:
@if [[ "$(uname -s)" == "Darwin" ]]; then \
echo "==> Linking GUI dotfiles..."; \
cd {{ DOTFILES }} && stow --restow -t "$HOME" {{ GUI_PACKAGES }}; \
else \
echo "==> Skipping GUI dotfiles (not macOS)"; \
fi
# Remove all symlinks
unlink:
@echo "==> Unlinking dotfiles..."
@cd {{ DOTFILES }} && stow --delete -t "$HOME" {{ ALL_PACKAGES }}
# Re-link all packages (alias for link)
relink: link
# ── Per-Package ─────────────────────────────────────────
# Link zsh config
zsh:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" zsh
# Link git config
git:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" git
# Link nvim config
nvim:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" nvim
# Link ghostty config
ghostty:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" ghostty
# Link tmux config
tmux:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" tmux
# Link lazygit config
lazygit:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" lazygit
# Link k9s config
k9s:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" k9s
# Link herdr config
herdr:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" herdr
# Link zed config
zed:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" zed
# Link opencode config
opencode:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" opencode
# Link claude config
claude:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" claude
# Sync live ~/.claude/settings.json back into the repo (Claude rewrites it in place, breaking the symlink)
claude-sync:
@cp "$HOME/.claude/settings.json" {{ DOTFILES }}/claude/.claude/settings.json
@echo "Synced ~/.claude/settings.json → repo. Review the diff and commit."
# Link cursor config
cursor:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" cursor
# Link obsidian config
obsidian:
@cd {{ DOTFILES }} && stow --restow -t "$HOME" obsidian
# ── Updates ─────────────────────────────────────────────
# Update Homebrew packages
update:
brew update
brew upgrade
brew cleanup
# ── Brew Lifecycle ──────────────────────────────────────
# Regenerate ~/.Brewfile from split sources
brew-gen:
cat {{ DOTFILES }}/brew/Brewfile.* > ~/.Brewfile
@echo "Generated ~/.Brewfile from $(ls -1 {{ DOTFILES }}/brew/Brewfile.* | wc -l | tr -d ' ') sources"
# Homebrew 6.0+ refuses to load formulae from untrusted taps, so taps must be
# added (brew-tap) and trusted (brew-trust) BEFORE bundling. just runs these
# dependencies in order before the recipe body.
#
# Install all packages from split Brewfiles
brew-install: brew-gen brew-tap brew-trust
brew bundle --file=~/.Brewfile
# Tap all repositories declared in Brewfile.00-taps (prerequisite for trusting)
brew-tap:
grep -hoE '^tap "[^"]+"' {{ DOTFILES }}/brew/Brewfile.00-taps | sed -E 's/tap "([^"]+)"/\1/' | xargs -L1 brew tap
@echo "Tapped all repositories from Brewfile.00-taps"
# Trust all non-official taps (Homebrew 6.0+ tap-trust requirement)
brew-trust:
brew tap | grep -vE '^homebrew/' | xargs brew trust --tap
@echo "Trusted all non-homebrew taps"
# List all packages from split Brewfiles
brew-list:
cat {{ DOTFILES }}/brew/Brewfile.* | brew bundle list --file=-
# Check which packages are not installed
brew-check: brew-gen
brew bundle check --file=~/.Brewfile
# Remove packages not in Brewfile (dry-run first)
brew-cleanup: brew-gen
brew bundle cleanup --file=~/.Brewfile
# Force-remove packages not in Brewfile
brew-cleanup-force: brew-gen
brew bundle cleanup --force --file=~/.Brewfile
# Dump currently installed packages to a temp file for comparison
brew-dump:
brew bundle dump --describe --file={{ DOTFILES }}/brew/Brewfile.dump --force
@echo "Dumped to brew/Brewfile.dump — compare with Brewfile.* sources"
# Edit split Brewfiles (opens directory)
brew-edit:
@echo "Split Brewfiles in {{ DOTFILES }}/brew/"
@ls -1 {{ DOTFILES }}/brew/Brewfile.*
@echo ""
@echo "Edit with: \$$EDITOR {{ DOTFILES }}/brew/Brewfile.<category>"
# ── macOS ───────────────────────────────────────────────
# Apply macOS system settings and dock
[macos]
macos:
@if [[ "$${CI:-}" != "true" ]]; then \
echo "==> Applying macOS settings..."; \
source {{ DOTFILES }}/_macOS/settings.sh; \
source {{ DOTFILES }}/_macOS/dock.sh; \
else \
echo "==> Skipping macOS settings (CI mode)"; \
fi
# Configure dock apps
[macos]
dock:
source {{ DOTFILES }}/_macOS/dock.sh
# Create development project folder structure
[macos]
project-folders:
source {{ DOTFILES }}/_macOS/project-folder-structure.sh
# ── Optional Dev Tools ──────────────────────────────────
# Install Go via g version manager
golang:
source {{ DOTFILES }}/_install/golang.sh
# Install Rust via rustup
rust:
source {{ DOTFILES }}/_install/rust.sh
# Install asdf plugins
asdf:
source {{ DOTFILES }}/asdf/plugins.sh
# Install herdr plugins & agent integrations
herdr-plugins:
source {{ DOTFILES }}/_install/herdr-plugins.sh
# ── Validation ──────────────────────────────────────────
# Check installed tools and symlinks
check:
#!/usr/bin/env bash
set -euo pipefail
echo "==> Checking stow symlinks..."
errors=0
for pkg in {{ ALL_PACKAGES }}; do
if cd {{ DOTFILES }} && stow --simulate --restow -t "$HOME" "$pkg" 2>&1 | grep -q "ERROR"; then
echo " FAIL: $pkg"
errors=$((errors + 1))
else
echo " OK: $pkg"
fi
done
echo ""
echo "==> Checking key tools..."
for tool in brew stow nvim git tmux zsh starship fzf bat eza rg fd lazygit k9s kubectl helm op just; do
if command -v "$tool" &>/dev/null; then
echo " OK: $tool"
else
echo " MISSING: $tool"
errors=$((errors + 1))
fi
done
if [[ $errors -gt 0 ]]; then
echo ""
echo "$errors issue(s) found."
exit 1
else
echo ""
echo "All checks passed."
fi
# ── Docker ──────────────────────────────────────────────
# Build all Docker images (local arch)
docker-build: docker-build-nvim docker-build-devenv docker-build-web-terminal docker-build-web-desktop
# Build snic/nvim image
docker-build-nvim:
docker build -f _images/nvim/Dockerfile -t snic/nvim:latest .
# Build snic/devenv image
docker-build-devenv:
docker build -f _images/devenv/Dockerfile -t snic/devenv:latest .
# Build snic/devenv-web-terminal image
docker-build-web-terminal:
docker build -t snic/devenv-web-terminal:latest _images/devenv-web-terminal
# Build snic/devenv-web-desktop image
docker-build-web-desktop:
docker build -t snic/devenv-web-desktop:latest _images/devenv-web-desktop
# Smoke test all Docker images
docker-test:
#!/usr/bin/env bash
set -euo pipefail
echo "==> Testing snic/nvim..."
docker run --rm snic/nvim:latest --version | head -1
docker run --rm snic/nvim:latest --headless -c 'lua print("Plugins: " .. #require("lazy").plugins())' +qa 2>&1
echo ""
echo "==> Testing snic/devenv..."
docker run --rm snic/devenv:latest -c 'starship --version | head -1 && lazygit --version | head -1 && delta --version && tmux -V && nvim --version | head -1'
echo ""
echo "==> Testing snic/devenv-web-terminal..."
docker run --rm --entrypoint ttyd snic/devenv-web-terminal:latest --version
echo ""
echo "==> Testing snic/devenv-web-desktop..."
docker run --rm --entrypoint /opt/selkies/bin/selkies snic/devenv-web-desktop:latest --help 2>&1 | head -1
docker run --rm --entrypoint supervisord snic/devenv-web-desktop:latest --version
echo ""
echo "All Docker tests passed."
# Run interactive devenv with current directory mounted
docker-run:
docker run -it --rm -v "$(pwd):/home/developer/workspace" snic/devenv:latest
# Start devenv-web-terminal on port 7681 (default: terminal)
docker-run-web-terminal:
docker run -it --rm -p 7681:7681 -v "$(pwd):/home/developer/workspace" snic/devenv-web-terminal:latest
# Start devenv-web-terminal with tmux
docker-run-web-terminal-tmux:
docker run -it --rm -p 7681:7681 -v "$(pwd):/home/developer/workspace" -e TTYD_MODE=tmux snic/devenv-web-terminal:latest
# Start devenv-web-terminal with NeoVim
docker-run-web-terminal-nvim:
docker run -it --rm -p 7681:7681 -v "$(pwd):/home/developer/workspace" -e TTYD_MODE=nvim snic/devenv-web-terminal:latest
# Start devenv-web-desktop on port 3000
docker-run-web-desktop:
docker run --rm -p 3000:3000 --shm-size=256m snic/devenv-web-desktop:latest
# Multi-arch build + push to Docker Hub
docker-push:
docker buildx build --platform linux/amd64,linux/arm64 -f _images/nvim/Dockerfile -t snic/nvim:latest --push .
docker buildx build --platform linux/amd64,linux/arm64 -f _images/devenv/Dockerfile -t snic/devenv:latest --push .
docker buildx build --platform linux/amd64,linux/arm64 -t snic/devenv-web-terminal:latest --push _images/devenv-web-terminal
docker buildx build --platform linux/amd64,linux/arm64 -t snic/devenv-web-desktop:latest --push _images/devenv-web-desktop
# Lint Dockerfiles with hadolint
docker-lint:
hadolint _images/nvim/Dockerfile _images/devenv/Dockerfile _images/devenv-web-terminal/Dockerfile _images/devenv-web-desktop/Dockerfile
# Analyze Docker image layers with dive
docker-dive image="snic/nvim:latest":
dive {{ image }}
# CI-mode dive analysis (fails on inefficiency thresholds)
docker-dive-ci:
CI=true dive snic/nvim:latest
CI=true dive snic/devenv:latest
CI=true dive snic/devenv-web-terminal:latest
CI=true dive snic/devenv-web-desktop:latest
# ── Validation ──────────────────────────────────────────
# Lint shell scripts
lint:
shellcheck _install/*.sh _macOS/*.sh _lib/*.sh _test/*.sh bootstrap.sh install.sh
# Validate stow symlinks (dry-run)
test-symlinks:
@bash _test/validate-symlinks.sh
# Validate JSON and TOML config syntax
test-configs:
@bash _test/validate-configs.sh
# Run all validation checks
test: lint test-symlinks test-configs
@echo "All tests passed."
# ── VM Testing ──────────────────────────────────────────
# Test dotfiles in a macOS VM (Tart, ~5-10 min, Apple Silicon only)
[macos]
test-macos *ARGS:
@bash _test/vm-test-macos.sh {{ ARGS }}
# Test dotfiles in a macOS VM (interactive — keeps VM open for inspection)
[macos]
test-macos-gui:
@bash _test/vm-test-macos.sh --interactive
# Test dotfiles in a Linux VM (Lima, ~3-5 min)
test-linux *ARGS:
@bash _test/vm-test-linux.sh {{ ARGS }}
# Test dotfiles in a Linux VM (interactive)
test-linux-gui:
@bash _test/vm-test-linux.sh --interactive
# Clean up all test VMs and cached images
vm-clean:
#!/usr/bin/env bash
echo "==> Cleaning Tart VMs..."
for vm in $(tart list 2>/dev/null | awk '/test-dotfiles/{print $2}'); do
tart stop "$vm" 2>/dev/null || true
tart delete "$vm" 2>/dev/null || true
done
echo "==> Pruning Tart OCI cache..."
tart prune --older-than 0 2>/dev/null || true
echo "==> Cleaning Lima VMs..."
for vm in $(limactl list 2>/dev/null | awk '/test-dotfiles/{print $1}'); do
limactl stop "$vm" 2>/dev/null || true
limactl delete -f "$vm" 2>/dev/null || true
done
echo "==> Done."
# ── Help ───────────────────────────────────────────────
# Show available recipes
help:
@just --list