mirror of
https://github.com/NixOS/nix.git
synced 2025-11-23 02:39:37 +01:00
Make path values lazy
This fixes the double copy problem and improves performance
for expressions that don't force the whole source to be added to the
store.
Rules for fast expressions:
- Use path literals where possible
- import ./foo.nix
- Use + operator with slash in string
- src = fetchTree foo + "/src";
- Use source filtering, lib.fileset
- AVOID toString
- If possible, AVOID interpolations ("${./.}")
- If possible, move slashes into the interpolation to add less to the store
- "${./src}/foo" -> "${./src/foo}"
toString may be improved later as part of lazy-trees, so these
recommendations are a snapshot. Path values are quite nice though.
This commit is contained in:
parent
b79c918e09
commit
ee6a764988
7 changed files with 58 additions and 13 deletions
|
|
@ -1978,6 +1978,7 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * const * lists, co
|
|||
v.mkList(list);
|
||||
}
|
||||
|
||||
// FIXME limit recursion
|
||||
Value * resolveOutPath(EvalState & state, Value * v, const PosIdx pos)
|
||||
{
|
||||
state.forceValue(*v, pos);
|
||||
|
|
@ -2335,6 +2336,8 @@ BackedStringView EvalState::coerceToString(
|
|||
v.payload.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()
|
||||
: std::string(v.path().path.abs());
|
||||
}
|
||||
|
||||
|
|
@ -2447,10 +2450,14 @@ 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);
|
||||
}
|
||||
i = v.attrs()->find(sToString);
|
||||
if (i != v.attrs()->end()) {
|
||||
Value v1;
|
||||
callFunction(*i->value, v, v1, pos);
|
||||
|
|
@ -3115,6 +3122,8 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
|
|||
store,
|
||||
fetchSettings,
|
||||
EvalSettings::resolvePseudoUrl(value));
|
||||
// Traditional search path lookups use the absolute path space for
|
||||
// historical consistency.
|
||||
auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy);
|
||||
res.emplace(rootPath(CanonPath(store->toRealPath(storePath))));
|
||||
} catch (Error & e) {
|
||||
|
|
|
|||
|
|
@ -136,7 +136,10 @@ struct ExprPath : Expr
|
|||
ExprPath(SourcePath && path)
|
||||
: path(path)
|
||||
{
|
||||
v.mkPath(&*path.accessor, strdup(path.path.abs().c_str()));
|
||||
v.mkPath(
|
||||
&*path.accessor,
|
||||
// TODO: GC_STRDUP
|
||||
strdup(path.path.abs().c_str()));
|
||||
}
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
COMMON_METHODS
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ struct FetchTreeParams {
|
|||
bool emptyRevFallback = false;
|
||||
bool allowNameArgument = false;
|
||||
bool isFetchGit = false;
|
||||
bool returnPath = true; // whether to return a SourcePath or a StorePath
|
||||
bool returnPath = true; // whether to return a SourcePath instead of a StorePath
|
||||
};
|
||||
|
||||
static void fetchTree(
|
||||
|
|
@ -212,18 +212,31 @@ static void fetchTree(
|
|||
|
||||
state.checkURI(input.toURLString());
|
||||
|
||||
auto [storePath, input2] = input.fetchToStore(state.store);
|
||||
if (params.returnPath) {
|
||||
// Clang16+: change to `auto [accessor, input2] =`
|
||||
auto pair = input.getAccessor(state.store);
|
||||
auto & accessor = pair.first;
|
||||
auto & input2 = pair.second;
|
||||
|
||||
state.allowPath(storePath);
|
||||
emitTreeAttrs(state, input2, v,
|
||||
[&](Value & vOutPath) {
|
||||
state.registerAccessor(accessor);
|
||||
vOutPath.mkPath(SourcePath { accessor, CanonPath::root });
|
||||
},
|
||||
params.emptyRevFallback, false);
|
||||
} else {
|
||||
auto pair = input.fetchToStore(state.store);
|
||||
auto & storePath = pair.first;
|
||||
auto & input2 = pair.second;
|
||||
|
||||
emitTreeAttrs(state, input2, v,
|
||||
[&](Value & vOutPath) {
|
||||
if (params.returnPath)
|
||||
vOutPath.mkPath(state.rootPath(state.store->toRealPath(storePath)));
|
||||
else
|
||||
state.allowPath(storePath);
|
||||
|
||||
emitTreeAttrs(state, input2, v,
|
||||
[&](Value & vOutPath) {
|
||||
state.mkStorePathString(storePath, vOutPath);
|
||||
},
|
||||
params.emptyRevFallback, false);
|
||||
},
|
||||
params.emptyRevFallback, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
|
|
|
|||
|
|
@ -195,4 +195,9 @@ ref<SourceAccessor> makeFSSourceAccessor(std::filesystem::path root)
|
|||
{
|
||||
return make_ref<PosixSourceAccessor>(std::move(root));
|
||||
}
|
||||
|
||||
bool PosixSourceAccessor::toStringReturnsStorePath() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ struct PosixSourceAccessor : virtual SourceAccessor
|
|||
*/
|
||||
static SourcePath createAtRoot(const std::filesystem::path & path);
|
||||
|
||||
virtual bool toStringReturnsStorePath() const override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -105,4 +105,8 @@ CanonPath SourceAccessor::resolveSymlinks(
|
|||
return res;
|
||||
}
|
||||
|
||||
bool SourceAccessor::toStringReturnsStorePath() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,15 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
|
|||
|
||||
virtual std::string showPath(const CanonPath & path);
|
||||
|
||||
/**
|
||||
* System paths: `toString /foo/bar = "/foo/bar"`
|
||||
* Virtual paths: fetched to the store
|
||||
*
|
||||
* In both cases, the returned string functionally identifies the path,
|
||||
* and can still be read.
|
||||
*/
|
||||
virtual bool toStringReturnsStorePath() const;
|
||||
|
||||
/**
|
||||
* Resolve any symlinks in `path` according to the given
|
||||
* resolution mode.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue