query
On this page

findFile

builtins.findFile

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


Nix manual

Takes 2 arguments

search-path, lookup-path

Find lookup-path in search-path.

Lookup path expressions are desugared using this and builtins.nixPath:

<nixpkgs>

is equivalent to:

builtins.findFile builtins.nixPath "nixpkgs"

A search path is represented as a list of attribute sets with two attributes:

  • prefix is a relative path.
  • path denotes a file system location

Examples of search path attribute sets:

  • {
      prefix = "";
      path = "/nix/var/nix/profiles/per-user/root/channels";
    }
    
  • {
      prefix = "nixos-config";
      path = "/etc/nixos/configuration.nix";
    }
    
  • {
      prefix = "nixpkgs";
      path = "https://github.com/NixOS/nixpkgs/tarballs/master";
    }
    
  • {
      prefix = "nixpkgs";
      path = "channel:nixpkgs-unstable";
    }
    
  • {
      prefix = "flake-compat";
      path = "flake:github:edolstra/flake-compat";
    }
    

The lookup algorithm checks each entry until a match is found, returning a path value of the match:

  • If a prefix of lookup-path matches prefix, then the remainder of lookup-path (the "suffix") is searched for within the directory denoted by path. The contents of path may need to be downloaded at this point to look inside.

  • If the suffix is found inside that directory, then the entry is a match. The combined absolute path of the directory (now downloaded if need be) and the suffix is returned.

Example

A search-path value

[
  {
    prefix = "";
    path = "/home/eelco/Dev";
  }
  {
    prefix = "nixos-config";
    path = "/etc/nixos";
  }
]

and a lookup-path value "nixos-config" causes Nix to try /home/eelco/Dev/nixos-config and /etc/nixos in that order and return the first path that exists.

If path starts with http:// or https://, it is interpreted as the URL of a tarball to be downloaded and unpacked to a temporary location. The tarball must consist of a single top-level directory.

The URLs of the tarballs from the official nixos.org channels can be abbreviated as channel:<channel-name>. See documentation on nix-channel for details about channels.

Example

These two search path entries are equivalent:

  • {
      prefix = "nixpkgs";
      path = "channel:nixpkgs-unstable";
    }
    
  • {
      prefix = "nixpkgs";
      path = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
    }
    

Search paths can also point to source trees using flake URLs.

Example

The search path entry

{
  prefix = "nixpkgs";
  path = "flake:nixpkgs";
}

specifies that the prefix nixpkgs shall refer to the source tree downloaded from the nixpkgs entry in the flake registry.

Similarly

{
  prefix = "nixpkgs";
  path = "flake:github:nixos/nixpkgs/nixos-22.05";
}

makes <nixpkgs> refer to a particular branch of the NixOS/nixpkgs repository on GitHub.

Implementation

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

src/libexpr/primops.cc:2168

static void prim_findFile(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
    state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.findFile");

    LookupPath lookupPath;

    for (auto v2 : args[0]->listView()) {
        state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.findFile");

        std::string prefix;
        auto i = v2->attrs()->get(state.s.prefix);
        if (i)
            prefix = state.forceStringNoCtx(
                *i->value,
                pos,
                "while evaluating the `prefix` attribute of an element of the list passed to builtins.findFile");

        i = state.getAttr(state.s.path, v2->attrs(), "in an element of the __nixPath");

        NixStringContext context;
        auto path =
            state
                .coerceToString(
                    pos,
                    *i->value,
                    context,
                    "while evaluating the `path` attribute of an element of the list passed to builtins.findFile",
                    false,
                    false)
                .toOwned();

        try {
            auto rewrites = state.realiseContext(context);
            path = rewriteStrings(std::move(path), rewrites);
        } catch (InvalidPathError & e) {
            state.error<EvalError>("cannot find '%1%', since path '%2%' is not valid", path, e.path.to_string())
                .atPos(pos)
                .debugThrow();
        }

        lookupPath.elements.emplace_back(
            LookupPath::Elem{
                .prefix = LookupPath::Prefix{.s = std::move(prefix)},
                .path = LookupPath::Path{.s = std::move(path)},
            });
    }

    auto path =
        state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");

    v.mkPath(state.findFile(lookupPath, path, pos), state.mem);
}