toFile
builtins.toFile
Nix manual
Takes 2 arguments
name, s
Store the string s in a file in the Nix store and return its path. The file has suffix name. This file can be used as an input to derivations. One application is to write builders “inline”. For instance, the following Nix expression combines the Nix expression for GNU Hello and its build script into one file:
{ stdenv, fetchurl, perl }:
stdenv.mkDerivation {
name = "hello-2.1.1";
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
PATH=$perl/bin:$PATH
tar xvfz $src
cd hello-*
./configure --prefix=$out
make
make install
";
src = fetchurl {
url = "http://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz";
sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465";
};
inherit perl;
}
It is even possible for one file to refer to another, e.g.,
builder = let
configFile = builtins.toFile "foo.conf" "
# This is some dummy configuration file.
...
";
in builtins.toFile "builder.sh" "
source $stdenv/setup
...
cp ${configFile} $out/etc/foo.conf
";
Note that ${configFile} is a
string interpolation, so the result of the
expression configFile
(i.e., a path like /nix/store/m7p7jfny445k...-foo.conf) will be
spliced into the resulting string.
It is however not allowed to have files mutually referring to each other, like so:
let
foo = builtins.toFile "foo" "...${bar}...";
bar = builtins.toFile "bar" "...${foo}...";
in foo
This is not allowed because it would cause a cyclic dependency in
the computation of the cryptographic hashes for foo and bar.
It is also not possible to reference the result of a derivation. If
you are using Nixpkgs, the writeTextFile function is able to do
that.
Noogle detected
toFile :: Path -> String -> StorePath
Implementation
This function is implemented in c++ and is part of the native nix runtime.
static void prim_toFile(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
NixStringContext context;
auto name = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.toFile");
auto contents =
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.toFile");
StorePathSet refs;
for (auto c : context) {
if (auto p = std::get_if<NixStringContextElem::Opaque>(&c.raw)) {
state.ensureLazyPathCopied(p->path);
refs.insert(p->path);
} else
state
.error<EvalError>(
"files created by %1% may not reference derivations, but %2% references %3%",
"builtins.toFile",
name,
c.to_string())
.atPos(pos)
.debugThrow();
}
auto storePath = settings.readOnlyMode ? state.store->makeFixedOutputPathFromCA(
name,
TextInfo{
.hash = hashString(HashAlgorithm::SHA256, contents),
.references = std::move(refs),
})
: ({
StringSource s{contents};
state.store->addToStoreFromDump(
s,
name,
FileSerialisationMethod::Flat,
ContentAddressMethod::Raw::Text,
HashAlgorithm::SHA256,
refs,
state.repair);
});
/* Note: we don't need to add `context' to the context of the
result, since `storePath' itself has references to the paths
used in args[1]. */
/* Add the output of this to the allowed paths. */
state.allowAndSetStorePathString(storePath, v);
}