-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
258 lines (234 loc) · 9.67 KB
/
Copy pathMakefile
File metadata and controls
258 lines (234 loc) · 9.67 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
.PHONY: help install stow unstow restow test validate fish plugins update lint docs path-audit clean
# 默认目标
.DEFAULT_GOAL := help
# 颜色定义
BLUE := \033[36m
GREEN := \033[32m
YELLOW := \033[33m
RED := \033[31m
NC := \033[0m # No Color
# 配置
DOTFILES_DIR := $(shell pwd)
HOME_DIR := $(HOME)
BIN_DIR := $(HOME)/.local/bin
# 标准包(通过 --dotfiles 选项处理)
STOW_PACKAGES := ghostty helix zellij mise git karabiner bat btop aichat
# Fish 需要特殊处理
FISH_PACKAGE := fish
# Bin 目录特殊目标
BIN_PACKAGE := bin
help: ## 显示帮助信息
@echo "$(BLUE)Dotfiles 管理工具$(NC)"
@echo ""
@echo "$(GREEN)安装:$(NC)"
@echo " $(YELLOW)make install$(NC) 运行安装脚本"
@echo ""
@echo "$(GREEN)同步配置:$(NC)"
@echo " $(YELLOW)make stow$(NC) 创建所有软链接(安装配置)"
@echo " $(YELLOW)make unstow$(NC) 删除所有软链接(卸载配置)"
@echo " $(YELLOW)make restow$(NC) 重新创建软链接(更新配置)"
@echo ""
@echo "$(GREEN)单独操作:$(NC)"
@echo " $(YELLOW)make stow-fish$(NC) 仅同步 Fish 配置"
@echo " $(YELLOW)make stow-bin$(NC) 仅同步 bin 脚本"
@echo " $(YELLOW)make stow-<pkg>$(NC) 同步指定包 (如: make stow-ghostty)"
@echo ""
@echo "$(GREEN)Fish Shell:$(NC)"
@echo " $(YELLOW)make fish$(NC) 设置 Fish 为默认 Shell"
@echo " $(YELLOW)make plugins$(NC) 安装/更新 Fisher 插件"
@echo ""
@echo "$(GREEN)macOS:$(NC)"
@echo " $(YELLOW)make macos$(NC) 配置 macOS 系统偏好设置"
@echo ""
@echo "$(GREEN)维护:$(NC)"
@echo " $(YELLOW)make clean$(NC) 清理 Fish 写入中断的临时残留与 OS 临时文件"
@echo " $(YELLOW)make path-audit$(NC) 审计 zsh -> fish 的 PATH 迁移覆盖率"
@echo " $(YELLOW)make test$(NC) 运行 lint + validate"
@echo " $(YELLOW)make validate$(NC) 验证所有配置文件语法"
@echo " $(YELLOW)make lint$(NC) 运行 shellcheck + Fish 静态检查 + Bash 基线检查"
@echo " $(YELLOW)make docs$(NC) 生成或更新 README 的目录 (TOC)"
@echo " $(YELLOW)make update$(NC) 更新 dotfiles 仓库与所有工具链"
@echo ""
install: ## 运行安装脚本
@echo "$(BLUE)🚀 运行安装脚本...$(NC)"
@./install.sh
stow: stow-packages stow-fish stow-bin ## 创建所有软链接
@echo "$(GREEN)✅ 所有配置已同步$(NC)"
# 忽略常见系统文件
STOW_IGNORE := --ignore='\.DS_Store' --ignore='Thumbs\.db' --ignore='.*\.swp'
stow-packages: ## 同步标准包配置
@echo "$(BLUE)📦 同步标准包配置...$(NC)"
@for pkg in $(STOW_PACKAGES); do \
if [ -d "$$pkg" ]; then \
echo " 同步 $$pkg..."; \
stow --restow --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) --dotfiles $$pkg; \
fi \
done
@echo "$(GREEN) ✅ 标准包同步完成$(NC)"
stow-fish: ## 同步 Fish 配置
@echo "$(BLUE)🐟 同步 Fish 配置...$(NC)"
@stow --restow --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) --dotfiles $(FISH_PACKAGE)
@echo "$(GREEN) ✅ Fish 配置同步完成$(NC)"
stow-bin: ## 同步 bin 脚本
@echo "$(BLUE)🔧 同步 bin 脚本...$(NC)"
@mkdir -p $(BIN_DIR)
@stow --restow --target=$(BIN_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) $(BIN_PACKAGE)
@echo "$(GREEN) ✅ bin 脚本同步完成$(NC)"
@echo " $(YELLOW)提示:$(NC) 确保 $(BIN_DIR) 在 PATH 中"
# 动态生成单独包的 stow 目标
$(foreach pkg,$(STOW_PACKAGES),stow-$(pkg)): ## 同步指定包
@pkg=$(subst stow-,,$@); \
if [ -d "$$pkg" ]; then \
echo "$(BLUE)📦 同步 $$pkg...$(NC)"; \
stow --restow --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) --dotfiles $$pkg; \
echo "$(GREEN) ✅ $$pkg 同步完成$(NC)"; \
else \
echo "$(RED) ❌ 包 $$pkg 不存在$(NC)"; \
exit 1; \
fi
unstow: ## 删除所有软链接
@echo "$(BLUE)🗑️ 删除所有软链接...$(NC)"
@for pkg in $(STOW_PACKAGES) $(FISH_PACKAGE); do \
if [ -d "$$pkg" ]; then \
echo " 删除 $$pkg..."; \
stow --delete --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) --dotfiles $$pkg 2>/dev/null || true; \
fi \
done
@echo " 删除 bin..."
@stow --delete --target=$(BIN_DIR) --dir=$(DOTFILES_DIR) $(BIN_PACKAGE) 2>/dev/null || true
@echo "$(GREEN)✅ 所有软链接已删除$(NC)"
restow: ## 重新创建所有软链接
@echo "$(BLUE)🔄 重新创建软链接...$(NC)"
@for pkg in $(STOW_PACKAGES); do \
if [ -d "$$pkg" ]; then \
echo " restow $$pkg..."; \
stow --restow --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) --dotfiles $$pkg; \
fi \
done
@echo " restow $(FISH_PACKAGE)..."
@stow --restow --target=$(HOME_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) --dotfiles $(FISH_PACKAGE)
@echo " restow $(BIN_PACKAGE)..."
@mkdir -p $(BIN_DIR)
@stow --restow --target=$(BIN_DIR) --dir=$(DOTFILES_DIR) $(STOW_IGNORE) $(BIN_PACKAGE)
@echo "$(GREEN)✅ 所有配置已更新$(NC)"
fish: ## 设置 Fish 为默认 Shell
@echo "$(BLUE)🐟 设置 Fish 为默认 Shell...$(NC)"
@if ! command -v fish > /dev/null 2>&1; then \
echo "$(RED) ❌ Fish 未安装$(NC)"; \
exit 1; \
fi
@fish_path=$$(which fish); \
if ! grep -q "$$fish_path" /etc/shells; then \
echo " 添加 Fish 到 /etc/shells..."; \
echo "$$fish_path" | sudo tee -a /etc/shells > /dev/null; \
fi; \
chsh -s "$$fish_path"
@echo "$(GREEN)✅ Fish 已设置为默认 Shell$(NC)"
@echo " $(YELLOW)提示:$(NC) 重新登录后生效"
macos: ## 配置 macOS 系统偏好设置
@echo "$(BLUE)🍎 配置 macOS 系统偏好设置...$(NC)"
@./macos.sh
plugins: ## 安装/更新 Fisher 插件
@echo "$(BLUE)🔌 安装/更新 Fisher 插件...$(NC)"
@if ! command -v fish > /dev/null 2>&1; then \
echo "$(RED) ❌ Fish 未安装$(NC)"; \
exit 1; \
fi
@echo " 清理残留插件缓存..."
@rm -rf $(HOME)/.local/share/fisher
@echo " 安装 Fisher..."
@tmp=$$(mktemp); \
if ! curl -fsSL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish -o "$$tmp"; then \
rm -f "$$tmp"; \
echo "$(RED) ❌ Fisher 下载失败$(NC)"; \
exit 1; \
fi; \
if ! fish -c "source '$$tmp' && fisher install jorgebucaran/fisher"; then \
rm -f "$$tmp"; \
echo "$(RED) ❌ Fisher 安装失败$(NC)"; \
exit 1; \
fi; \
rm -f "$$tmp"
@if [ -f fish/dot-config/fish/fish_plugins ]; then \
fish -c "set -l plugins (string trim < fish/dot-config/fish/fish_plugins | string match -rv '^(#|$$)'); test (count \$$plugins) -gt 0; and fisher install \$$plugins"; \
fi
@echo "$(GREEN)✅ Fisher 插件已更新$(NC)"
test: lint validate ## 运行仓库级验证
path-audit: ## 审计 zsh -> fish 的 PATH 迁移覆盖率
@./bin/path-audit
validate: ## 验证所有配置文件语法
@echo "$(BLUE)🔍 运行工具验证...$(NC)"
@./bin/validate-configs all 2>&1 || exit 1
@echo "$(GREEN)✅ 所有配置文件验证通过$(NC)"
lint: ## 静态分析 Shell/Fish 脚本并检查 Bash 基线
@echo "$(BLUE)🔍 运行 shellcheck 静态分析...$(NC)"
@if ! command -v shellcheck > /dev/null 2>&1; then \
echo "$(RED) ❌ shellcheck 未安装,请运行 'mise install shellcheck'$(NC)"; \
exit 1; \
fi
@errors=0; \
for script in bootstrap.sh install.sh macos.sh bin/*; do \
if [ -f "$$script" ]; then \
if file "$$script" | grep -q "shell script" || head -1 "$$script" | grep -Eq '^#!.*(bash|sh)'; then \
if shellcheck -S warning "$$script" 2>/dev/null; then \
echo "$(GREEN) ✓$(NC) $$script"; \
else \
errors=$$((errors + 1)); \
fi; \
fi; \
fi; \
done; \
if [ "$$errors" -eq 0 ]; then \
echo "$(GREEN)✅ 所有脚本通过 shellcheck 检查$(NC)"; \
else \
echo "$(RED)❌ $$errors 个脚本存在问题$(NC)"; \
exit 1; \
fi
@./bin/check-shell-baseline
@echo "$(BLUE)🐟 运行 Fish 静态检查 (fish --no-execute)...$(NC)"
@if ! command -v fish > /dev/null 2>&1; then \
echo "$(YELLOW) ⚠ fish 未安装,跳过 Fish 静态检查$(NC)"; \
else \
fish_errors=0; \
fish_files=$$(find fish/dot-config/fish -type f -name '*.fish' | sort); \
for script in $$fish_files; do \
if fish --no-execute "$$script" 2>/dev/null; then \
echo "$(GREEN) ✓$(NC) $$script"; \
else \
fish --no-execute "$$script"; \
fish_errors=$$((fish_errors + 1)); \
fi; \
done; \
if [ "$$fish_errors" -eq 0 ]; then \
echo "$(GREEN)✅ 所有 Fish 脚本通过 --no-execute 语法检查$(NC)"; \
else \
echo "$(RED)❌ $$fish_errors 个 Fish 脚本存在语法问题$(NC)"; \
exit 1; \
fi; \
fi
clean: ## 清理 Fish 写入中断的临时残留与 OS 临时文件
@echo "$(BLUE)🧹 清理工作树临时残留...$(NC)"
@removed=0; \
fish_residue=$$(find fish/dot-config/fish -maxdepth 1 -type f -name 'fish_variables[A-Za-z0-9]*' ! -name 'fish_variables' 2>/dev/null); \
ds_files=$$(find . -name '.DS_Store' -not -path './.git/*' 2>/dev/null); \
for f in $$fish_residue $$ds_files; do \
echo " 删除 $$f"; \
rm -f "$$f"; \
removed=$$((removed + 1)); \
done; \
echo "$(GREEN)✅ 清理完成 (共 $$removed 个文件)$(NC)"
docs: ## 生成或更新 README 文档目录 (中英文 TOC)
@echo "$(BLUE)📚 生成或更新 README 中英文目录结构...$(NC)"
@if ! command -v npx > /dev/null 2>&1; then \
echo "$(RED) ❌ npx 未安装,请先安装 Node.js$(NC)"; \
exit 1; \
fi
@npx --yes doctoc README.md README.en.md --notitle --maxlevel 3
@echo "$(GREEN)✅ README.md / README.en.md 目录已更新$(NC)"
update: ## 更新 dotfiles 仓库与所有工具链
@echo "$(BLUE)🔄 更新 dotfiles 及相关工具链...$(NC)"
@git pull --rebase
@./bin/dot-update
@echo "$(GREEN)✅ 更新完成$(NC)"
@echo " $(YELLOW)提示:$(NC) 若仅更新已存在软链文件的内容,通常无需运行 'make restow'"
@echo " $(YELLOW) $(NC) 如涉及新增/删除/重命名文件、包结构变更或软链接异常,再执行 'make restow'"