diff options
Diffstat (limited to 'src/nix-env')
-rw-r--r-- | src/nix-env/nix-env.cc | 359 | ||||
-rw-r--r-- | src/nix-env/user-env.cc | 61 | ||||
-rw-r--r-- | src/nix-env/user-env.hh | 2 |
3 files changed, 246 insertions, 176 deletions
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index a86f55f84..12e08bbe1 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -46,7 +46,7 @@ struct InstallSourceInfo InstallSourceType type; Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ Path profile; /* for srcProfile */ - string systemFilter; /* for srcNixExprDrvs */ + std::string systemFilter; /* for srcNixExprDrvs */ Bindings * autoArgs; }; @@ -59,7 +59,7 @@ struct Globals bool dryRun; bool preserveInstalled; bool removeAll; - string forceName; + std::string forceName; bool prebuiltOnly; }; @@ -68,8 +68,8 @@ typedef void (* Operation) (Globals & globals, Strings opFlags, Strings opArgs); -static string needArg(Strings::iterator & i, - Strings & args, const string & arg) +static std::string needArg(Strings::iterator & i, + Strings & args, const std::string & arg) { if (i == args.end()) throw UsageError("'%1%' requires an argument", arg); return *i++; @@ -77,7 +77,7 @@ static string needArg(Strings::iterator & i, static bool parseInstallSourceOptions(Globals & globals, - Strings::iterator & i, Strings & args, const string & arg) + Strings::iterator & i, Strings & args, const std::string & arg) { if (arg == "--from-expression" || arg == "-E") globals.instSource.type = srcNixExprs; @@ -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); @@ -121,25 +124,24 @@ static void getAllExprs(EvalState & state, otherwise the attribute cannot be selected with the `-A' option. Useful if you want to stick a Nix expression directly in ~/.nix-defexpr. */ - string attrName = i; + std::string attrName = i; if (hasSuffix(attrName, ".nix")) - attrName = string(attrName, 0, attrName.size() - 4); - if (!attrs.insert(attrName).second) { + attrName = std::string(attrName, 0, attrName.size() - 4); + 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); @@ -173,8 +175,8 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v) static void loadDerivations(EvalState & state, Path nixExprPath, - string systemFilter, Bindings & autoArgs, - const string & pathPrefix, DrvInfos & elems) + std::string systemFilter, Bindings & autoArgs, + const std::string & pathPrefix, DrvInfos & elems) { Value vRoot; loadSourceExpr(state, nixExprPath, vRoot); @@ -224,6 +226,91 @@ static void checkSelectorUse(DrvNames & selectors) } +namespace { + +std::set<std::string> searchByPrefix(const DrvInfos & allElems, std::string_view prefix) { + constexpr std::size_t maxResults = 3; + std::set<std::string> result; + for (const auto & drvInfo : allElems) { + const auto drvName = DrvName { drvInfo.queryName() }; + if (hasPrefix(drvName.name, prefix)) { + result.emplace(drvName.name); + + if (result.size() >= maxResults) { + break; + } + } + } + return result; +} + +struct Match +{ + DrvInfo drvInfo; + std::size_t index; + + Match(DrvInfo drvInfo_, std::size_t index_) + : drvInfo{std::move(drvInfo_)} + , index{index_} + {} +}; + +/* If a selector matches multiple derivations + with the same name, pick the one matching the current + system. If there are still multiple derivations, pick the + one with the highest priority. If there are still multiple + derivations, pick the one with the highest version. + Finally, if there are still multiple derivations, + arbitrarily pick the first one. */ +std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches) { + /* Map from package names to derivations. */ + std::map<std::string, Match> newest; + StringSet multiple; + + for (auto & match : matches) { + auto & oneDrv = match.drvInfo; + + const auto drvName = DrvName { oneDrv.queryName() }; + long comparison = 1; + + const auto itOther = newest.find(drvName.name); + + if (itOther != newest.end()) { + auto & newestDrv = itOther->second.drvInfo; + + comparison = + oneDrv.querySystem() == newestDrv.querySystem() ? 0 : + oneDrv.querySystem() == settings.thisSystem ? 1 : + newestDrv.querySystem() == settings.thisSystem ? -1 : 0; + if (comparison == 0) + comparison = comparePriorities(state, oneDrv, newestDrv); + if (comparison == 0) + comparison = compareVersions(drvName.version, DrvName { newestDrv.queryName() }.version); + } + + if (comparison > 0) { + newest.erase(drvName.name); + newest.emplace(drvName.name, match); + multiple.erase(drvName.fullName); + } else if (comparison == 0) { + multiple.insert(drvName.fullName); + } + } + + matches.clear(); + for (auto & [name, match] : newest) { + if (multiple.find(name) != multiple.end()) + warn( + "there are multiple derivations named '%1%'; using the first one", + name); + matches.push_back(match); + } + + return matches; +} + +} // end namespace + static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, const Strings & args, bool newestOnly) { @@ -232,87 +319,50 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, selectors.emplace_back("*"); DrvInfos elems; - set<unsigned int> done; - - for (auto & i : selectors) { - typedef list<std::pair<DrvInfo, unsigned int> > Matches; - Matches matches; - unsigned int n = 0; - for (DrvInfos::const_iterator j = allElems.begin(); - j != allElems.end(); ++j, ++n) - { - DrvName drvName(j->queryName()); - if (i.matches(drvName)) { - i.hits++; - matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n)); + std::set<std::size_t> done; + + for (auto & selector : selectors) { + std::vector<Match> matches; + for (const auto & [index, drvInfo] : enumerate(allElems)) { + const auto drvName = DrvName { drvInfo.queryName() }; + if (selector.matches(drvName)) { + ++selector.hits; + matches.emplace_back(drvInfo, index); } } - /* If `newestOnly', if a selector matches multiple derivations - with the same name, pick the one matching the current - system. If there are still multiple derivations, pick the - one with the highest priority. If there are still multiple - derivations, pick the one with the highest version. - Finally, if there are still multiple derivations, - arbitrarily pick the first one. */ if (newestOnly) { + matches = pickNewestOnly(state, std::move(matches)); + } - /* Map from package names to derivations. */ - typedef map<string, std::pair<DrvInfo, unsigned int> > Newest; - Newest newest; - StringSet multiple; - - for (auto & j : matches) { - DrvName drvName(j.first.queryName()); - long d = 1; - - Newest::iterator k = newest.find(drvName.name); - - if (k != newest.end()) { - d = j.first.querySystem() == k->second.first.querySystem() ? 0 : - j.first.querySystem() == settings.thisSystem ? 1 : - k->second.first.querySystem() == settings.thisSystem ? -1 : 0; - if (d == 0) - d = comparePriorities(state, j.first, k->second.first); - if (d == 0) - d = compareVersions(drvName.version, DrvName(k->second.first.queryName()).version); - } + /* Insert only those elements in the final list that we + haven't inserted before. */ + for (auto & match : matches) + if (done.insert(match.index).second) + elems.push_back(match.drvInfo); - if (d > 0) { - newest.erase(drvName.name); - newest.insert(Newest::value_type(drvName.name, j)); - multiple.erase(j.first.queryName()); - } else if (d == 0) { - multiple.insert(j.first.queryName()); - } - } + if (selector.hits == 0 && selector.fullName != "*") { + const auto prefixHits = searchByPrefix(allElems, selector.name); - matches.clear(); - for (auto & j : newest) { - if (multiple.find(j.second.first.queryName()) != multiple.end()) - printInfo( - "warning: there are multiple derivations named '%1%'; using the first one", - j.second.first.queryName()); - matches.push_back(j.second); + if (prefixHits.empty()) { + throw Error("selector '%1%' matches no derivations", selector.fullName); + } else { + std::string suggestionMessage = ", maybe you meant:"; + for (const auto & drvName : prefixHits) { + suggestionMessage += fmt("\n%s", drvName); + } + throw Error("selector '%1%' matches no derivations" + suggestionMessage, selector.fullName); } } - - /* Insert only those elements in the final list that we - haven't inserted before. */ - for (auto & j : matches) - if (done.insert(j.second).second) - elems.push_back(j.first); } - checkSelectorUse(selectors); - return elems; } -static bool isPath(const string & s) +static bool isPath(std::string_view s) { - return s.find('/') != string::npos; + return s.find('/') != std::string_view::npos; } @@ -358,7 +408,7 @@ static void queryInstSources(EvalState & state, Expr * eFun = state.parseExprFromString(i, absPath(".")); Value vFun, vTmp; state.eval(eFun, vFun); - mkApp(vTmp, vFun, vArg); + vTmp.mkApp(&vFun, &vArg); getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true); } @@ -383,8 +433,8 @@ static void queryInstSources(EvalState & state, auto outputs = state.store->queryDerivationOutputMap(path); elem.setOutPath(state.store->printStorePath(outputs.at("out"))); if (name.size() >= drvExtension.size() && - string(name, name.size() - drvExtension.size()) == drvExtension) - name = string(name, 0, name.size() - drvExtension.size()); + std::string(name, name.size() - drvExtension.size()) == drvExtension) + name = name.substr(0, name.size() - drvExtension.size()); } else elem.setOutPath(state.store->printStorePath(path)); @@ -465,7 +515,7 @@ static void installDerivations(Globals & globals, while (true) { - string lockToken = optimisticLockProfile(profile); + auto lockToken = optimisticLockProfile(profile); DrvInfos allElems(newElems); @@ -501,7 +551,7 @@ static void installDerivations(Globals & globals, static void opInstall(Globals & globals, Strings opFlags, Strings opArgs) { for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { - string arg = *i++; + auto arg = *i++; if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; else if (arg == "--preserve-installed" || arg == "-P") globals.preserveInstalled = true; @@ -528,7 +578,7 @@ static void upgradeDerivations(Globals & globals, name and a higher version number. */ while (true) { - string lockToken = optimisticLockProfile(globals.profile); + auto lockToken = optimisticLockProfile(globals.profile); DrvInfos installedElems = queryInstalled(*globals.state, globals.profile); @@ -556,7 +606,7 @@ static void upgradeDerivations(Globals & globals, take the one with the highest version. Do not upgrade if it would decrease the priority. */ DrvInfos::iterator bestElem = availElems.end(); - string bestVersion; + std::string bestVersion; for (auto j = availElems.begin(); j != availElems.end(); ++j) { if (comparePriorities(*globals.state, i, *j) > 0) continue; @@ -612,7 +662,7 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs) { UpgradeType upgradeType = utLt; for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { - string arg = *i++; + std::string arg = *i++; if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; else if (arg == "--lt") upgradeType = utLt; else if (arg == "--leq") upgradeType = utLeq; @@ -626,10 +676,10 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs) static void setMetaFlag(EvalState & state, DrvInfo & drv, - const string & name, const string & value) + const std::string & name, const std::string & value) { - Value * v = state.allocValue(); - mkString(*v, value.c_str()); + auto v = state.allocValue(); + v->mkString(value); drv.setMeta(name, v); } @@ -642,12 +692,12 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) throw UsageError("not enough arguments to '--set-flag'"); Strings::iterator arg = opArgs.begin(); - string flagName = *arg++; - string flagValue = *arg++; + std::string flagName = *arg++; + std::string flagValue = *arg++; DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end())); while (true) { - string lockToken = optimisticLockProfile(globals.profile); + std::string lockToken = optimisticLockProfile(globals.profile); DrvInfos installedElems = queryInstalled(*globals.state, globals.profile); @@ -678,7 +728,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) if (!store2) throw Error("--set is not supported for this Nix store"); for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { - string arg = *i++; + std::string arg = *i++; if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; else throw UsageError("unknown flag '%1%'", arg); } @@ -719,7 +769,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, Path & profile) { while (true) { - string lockToken = optimisticLockProfile(profile); + auto lockToken = optimisticLockProfile(profile); DrvInfos workingElems = queryInstalled(*globals.state, profile); @@ -783,14 +833,14 @@ static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) } -typedef list<Strings> Table; +typedef std::list<Strings> Table; void printTable(Table & table) { auto nrColumns = table.size() > 0 ? table.front().size() : 0; - vector<size_t> widths; + std::vector<size_t> widths; widths.resize(nrColumns); for (auto & i : table) { @@ -805,11 +855,11 @@ void printTable(Table & table) Strings::iterator j; size_t column; for (j = i.begin(), column = 0; j != i.end(); ++j, ++column) { - string s = *j; + std::string s = *j; replace(s.begin(), s.end(), '\n', ' '); cout << s; if (column < nrColumns - 1) - cout << string(widths[column] - s.size() + 2, ' '); + cout << std::string(widths[column] - s.size() + 2, ' '); } cout << std::endl; } @@ -826,7 +876,7 @@ void printTable(Table & table) typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff; static VersionDiff compareVersionAgainstSet( - const DrvInfo & elem, const DrvInfos & elems, string & version) + const DrvInfo & elem, const DrvInfos & elems, std::string & version) { DrvName name(elem.queryName()); @@ -857,30 +907,49 @@ static VersionDiff compareVersionAgainstSet( } -static void queryJSON(Globals & globals, vector<DrvInfo> & elems) +static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printMeta) { JSONObject topObj(cout, true); for (auto & i : elems) { - JSONObject pkgObj = topObj.object(i.attrPath); - - auto drvName = DrvName(i.queryName()); - pkgObj.attr("name", drvName.fullName); - pkgObj.attr("pname", drvName.name); - pkgObj.attr("version", drvName.version); - pkgObj.attr("system", i.querySystem()); - - JSONObject metaObj = pkgObj.object("meta"); - StringSet metaNames = i.queryMetaNames(); - for (auto & j : metaNames) { - auto placeholder = metaObj.placeholder(j); - Value * v = i.queryMeta(j); - if (!v) { - printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j); - placeholder.write(nullptr); - } else { - PathSet context; - printValueAsJSON(*globals.state, true, *v, placeholder, context); + try { + if (i.hasFailed()) continue; + + JSONObject pkgObj = topObj.object(i.attrPath); + + auto drvName = DrvName(i.queryName()); + pkgObj.attr("name", drvName.fullName); + pkgObj.attr("pname", drvName.name); + pkgObj.attr("version", drvName.version); + pkgObj.attr("system", i.querySystem()); + + if (printOutPath) { + DrvInfo::Outputs outputs = i.queryOutputs(); + JSONObject outputObj = pkgObj.object("outputs"); + for (auto & j : outputs) { + outputObj.attr(j.first, j.second); + } } + + if (printMeta) { + JSONObject metaObj = pkgObj.object("meta"); + StringSet metaNames = i.queryMetaNames(); + for (auto & j : metaNames) { + auto placeholder = metaObj.placeholder(j); + Value * v = i.queryMeta(j); + if (!v) { + printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j); + placeholder.write(nullptr); + } else { + PathSet context; + printValueAsJSON(*globals.state, true, *v, noPos, placeholder, context); + } + } + } + } catch (AssertionError & e) { + printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName()); + } catch (Error & e) { + e.addTrace(std::nullopt, "while querying the derivation named '%1%'", i.queryName()); + throw; } } } @@ -889,7 +958,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems) static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) { Strings remaining; - string attrPath; + std::string attrPath; bool printStatus = false; bool printName = true; @@ -908,7 +977,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) settings.readOnlyMode = true; /* makes evaluation a bit faster */ for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { - string arg = *i++; + auto arg = *i++; if (arg == "--status" || arg == "-s") printStatus = true; else if (arg == "--no-name") printName = false; else if (arg == "--system") printSystem = true; @@ -951,7 +1020,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) /* Sort them by name. */ /* !!! */ - vector<DrvInfo> elems; + std::vector<DrvInfo> elems; for (auto & i : elems_) elems.push_back(i); sort(elems.begin(), elems.end(), cmpElemByName); @@ -985,7 +1054,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) /* Print the desired columns, or XML output. */ if (jsonOutput) { - queryJSON(globals, elems); + queryJSON(globals, elems, printOutPath, printMeta); return; } @@ -1025,7 +1094,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs["substitutable"] = hasSubs ? "1" : "0"; } else columns.push_back( - (string) (isInstalled ? "I" : "-") + (std::string) (isInstalled ? "I" : "-") + (isValid ? "P" : "-") + (hasSubs ? "S" : "-")); } @@ -1049,7 +1118,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) same named packages in either the set of available elements, or the set of installed elements. !!! This is O(N * M), should be O(N * lg M). */ - string version; + std::string version; VersionDiff diff = compareVersionAgainstSet(i, otherElems, version); char ch; @@ -1067,7 +1136,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs["maxComparedVersion"] = version; } } else { - string column = (string) "" + ch + " " + version; + auto column = (std::string) "" + ch + " " + version; if (diff == cvGreater && tty) column = ANSI_RED + column + ANSI_NORMAL; columns.push_back(column); @@ -1081,7 +1150,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) columns.push_back(i.querySystem()); if (printDrvPath) { - string drvPath = i.queryDrvPath(); + auto drvPath = i.queryDrvPath(); if (xmlOutput) { if (drvPath != "") attrs["drvPath"] = drvPath; } else @@ -1090,7 +1159,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) if (printOutPath && !xmlOutput) { DrvInfo::Outputs outputs = i.queryOutputs(); - string s; + std::string s; for (auto & j : outputs) { if (!s.empty()) s += ';'; if (j.first != "out") { s += j.first; s += "="; } @@ -1100,7 +1169,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) } if (printDescription) { - string descr = i.queryMetaString("description"); + auto descr = i.queryMetaString("description"); if (xmlOutput) { if (descr != "") attrs["description"] = descr; } else @@ -1149,10 +1218,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) } else if (v->type() == nList) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); - for (unsigned int j = 0; j < v->listSize(); ++j) { - if (v->listElems()[j]->type() != nString) continue; + for (auto elem : v->listItems()) { + if (elem->type() != nString) continue; XMLAttrs attrs3; - attrs3["value"] = v->listElems()[j]->string.s; + attrs3["value"] = elem->string.s; xml.writeEmptyElement("string", attrs3); } } else if (v->type() == nAttrs) { @@ -1262,12 +1331,12 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr if (opArgs.size() == 1 && opArgs.front() == "old") { deleteOldGenerations(globals.profile, globals.dryRun); - } else if (opArgs.size() == 1 && opArgs.front().find('d') != string::npos) { + } else if (opArgs.size() == 1 && opArgs.front().find('d') != std::string::npos) { deleteGenerationsOlderThan(globals.profile, opArgs.front(), globals.dryRun); - } else if (opArgs.size() == 1 && opArgs.front().find('+') != string::npos) { + } else if (opArgs.size() == 1 && opArgs.front().find('+') != std::string::npos) { if (opArgs.front().size() < 2) throw Error("invalid number of generations '%1%'", opArgs.front()); - string str_max = string(opArgs.front(), 1, opArgs.front().size()); + auto str_max = opArgs.front().substr(1); auto max = string2Int<GenerationNumber>(str_max); if (!max || *max == 0) throw Error("invalid number of generations to keep '%1%'", opArgs.front()); @@ -1297,7 +1366,7 @@ static int main_nix_env(int argc, char * * argv) Strings opFlags, opArgs; Operation op = 0; RepairFlag repair = NoRepair; - string file; + std::string file; Globals globals; diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 1fd4bcbd3..37e4086cb 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -32,7 +32,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv) bool createUserEnv(EvalState & state, DrvInfos & elems, const Path & profile, bool keepDerivations, - const string & lockToken) + const std::string & lockToken) { /* Build the components in the user environment, if they don't exist already. */ @@ -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,17 +116,20 @@ 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"); - state.forceValue(topLevel); + state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); }); PathSet context; Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath)); auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context)); diff --git a/src/nix-env/user-env.hh b/src/nix-env/user-env.hh index f188efe9b..10646f713 100644 --- a/src/nix-env/user-env.hh +++ b/src/nix-env/user-env.hh @@ -8,6 +8,6 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv); bool createUserEnv(EvalState & state, DrvInfos & elems, const Path & profile, bool keepDerivations, - const string & lockToken); + const std::string & lockToken); } |