背景
我在上一篇文章构建下一代个人开发环境提到的解决方案,在推广给组内同事使用过程中,大家用得挺愉快,也提了一些改进意见。主要是易用性上,比如要修改的配置较分散,比如能否一键安装。当然可以,趁周末通通安排上。顺便将相关示例代码整理开源到Github。
快速上手
如果你还没试用过,欢迎参考README中说明,只需执行以下命令,根据提示一路下去即可:
1
| sh <(curl -L https://raw.githubusercontent.com/kevin1sMe/dev-with-nix/main/install)
|
脚本主要做了如下事情:
- 检查 Nix 是否已安装: 如果已安装,则跳过安装步骤;如果未安装,将自动进行安装。
- 配置 Nix: 开启 Nix 的 Flakes 功能。
- 克隆项目仓库: 克隆
dev-with-nix
仓库到本地。
之后请参考config-tmpl.toml
来建立个人配置~/.dev-with-nix.toml
并执行
1
| nix run nixpkgs#home-manager -- switch --flake .#dev --impure
|
即可开始配置个人环境。初次会下载比较多的软件包(用时视你网络而定),请起身去喝杯水吧~~
如果上面默认的配置已经够了,就可以到此为止。但如果不满足你的需求,接下来聊聊如何一步步调整到你所需。
如何自定义你的修改?
我建议你fork下本仓库,然后做一些调整。以下将详细讲述如何调整为你的私有配置。
如何安装软件
本套方案基于home-manager来管理软件包,你可以看到home-manager/home.nix
中的home.packages:
1
2
3
4
5
6
7
8
9
10
| home.packages = with pkgs; [
python3
git
openssh
curl
htop
lsof
neofetch
...
];
|
如果不需要指定版本,则直接增加对应软件名即可,当前所支持的软件列表可以从NixOS Search Packages,主流的软件应该都有。
如何安装指定版本的软件
大多数时候home-manager会设置使用和nixpkgs相同的源,这块定义见flake.nix
:
1
2
3
4
5
| # home-manager,用于管理用户配置
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
|
那么要安装指定版本的软件,比如我们在用k8s时,对kubectl的版本会有要求,通过上面方式安装的版本可能较高非你所希望的,比如我们想要安装v1.23.4版本,这需要从nixpkgs的历史中找到对应版本的commit,如下示例展示了如何配置它:
首先,在flake.nix中的inputs部分指定对应版本的nixpkgs:
1
2
| # 给指定版本的kubectl使用的nixpkgs
nixpkgs-for-kubectl.url = "github:NixOS/nixpkgs/e7e54ace729a1e88177c0121d05f35352b05aed8";
|
然后将这个输入传递给outputs:
1
| outputs = { self, nixpkgs, nixpkgs-for-kubectl, home-manager, nvimdots, ... } @inputs:
|
最后,将它一路传给home-manager,然后将它加入到home.packages列表中即可,详情请参考仓库中的做法。
如何安装不在仓库中的软件
这个分两部分,有一些提供了下载链接的软件,我们可以写个flake来下载,有些软件可能是私有的需要构建的,我们要让它自动构建安装到系统中。具体如下:
基于下载链接安装软件
在这里有个示例home-manager/apps/k9s.nix
,展示了怎样基于URL安装:
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
| { stdenv, fetchurl, lib }:
# 这是一个示例:解释了如何下载一个二进制文件并安装到 $out/bin 目录下
# 安装指定版本的软件
stdenv.mkDerivation rec {
pname = "k9s";
version = "0.27.4";
src = fetchurl {
url = "https://github.com/derailed/k9s/releases/download/v${version}/k9s_Linux_amd64.tar.gz";
sha256 = "sha256-5QeDHr1fm4wDgPISZp81LG40y3YMkWtJi6uui+g8Q5I=";
};
setSourceRoot = "sourceRoot=$(mktemp -d)";
sourceRoot = ".";
phases = [ "unpackPhase" "installPhase" ];
unpackPhase = ''
tar -xvf $src -C $sourceRoot
ls -al $sourceRoot
'';
installPhase = ''
ls -la $sourceRoot
mkdir -p $out/bin
cp -a k9s $out/bin/
'';
meta = with lib; {
description = "Kubernetes CLI To Manage Your Clusters In Style!";
homepage = "https://github.com/derailed/k9s";
license = licenses.asl20;
platforms = platforms.linux;
};
}
|
可能遇上的一个问题是上面sha256不知道填什么,可以先设置为空,然后第一次构建会报错,同时会提示远端的sha值是多少,复制过去即可。
基于仓库自动构建软件包
nix提供了很多构建软件的库,C/C++、Go、Rust等一应俱全,我在home-manager/apps/go-example.nix
展示了如何构建一个Go程序:
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
| { lib, buildGoModule, fetchFromGitHub }:
# 这是一个示例,基于某个仓库编译构建,生成相关的二进制文件
buildGoModule rec {
pname = "go-dnsmasq";
version = "unstable-2022-07-19"; # 添加实际的提交日期
src = fetchFromGitHub {
owner = "kevin1sMe";
repo = pname;
rev = "6505b037c29de3b4cc6e1ddfab570cefd360c395"; # 添加你想要打包的版本的commit hash
sha256 = "sha256-3b4K0kx10SJ9OAv6cEK52PBSRJC/bUuULKdufBFPapA="; # 添加正确的SHA-256哈希
};
vendorSha256 = "sha256-0DqS/scc4MD+KVs9lGC6t0hHNCaYLf56k0W1bk5cE9s="; # 添加正确的SHA-256哈希
subPackages = [ "cmd/dnsmasq" ]; # 打包的子目录路径
meta = with lib; {
description = "A golang dnsmasq application"; # 添加合适的描述
homepage = "https://github.com/kevin1sMe/go-dnsmasq";
license = licenses.mit; # 确保许可证匹配实际项目许可证
platforms = platforms.unix;
maintainers = with maintainers; [ kevinlin ]; # 将其替换为你的名字
};
}
|
同样的,上面的sha值不知道怎么写就填空,等报错再来覆盖上。不过网上也有开源工具直接帮你计算获得这个值,我感觉…好像也没太大必要:)
如何定义程序的配置
home-manager给我们提供了不少的程序配置能力,可以在这里看到,比如我们想配置zsh:
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
| {userConfig}:
{
programs.zsh = {
enable = true;
enableCompletion = true;
enableAutosuggestions = true;
syntaxHighlighting.enable = true;
oh-my-zsh = {
enable = true;
plugins = [ "vi-mode" "z" "colored-man-pages" "sudo" "last-working-dir" ];
theme = "dst";
};
initExtra = ''
bindkey '^f' autosuggest-accept
neofetch
'';
# 设置一些alias
shellAliases = {
k = "kubectl";
b = "byobu";
};
};
programs.fzf = {
enable = true;
enableZshIntegration = true;
};
}
|
定义了部分配置让zsh更好用,并且使用了oh-my-zsh
的配置方案,这过程你居然都不用关心怎么安装下载它,直接声明使用它的哪些插件即可。或许这就是声明式开发环境的另一个魅力所在吧:)
如何定义个人配置
可能你还有一些配置,比如.gitconfig
的配置,甚至涉及个人敏感信息,这里提供一个配置思路。你可以看到在home-manager/files/gitconfig
中的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 省略...
[push]
default = simple
[log]
date = local
# User信息是在构建后自动被替换的,你不必修改这里
[user]
name = REPLACE_NAME_AUTO
email = REPLACE_EMAIL_AUTO
# ...
|
我们提交到仓库中的配置不想带上敏感信息,可以通过外部配置去渲染它。比如在~/.dev-with-nix.toml
中(模版见config-tmpl.toml
)定义:
1
2
3
| [gitconfig]
name = "kevin"
email = "abc@gmail.com"
|
然后只要写一个简单的nix表达式即可:
1
2
3
4
5
6
7
8
9
10
11
12
| {userConfig, ...}:
# 这是一个示例,如何设置一些用户配置
let
# 设置git配置
gitConfigContent = builtins.readFile ../files/gitconfig;
in
{
#name = REPLACE_NAME_AUTO
#email = REPLACE_EMAIL_AUTO
# 将内容中的name/email替换为用户输入的值
home.file.".gitconfig".text = builtins.replaceStrings ["REPLACE_NAME_AUTO" "REPLACE_EMAIL_AUTO"] [userConfig.gitconfig.name userConfig.gitconfig.email] gitConfigContent;
}
|
这里参数userConfig是用户配置,即~/.dev-with-nix.toml
,它将自动解析为nix中可引用的对象。其它的可以明文保存的文件,参考仓库中对于[neofetch
]home-manager/files/neofetch的做法。
如何设置环境变量
有时我们会有些变量希望可以从外部传递,并且经常有些敏感信息,当然不能放在仓库中明文写,所以同样的,当前我们可以继续写到私有文件~/.dev-with-nix.toml
中,然后将它追加到home.sessionVariables
中(这是home-manager的能力)。
1
2
3
4
5
6
7
8
9
10
11
| { userConfig, ... }:
let
envs = builtins.concatStringsSep " + " (builtins.attrNames userConfig.env);
appendEnvs = builtins.trace "user append envs: *** ${envs} ***" userConfig.env;
in
{
home.sessionVariables = {
# 默认编辑器
EDITOR = "nvim";
} // appendEnvs;
}
|
之后我们只要在配置文件中类似如下定义键值对即可:
1
2
3
4
| # 在这里添加一些希望设定的环境变量
[env]
WELCOME_TO_USE_NIX = "greet from kevin"
TEST="abc"
|
后记
相信通过上文,你已经学会了如何打造自己私人化开发环境了。请记得将它保存到版本控制仓库中,未来随时随地可重现你的环境。这个方案当前对于如何保存个人配置,有朋友建议将私有化的个人配置也保存在另一个仓库中,然后将它以inputs传递给falke,我感觉也挺有道理,全面的声明式,你说呢?
本文仅限我当前对Nix的了解,若有错漏欢迎指出哈!
本项目仓库的README的中英文是GPT给我写的,感谢它!配的表情真棒:)
最后,欢迎试用,有问题请留言或在Github提Issue。
-EOF