feat: NixOS 声明式配置(从 Arch + decman 迁移)

- flake.nix: NixOS + home-manager + nixos-wsl 三输入
- hosts/wsl + hosts/bare: WSL 与裸机共享模块,分主机配置
- modules/: base(CLI 工具) + dev(工具链+LSP) + docker + locale + shell
- home/: zsh(oh-my-zsh+插件+别名) + git(delta) + starship + 工具集成
- scripts/install.sh: 一键安装脚本(WSL/裸机通用)
- 原 bun/go 全局包 hack 改为 nixpkgs 声明式管理
This commit is contained in:
2026-04-03 19:05:06 +08:00
parent 5c851ea250
commit d58c650d59
33 changed files with 574 additions and 1058 deletions
View File
+49
View File
@@ -0,0 +1,49 @@
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# ── 核心工具 ──
curl
git
micro
vim
wget
# ── 现代 CLI 替代 ──
bat # cat
btop # top
duf # df
dust # du
eza # ls
fd # find
jq # JSON
procs # ps
ripgrep # grep
sd # sed
xh # curl/httpie
yq # YAML
# ── 文件管理 ──
trash-cli
yazi
# ── 系统信息 ──
fastfetch
tealdeer # tldr
];
# ── Nix 设置 ──
nix.settings = {
experimental-features = [
"nix-command"
"flakes"
];
# 国内镜像(按需取消注释)
# substituters = [
# "https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store"
# "https://cache.nixos.org"
# ];
};
nixpkgs.config.allowUnfree = true;
}
-71
View File
@@ -1,71 +0,0 @@
from decman import File, Module
from decman.plugins.aur import packages as aur_packages
from decman.plugins.pacman import packages as pacman_packages
class BaseModule(Module):
def __init__(self, user: str):
super().__init__("base")
self.user = user
def files(self):
return {
"/etc/pacman.conf": File(
source_file="./system/etc/pacman.conf",
),
"/etc/pacman.d/mirrorlist": File(
source_file="./system/etc/pacman.d/mirrorlist",
),
"/etc/sudoers.d/10-wheel": File(
source_file="./system/etc/sudoers.d/10-wheel",
permissions=0o440,
),
f"/home/{self.user}/.config/git/config": File(
source_file="./home/.config/git/config",
owner=self.user,
),
f"/home/{self.user}/.config/starship.toml": File(
source_file="./home/.config/starship.toml",
owner=self.user,
),
}
@pacman_packages
def pacman_packages(self) -> set[str]:
return {
"atuin",
"base-devel",
"base",
"bat",
"btop",
"curl",
"direnv",
"duf",
"dust",
"eza",
"fastfetch",
"fd",
"git-delta",
"git",
"jq",
"micro",
"procs",
"ripgrep",
"sd",
"starship",
"sudo",
"tealdeer",
"trash-cli",
"vim",
"wget",
"xh",
"yazi",
"yq",
"zoxide",
}
@aur_packages
def aur_packages(self) -> set[str]:
return {
"decman",
}
+54
View File
@@ -0,0 +1,54 @@
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# ── 语言运行时 ──
bun
go
nodejs
# ── 包管理 / 版本管理 ──
mise
uv
# ── 编辑器 ──
neovim
# ── 终端复用 ──
tmux
zellij
# ── Git 增强 ──
delta # Arch 包名: git-delta
gh # Arch 包名: github-cli
lazygit
# ── Linter / Formatter ──
biome
ruff
shellcheck
shfmt
# ── LSP 服务器 ──
ast-grep
bash-language-server
gopls
typescript-language-server # 若报错尝试 nodePackages.typescript-language-server
yaml-language-server # 若报错尝试 nodePackages.yaml-language-server
vue-language-server # 替代原 bun -g @vue/language-server
dockerfile-language-server-nodejs # 替代原 bun -g dockerfile-language-server
# ── 原 bun/go 全局安装的工具 ──
# 以下工具如果在 nixpkgs 中不存在,需要自定义打包:
#
# opencode-ai:
# buildNpmPackage { pname = "opencode-ai"; ... }
#
# go-claude-code-comment-checker:
# buildGoModule {
# pname = "comment-checker";
# src = fetchFromGitHub { owner = "code-yeongyu"; repo = "..."; ... };
# vendorHash = "sha256-...";
# }
];
}
-69
View File
@@ -1,69 +0,0 @@
import decman
from decman import File, Module
from decman.plugins.pacman import packages as pacman_packages
BUN_GLOBAL_PACKAGES = [
"@vue/language-server",
"dockerfile-language-server", # TODO: 等 extra-testing -> extra 后改用 pacman
"opencode-ai",
]
GO_INSTALL_PACKAGES = [
"github.com/code-yeongyu/go-claude-code-comment-checker/cmd/comment-checker@latest",
]
class DevModule(Module):
def __init__(self, user: str):
super().__init__("dev")
self.user = user
def files(self):
return {
f"/home/{self.user}/.config/mise/config.toml": File(
source_file="./home/.config/mise/config.toml",
owner=self.user,
),
}
@pacman_packages
def pacman_packages(self) -> set[str]:
return {
"ast-grep",
"bash-language-server",
"biome",
"bun",
"github-cli",
"go",
"gopls",
"lazygit",
"mise",
"neovim",
"nodejs",
"ruff",
"shellcheck",
"shfmt",
"tmux",
"typescript-language-server",
"uv",
"yaml-language-server",
"zellij",
}
def after_update(self, store):
failures: list[str] = []
for pkg in BUN_GLOBAL_PACKAGES:
try:
decman.prg(["bun", "add", "-g", pkg], user=self.user, mimic_login=True)
except Exception as e:
failures.append(f"bun: {pkg} ({e})")
for pkg in GO_INSTALL_PACKAGES:
try:
decman.prg(["go", "install", pkg], user=self.user, mimic_login=True)
except Exception as e:
failures.append(f"go: {pkg} ({e})")
if failures:
print(f"\n{len(failures)} 个全局包安装失败:")
for f in failures:
print(f" - {f}")
print()
+17
View File
@@ -0,0 +1,17 @@
{ config, pkgs, ... }:
{
virtualisation.docker = {
enable = true;
};
environment.systemPackages = with pkgs; [
docker-compose
];
# 注:用户 docker 组权限在 hosts/*/default.nix 中配置
#
# WSL 环境下如使用 Docker Desktop,可改为:
# wsl.docker-desktop.enable = true;
# 并将上面的 virtualisation.docker.enable 设为 false
}
-29
View File
@@ -1,29 +0,0 @@
import subprocess
import decman
from decman import Module
from decman.plugins.pacman import packages as pacman_packages
from decman.plugins.systemd import units
class DockerModule(Module):
def __init__(self, user: str):
super().__init__("docker")
self.user = user
@pacman_packages
def pacman_packages(self) -> set[str]:
return {"docker", "docker-compose"}
@units
def units(self) -> set[str]:
return {"docker.socket"}
def after_update(self, store):
result = subprocess.run(
["id", "-nG", self.user], capture_output=True, text=True
)
if result.returncode != 0:
return
if "docker" not in result.stdout.split():
decman.prg(["gpasswd", "-a", self.user, "docker"])
+8
View File
@@ -0,0 +1,8 @@
{ config, ... }:
{
i18n = {
defaultLocale = "en_US.UTF-8";
supportedLocales = [ "en_US.UTF-8/UTF-8" ];
};
}
-16
View File
@@ -1,16 +0,0 @@
import decman
from decman import File, Module
class LocaleModule(Module):
def __init__(self):
super().__init__("locale")
def files(self):
return {
"/etc/locale.conf": File(content="LANG=en_US.UTF-8\n"),
"/etc/locale.gen": File(content="en_US.UTF-8 UTF-8\n"),
}
def on_change(self, store):
decman.prg(["locale-gen"])
+6
View File
@@ -0,0 +1,6 @@
{ config, pkgs, ... }:
{
# 系统级启用 Zsh(用户级配置在 home/shell.nix
programs.zsh.enable = true;
}
-48
View File
@@ -1,48 +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",
"oh-my-zsh-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])