我过去注意到在
nix
中,一个./myfile.txt
路径类型似乎
/home/myuser/mydir/myfile.txt
,和/nix/store/55j24v9qwdarikv7kd3lc0pvxdr9r2y8-myfile.txt
.我想知道到底是什么时候发生的。
这对于包含任何形式的秘密信息的文件尤为重要,因为
/nix/store
中的所有文件都可以被系统上的所有用户读取。
(使用
nixops
时,有一个特殊的“键”功能用于此目的,请参阅手册中的管理键部分,但我认为在中何时以及如何进行这种路径到存储路径的复制仍然很重要nix
本身。)
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);
}