mirror of
https://github.com/NixOS/nix
synced 2025-07-06 21:41:48 +02:00
Ensure that attrsets are sorted
Previously you had to remember to call value->attrs->sort() after populating value->attrs. Now there is a BindingsBuilder helper that wraps Bindings and ensures that sort() is called before you can use it.
This commit is contained in:
parent
1ffacad8a5
commit
6d9a6d2cc3
17 changed files with 260 additions and 198 deletions
|
@ -98,8 +98,11 @@ static bool isNixExpr(const Path & path, struct stat & st)
|
|||
}
|
||||
|
||||
|
||||
static constexpr size_t maxAttrs = 1024;
|
||||
|
||||
|
||||
static void getAllExprs(EvalState & state,
|
||||
const Path & path, StringSet & attrs, Value & v)
|
||||
const Path & path, StringSet & seen, BindingsBuilder & attrs)
|
||||
{
|
||||
StringSet namesSorted;
|
||||
for (auto & i : readDirectory(path)) namesSorted.insert(i.name);
|
||||
|
@ -124,22 +127,21 @@ static void getAllExprs(EvalState & state,
|
|||
string attrName = i;
|
||||
if (hasSuffix(attrName, ".nix"))
|
||||
attrName = string(attrName, 0, attrName.size() - 4);
|
||||
if (!attrs.insert(attrName).second) {
|
||||
if (!seen.insert(attrName).second) {
|
||||
printError("warning: name collision in input Nix expressions, skipping '%1%'", path2);
|
||||
continue;
|
||||
}
|
||||
/* Load the expression on demand. */
|
||||
Value & vFun = state.getBuiltin("import");
|
||||
Value & vArg(*state.allocValue());
|
||||
mkString(vArg, path2);
|
||||
if (v.attrs->size() == v.attrs->capacity())
|
||||
auto vArg = state.allocValue();
|
||||
vArg->mkString(path2);
|
||||
if (seen.size() == maxAttrs)
|
||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
||||
mkApp(*state.allocAttr(v, state.symbols.create(attrName)), vFun, vArg);
|
||||
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg);
|
||||
}
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
/* `path2' is a directory (with no default.nix in it);
|
||||
recurse into it. */
|
||||
getAllExprs(state, path2, attrs, v);
|
||||
getAllExprs(state, path2, seen, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,11 +163,11 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
|
|||
~/.nix-defexpr directory that includes some system-wide
|
||||
directory). */
|
||||
else if (S_ISDIR(st.st_mode)) {
|
||||
state.mkAttrs(v, 1024);
|
||||
state.mkList(*state.allocAttr(v, state.symbols.create("_combineChannels")), 0);
|
||||
StringSet attrs;
|
||||
getAllExprs(state, path, attrs, v);
|
||||
v.attrs->sort();
|
||||
auto attrs = state.buildBindings(maxAttrs);
|
||||
attrs.alloc("_combineChannels").mkList(0);
|
||||
StringSet seen;
|
||||
getAllExprs(state, path, seen, attrs);
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
||||
else throw Error("path '%s' is not a directory or a Nix expression", path);
|
||||
|
|
|
@ -50,7 +50,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
StorePathSet references;
|
||||
Value manifest;
|
||||
state.mkList(manifest, elems.size());
|
||||
unsigned int n = 0;
|
||||
size_t n = 0;
|
||||
for (auto & i : elems) {
|
||||
/* Create a pseudo-derivation containing the name, system,
|
||||
output paths, and optionally the derivation path, as well
|
||||
|
@ -59,28 +59,25 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
||||
StringSet metaNames = i.queryMetaNames();
|
||||
|
||||
Value & v(*state.allocValue());
|
||||
manifest.listElems()[n++] = &v;
|
||||
state.mkAttrs(v, 7 + outputs.size());
|
||||
auto attrs = state.buildBindings(7 + outputs.size());
|
||||
|
||||
mkString(*state.allocAttr(v, state.sType), "derivation");
|
||||
mkString(*state.allocAttr(v, state.sName), i.queryName());
|
||||
attrs.alloc(state.sType).mkString("derivation");
|
||||
attrs.alloc(state.sName).mkString(i.queryName());
|
||||
auto system = i.querySystem();
|
||||
if (!system.empty())
|
||||
mkString(*state.allocAttr(v, state.sSystem), system);
|
||||
mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath());
|
||||
attrs.alloc(state.sSystem).mkString(system);
|
||||
attrs.alloc(state.sOutPath).mkString(i.queryOutPath());
|
||||
if (drvPath != "")
|
||||
mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath());
|
||||
attrs.alloc(state.sDrvPath).mkString(i.queryDrvPath());
|
||||
|
||||
// Copy each output meant for installation.
|
||||
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
|
||||
auto & vOutputs = attrs.alloc(state.sOutputs);
|
||||
state.mkList(vOutputs, outputs.size());
|
||||
unsigned int m = 0;
|
||||
for (auto & j : outputs) {
|
||||
mkString(*(vOutputs.listElems()[m++] = state.allocValue()), j.first);
|
||||
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j.first));
|
||||
state.mkAttrs(vOutputs, 2);
|
||||
mkString(*state.allocAttr(vOutputs, state.sOutPath), j.second);
|
||||
for (const auto & [m, j] : enumerate(outputs)) {
|
||||
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
||||
auto outputAttrs = state.buildBindings(2);
|
||||
outputAttrs.alloc(state.sOutPath).mkString(j.second);
|
||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||
|
||||
/* This is only necessary when installing store paths, e.g.,
|
||||
`nix-env -i /nix/store/abcd...-foo'. */
|
||||
|
@ -91,15 +88,16 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
}
|
||||
|
||||
// Copy the meta attributes.
|
||||
Value & vMeta = *state.allocAttr(v, state.sMeta);
|
||||
state.mkAttrs(vMeta, metaNames.size());
|
||||
auto meta = state.buildBindings(metaNames.size());
|
||||
for (auto & j : metaNames) {
|
||||
Value * v = i.queryMeta(j);
|
||||
if (!v) continue;
|
||||
vMeta.attrs->push_back(Attr(state.symbols.create(j), v));
|
||||
meta.insert(state.symbols.create(j), v);
|
||||
}
|
||||
vMeta.attrs->sort();
|
||||
v.attrs->sort();
|
||||
|
||||
attrs.alloc(state.sMeta).mkAttrs(meta);
|
||||
|
||||
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
||||
|
||||
if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
|
||||
}
|
||||
|
@ -118,13 +116,16 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
|
||||
/* Construct a Nix expression that calls the user environment
|
||||
builder with the manifest as argument. */
|
||||
Value args, topLevel;
|
||||
state.mkAttrs(args, 3);
|
||||
mkString(*state.allocAttr(args, state.symbols.create("manifest")),
|
||||
state.store->printStorePath(manifestFile), {state.store->printStorePath(manifestFile)});
|
||||
args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest));
|
||||
args.attrs->sort();
|
||||
mkApp(topLevel, envBuilder, args);
|
||||
auto attrs = state.buildBindings(3);
|
||||
attrs.alloc("manifest").mkString(
|
||||
state.store->printStorePath(manifestFile),
|
||||
{state.store->printStorePath(manifestFile)});
|
||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||
Value args;
|
||||
args.mkAttrs(attrs);
|
||||
|
||||
Value topLevel;
|
||||
topLevel.mkApp(&envBuilder, &args);
|
||||
|
||||
/* Evaluate it. */
|
||||
debug("evaluating user environment builder");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue