findFile
builtins.findFile
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:
prefixis a relative path.pathdenotes 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-pathmatchesprefix, then the remainder of lookup-path (the "suffix") is searched for within the directory denoted bypath. The contents ofpathmay 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-configand/etc/nixosin 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
nixpkgsshall refer to the source tree downloaded from thenixpkgsentry in the flake registry.Similarly
{ prefix = "nixpkgs"; path = "flake:github:nixos/nixpkgs/nixos-22.05"; }makes
<nixpkgs>refer to a particular branch of theNixOS/nixpkgsrepository on GitHub.
Implementation
This function is implemented in c++ and is part of the native nix runtime.
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);
}