如何在 nix 中记录可重现的配置文件(尤其是来自 nix-env)?
How to record a reproducible profile in nix (especially from nix-env)?
所以,终于开始获得一个稳定的 nix 环境,我基本上可以在其中进行所有开发。万岁!
现在我想让它可重现,如 yarn.lock (for those familiar with npm/yarn in javascript land) or Pipfile.lock(与 Python 非常相似)。
基本上我的想法是,每当我 运行 nix-env -if my-env.nix
或 运行 执行此命令后,我都会有一种生成类似锁定文件的方法,如果是这样的话会工作。从这个锁定文件中,我可以准确地恢复我的 nix 配置文件,直到已安装配置文件的依赖项和子依赖项的确切版本。这可以在测试新改进后检查到 git 或其他任何内容,因此将维护环境记录。
在我看来,这将是 Nix 最明显的用例之一,也是仅使用 Docker 的主要优势之一(尽管两者并不相互排斥),所以我深表歉意如果我遗漏了一些相关文档。
经过IRC上很多人的建议,我整理了下面的脚本,它以一个nix表达式作为唯一的参数,并在安装指定环境的同时复制派生文件并在本地记录nixpkgs版本:
#!/bin/bash
if [ -z "" ] || [ "${1: -4}" != ".nix" ] || [ ! -f "" ]
then
echo "No .nix file supplied"
exit -1
fi
ENV_DRV=$(nix-instantiate "")
cp "$ENV_DRV" ./env_backup.drv
chmod u+rw ./env_backup.drv
nix-env --set "$ENV_DRV"
NIXPKGS_VERSION=$(nix-instantiate --eval '<nixpkgs/lib>' -A version)
NIXOS_VERSION=$(nix-instantiate --eval '<nixos/lib>' -A version)
printf "nixpkgs: %s\nnixos: %s" "$NIXPKGS_VERSION" "${NIXOS_VERSION}" > .nix_versions
警告:你的 nix 表达式应该包含 nix
包,因为我们使用的是 nix-env --set
.
我还没有尝试使用复制的 .drv 文件,但它需要以某种方式恢复到 nix 存储中;我主要把它作为最后的手段和调试。 .nix_versions
的输出应该更有帮助,因为它们包含 git 提交哈希(在最后一个“.”之后),可用于使用正确的 nixpkgs 修订版(感谢 IRC 上的 infinisil):
pkgs = import "${(import <nixpkgs> {}).fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; rev = "<your revision hash>"; sha256 = "<the hash of the output>"; }}" {}
要填写哈希值,请提供不正确的哈希值以返回正确的哈希值,或者只使用以下内容:nix-prefetch-url --unpack github.com/nixos/nixpkgs/archive/<revision>.tar.gz
.
或者,如果手动检查 nixpkgs,您可以执行例如:
with import ((builtins.getEnv "HOME") + "/workspace/nixpkgs") { }; # or:
with import "../nixpkgs" { }; # or similar
我还没有用 nix-shell
测试过这类东西,但希望尽快测试。
您可能正在寻找的是这样的 shell.nix
文件:
let
pkgs = import (fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
}) {};
in pkgs.mkShell {
buildInputs = with pkgs; [
git
hello
];
}
调用 nix-shell
(默认情况下使用当前目录中的 shell.nix
文件)后,您将处于 git
和 hello
的环境中具体给定的 nixpkgs 修订版。这可以在所有 nix 用户中重现(好吧几乎*)。我真的可以推荐使用 shell.nix
文件进行所有开发。
或者,还有一个鲜为人知的 -r
标志 nix-env
,它指出
--remove-all, -r
Remove all previously installed packages first. This is equivalent to running nix-env -e '.*' first, except that everything happens in a single transaction.
您可以有效地使用它来替换有状态的~/.nix-profile/manifest.nix
。创建一个文件 env.nix
包含:
let
pkgs = import <nixpkgs> {};
in {
inherit (pkgs) git hello;
}
现在 运行ning nix-env -ir env.nix
将完全安装 git
和 hello
并删除所有其他内容,因此您可以使用此单个文件重现您的 nix-env 安装。要安装其他东西:将其添加到文件中,然后再次 运行 命令。您还可以将 nixpkgs 固定到上面文件中的特定版本,而不关心您的 nix-channel
设置(这也是有状态的)。
编辑:也可以从您的频道获取一些软件包和一些特定的 nixpkgs 修订版:
let
pkgs = import <nixpkgs> {};
fixed = import (fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
}) {};
in {
inherit (pkgs) git;
inherit (fixed) hello;
}
*:nix 配置、叠加层和您的系统 (Linux/Mac) 仍然会影响这一点。最好使用 import <nixpkgs> { config = {}; overlays = []; }
进行开发以避免这种情况。
所以,终于开始获得一个稳定的 nix 环境,我基本上可以在其中进行所有开发。万岁!
现在我想让它可重现,如 yarn.lock (for those familiar with npm/yarn in javascript land) or Pipfile.lock(与 Python 非常相似)。
基本上我的想法是,每当我 运行 nix-env -if my-env.nix
或 运行 执行此命令后,我都会有一种生成类似锁定文件的方法,如果是这样的话会工作。从这个锁定文件中,我可以准确地恢复我的 nix 配置文件,直到已安装配置文件的依赖项和子依赖项的确切版本。这可以在测试新改进后检查到 git 或其他任何内容,因此将维护环境记录。
在我看来,这将是 Nix 最明显的用例之一,也是仅使用 Docker 的主要优势之一(尽管两者并不相互排斥),所以我深表歉意如果我遗漏了一些相关文档。
经过IRC上很多人的建议,我整理了下面的脚本,它以一个nix表达式作为唯一的参数,并在安装指定环境的同时复制派生文件并在本地记录nixpkgs版本:
#!/bin/bash
if [ -z "" ] || [ "${1: -4}" != ".nix" ] || [ ! -f "" ]
then
echo "No .nix file supplied"
exit -1
fi
ENV_DRV=$(nix-instantiate "")
cp "$ENV_DRV" ./env_backup.drv
chmod u+rw ./env_backup.drv
nix-env --set "$ENV_DRV"
NIXPKGS_VERSION=$(nix-instantiate --eval '<nixpkgs/lib>' -A version)
NIXOS_VERSION=$(nix-instantiate --eval '<nixos/lib>' -A version)
printf "nixpkgs: %s\nnixos: %s" "$NIXPKGS_VERSION" "${NIXOS_VERSION}" > .nix_versions
警告:你的 nix 表达式应该包含 nix
包,因为我们使用的是 nix-env --set
.
我还没有尝试使用复制的 .drv 文件,但它需要以某种方式恢复到 nix 存储中;我主要把它作为最后的手段和调试。 .nix_versions
的输出应该更有帮助,因为它们包含 git 提交哈希(在最后一个“.”之后),可用于使用正确的 nixpkgs 修订版(感谢 IRC 上的 infinisil):
pkgs = import "${(import <nixpkgs> {}).fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; rev = "<your revision hash>"; sha256 = "<the hash of the output>"; }}" {}
要填写哈希值,请提供不正确的哈希值以返回正确的哈希值,或者只使用以下内容:nix-prefetch-url --unpack github.com/nixos/nixpkgs/archive/<revision>.tar.gz
.
或者,如果手动检查 nixpkgs,您可以执行例如:
with import ((builtins.getEnv "HOME") + "/workspace/nixpkgs") { }; # or:
with import "../nixpkgs" { }; # or similar
我还没有用 nix-shell
测试过这类东西,但希望尽快测试。
您可能正在寻找的是这样的 shell.nix
文件:
let
pkgs = import (fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
}) {};
in pkgs.mkShell {
buildInputs = with pkgs; [
git
hello
];
}
调用 nix-shell
(默认情况下使用当前目录中的 shell.nix
文件)后,您将处于 git
和 hello
的环境中具体给定的 nixpkgs 修订版。这可以在所有 nix 用户中重现(好吧几乎*)。我真的可以推荐使用 shell.nix
文件进行所有开发。
或者,还有一个鲜为人知的 -r
标志 nix-env
,它指出
--remove-all, -r
Remove all previously installed packages first. This is equivalent to running nix-env -e '.*' first, except that everything happens in a single transaction.
您可以有效地使用它来替换有状态的~/.nix-profile/manifest.nix
。创建一个文件 env.nix
包含:
let
pkgs = import <nixpkgs> {};
in {
inherit (pkgs) git hello;
}
现在 运行ning nix-env -ir env.nix
将完全安装 git
和 hello
并删除所有其他内容,因此您可以使用此单个文件重现您的 nix-env 安装。要安装其他东西:将其添加到文件中,然后再次 运行 命令。您还可以将 nixpkgs 固定到上面文件中的特定版本,而不关心您的 nix-channel
设置(这也是有状态的)。
编辑:也可以从您的频道获取一些软件包和一些特定的 nixpkgs 修订版:
let
pkgs = import <nixpkgs> {};
fixed = import (fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
}) {};
in {
inherit (pkgs) git;
inherit (fixed) hello;
}
*:nix 配置、叠加层和您的系统 (Linux/Mac) 仍然会影响这一点。最好使用 import <nixpkgs> { config = {}; overlays = []; }
进行开发以避免这种情况。