Nix 路径类型在转换为字符串时何时进入 Nix 存储区,何时不进入?

问题描述 投票:0回答:1

我过去注意到在

nix
中,一个
./myfile.txt
路径类型似乎

  • 有时评估为
    /home/myuser/mydir/myfile.txt
    ,和
  • 有时到
    /nix/store/55j24v9qwdarikv7kd3lc0pvxdr9r2y8-myfile.txt
    .

我想知道到底是什么时候发生的。

这对于包含任何形式的秘密信息的文件尤为重要,因为

/nix/store
中的所有文件都可以被系统上的所有用户读取。

(使用

nixops
时,有一个特殊的“键”功能用于此目的,请参阅手册中的管理键部分,但我认为在
中何时以及如何进行这种路径到存储路径的复制仍然很重要nix
本身。)

nix nixos
1个回答
34
投票

clever
IRC频道的用户
#nixos
解释:

什么时候发生

当您在

/nix/store/...
字符串插值中使用路径时,会发生
扩展为
${}
,例如
mystring = "cat ${./myfile.txt}
.

使用

toString
功能时不会发生,例如
toString ./myfile.txt
不会给你一条指向
/nix/store
的路径。

例如:

toString ./notes.txt == "/home/clever/apps/nixos-installer/installer-gui/notes.txt"
"${./notes.txt}"     == "/nix/store/55j24v9qwdarikv7kd3lc0pvxdr9r2y8-notes.txt"

它是如何发生的

55j24v9qwdarikv7kd3lc0pvxdr9r2y8
哈希部分取自
./path
引用的文件的内容,因此它会随着文件的变化而变化,依赖它的东西可以相应地重建。

文件复制到

/nix/store
发生在
nix-instantiate
时; nix 表达式的 evaluation 仍然是纯函数式的(在求值时没有复制发生),但是 instantiation(“构建”)不是。

为了使这成为可能,

nix
中的每个字符串都有一个“上下文”来跟踪字符串所依赖的内容(实际上是它背后的
.drv
路径列表)。

例如,

"/nix/store/rkvwvi007k7w8lp4cc0n10yhlz5xjfmk-hello-2.10"
包中的字符串
GNU hello
有一些不可见的状态,也就是说它取决于
hello
的推导。如果该字符串最终作为 stdenv.mkDerivation 的输入,新生成的推导将“神奇地”取决于正在构建的
hello
包。

即使您通过

builtins.substring
弄乱了字符串,这仍然有效。有关如何在第 1653 行提取较长字符串的上下文,并在第 1657 行用作子字符串的上下文,请参见 nix 的this code

您可以使用

builtins.unsafeDiscardStringContext
摆脱字符串的依赖上下文。

nix
代码中发生的地方

${}
插值使用
coerceToString
,它有一个
bool copyToStore
参数默认为
true

/* String coercion.  Converts strings, paths and derivations to a
   string.  If `coerceMore' is set, also converts nulls, integers,
   booleans and lists to a string.  If `copyToStore' is set,
   referenced paths are copied to the Nix store as a side effect. */
string coerceToString(const Pos & pos, Value & v, PathSet & context,
                      bool coerceMore = false, bool copyToStore = true);

它是在这里实现的,并且检查内插的东西是

./path
,并且复制到
/nix/store
,正在发生就在下面

if (v.type == tPath) {
    Path path(canonPath(v.path));
    return copyToStore ? copyPathToStore(context, path) : path;
}

toString
是用
prim_toString
实现的,它通过
false
copyToStore
参数:

/* Convert the argument to a string.  Paths are *not* copied to the
   store, so `toString /foo/bar' yields `"/foo/bar"', not
   `"/nix/store/whatever..."'. */
static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
    PathSet context;
    string s = state.coerceToString(pos, *args[0], context, true, false);
    mkString(v, s, context);
}
© www.soinside.com 2019 - 2024. All rights reserved.