一个 Nix flake 统治所有
Flakes 无疑已经成为常态,我对它们的看法也众所周知:它们是“一般”。尽管它们无处不在,但添加一个 flake 输入仍然是一种小烦恼,永远无法消失。人们将 flakes 的联邦特性视为一项积极功能,但现实是我更想要一个简单的集中式 flake。那正是 nixpkgs 的美和力量。流程是:你想要 disko,因此你添加一个 url,然后用 follows 使其停止拖动自己的 nixpkgs,然后再对下一个做同样的事。这在 Nix 社区中已经成为关于每个 flake 都拖动自己的 flake-utils 的梗。我拒绝接受这种用户体验。因此,我想知道:是否可以有一个 flake 携带所有其他 flake,你只需取用所需的部分?🤯 § Omniflake omniflake 是成千上万个 Nix flakes 背后的一个 flake 输入。 inputs . omniflake . url = "github:fzakaria/omniflake" ; inputs . omniflake . inputs . nixpkgs . follows = "nixpkgs" ; 一旦你有了 omniflake,你可以像使用其他输入一样使用它。一个包,在一个 shell 或系统中: environment . systemPackages = [ omniflake . flakes . nh . packages . ${ system } . default ]; 一个 overlay: nixpkgs . overlays = [ omniflake . flakes . rust-overlay . overlays . default ]; 一个 NixOS 模块: imports = [ omniflake . flakes . disko . nixosModules . disko ]; 或者直接从命令行中什么都不需要: $ nix run 'github:fzakaria/omniflake#flakes.nh.packages.x86_64-linux.default' -- --version 它有一个可访问的网站,你可以访问 https://omniflake.com/ 查看它携带的 flakes 列表和一些有用的文档。截至目前为止,添加后你可以懒惰地访问近一万两千个 flakes。你只需为你使用的部分付费。这听起来荒谬,但它确实有效。具有成千上万个输入的 flake 应该是不可用的,但得益于 Nix 语言的惰性和 flake 锁机制,它完美运行。如何能够将几乎每一个 flake 包含在这个中? § 关于 flakes 的简短入门 flake 是一个目录,包含一个 flake.nix 文件,该文件声明了两件事:输入(它所依赖的其他 flakes)和输出(这些输入的一个函数)。 { inputs . nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ; outputs = { self , nixpkgs }: { packages . x86_64-linux . hello = nixpkgs . legacyPackages . x86_64-linux . hello ; }; } inputs 表示你依赖的内容,宽泛而言:“nixos-unstable”是一个移动分支。旁边的 flake.lock 文件明确说明了其解析到的确切提交,因此构建是可重复的。这相当于 npm 的 package-lock.json 或 Cargo.lock 。锁文件并不仅仅锁定自己的输入。它还锁定了每一个 flake 的整个传递图。这意味着如果两个子 flake 都依赖于 nixpkgs,它们各自在锁文件中都将有自己的 nixpkgs 副本,并且可能是不同的提交。 { "nodes" : { "root" : { "inputs" : { "agenix" : "agenix" , "nixpkgs" : "nixpkgs" } }, "agenix" : { "inputs" : { "home-manager" : "home-manager" }, "locked" : { "rev" : "5182..." , "type" : "github" } }, "home-manager" : { "inputs" : { "nixpkgs" : "nixpkgs_2" }, ... }, "nixpkgs" : { "locked" : { "rev" : "9fbb..." , "type" : "github" } }, "nixpkgs_2" : { "locked" : { "rev" : "50ab..." , "type" : "github" } } } } 在此示例中,有两个 nixpkgs : nixpkgs 和 nixpkgs_2。这就是每个人抱怨的重复,之所以存在 follows 就是为了:follows 将一个依赖重定向为已经拥有的节点,而不是提取另一个副本。这样做虽然减少了图的规模,但不再是构建在作者测试的确切 nixpkgs 上。这里有一个简单的 flake,使用 follows 来统一 nixpkgs: { inputs = { nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ; disko . url = "github:nix-community/disko" ; disko . inputs . nixpkgs . follows = "nixpkgs" ; agenix . url = "github:ryantm/agenix" ; agenix . inputs . home-manager . inputs . nixpkgs . follows = "nixpkgs" ; }; } follows 你你的 flake disko disko 你->disko agenix agenix 你->agenix npkgs nixpkgs disko->npkgs follows hm home-manager agenix->hm hm->npkgs follows 实线表示输入;虚线表示跟随边,压缩到一个共享的 nixpkgs 上。 § 输入是惰性的 Nix 中许多疯狂事物的美在于它是一种惰性语言。一个没有输出触及的输入从未被提取。你可以通过破坏性方式证明这一点:锁定一个具有两个输入的 flake,然后损坏 flake.lock 中的一个条目,使其无法解析。 $ sed -i 's/2810303efc.../0000000000000000000000000000000000000000/' flake.lock $ nix eval .#justB [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ] 那在一个包含不存在修订的锁中评估得很好。只有强迫被污染的输入才会报错: $ nix eval .#useA error: unable to download '.../0000000000000000000000000000000000000000.tar.gz': HTTP error 404 当你将一个 flake 添加为输入时,它的整个传递图被复制到你的锁中作为元数据。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