nix 路径类型何时进入 nix 存储区,何时不进入?
When does a nix path type make it into the nix store and when not?
我过去注意到 nix
中的 ./myfile.txt
路径类型似乎
- 有时计算为
/home/myuser/mydir/myfile.txt
,并且
- 有时
/nix/store/55j24v9qwdarikv7kd3lc0pvxdr9r2y8-myfile.txt
。
我想知道到底是什么时候发生的。
这对于包含任何形式的秘密信息的文件尤其重要,因为 /nix/store
中的所有文件对于系统上的所有用户都是全球可读的。
(当使用 nixops
时,有一个特殊的 "keys" 功能用于此目的,请参阅手册中的 Managing keys 部分,但我认为这条路径何时以及如何仍然很重要-存储路径复制发生在 nix
本身。)
#nixos
IRC 频道上的用户 clever
解释:
什么时候发生
当您在 ${}
字符串插值 中使用路径时, 会扩展到 /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 ("building") 不是.
为了实现这一点,nix
中的每个字符串都有一个 "context" 来跟踪字符串所依赖的内容(实际上是它后面的 .drv
路径列表)。
例如,来自 GNU hello
包的字符串 "/nix/store/rkvwvi007k7w8lp4cc0n10yhlz5xjfmk-hello-2.10"
有一些不可见的状态,表示它取决于 hello
推导。如果该字符串最终作为 stdenv.mkDerivation 的输入,新的推导将 "magically" 取决于正在构建的 hello
包。
即使您通过 builtins.substring
弄乱了字符串,这仍然有效。请参阅 nix 的 this code,了解如何在第 1653 行中提取较长字符串的上下文,并在第 1657 行中将其用作子字符串的上下文。
您可以使用 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);
实现了here, and the check for the interpolated thing being a ./path
, and the copying to /nix/store
, is happening just below:
if (v.type == tPath) {
Path path(canonPath(v.path));
return copyToStore ? copyPathToStore(context, path) : path;
}
toString
是用 prim_toString
实现的,它为 copyToStore
参数传递 false
:
/* 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);
}
我过去注意到 nix
中的 ./myfile.txt
路径类型似乎
- 有时计算为
/home/myuser/mydir/myfile.txt
,并且 - 有时
/nix/store/55j24v9qwdarikv7kd3lc0pvxdr9r2y8-myfile.txt
。
我想知道到底是什么时候发生的。
这对于包含任何形式的秘密信息的文件尤其重要,因为 /nix/store
中的所有文件对于系统上的所有用户都是全球可读的。
(当使用 nixops
时,有一个特殊的 "keys" 功能用于此目的,请参阅手册中的 Managing keys 部分,但我认为这条路径何时以及如何仍然很重要-存储路径复制发生在 nix
本身。)
#nixos
IRC 频道上的用户 clever
解释:
什么时候发生
当您在 ${}
字符串插值 中使用路径时, 会扩展到 /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 ("building") 不是.
为了实现这一点,nix
中的每个字符串都有一个 "context" 来跟踪字符串所依赖的内容(实际上是它后面的 .drv
路径列表)。
例如,来自 GNU hello
包的字符串 "/nix/store/rkvwvi007k7w8lp4cc0n10yhlz5xjfmk-hello-2.10"
有一些不可见的状态,表示它取决于 hello
推导。如果该字符串最终作为 stdenv.mkDerivation 的输入,新的推导将 "magically" 取决于正在构建的 hello
包。
即使您通过 builtins.substring
弄乱了字符串,这仍然有效。请参阅 nix 的 this code,了解如何在第 1653 行中提取较长字符串的上下文,并在第 1657 行中将其用作子字符串的上下文。
您可以使用 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);
实现了here, and the check for the interpolated thing being a ./path
, and the copying to /nix/store
, is happening just below:
if (v.type == tPath) {
Path path(canonPath(v.path));
return copyToStore ? copyPathToStore(context, path) : path;
}
toString
是用 prim_toString
实现的,它为 copyToStore
参数传递 false
:
/* 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);
}