forked from lix-project/lix
nix-env: always print output names in JSON and XML
The current `--out-path` flag has two disadvantages when one is only concerned with querying the names of outputs: - it requires evaluating every output's `outPath`, which takes significantly more resources and runs into more failures - it destroys the information of the order of outputs so we can't tell which one is the main output This patch makes the output names always present (replacing paths with `null` in JSON if `--out-path` isn't given), and adds an `outputName` field.
This commit is contained in:
parent
d5322698a2
commit
5736661922
|
@ -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,20 +112,24 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
||||||
|
|
||||||
/* For each output... */
|
/* For each output... */
|
||||||
for (auto elem : i->value->listItems()) {
|
for (auto elem : i->value->listItems()) {
|
||||||
/* Evaluate the corresponding set. */
|
std::string output(state->forceStringNoCtx(*elem, *i->pos));
|
||||||
std::string name(state->forceStringNoCtx(*elem, *i->pos));
|
|
||||||
Bindings::iterator out = attrs->find(state->symbols.create(name));
|
|
||||||
if (out == attrs->end()) continue; // FIXME: throw error?
|
|
||||||
state->forceAttrs(*out->value, *i->pos);
|
|
||||||
|
|
||||||
/* And evaluate its ‘outPath’ attribute. */
|
if (withPaths) {
|
||||||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
/* Evaluate the corresponding set. */
|
||||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
Bindings::iterator out = attrs->find(state->symbols.create(output));
|
||||||
PathSet context;
|
if (out == attrs->end()) continue; // FIXME: throw error?
|
||||||
outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
|
state->forceAttrs(*out->value, *i->pos);
|
||||||
|
|
||||||
|
/* And evaluate its ‘outPath’ attribute. */
|
||||||
|
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
||||||
|
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
||||||
|
PathSet 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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -918,12 +918,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) {
|
||||||
|
@ -1154,13 +1159,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);
|
||||||
}
|
}
|
||||||
|
@ -1174,71 +1182,67 @@ 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);
|
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
|
||||||
if (printOutPath) {
|
for (auto & j : outputs) {
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs();
|
XMLAttrs attrs2;
|
||||||
for (auto & j : outputs) {
|
attrs2["name"] = j.first;
|
||||||
XMLAttrs attrs2;
|
if (j.second)
|
||||||
attrs2["name"] = j.first;
|
attrs2["path"] = store.printStorePath(*j.second);
|
||||||
attrs2["path"] = store.printStorePath(j.second);
|
xml.writeEmptyElement("output", attrs2);
|
||||||
xml.writeEmptyElement("output", attrs2);
|
}
|
||||||
}
|
if (printMeta) {
|
||||||
}
|
StringSet metaNames = i.queryMetaNames();
|
||||||
if (printMeta) {
|
for (auto & j : metaNames) {
|
||||||
StringSet metaNames = i.queryMetaNames();
|
XMLAttrs attrs2;
|
||||||
for (auto & j : metaNames) {
|
attrs2["name"] = j;
|
||||||
XMLAttrs attrs2;
|
Value * v = i.queryMeta(j);
|
||||||
attrs2["name"] = j;
|
if (!v)
|
||||||
Value * v = i.queryMeta(j);
|
printError(
|
||||||
if (!v)
|
"derivation '%s' has invalid meta attribute '%s'",
|
||||||
printError(
|
i.queryName(), j);
|
||||||
"derivation '%s' has invalid meta attribute '%s'",
|
else {
|
||||||
i.queryName(), j);
|
if (v->type() == nString) {
|
||||||
else {
|
attrs2["type"] = "string";
|
||||||
if (v->type() == nString) {
|
attrs2["value"] = v->string.s;
|
||||||
attrs2["type"] = "string";
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
attrs2["value"] = v->string.s;
|
} else if (v->type() == nInt) {
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
attrs2["type"] = "int";
|
||||||
} else if (v->type() == nInt) {
|
attrs2["value"] = (format("%1%") % v->integer).str();
|
||||||
attrs2["type"] = "int";
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
attrs2["value"] = (format("%1%") % v->integer).str();
|
} else if (v->type() == nFloat) {
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
attrs2["type"] = "float";
|
||||||
} else if (v->type() == nFloat) {
|
attrs2["value"] = (format("%1%") % v->fpoint).str();
|
||||||
attrs2["type"] = "float";
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
attrs2["value"] = (format("%1%") % v->fpoint).str();
|
} else if (v->type() == nBool) {
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
attrs2["type"] = "bool";
|
||||||
} else if (v->type() == nBool) {
|
attrs2["value"] = v->boolean ? "true" : "false";
|
||||||
attrs2["type"] = "bool";
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
attrs2["value"] = v->boolean ? "true" : "false";
|
} else if (v->type() == nList) {
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
attrs2["type"] = "strings";
|
||||||
} else if (v->type() == nList) {
|
XMLOpenElement m(xml, "meta", attrs2);
|
||||||
attrs2["type"] = "strings";
|
for (auto elem : v->listItems()) {
|
||||||
XMLOpenElement m(xml, "meta", attrs2);
|
if (elem->type() != nString) continue;
|
||||||
for (auto elem : v->listItems()) {
|
XMLAttrs attrs3;
|
||||||
if (elem->type() != nString) continue;
|
attrs3["value"] = elem->string.s;
|
||||||
XMLAttrs attrs3;
|
xml.writeEmptyElement("string", attrs3);
|
||||||
attrs3["value"] = elem->string.s;
|
|
||||||
xml.writeEmptyElement("string", attrs3);
|
|
||||||
}
|
|
||||||
} else if (v->type() == nAttrs) {
|
|
||||||
attrs2["type"] = "strings";
|
|
||||||
XMLOpenElement m(xml, "meta", attrs2);
|
|
||||||
Bindings & attrs = *v->attrs;
|
|
||||||
for (auto &i : attrs) {
|
|
||||||
Attr & a(*attrs.find(i.name));
|
|
||||||
if(a.value->type() != nString) continue;
|
|
||||||
XMLAttrs attrs3;
|
|
||||||
attrs3["type"] = i.name;
|
|
||||||
attrs3["value"] = a.value->string.s;
|
|
||||||
xml.writeEmptyElement("string", attrs3);
|
|
||||||
}
|
}
|
||||||
}
|
} else if (v->type() == nAttrs) {
|
||||||
|
attrs2["type"] = "strings";
|
||||||
|
XMLOpenElement m(xml, "meta", attrs2);
|
||||||
|
Bindings & attrs = *v->attrs;
|
||||||
|
for (auto &i : attrs) {
|
||||||
|
Attr & a(*attrs.find(i.name));
|
||||||
|
if(a.value->type() != nString) continue;
|
||||||
|
XMLAttrs attrs3;
|
||||||
|
attrs3["type"] = i.name;
|
||||||
|
attrs3["value"] = a.value->string.s;
|
||||||
|
xml.writeEmptyElement("string", attrs3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
xml.writeEmptyElement("item", attrs);
|
|
||||||
} else
|
} else
|
||||||
table.push_back(columns);
|
table.push_back(columns);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue