Merge pull request #6242 from ncfavier/print-output-names

nix-env: always print output names in JSON and XML
This commit is contained in:
Théophane Hufschmitt 2022-03-17 10:55:22 +01:00 committed by GitHub
commit a0b517de57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 86 deletions

View file

@ -102,7 +102,7 @@ StorePath DrvInfo::queryOutPath() const
} }
DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall)
{ {
if (outputs.empty()) { if (outputs.empty()) {
/* Get the outputs list. */ /* Get the outputs list. */
@ -112,9 +112,11 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* For each output... */ /* For each output... */
for (auto elem : i->value->listItems()) { for (auto elem : i->value->listItems()) {
std::string output(state->forceStringNoCtx(*elem, *i->pos));
if (withPaths) {
/* Evaluate the corresponding set. */ /* Evaluate the corresponding set. */
std::string name(state->forceStringNoCtx(*elem, *i->pos)); Bindings::iterator out = attrs->find(state->symbols.create(output));
Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error? if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value, *i->pos); state->forceAttrs(*out->value, *i->pos);
@ -122,10 +124,12 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error? if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context; PathSet context;
outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context)); outputs.emplace(output, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
} else
outputs.emplace(output, std::nullopt);
} }
} else } else
outputs.emplace("out", queryOutPath()); outputs.emplace("out", withPaths ? std::optional{queryOutPath()} : std::nullopt);
} }
if (!onlyOutputsToInstall || !attrs) if (!onlyOutputsToInstall || !attrs)
return outputs; return outputs;

View file

@ -13,7 +13,7 @@ namespace nix {
struct DrvInfo struct DrvInfo
{ {
public: public:
typedef std::map<std::string, StorePath> Outputs; typedef std::map<std::string, std::optional<StorePath>> Outputs;
private: private:
EvalState * state; EvalState * state;
@ -46,8 +46,9 @@ public:
StorePath requireDrvPath() const; StorePath requireDrvPath() const;
StorePath queryOutPath() const; StorePath queryOutPath() const;
std::string queryOutputName() const; std::string queryOutputName() const;
/** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */ /** Return the unordered map of output names to (optional) output paths.
Outputs queryOutputs(bool onlyOutputsToInstall = false); * The "outputs to install" are determined by `meta.outputsToInstall`. */
Outputs queryOutputs(bool withPaths = true, bool onlyOutputsToInstall = false);
StringSet queryMetaNames(); StringSet queryMetaNames();
Value * queryMeta(const std::string & name); Value * queryMeta(const std::string & name);

View file

@ -923,12 +923,17 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
pkgObj.attr("pname", drvName.name); pkgObj.attr("pname", drvName.name);
pkgObj.attr("version", drvName.version); pkgObj.attr("version", drvName.version);
pkgObj.attr("system", i.querySystem()); pkgObj.attr("system", i.querySystem());
pkgObj.attr("outputName", i.queryOutputName());
if (printOutPath) { {
DrvInfo::Outputs outputs = i.queryOutputs(); DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
JSONObject outputObj = pkgObj.object("outputs"); JSONObject outputObj = pkgObj.object("outputs");
for (auto & j : outputs) for (auto & j : outputs) {
outputObj.attr(j.first, globals.state->store->printStorePath(j.second)); if (j.second)
outputObj.attr(j.first, globals.state->store->printStorePath(*j.second));
else
outputObj.attr(j.first, nullptr);
}
} }
if (printMeta) { if (printMeta) {
@ -1057,6 +1062,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
/* Print the desired columns, or XML output. */ /* Print the desired columns, or XML output. */
if (jsonOutput) { if (jsonOutput) {
queryJSON(globals, elems, printOutPath, printMeta); queryJSON(globals, elems, printOutPath, printMeta);
cout << '\n';
return; return;
} }
@ -1159,13 +1165,16 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-"); columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-");
} }
if (xmlOutput)
attrs["outputName"] = i.queryOutputName();
if (printOutPath && !xmlOutput) { if (printOutPath && !xmlOutput) {
DrvInfo::Outputs outputs = i.queryOutputs(); DrvInfo::Outputs outputs = i.queryOutputs();
std::string s; std::string s;
for (auto & j : outputs) { for (auto & j : outputs) {
if (!s.empty()) s += ';'; if (!s.empty()) s += ';';
if (j.first != "out") { s += j.first; s += "="; } if (j.first != "out") { s += j.first; s += "="; }
s += store.printStorePath(j.second); s += store.printStorePath(*j.second);
} }
columns.push_back(s); columns.push_back(s);
} }
@ -1179,17 +1188,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
} }
if (xmlOutput) { if (xmlOutput) {
if (printOutPath || printMeta) {
XMLOpenElement item(xml, "item", attrs); XMLOpenElement item(xml, "item", attrs);
if (printOutPath) { DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
DrvInfo::Outputs outputs = i.queryOutputs();
for (auto & j : outputs) { for (auto & j : outputs) {
XMLAttrs attrs2; XMLAttrs attrs2;
attrs2["name"] = j.first; attrs2["name"] = j.first;
attrs2["path"] = store.printStorePath(j.second); if (j.second)
attrs2["path"] = store.printStorePath(*j.second);
xml.writeEmptyElement("output", attrs2); xml.writeEmptyElement("output", attrs2);
} }
}
if (printMeta) { if (printMeta) {
StringSet metaNames = i.queryMetaNames(); StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) { for (auto & j : metaNames) {
@ -1242,8 +1249,6 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
} }
} }
} }
} else
xml.writeEmptyElement("item", attrs);
} else } else
table.push_back(columns); table.push_back(columns);

