From 8e8e9d8705a68e1be63d6d8059c6c07127826525 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 30 May 2022 11:32:37 +0200 Subject: [PATCH] Respect the outputSpecified attribute E.g. 'nix build nixpkgs#libxml2.dev' will build the 'dev' output. --- doc/manual/src/release-notes/rl-next.md | 3 -- src/libcmd/installables.cc | 9 +++++- src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 3 +- src/libexpr/get-drvs.cc | 37 +++++++++++++++++-------- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 878916dc9..7151751dd 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -22,9 +22,6 @@ `meta.outputsToInstall` attribute if it exists, or all outputs otherwise. - Selecting derivation outputs using the attribute selection syntax - (e.g. `nixpkgs#glibc.dev`) no longer works. - * Running nix with the new `--debugger` flag will cause it to start a repl session if there is an exception thrown during eval, or if `builtins.break` is called. From there one can inspect symbol values and evaluate nix expressions. In debug mode diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 635ce19b6..21db2b08b 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -623,7 +623,14 @@ std::tuple InstallableF std::set outputsToInstall; std::optional priority; - if (auto aMeta = attr->maybeGetAttr(state->sMeta)) { + if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) { + if (aOutputSpecified->getBool()) { + if (auto aOutputName = attr->maybeGetAttr("outputName")) + outputsToInstall = { aOutputName->getString() }; + } + } + + else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) { if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall")) for (auto & s : aOutputsToInstall->getListOfStrings()) outputsToInstall.insert(s); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 18baf1cb7..40462afdf 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -459,6 +459,7 @@ EvalState::EvalState( , sKey(symbols.create("key")) , sPath(symbols.create("path")) , sPrefix(symbols.create("prefix")) + , sOutputSpecified(symbols.create("outputSpecified")) , repair(NoRepair) , emptyBindings(0) , store(store) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0a32d5885..7b8732169 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -103,7 +103,8 @@ public: sOutputHash, sOutputHashAlgo, sOutputHashMode, sRecurseForDerivations, sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, - sPrefix; + sPrefix, + sOutputSpecified; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index d616b3921..346741dd5 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -132,23 +132,36 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall } else outputs.emplace("out", withPaths ? std::optional{queryOutPath()} : std::nullopt); } + if (!onlyOutputsToInstall || !attrs) return outputs; - /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */ - const Value * outTI = queryMeta("outputsToInstall"); - if (!outTI) return outputs; - const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'"); - /* ^ this shows during `nix-env -i` right under the bad derivation */ - if (!outTI->isList()) throw errMsg; - Outputs result; - for (auto elem : outTI->listItems()) { - if (elem->type() != nString) throw errMsg; - auto out = outputs.find(elem->string.s); - if (out == outputs.end()) throw errMsg; + Bindings::iterator i; + if (attrs && (i = attrs->find(state->sOutputSpecified)) != attrs->end() && state->forceBool(*i->value, i->pos)) { + Outputs result; + auto out = outputs.find(queryOutputName()); + if (out == outputs.end()) + throw Error("derivation does not have output '%s'", queryOutputName()); result.insert(*out); + return result; + } + + else { + /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */ + const Value * outTI = queryMeta("outputsToInstall"); + if (!outTI) return outputs; + const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'"); + /* ^ this shows during `nix-env -i` right under the bad derivation */ + if (!outTI->isList()) throw errMsg; + Outputs result; + for (auto elem : outTI->listItems()) { + if (elem->type() != nString) throw errMsg; + auto out = outputs.find(elem->string.s); + if (out == outputs.end()) throw errMsg; + result.insert(*out); + } + return result; } - return result; }