1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-19 10:50:24 -04:00

Factor out flake:... lookup path from evaluator

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
John Ericson 2024-06-24 17:33:15 -04:00
parent 88f9d8ccb1
commit 52730d38e2
4 changed files with 68 additions and 20 deletions

View file

@ -15,7 +15,20 @@
namespace nix { namespace nix {
EvalSettings evalSettings { EvalSettings evalSettings {
settings.readOnlyMode settings.readOnlyMode,
{
{
"flake",
[](ref<Store> store, std::string_view rest) {
experimentalFeatureSettings.require(Xp::Flakes);
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(std::string { rest }, {}, true, false);
debug("fetching flake search path element '%s''", rest);
auto storePath = flakeRef.resolve(store).fetchTree(store).first;
return store->toRealPath(storePath);
},
},
},
}; };
static GlobalConfig::Register rEvalSettings(&evalSettings); static GlobalConfig::Register rEvalSettings(&evalSettings);

View file

@ -45,8 +45,9 @@ static Strings parseNixPath(const std::string & s)
return res; return res;
} }
EvalSettings::EvalSettings(bool & readOnlyMode) EvalSettings::EvalSettings(bool & readOnlyMode, EvalSettings::LookupPathHooks lookupPathHooks)
: readOnlyMode{readOnlyMode} : readOnlyMode{readOnlyMode}
, lookupPathHooks{lookupPathHooks}
{ {
auto var = getEnv("NIX_PATH"); auto var = getEnv("NIX_PATH");
if (var) nixPath = parseNixPath(*var); if (var) nixPath = parseNixPath(*var);

View file

@ -5,9 +5,40 @@
namespace nix { namespace nix {
class Store;
struct EvalSettings : Config struct EvalSettings : Config
{ {
EvalSettings(bool & readOnlyMode); /**
* Function used to interpet look path entries of a given scheme.
*
* The argument is the non-scheme part of the lookup path entry (see
* `LookupPathHooks` below).
*
* The return value is (a) whether the entry was valid, and, if so,
* what does it map to.
*
* @todo Return (`std::optional` of) `SourceAccssor` or something
* more structured instead of mere `std::string`?
*/
using LookupPathHook = std::optional<std::string>(ref<Store> store, std::string_view);
/**
* Map from "scheme" to a `LookupPathHook`.
*
* Given a lookup path value (i.e. either the whole thing, or after
* the `<key>=`) in the form of:
*
* ```
* <scheme>:<arbitrary string>
* ```
*
* if `<scheme>` is a key in this map, then `<arbitrary string>` is
* passed to the hook that is the value in this map.
*/
using LookupPathHooks = std::map<std::string, std::function<LookupPathHook>>;
EvalSettings(bool & readOnlyMode, LookupPathHooks lookupPathHooks = {});
bool & readOnlyMode; bool & readOnlyMode;
@ -17,6 +48,8 @@ struct EvalSettings : Config
static std::string resolvePseudoUrl(std::string_view url); static std::string resolvePseudoUrl(std::string_view url);
LookupPathHooks lookupPathHooks;
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation", R"( Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation", R"(
Enable built-in functions that allow executing native code. Enable built-in functions that allow executing native code.

View file

@ -2760,14 +2760,18 @@ std::optional<std::string> EvalState::resolveLookupPathPath(const LookupPath::Pa
auto i = lookupPathResolved.find(value); auto i = lookupPathResolved.find(value);
if (i != lookupPathResolved.end()) return i->second; if (i != lookupPathResolved.end()) return i->second;
std::optional<std::string> res; auto finish = [&](std::string res) {
debug("resolved search path element '%s' to '%s'", value, res);
lookupPathResolved.emplace(value, res);
return res;
};
if (EvalSettings::isPseudoUrl(value)) { if (EvalSettings::isPseudoUrl(value)) {
try { try {
auto accessor = fetchers::downloadTarball( auto accessor = fetchers::downloadTarball(
EvalSettings::resolvePseudoUrl(value)).accessor; EvalSettings::resolvePseudoUrl(value)).accessor;
auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy); auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy);
res = { store->toRealPath(storePath) }; return finish(store->toRealPath(storePath));
} catch (Error & e) { } catch (Error & e) {
logWarning({ logWarning({
.msg = HintFmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value) .msg = HintFmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value)
@ -2775,15 +2779,17 @@ std::optional<std::string> EvalState::resolveLookupPathPath(const LookupPath::Pa
} }
} }
else if (hasPrefix(value, "flake:")) { if (auto colPos = value.find(':'); colPos != value.npos) {
experimentalFeatureSettings.require(Xp::Flakes); auto scheme = value.substr(0, colPos);
auto flakeRef = parseFlakeRef(value.substr(6), {}, true, false); auto rest = value.substr(colPos + 1);
debug("fetching flake search path element '%s''", value); if (auto * hook = get(settings.lookupPathHooks, scheme)) {
auto storePath = flakeRef.resolve(store).fetchTree(store).first; auto res = (*hook)(store, rest);
res = { store->toRealPath(storePath) }; if (res)
return finish(std::move(*res));
}
} }
else { {
auto path = absPath(value); auto path = absPath(value);
/* Allow access to paths in the search path. */ /* Allow access to paths in the search path. */
@ -2800,22 +2806,17 @@ std::optional<std::string> EvalState::resolveLookupPathPath(const LookupPath::Pa
} }
if (pathExists(path)) if (pathExists(path))
res = { path }; return finish(std::move(path));
else { else {
logWarning({ logWarning({
.msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value) .msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value)
}); });
res = std::nullopt;
} }
} }
if (res) debug("failed to resolve search path element '%s'", value);
debug("resolved search path element '%s' to '%s'", value, *res); return std::nullopt;
else
debug("failed to resolve search path element '%s'", value);
lookupPathResolved.emplace(value, res);
return res;
} }