diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 9eb5fc7589..676dd3ac46 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -138,6 +138,7 @@ EvalState::EvalState() , sName(symbols.create("name")) , sSystem(symbols.create("system")) , sOverrides(symbols.create("__overrides")) + , sOutputs(symbols.create("outputs")) , sOutputName(symbols.create("outputName")) , sIgnoreNulls(symbols.create("__ignoreNulls")) , baseEnv(allocEnv(128)) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1d3baaab8f..a57efa08f1 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -93,7 +93,7 @@ public: SymbolTable symbols; const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, - sSystem, sOverrides, sOutputName, sIgnoreNulls; + sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls; /* If set, force copying files to the Nix store even if they already exist there. */ diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 2ee55bdcae..f1cbc0baba 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -28,12 +28,42 @@ string DrvInfo::queryOutPath(EvalState & state) const } +DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state) +{ + if (outputs.empty()) { + /* Get the ‘outputs’ list. */ + Bindings::iterator i = attrs->find(state.sOutputs); + + if (i == attrs->end()) + outputs["out"] = queryOutPath(state); + else { + state.forceList(*i->value); + + /* For each output... */ + for (unsigned int j = 0; j < i->value->list.length; ++j) { + /* Evaluate the corresponding attribute set. */ + string name = state.forceStringNoCtx(*i->value->list.elems[j]); + Bindings::iterator out = attrs->find(state.symbols.create(name)); + if (out == attrs->end()) continue; // FIXME: throw error? + state.forceAttrs(*out->value); + + /* 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[name] = state.coerceToPath(*outPath->value, context); + } + } + } + return outputs; +} + + string DrvInfo::queryOutputName(EvalState & state) const { if (outputName == "" && attrs) { Bindings::iterator i = attrs->find(state.sOutputName); - PathSet context; - (string &) outputName = i != attrs->end() ? state.coerceToString(*i->value, context) : ""; + (string &) outputName = i != attrs->end() ? state.forceStringNoCtx(*i->value) : ""; } return outputName; } @@ -42,9 +72,9 @@ string DrvInfo::queryOutputName(EvalState & state) const MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const { if (metaInfoRead) return meta; - + (bool &) metaInfoRead = true; - + Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ @@ -108,7 +138,7 @@ static bool getDerivation(EvalState & state, Value & v, done.insert(v.attrs); DrvInfo drv; - + Bindings::iterator i = v.attrs->find(state.sName); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); @@ -126,7 +156,7 @@ static bool getDerivation(EvalState & state, Value & v, drvs.push_back(drv); return false; - + } catch (AssertionError & e) { if (ignoreAssertionFailures) return false; throw; @@ -159,7 +189,7 @@ static void getDerivations(EvalState & state, Value & vIn, { Value v; state.autoCallFunction(autoArgs, vIn, v); - + /* Process the expression. */ DrvInfo drv; @@ -222,5 +252,5 @@ void getDerivations(EvalState & state, Value & v, const string & pathPrefix, getDerivations(state, v, pathPrefix, autoArgs, drvs, done, ignoreAssertionFailures); } - + } diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index f84636a1ab..af3998e400 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -25,16 +25,20 @@ typedef std::map MetaInfo; struct DrvInfo { +public: + typedef std::map Outputs; + private: string drvPath; string outPath; string outputName; + Outputs outputs; bool metaInfoRead; MetaInfo meta; bool failed; // set if we get an AssertionError - + public: string name; string attrPath; /* path towards the derivation */ @@ -48,6 +52,7 @@ public: string queryDrvPath(EvalState & state) const; string queryOutPath(EvalState & state) const; string queryOutputName(EvalState & state) const; + Outputs queryOutputs(EvalState & state); MetaInfo queryMetaInfo(EvalState & state) const; MetaValue queryMetaInfo(EvalState & state, const string & name) const; @@ -55,7 +60,7 @@ public: { drvPath = s; } - + void setOutPath(const string & s) { outPath = s; @@ -84,5 +89,5 @@ void getDerivations(EvalState & state, Value & v, const string & pathPrefix, Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures); - + } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 5e171d0a0b..c980116b20 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1030,7 +1030,7 @@ static void opQuery(Globals & globals, if (xmlOutput) { if (i->system != "") attrs["system"] = i->system; } - else if (printSystem) + else if (printSystem) columns.push_back(i->system); if (printDrvPath) { @@ -1040,13 +1040,16 @@ static void opQuery(Globals & globals, } else columns.push_back(drvPath == "" ? "-" : drvPath); } - - if (printOutPath) { - string outPath = i->queryOutPath(globals.state); - if (xmlOutput) { - if (outPath != "") attrs["outPath"] = outPath; - } else - columns.push_back(outPath); + + if (printOutPath && !xmlOutput) { + DrvInfo::Outputs outputs = i->queryOutputs(globals.state); + string s; + foreach (DrvInfo::Outputs::iterator, j, outputs) { + if (!s.empty()) s += ';'; + if (j->first != "out") { s += j->first; s += "="; } + s += j->second; + } + columns.push_back(s); } if (printDescription) { @@ -1059,35 +1062,45 @@ static void opQuery(Globals & globals, columns.push_back(descr); } - if (xmlOutput) - if (printMeta) { + if (xmlOutput) { + if (printOutPath || printMeta) { XMLOpenElement item(xml, "item", attrs); - MetaInfo meta = i->queryMetaInfo(globals.state); - for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { - XMLAttrs attrs2; - attrs2["name"] = j->first; - if (j->second.type == MetaValue::tpString) { - attrs2["type"] = "string"; - attrs2["value"] = j->second.stringValue; - xml.writeEmptyElement("meta", attrs2); - } else if (j->second.type == MetaValue::tpInt) { - attrs2["type"] = "int"; - attrs2["value"] = (format("%1%") % j->second.intValue).str(); - xml.writeEmptyElement("meta", attrs2); - } else if (j->second.type == MetaValue::tpStrings) { - attrs2["type"] = "strings"; - XMLOpenElement m(xml, "meta", attrs2); - foreach (Strings::iterator, k, j->second.stringValues) { - XMLAttrs attrs3; - attrs3["value"] = *k; - xml.writeEmptyElement("string", attrs3); - } + if (printOutPath) { + DrvInfo::Outputs outputs = i->queryOutputs(globals.state); + foreach (DrvInfo::Outputs::iterator, j, outputs) { + XMLAttrs attrs2; + attrs2["name"] = j->first; + attrs2["path"] = j->second; + xml.writeEmptyElement("output", attrs2); } } - } - else + if (printMeta) { + MetaInfo meta = i->queryMetaInfo(globals.state); + for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { + XMLAttrs attrs2; + attrs2["name"] = j->first; + if (j->second.type == MetaValue::tpString) { + attrs2["type"] = "string"; + attrs2["value"] = j->second.stringValue; + xml.writeEmptyElement("meta", attrs2); + } else if (j->second.type == MetaValue::tpInt) { + attrs2["type"] = "int"; + attrs2["value"] = (format("%1%") % j->second.intValue).str(); + xml.writeEmptyElement("meta", attrs2); + } else if (j->second.type == MetaValue::tpStrings) { + attrs2["type"] = "strings"; + XMLOpenElement m(xml, "meta", attrs2); + foreach (Strings::iterator, k, j->second.stringValues) { + XMLAttrs attrs3; + attrs3["value"] = *k; + xml.writeEmptyElement("string", attrs3); + } + } + } + } + } else xml.writeEmptyElement("item", attrs); - else + } else table.push_back(columns); cout.flush();