-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lazy fetchTree
outPath
path values
#10252
Changes from all commits
202b188
fece409
fa2ad13
9707d2f
bde36d8
6f01e4b
446d59b
4332b9a
e21e54e
23d8c06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -428,6 +428,7 @@ EvalState::EvalState( | |
{ | ||
corepkgsFS->setPathDisplay("<nix", ">"); | ||
internalFS->setPathDisplay("«nix-internal»", ""); | ||
rootFS->setPathDisplay("/", ""); | ||
|
||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0"; | ||
|
||
|
@@ -902,6 +903,11 @@ void Value::mkPath(const SourcePath & path) | |
mkPath(&*path.accessor, makeImmutableString(path.path.abs())); | ||
} | ||
|
||
void EvalState::registerAccessor(const ref<InputAccessor> accessor) | ||
{ | ||
inputAccessors.push_back(accessor); | ||
} | ||
|
||
|
||
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) | ||
{ | ||
|
@@ -1985,10 +1991,22 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * const * lists, co | |
v.mkList(list); | ||
} | ||
|
||
// FIXME limit recursion | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Known issue, solve later with #10240 |
||
Value * resolveOutPath(EvalState & state, Value * v, const PosIdx pos) | ||
{ | ||
state.forceValue(*v, pos); | ||
if (v->type() != nAttrs) | ||
return v; | ||
auto found = v->attrs->find(state.sOutPath); | ||
if (found != v->attrs->end()) | ||
return resolveOutPath(state, found->value, pos); | ||
return v; | ||
} | ||
|
||
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) | ||
{ | ||
NixStringContext context; | ||
std::shared_ptr<InputAccessor> accessor; | ||
std::vector<BackedStringView> s; | ||
size_t sSize = 0; | ||
NixInt n = 0; | ||
|
@@ -2022,15 +2040,19 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) | |
Value * vTmpP = values.data(); | ||
|
||
for (auto & [i_pos, i] : *es) { | ||
Value & vTmp = *vTmpP++; | ||
i->eval(state, env, vTmp); | ||
Value & vTmp0 = *vTmpP++; | ||
i->eval(state, env, vTmp0); | ||
Value & vTmp = *resolveOutPath(state, &vTmp0, i_pos); | ||
|
||
/* If the first element is a path, then the result will also | ||
be a path, we don't copy anything (yet - that's done later, | ||
since paths are copied when they are used in a derivation), | ||
and none of the strings are allowed to have contexts. */ | ||
if (first) { | ||
firstType = vTmp.type(); | ||
if (firstType == nPath) { | ||
accessor = vTmp.path().accessor; | ||
} | ||
Comment on lines
+2043
to
+2055
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar but not equal to lazy-trees.
|
||
} | ||
|
||
if (firstType == nInt) { | ||
|
@@ -2072,7 +2094,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) | |
else if (firstType == nPath) { | ||
if (!context.empty()) | ||
state.error<EvalError>("a string that refers to a store path cannot be appended to a path").atPos(pos).withFrame(env, *this).debugThrow(); | ||
v.mkPath(state.rootPath(CanonPath(canonPath(str())))); | ||
v.mkPath({ref(accessor), CanonPath(str())}); | ||
} else | ||
v.mkStringMove(c_str(), context); | ||
} | ||
|
@@ -2322,6 +2344,8 @@ BackedStringView EvalState::coerceToString( | |
v._path.path | ||
: copyToStore | ||
? store->printStorePath(copyPathToStore(context, v.path())) | ||
: v.path().accessor->toStringReturnsStorePath() | ||
? store->printStorePath(copyPathToStore(context, SourcePath(v.path().accessor, CanonPath::root))) + v.path().path.absOrEmpty() | ||
Comment on lines
+2347
to
+2348
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is new, in order for |
||
: std::string(v.path().path.abs()); | ||
} | ||
|
||
|
@@ -2434,10 +2458,15 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext | |
if (v.type() == nPath) | ||
return v.path(); | ||
|
||
/* Similarly, handle __toString where the result may be a path | ||
/* Similarly, handle outPath and __toString where the result may be a path | ||
value. */ | ||
if (v.type() == nAttrs) { | ||
auto i = v.attrs->find(sToString); | ||
auto i = v.attrs->find(sOutPath); | ||
if (i != v.attrs->end()) { | ||
return coerceToPath(pos, *i->value, context, errorCtx); | ||
} | ||
Comment on lines
+2464
to
+2467
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This rule is not new. Previously, it would have worked by falling through to the |
||
|
||
i = v.attrs->find(sToString); | ||
if (i != v.attrs->end()) { | ||
Value v1; | ||
callFunction(*i->value, v, v1, pos); | ||
|
@@ -2835,8 +2864,8 @@ SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_ | |
if (!rOpt) continue; | ||
auto r = *rOpt; | ||
|
||
Path res = suffix == "" ? r : concatStrings(r, "/", suffix); | ||
if (pathExists(res)) return rootPath(CanonPath(canonPath(res))); | ||
auto res = r / suffix; | ||
if (res.pathExists()) return res; | ||
} | ||
|
||
if (hasPrefix(path, "nix/")) | ||
|
@@ -2851,20 +2880,22 @@ SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_ | |
} | ||
|
||
|
||
std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Path & value0, bool initAccessControl) | ||
std::optional<SourcePath> EvalState::resolveSearchPathPath(const SearchPath::Path & value0, bool initAccessControl) | ||
{ | ||
auto & value = value0.s; | ||
auto i = searchPathResolved.find(value); | ||
if (i != searchPathResolved.end()) return i->second; | ||
|
||
std::optional<std::string> res; | ||
std::optional<SourcePath> res; | ||
|
||
if (EvalSettings::isPseudoUrl(value)) { | ||
try { | ||
auto accessor = fetchers::downloadTarball( | ||
EvalSettings::resolvePseudoUrl(value)).accessor; | ||
// Traditional search path lookups use the absolute path space for | ||
// historical consistency. | ||
auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy); | ||
res = { store->toRealPath(storePath) }; | ||
res.emplace(rootPath(CanonPath(store->toRealPath(storePath)))); | ||
} catch (Error & e) { | ||
logWarning({ | ||
.msg = HintFmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value) | ||
|
@@ -2876,28 +2907,28 @@ std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Pa | |
experimentalFeatureSettings.require(Xp::Flakes); | ||
auto flakeRef = parseFlakeRef(value.substr(6), {}, true, false); | ||
debug("fetching flake search path element '%s''", value); | ||
auto storePath = flakeRef.resolve(store).fetchTree(store).first; | ||
res = { store->toRealPath(storePath) }; | ||
auto accessor = flakeRef.resolve(store).lazyFetch(store).first; | ||
res.emplace(SourcePath(accessor)); | ||
} | ||
|
||
else { | ||
auto path = absPath(value); | ||
auto path = rootPath(value); | ||
|
||
/* Allow access to paths in the search path. */ | ||
if (initAccessControl) { | ||
allowPath(path); | ||
if (store->isInStore(path)) { | ||
allowPath(path.path.abs()); | ||
if (store->isInStore(path.path.abs())) { | ||
try { | ||
StorePathSet closure; | ||
store->computeFSClosure(store->toStorePath(path).first, closure); | ||
store->computeFSClosure(store->toStorePath(path.path.abs()).first, closure); | ||
for (auto & p : closure) | ||
allowPath(p); | ||
} catch (InvalidPath &) { } | ||
} | ||
} | ||
|
||
if (pathExists(path)) | ||
res = { path }; | ||
if (path.pathExists()) | ||
res.emplace(path); | ||
else { | ||
logWarning({ | ||
.msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is like lazy-trees, except we only do it so that we don't destroy them when we put a non-smart pointer in
Value
, which has no finalizer because of GC and performance.