View file

@ -56,7 +56,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
output paths, and optionally the derivation path, as well output paths, and optionally the derivation path, as well
as the meta attributes. */ as the meta attributes. */
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt; std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt;
DrvInfo::Outputs outputs = i.queryOutputs(true); DrvInfo::Outputs outputs = i.queryOutputs(true, true);
StringSet metaNames = i.queryMetaNames(); StringSet metaNames = i.queryMetaNames();
auto attrs = state.buildBindings(7 + outputs.size()); auto attrs = state.buildBindings(7 + outputs.size());
@ -76,15 +76,15 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
for (const auto & [m, j] : enumerate(outputs)) { for (const auto & [m, j] : enumerate(outputs)) {
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first); (vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
auto outputAttrs = state.buildBindings(2); auto outputAttrs = state.buildBindings(2);
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(j.second)); outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
attrs.alloc(j.first).mkAttrs(outputAttrs); attrs.alloc(j.first).mkAttrs(outputAttrs);
/* This is only necessary when installing store paths, e.g., /* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */ `nix-env -i /nix/store/abcd...-foo'. */
state.store->addTempRoot(j.second); state.store->addTempRoot(*j.second);
state.store->ensurePath(j.second); state.store->ensurePath(*j.second);
references.insert(j.second); references.insert(*j.second);
} }
// Copy the meta attributes. // Copy the meta attributes.

View file

@ -17,6 +17,16 @@ outPath10=$(nix-env -f ./user-envs.nix -qa --out-path --no-name '*' | grep foo-1
drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0) drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0)
[ -n "$outPath10" -a -n "$drvPath10" ] [ -n "$outPath10" -a -n "$drvPath10" ]
# Query with json
nix-env -f ./user-envs.nix -qa --json | jq -e '.[] | select(.name == "bar-0.1") | [
.outputName == "out",
.outputs.out == null
] | all'
nix-env -f ./user-envs.nix -qa --json --out-path | jq -e '.[] | select(.name == "bar-0.1") | [
.outputName == "out",
(.outputs.out | test("'$NIX_STORE_DIR'.*-0\\.1"))
] | all'
# Query descriptions. # Query descriptions.
nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly
rm -rf $HOME/.nix-defexpr rm -rf $HOME/.nix-defexpr