query
On this page

toFile

builtins.toFile

Primop
Docs pulled from | This Revision | about 10 hours ago


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

Aliases

Detected Type
toFile :: Path -> String -> StorePath

Implementation

This function is implemented in c++ and is part of the native nix runtime.

src/libexpr/primops.cc:2676

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);
}