Compare commits
28 Commits
885926335f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e411c4c97 | |||
| e94eda2a5f | |||
| ac66aadea2 | |||
| 04bf913d35 | |||
| d2b2c7376f | |||
| b84368259d | |||
| 3895221c48 | |||
| 27d4c68f23 | |||
| af42eb913f | |||
| 33f4beb72a | |||
| 193cbdb11b | |||
| 99f9608282 | |||
| b96e144e82 | |||
| 4182b3c300 | |||
| ff31160602 | |||
| 34e71deed0 | |||
| e34d7da3ea | |||
| e9a77f907e | |||
| 77d51c65b3 | |||
| 2b3544b4a5 | |||
| d4cb2f8acb | |||
| 0b6830f6d8 | |||
| 9befd389af | |||
| f626c12e49 | |||
| 04d517a2c2 | |||
| 171aaa55fd | |||
| f4c42d3d94 | |||
| 1f94c3f63f |
@@ -14,17 +14,17 @@
|
|||||||
.
|
.
|
||||||
├── source.py # decman 主配置入口
|
├── source.py # decman 主配置入口
|
||||||
├── modules/
|
├── modules/
|
||||||
│ ├── base.py # 基础模块(系统包 + 现代 CLI 工具 + 配置文件)
|
│ ├── base.py # 基础模块(系统包 + CLI 工具 + dotfiles)
|
||||||
│ ├── dev.py # 开发模块(语言运行时 + 编辑器 + 工具链)
|
│ ├── dev.py # 开发模块(语言运行时 + LSP + 工具链)
|
||||||
│ ├── docker.py # Docker 模块(packages + systemd units)
|
│ ├── docker.py # Docker 模块(packages + systemd units)
|
||||||
│ ├── locale.py # locale 模块(files + on_change hook)
|
│ ├── locale.py # locale 模块(on_change hook 示例)
|
||||||
│ └── zsh.py # Zsh 模块(shell + oh-my-zsh + 插件)
|
│ └── fish.py # Fish 模块(shell + fzf + 自动 chsh)
|
||||||
├── system/etc/ # 系统配置文件源 → 部署到 /etc/
|
├── system/etc/ # 系统配置文件源 → /etc/
|
||||||
├── home/ # 用户配置文件源 → 部署到 ~/
|
├── home/ # 用户配置文件源 → ~/(必须指定 owner)
|
||||||
├── scripts/
|
├── scripts/
|
||||||
│ ├── install.sh # 引导脚本(git → decman → 首次 sync)
|
│ ├── install.sh # 引导脚本(curl | bash)
|
||||||
│ └── wsl-init.sh # WSL 首次初始化(创建用户)
|
│ └── wsl-init.sh # WSL 首次初始化
|
||||||
└── pyproject.toml # 开发依赖(decman + 插件,仅用于类型检查)
|
└── pyproject.toml # 开发依赖(decman 插件,仅类型检查)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 命令
|
## 命令
|
||||||
@@ -70,15 +70,15 @@ uv sync
|
|||||||
files → pacman → aur → systemd
|
files → pacman → aur → systemd
|
||||||
```
|
```
|
||||||
|
|
||||||
`source.py` 中的声明分区按此排列:系统文件 → 用户配置 → modules → pacman 包 → AUR 包。
|
`source.py` 是纯模块注册入口,所有 files / packages / units 声明都在各 Module 内部实现。
|
||||||
|
|
||||||
## 代码风格
|
## 代码风格
|
||||||
|
|
||||||
### Python(source.py 及模块)
|
### Python(source.py 及模块)
|
||||||
|
|
||||||
**source.py 结构**:
|
**source.py 结构**:
|
||||||
- 纯模块注册,不直接声明文件或包
|
- 纯模块注册入口,不直接声明文件或包
|
||||||
- 校验 `SUDO_USER` 和必要插件存在性
|
- 校验 `SUDO_USER`(插件缺失时 `import modules.*` 阶段会直接 ImportError,无需运行时检查)
|
||||||
- 通过 `decman.modules += [...]` 注册所有模块
|
- 通过 `decman.modules += [...]` 注册所有模块
|
||||||
|
|
||||||
**模块模式**(适用于需要 hook 或跨步骤声明的场景):
|
**模块模式**(适用于需要 hook 或跨步骤声明的场景):
|
||||||
@@ -101,10 +101,7 @@ class DockerModule(Module):
|
|||||||
return {"docker.socket"}
|
return {"docker.socket"}
|
||||||
```
|
```
|
||||||
|
|
||||||
**何时用模块 vs 直接声明**:
|
**模块组织原则**:所有 files / packages / units 声明都通过 Module 封装,按领域拆分(base / dev / docker / locale / fish)。新增功能优先加到对应现有模块;跨领域、需要 lifecycle hook(`on_change` / `after_update`)或需要绑定 packages + systemd units 时再新建模块。
|
||||||
- 需要 `on_change` hook(如 `locale-gen`)→ Module
|
|
||||||
- 需要绑定 packages + systemd units → Module(`@packages` + `@units` 装饰器)
|
|
||||||
- 纯静态文件、无副作用 → 直接在 `source.py` 用 `File()`
|
|
||||||
|
|
||||||
### Shell 脚本
|
### Shell 脚本
|
||||||
|
|
||||||
@@ -124,19 +121,32 @@ class DockerModule(Module):
|
|||||||
- 示例:`feat(docker): 添加 Docker 支持并重排声明顺序`
|
- 示例:`feat(docker): 添加 Docker 支持并重排声明顺序`
|
||||||
- 分支:直接在 `main` 上工作
|
- 分支:直接在 `main` 上工作
|
||||||
|
|
||||||
|
## 关键依赖关系
|
||||||
|
|
||||||
|
`.config/fish/config.fish` 别名与包的绑定(修改前务必检查):
|
||||||
|
|
||||||
|
| 别名 | 依赖包 | 位置 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `rm="gomi"` | `gomi-bin` (AUR) | `base.py` |
|
||||||
|
| `cat="bat"` | `bat` | `base.py` |
|
||||||
|
| `ls="eza"` | `eza` | `base.py` |
|
||||||
|
| `vi="nvim"` | `neovim` | `dev.py` |
|
||||||
|
| `lg="lazygit"` | `lazygit` | `dev.py` |
|
||||||
|
| `x="ouch decompress"` | `ouch` | `base.py` |
|
||||||
|
|
||||||
## Agent 须知
|
## Agent 须知
|
||||||
|
|
||||||
1. **decman 是唯一真相**:不要手动装包,加到 `source.py` 或模块里,跑 `sudo decman`。
|
1. **decman 是唯一真相**:不要手动装包,加到 `source.py` 或模块里,跑 `sudo decman`。
|
||||||
|
|
||||||
2. **Pacman vs AUR**:用 `pacman -Ss` 确认包在官方仓库还是 AUR,分别加到 `decman.pacman.packages` 或 `decman.aur.packages`。
|
2. **Pacman vs AUR**:用 `pacman -Ss` 确认包在官方仓库还是 AUR,分别加到对应模块的 `@pacman_packages` 或 `@aur_packages` 装饰器方法返回集合。
|
||||||
|
|
||||||
3. **系统文件**:源文件放 `system/`,目录结构对应目标路径(`system/etc/foo.conf` → `/etc/foo.conf`)。decman 复制(非 symlink)到目标位置。
|
3. **系统文件**:源文件放 `system/`,目录结构对应目标路径(`system/etc/foo.conf` → `/etc/foo.conf`)。decman 复制(非 symlink)到目标位置。
|
||||||
|
|
||||||
4. **用户配置**:源文件放 `home/`,必须指定 `owner=USERNAME`。
|
4. **用户配置**:源文件放 `home/`,必须指定 `owner=USERNAME`。
|
||||||
|
|
||||||
5. **Runs as root**:`sudo decman` 以 root 执行 `source.py`。`SUDO_USER` 是调用 sudo 的原始用户名,不要 fallback。
|
5. **环境变量**:`sudo decman` 以 root 执行,`SUDO_USER` 是原始用户名。配置内不要 fallback 到 `os.getenv("USER")`。
|
||||||
|
|
||||||
6. **开发环境**:`pyproject.toml` + `uv sync` 管理开发依赖(decman、decman-pacman、decman-systemd),仅用于 IDE 类型检查,不影响运行时。
|
6. **开发依赖**:`pyproject.toml` 仅用 uv 管理类型检查依赖,不影响运行时。修改依赖后运行 `uv sync`。
|
||||||
|
|
||||||
7. **幂等性**:所有脚本和配置必须可安全重复执行。
|
7. **幂等性**:所有脚本和配置必须可安全重复执行。
|
||||||
|
|
||||||
@@ -144,11 +154,11 @@ class DockerModule(Module):
|
|||||||
|
|
||||||
## 常见任务
|
## 常见任务
|
||||||
|
|
||||||
**添加包**:确认 pacman/AUR → 加到 `source.py` 对应集合 → `sudo decman`
|
**添加包**:确认 pacman/AUR → 加到对应模块的 `@pacman_packages` / `@aur_packages` 方法返回集合 → `sudo decman`
|
||||||
|
|
||||||
**添加系统文件**:放 `system/` → 在 `source.py` 加 `File(source_file=...)` → `sudo decman`
|
**添加系统文件**:放 `system/` → 在对应模块的 `files()` 方法加 `File(source_file=...)` → `sudo decman`
|
||||||
|
|
||||||
**添加 dotfile**:放 `home/` → 在 `source.py` 加 `File(source_file=..., owner=USERNAME)` → `sudo decman`
|
**添加 dotfile**:放 `home/` → 在对应模块的 `files()` 方法加 `File(source_file=..., owner=self.user)` → `sudo decman`
|
||||||
|
|
||||||
**添加需要 systemd 服务的软件**:创建 Module 文件,用 `@packages` + `@units` 装饰器 → 在 `source.py` 注册 → `sudo decman`
|
**添加需要 systemd 服务的软件**:创建 Module 文件,用 `@packages` + `@units` 装饰器 → 在 `source.py` 注册 → `sudo decman`
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,17 @@
|
|||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
|
### 安装 Arch Linux(WSL)
|
||||||
|
|
||||||
|
需要 Windows 10/11 并已启用 WSL 2。在 PowerShell 中执行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl --update
|
||||||
|
wsl --install archlinux
|
||||||
|
```
|
||||||
|
|
||||||
|
安装完成后,可通过开始菜单的 `archlinux` 应用或命令 `wsl -d archlinux` 启动,首次进入默认以 `root` 身份登录。
|
||||||
|
|
||||||
### WSL 首次启动(默认 root 登录)
|
### WSL 首次启动(默认 root 登录)
|
||||||
|
|
||||||
1. 初始化普通用户:
|
1. 初始化普通用户:
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
fish_add_path "$HOME/go/bin" "$HOME/.bun/bin"
|
||||||
|
|
||||||
|
set -gx EDITOR nvim
|
||||||
|
set -gx VISUAL nvim
|
||||||
|
set -gx PAGER less
|
||||||
|
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
||||||
|
|
||||||
|
set -g fish_greeting
|
||||||
|
|
||||||
|
function __prepend_sudo
|
||||||
|
set -l buffer (commandline)
|
||||||
|
if test -z "$buffer"
|
||||||
|
commandline -f up-line
|
||||||
|
set buffer (commandline)
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -n "$buffer"
|
||||||
|
if not string match -qr '^sudo\b' -- "$buffer"
|
||||||
|
commandline -r "sudo $buffer"
|
||||||
|
end
|
||||||
|
commandline -f end-of-line repaint
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
bind escape,escape __prepend_sudo # Fish 4.0+ 语法:双击 Escape 添加 sudo
|
||||||
|
bind ctrl-space accept-autosuggestion # Fish 4.0+ 语法
|
||||||
|
|
||||||
|
set -gx FZF_DEFAULT_OPTS '--height=50% --layout=reverse --border --preview-window=right:60%'
|
||||||
|
set -gx FZF_DEFAULT_COMMAND 'fd --type f --hidden --follow --exclude .git'
|
||||||
|
set -gx FZF_CTRL_T_COMMAND "$FZF_DEFAULT_COMMAND"
|
||||||
|
set -gx FZF_ALT_C_COMMAND 'fd --type d --hidden --follow --exclude .git'
|
||||||
|
|
||||||
|
alias ..='cd ..'
|
||||||
|
alias ...='cd ../..'
|
||||||
|
|
||||||
|
function ls
|
||||||
|
command eza --icons --group-directories-first --git $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
function l
|
||||||
|
command eza -la --icons --group-directories-first --git $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
function ll
|
||||||
|
command eza -l --icons --group-directories-first --git $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
function la
|
||||||
|
command eza -lA --icons --group-directories-first --git $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
function lt
|
||||||
|
command eza --tree --level=2 --icons --group-directories-first --git $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
alias cat='bat --paging=never'
|
||||||
|
alias rm='gomi'
|
||||||
|
alias lg='lazygit'
|
||||||
|
alias vi='nvim'
|
||||||
|
alias x='ouch decompress'
|
||||||
|
|
||||||
|
if set -q WSL_DISTRO_NAME
|
||||||
|
alias pbcopy='clip.exe'
|
||||||
|
alias pbpaste='powershell.exe -noprofile -c Get-Clipboard'
|
||||||
|
|
||||||
|
function keep_current_path --on-event fish_prompt
|
||||||
|
printf '\e]9;9;%s\e\\' (wslpath -w "$PWD")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if status is-interactive
|
||||||
|
zoxide init fish --cmd cd | source
|
||||||
|
mise activate fish | source
|
||||||
|
|
||||||
|
set -g direnv_fish_mode eval_after_arrow
|
||||||
|
direnv hook fish | source
|
||||||
|
|
||||||
|
fzf --fish | source
|
||||||
|
|
||||||
|
set -gx ATUIN_NOBIND true
|
||||||
|
atuin init fish | source
|
||||||
|
bind \cr _atuin_search
|
||||||
|
bind up _atuin_bind_up
|
||||||
|
|
||||||
|
starship init fish | source
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -f ~/.config/fish/config.local.fish
|
||||||
|
source ~/.config/fish/config.local.fish
|
||||||
|
end
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
function yy
|
||||||
|
set -l tmp (mktemp -t yazi-cwd.XXXXXX)
|
||||||
|
command yazi $argv --cwd-file="$tmp"
|
||||||
|
|
||||||
|
if set -l cwd (command cat -- "$tmp")
|
||||||
|
if test -n "$cwd" -a "$cwd" != "$PWD"
|
||||||
|
builtin cd -- "$cwd"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
command rm -f -- "$tmp"
|
||||||
|
end
|
||||||
@@ -20,3 +20,5 @@
|
|||||||
defaultBranch = main
|
defaultBranch = main
|
||||||
[rerere]
|
[rerere]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
[include]
|
||||||
|
path = ~/.config/git/config.local
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
[settings]
|
[settings]
|
||||||
trusted_config_paths = ["/"]
|
trusted_config_paths = ["/"]
|
||||||
|
|
||||||
|
[tools]
|
||||||
|
usage = "latest"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ $git_status\
|
|||||||
$nodejs\
|
$nodejs\
|
||||||
$rust\
|
$rust\
|
||||||
$golang\
|
$golang\
|
||||||
$php\
|
$python\
|
||||||
[](fg:#212736 bg:#1d2230)\
|
[](fg:#212736 bg:#1d2230)\
|
||||||
$time\
|
$time\
|
||||||
[ ](fg:#1d2230)\
|
[ ](fg:#1d2230)\
|
||||||
@@ -54,8 +54,8 @@ symbol = ""
|
|||||||
style = "bg:#212736"
|
style = "bg:#212736"
|
||||||
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
|
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
|
||||||
|
|
||||||
[php]
|
[python]
|
||||||
symbol = ""
|
symbol = ""
|
||||||
style = "bg:#212736"
|
style = "bg:#212736"
|
||||||
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
|
format = '[[ $symbol ($version) ](fg:#769ff0 bg:#212736)]($style)'
|
||||||
|
|
||||||
|
|||||||
-64
@@ -1,64 +0,0 @@
|
|||||||
# ── PATH ──
|
|
||||||
export PATH="$HOME/go/bin:$HOME/.bun/bin:$PATH"
|
|
||||||
|
|
||||||
# ── Shell 选项 ──
|
|
||||||
setopt AUTO_CD # 输目录名直接 cd
|
|
||||||
setopt INTERACTIVE_COMMENTS # 允许交互式 # 注释
|
|
||||||
setopt NO_BEEP # 关蜂鸣
|
|
||||||
|
|
||||||
# ── 补全系统(必须在 fzf-tab 之前)──
|
|
||||||
autoload -Uz compinit && compinit
|
|
||||||
|
|
||||||
# ── 外部插件 ──
|
|
||||||
source /usr/share/zsh/plugins/fzf-tab-git/fzf-tab.plugin.zsh
|
|
||||||
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
|
|
||||||
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh # 必须最后
|
|
||||||
|
|
||||||
# ── 双击 ESC 自动加 sudo ──
|
|
||||||
sudo-command-line() {
|
|
||||||
[[ -z $BUFFER ]] && zle up-history
|
|
||||||
[[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
|
|
||||||
zle end-of-line
|
|
||||||
}
|
|
||||||
zle -N sudo-command-line
|
|
||||||
bindkey '\e\e' sudo-command-line
|
|
||||||
|
|
||||||
# ── 工具初始化(顺序重要)──
|
|
||||||
eval "$(starship init zsh)"
|
|
||||||
eval "$(zoxide init zsh)"
|
|
||||||
eval "$(mise activate zsh)"
|
|
||||||
eval "$(direnv hook zsh)"
|
|
||||||
eval "$(fzf --zsh)" # Ctrl+T 搜文件, Alt+C 搜目录
|
|
||||||
eval "$(atuin init zsh)" # 必须在 fzf 之后,接管 Ctrl+R
|
|
||||||
|
|
||||||
# ── 别名 ──
|
|
||||||
# 导航
|
|
||||||
alias cd="z"
|
|
||||||
alias cdi="zi"
|
|
||||||
alias ..="cd .."
|
|
||||||
alias ...="cd ../.."
|
|
||||||
|
|
||||||
# 文件列表
|
|
||||||
alias ls="eza --icons --group-directories-first"
|
|
||||||
alias ll="eza -la --icons --git --group-directories-first"
|
|
||||||
alias la="eza -a --icons --group-directories-first"
|
|
||||||
alias lt="eza --tree --level=2 --icons"
|
|
||||||
|
|
||||||
# 工具
|
|
||||||
alias cat="bat --paging=never"
|
|
||||||
alias rm="trash-put"
|
|
||||||
alias lg="lazygit"
|
|
||||||
alias vi="nvim"
|
|
||||||
alias x="aunpack" # 万能解压(支持 tar/zip/7z/rar 等)
|
|
||||||
|
|
||||||
# 网络
|
|
||||||
alias http="xh"
|
|
||||||
|
|
||||||
# ── WSL 剪贴板 ──
|
|
||||||
if [[ -n "$WSL_DISTRO_NAME" ]]; then
|
|
||||||
alias pbcopy="clip.exe"
|
|
||||||
alias pbpaste="powershell.exe -noprofile -c Get-Clipboard"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Local ──
|
|
||||||
[[ -f ~/.zshrc.local ]] && source ~/.zshrc.local
|
|
||||||
+6
-8
@@ -8,7 +8,7 @@ class BaseModule(Module):
|
|||||||
super().__init__("base")
|
super().__init__("base")
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
def files(self):
|
def files(self) -> dict[str, File]:
|
||||||
return {
|
return {
|
||||||
"/etc/pacman.conf": File(
|
"/etc/pacman.conf": File(
|
||||||
source_file="./system/etc/pacman.conf",
|
source_file="./system/etc/pacman.conf",
|
||||||
@@ -34,12 +34,14 @@ class BaseModule(Module):
|
|||||||
def pacman_packages(self) -> set[str]:
|
def pacman_packages(self) -> set[str]:
|
||||||
return {
|
return {
|
||||||
"7zip",
|
"7zip",
|
||||||
"atool",
|
"adobe-source-han-sans-cn-fonts",
|
||||||
|
"adobe-source-han-serif-cn-fonts",
|
||||||
"atuin",
|
"atuin",
|
||||||
"base-devel",
|
"base-devel",
|
||||||
"base",
|
"base",
|
||||||
"bat",
|
"bat",
|
||||||
"btop",
|
"btop",
|
||||||
|
"chromium",
|
||||||
"curl",
|
"curl",
|
||||||
"direnv",
|
"direnv",
|
||||||
"duf",
|
"duf",
|
||||||
@@ -51,18 +53,13 @@ class BaseModule(Module):
|
|||||||
"git",
|
"git",
|
||||||
"jq",
|
"jq",
|
||||||
"micro",
|
"micro",
|
||||||
|
"ouch",
|
||||||
"procs",
|
"procs",
|
||||||
"ripgrep",
|
"ripgrep",
|
||||||
"sd",
|
"sd",
|
||||||
"starship",
|
"starship",
|
||||||
"sudo",
|
"sudo",
|
||||||
"tealdeer",
|
|
||||||
"trash-cli",
|
|
||||||
"unrar",
|
|
||||||
"unzip",
|
|
||||||
"vim",
|
|
||||||
"wget",
|
"wget",
|
||||||
"xh",
|
|
||||||
"yazi",
|
"yazi",
|
||||||
"yq",
|
"yq",
|
||||||
"zoxide",
|
"zoxide",
|
||||||
@@ -72,4 +69,5 @@ class BaseModule(Module):
|
|||||||
def aur_packages(self) -> set[str]:
|
def aur_packages(self) -> set[str]:
|
||||||
return {
|
return {
|
||||||
"decman",
|
"decman",
|
||||||
|
"gomi-bin",
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-8
@@ -2,13 +2,14 @@ import decman
|
|||||||
from decman import File, Module
|
from decman import File, Module
|
||||||
from decman.plugins.pacman import packages as pacman_packages
|
from decman.plugins.pacman import packages as pacman_packages
|
||||||
|
|
||||||
BUN_GLOBAL_PACKAGES = [
|
BUN_GLOBAL_PACKAGES: list[str] = [
|
||||||
"@vue/language-server",
|
"@vue/language-server",
|
||||||
"dockerfile-language-server-nodejs",
|
"dockerfile-language-server-nodejs",
|
||||||
|
"oxlint",
|
||||||
"opencode-ai",
|
"opencode-ai",
|
||||||
]
|
]
|
||||||
|
|
||||||
GO_INSTALL_PACKAGES = [
|
GO_INSTALL_PACKAGES: list[str] = [
|
||||||
"github.com/code-yeongyu/go-claude-code-comment-checker/cmd/comment-checker@latest",
|
"github.com/code-yeongyu/go-claude-code-comment-checker/cmd/comment-checker@latest",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ class DevModule(Module):
|
|||||||
super().__init__("dev")
|
super().__init__("dev")
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
def files(self):
|
def files(self) -> dict[str, File]:
|
||||||
return {
|
return {
|
||||||
f"/home/{self.user}/.config/mise/config.toml": File(
|
f"/home/{self.user}/.config/mise/config.toml": File(
|
||||||
source_file="./home/.config/mise/config.toml",
|
source_file="./home/.config/mise/config.toml",
|
||||||
@@ -50,7 +51,7 @@ class DevModule(Module):
|
|||||||
"zellij",
|
"zellij",
|
||||||
}
|
}
|
||||||
|
|
||||||
def after_update(self, store):
|
def after_update(self, store: object) -> None:
|
||||||
failures: list[str] = []
|
failures: list[str] = []
|
||||||
for pkg in BUN_GLOBAL_PACKAGES:
|
for pkg in BUN_GLOBAL_PACKAGES:
|
||||||
try:
|
try:
|
||||||
@@ -78,7 +79,7 @@ class DevModule(Module):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
failures.append(f"go: {pkg} ({e})")
|
failures.append(f"go: {pkg} ({e})")
|
||||||
if failures:
|
if failures:
|
||||||
print(f"\n⚠ {len(failures)} 个全局包安装失败:")
|
raise decman.SourceError(
|
||||||
for f in failures:
|
f"{len(failures)} 个全局包安装失败:\n"
|
||||||
print(f" - {f}")
|
+ "\n".join(f" - {f}" for f in failures)
|
||||||
print()
|
)
|
||||||
|
|||||||
+32
-3
@@ -1,4 +1,5 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import decman
|
import decman
|
||||||
from decman import Module
|
from decman import Module
|
||||||
@@ -6,10 +7,19 @@ from decman.plugins.pacman import packages as pacman_packages
|
|||||||
from decman.plugins.systemd import units
|
from decman.plugins.systemd import units
|
||||||
|
|
||||||
|
|
||||||
|
def _is_wsl() -> bool:
|
||||||
|
"""检测是否在 WSL 环境"""
|
||||||
|
try:
|
||||||
|
return "microsoft" in Path("/proc/version").read_text().lower()
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class DockerModule(Module):
|
class DockerModule(Module):
|
||||||
def __init__(self, user: str):
|
def __init__(self, user: str):
|
||||||
super().__init__("docker")
|
super().__init__("docker")
|
||||||
self.user = user
|
self.user = user
|
||||||
|
self._is_wsl = _is_wsl()
|
||||||
|
|
||||||
@pacman_packages
|
@pacman_packages
|
||||||
def pacman_packages(self) -> set[str]:
|
def pacman_packages(self) -> set[str]:
|
||||||
@@ -19,11 +29,30 @@ class DockerModule(Module):
|
|||||||
def units(self) -> set[str]:
|
def units(self) -> set[str]:
|
||||||
return {"docker.socket"}
|
return {"docker.socket"}
|
||||||
|
|
||||||
def after_update(self, store):
|
def after_update(self, store: object) -> None:
|
||||||
|
self._ensure_user_in_docker_group()
|
||||||
|
if self._is_wsl:
|
||||||
|
self._disable_networkd_wait_online()
|
||||||
|
|
||||||
|
def _ensure_user_in_docker_group(self) -> None:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["id", "-nG", self.user], capture_output=True, text=True
|
["id", "-nG", self.user],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
)
|
)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
return
|
raise decman.SourceError(f"无法读取用户 {self.user} 的组信息")
|
||||||
if "docker" not in result.stdout.split():
|
if "docker" not in result.stdout.split():
|
||||||
decman.prg(["gpasswd", "-a", self.user, "docker"])
|
decman.prg(["gpasswd", "-a", self.user, "docker"])
|
||||||
|
|
||||||
|
def _disable_networkd_wait_online(self) -> None:
|
||||||
|
"""WSL 环境:禁用 systemd-networkd-wait-online 避免启动阻塞"""
|
||||||
|
result = subprocess.run(
|
||||||
|
["systemctl", "is-enabled", "systemd-networkd-wait-online.service"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
if result.returncode == 0 and result.stdout.strip() == "enabled":
|
||||||
|
decman.prg(["systemctl", "disable", "systemd-networkd-wait-online.service"])
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
|
import decman
|
||||||
|
from decman import File, Module
|
||||||
|
from decman.plugins.pacman import packages as pacman_packages
|
||||||
|
|
||||||
|
|
||||||
|
class FishModule(Module):
|
||||||
|
def __init__(self, user: str):
|
||||||
|
super().__init__("fish")
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
def files(self) -> dict[str, File]:
|
||||||
|
return {
|
||||||
|
f"/home/{self.user}/.config/fish/config.fish": File(
|
||||||
|
source_file="./home/.config/fish/config.fish",
|
||||||
|
owner=self.user,
|
||||||
|
),
|
||||||
|
f"/home/{self.user}/.config/fish/functions/yy.fish": File(
|
||||||
|
source_file="./home/.config/fish/functions/yy.fish",
|
||||||
|
owner=self.user,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
@pacman_packages
|
||||||
|
def pacman_packages(self) -> set[str]:
|
||||||
|
return {
|
||||||
|
"fish",
|
||||||
|
"fzf",
|
||||||
|
}
|
||||||
|
|
||||||
|
def after_update(self, store: object) -> None:
|
||||||
|
result = subprocess.run(
|
||||||
|
["getent", "passwd", self.user],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise decman.SourceError(f"无法读取用户 {self.user} 的 passwd 信息")
|
||||||
|
# passwd 格式: name:x:uid:gid:gecos:home:shell
|
||||||
|
shell = result.stdout.strip().split(":")[-1]
|
||||||
|
if shell != "/usr/bin/fish":
|
||||||
|
decman.prg(["chsh", "-s", "/usr/bin/fish", self.user])
|
||||||
+2
-2
@@ -6,11 +6,11 @@ class LocaleModule(Module):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("locale")
|
super().__init__("locale")
|
||||||
|
|
||||||
def files(self):
|
def files(self) -> dict[str, File]:
|
||||||
return {
|
return {
|
||||||
"/etc/locale.conf": File(content="LANG=en_US.UTF-8\n"),
|
"/etc/locale.conf": File(content="LANG=en_US.UTF-8\n"),
|
||||||
"/etc/locale.gen": File(content="en_US.UTF-8 UTF-8\n"),
|
"/etc/locale.gen": File(content="en_US.UTF-8 UTF-8\n"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_change(self, store):
|
def on_change(self, store: object) -> None:
|
||||||
decman.prg(["locale-gen"])
|
decman.prg(["locale-gen"])
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
|
|
||||||
import decman
|
|
||||||
from decman import File, Module
|
|
||||||
from decman.plugins.aur import packages as aur_packages
|
|
||||||
from decman.plugins.pacman import packages as pacman_packages
|
|
||||||
|
|
||||||
|
|
||||||
class ZshModule(Module):
|
|
||||||
def __init__(self, user: str):
|
|
||||||
super().__init__("zsh")
|
|
||||||
self.user = user
|
|
||||||
|
|
||||||
def files(self):
|
|
||||||
return {
|
|
||||||
f"/home/{self.user}/.zshrc": File(
|
|
||||||
source_file="./home/.zshrc",
|
|
||||||
owner=self.user,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
@pacman_packages
|
|
||||||
def pacman_packages(self) -> set[str]:
|
|
||||||
return {
|
|
||||||
"fzf",
|
|
||||||
"zsh",
|
|
||||||
"zsh-autosuggestions",
|
|
||||||
"zsh-completions",
|
|
||||||
"zsh-syntax-highlighting",
|
|
||||||
}
|
|
||||||
|
|
||||||
@aur_packages
|
|
||||||
def aur_packages(self) -> set[str]:
|
|
||||||
return {
|
|
||||||
"fzf-tab-git",
|
|
||||||
}
|
|
||||||
|
|
||||||
def after_update(self, store):
|
|
||||||
result = subprocess.run(
|
|
||||||
["getent", "passwd", self.user], capture_output=True, text=True
|
|
||||||
)
|
|
||||||
if result.returncode != 0:
|
|
||||||
return
|
|
||||||
# passwd 格式: name:x:uid:gid:gecos:home:shell
|
|
||||||
shell = result.stdout.strip().split(":")[-1]
|
|
||||||
if shell != "/usr/bin/zsh":
|
|
||||||
decman.prg(["chsh", "-s", "/usr/bin/zsh", self.user])
|
|
||||||
+15
-12
@@ -5,7 +5,10 @@ REPO_URL="https://git.furtherverse.com/imbytecat/archlinux-config.git"
|
|||||||
CONFIG_DIR="$HOME/.config/archlinux-config"
|
CONFIG_DIR="$HOME/.config/archlinux-config"
|
||||||
|
|
||||||
echo "🔑 验证 sudo 权限..."
|
echo "🔑 验证 sudo 权限..."
|
||||||
sudo -v < /dev/tty || { echo "❌ 需要 sudo 权限,请确认当前用户已配置 sudo"; exit 1; }
|
sudo -v </dev/tty || {
|
||||||
|
echo "❌ 需要 sudo 权限,请确认当前用户已配置 sudo"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
echo "🔄 更新系统..."
|
echo "🔄 更新系统..."
|
||||||
sudo pacman -Syu --noconfirm
|
sudo pacman -Syu --noconfirm
|
||||||
@@ -16,27 +19,27 @@ sudo pacman -S --needed --noconfirm git base-devel
|
|||||||
echo "📥 克隆配置仓库..."
|
echo "📥 克隆配置仓库..."
|
||||||
mkdir -p "$(dirname "$CONFIG_DIR")"
|
mkdir -p "$(dirname "$CONFIG_DIR")"
|
||||||
if [[ -d "$CONFIG_DIR/.git" ]]; then
|
if [[ -d "$CONFIG_DIR/.git" ]]; then
|
||||||
echo "⏩ 配置仓库已存在,跳过克隆"
|
echo "⏩ 配置仓库已存在,跳过克隆"
|
||||||
elif [[ -e "$CONFIG_DIR" ]]; then
|
elif [[ -e "$CONFIG_DIR" ]]; then
|
||||||
echo "❌ 目标路径已存在且不是 git 仓库:$CONFIG_DIR"
|
echo "❌ 目标路径已存在且不是 git 仓库:$CONFIG_DIR"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
git clone "$REPO_URL" "$CONFIG_DIR"
|
git clone "$REPO_URL" "$CONFIG_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "📦 安装 decman..."
|
echo "📦 安装 decman..."
|
||||||
if ! command -v decman &> /dev/null; then
|
if ! command -v decman &>/dev/null; then
|
||||||
_tmpdir=$(mktemp -d)
|
_tmpdir=$(mktemp -d)
|
||||||
trap 'rm -rf "$_tmpdir"' EXIT
|
trap 'rm -rf "$_tmpdir"' EXIT
|
||||||
git clone https://aur.archlinux.org/decman.git "$_tmpdir"
|
git clone https://aur.archlinux.org/decman.git "$_tmpdir"
|
||||||
(cd "$_tmpdir" && makepkg -si --noconfirm)
|
(cd "$_tmpdir" && makepkg -si --noconfirm)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "⚙️ 应用系统配置..."
|
echo "⚙️ 应用系统配置..."
|
||||||
sudo decman --source "$CONFIG_DIR/source.py" < /dev/tty
|
sudo decman --source "$CONFIG_DIR/source.py" </dev/tty
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "🎉 安装完成!重新登录以使用 zsh。"
|
echo "🎉 安装完成!重新登录以使用 fish。"
|
||||||
echo ""
|
echo ""
|
||||||
echo "后续更新配置:"
|
echo "后续更新配置:"
|
||||||
echo " cd $CONFIG_DIR && git pull && sudo decman"
|
echo " cd $CONFIG_DIR && git pull && sudo decman"
|
||||||
|
|||||||
+17
-17
@@ -1,40 +1,40 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [[ "$(id -u)" -ne 0 ]]; then
|
||||||
echo "❌ 请以 root 身份运行此脚本"
|
echo "❌ 请以 root 身份运行此脚本"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
USERNAME="${1:-}"
|
USERNAME="${1:-}"
|
||||||
if [ -z "$USERNAME" ]; then
|
if [[ -z "$USERNAME" ]]; then
|
||||||
echo "用法: wsl-init.sh <用户名>"
|
echo "用法: wsl-init.sh <用户名>"
|
||||||
echo "示例: wsl-init.sh imbytecat"
|
echo "示例: wsl-init.sh imbytecat"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🔄 更新系统..."
|
echo "🔄 更新系统..."
|
||||||
pacman -Syu --noconfirm
|
pacman -Syu --noconfirm
|
||||||
|
|
||||||
if ! command -v sudo &> /dev/null; then
|
if ! command -v sudo &>/dev/null; then
|
||||||
echo "📦 安装 sudo..."
|
echo "📦 安装 sudo..."
|
||||||
pacman -S --needed --noconfirm sudo
|
pacman -S --needed --noconfirm sudo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🔐 配置 sudo 权限..."
|
echo "🔐 配置 sudo 权限..."
|
||||||
cat > /etc/sudoers.d/10-wheel << 'EOF'
|
cat >/etc/sudoers.d/10-wheel <<'EOF'
|
||||||
%wheel ALL=(ALL) NOPASSWD: ALL
|
%wheel ALL=(ALL) NOPASSWD: ALL
|
||||||
EOF
|
EOF
|
||||||
chmod 440 /etc/sudoers.d/10-wheel
|
chmod 440 /etc/sudoers.d/10-wheel
|
||||||
|
|
||||||
echo "👤 创建用户 $USERNAME..."
|
echo "👤 创建用户 $USERNAME..."
|
||||||
if id "$USERNAME" &> /dev/null; then
|
if id "$USERNAME" &>/dev/null; then
|
||||||
echo "⏩ 用户 $USERNAME 已存在,确保 wheel 组成员"
|
echo "⏩ 用户 $USERNAME 已存在,确保 wheel 组成员"
|
||||||
usermod -aG wheel "$USERNAME"
|
usermod -aG wheel "$USERNAME"
|
||||||
else
|
else
|
||||||
useradd -m -G wheel -s /bin/bash "$USERNAME"
|
useradd -m -G wheel -s /bin/bash "$USERNAME"
|
||||||
echo "请设置 $USERNAME 的密码:"
|
echo "请设置 $USERNAME 的密码:"
|
||||||
passwd "$USERNAME" < /dev/tty
|
passwd "$USERNAME" </dev/tty
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ import modules.base
|
|||||||
import modules.dev
|
import modules.dev
|
||||||
import modules.docker
|
import modules.docker
|
||||||
import modules.locale
|
import modules.locale
|
||||||
import modules.zsh
|
import modules.fish
|
||||||
|
|
||||||
if decman.pacman is None or decman.aur is None or decman.systemd is None:
|
|
||||||
raise decman.SourceError("缺少必要插件,请检查 decman 安装")
|
|
||||||
|
|
||||||
USERNAME = os.environ.get("SUDO_USER")
|
USERNAME = os.environ.get("SUDO_USER")
|
||||||
if not USERNAME:
|
if not USERNAME:
|
||||||
@@ -20,5 +17,5 @@ decman.modules += [
|
|||||||
modules.dev.DevModule(USERNAME),
|
modules.dev.DevModule(USERNAME),
|
||||||
modules.docker.DockerModule(USERNAME),
|
modules.docker.DockerModule(USERNAME),
|
||||||
modules.locale.LocaleModule(),
|
modules.locale.LocaleModule(),
|
||||||
modules.zsh.ZshModule(USERNAME),
|
modules.fish.FishModule(USERNAME),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user