cleanup and slightly refactor DrvInfo::queryOutputs
Change-Id: I00d9ff707fe61995737b86af6d2eaa1e4d8116ff
This commit is contained in:
parent
c347d3df8f
commit
eb18dcb0ea
|
@ -101,66 +101,134 @@ StorePath DrvInfo::queryOutPath()
|
||||||
return *outPath;
|
return *outPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrvInfo::fillOutputs(bool withPaths)
|
||||||
|
{
|
||||||
|
auto fillDefault = [&]() {
|
||||||
|
std::optional<StorePath> outPath = std::nullopt;
|
||||||
|
if (withPaths) {
|
||||||
|
outPath.emplace(this->queryOutPath());
|
||||||
|
}
|
||||||
|
this->outputs.emplace("out", outPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
// lol. lmao even.
|
||||||
|
if (this->attrs == nullptr) {
|
||||||
|
fillDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attr * outputs = this->attrs->get(this->state->sOutputs);
|
||||||
|
if (outputs == nullptr) {
|
||||||
|
fillDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(Qyriad): I don't think there is any codepath that can cause this to error.
|
||||||
|
this->state->forceList(
|
||||||
|
*outputs->value,
|
||||||
|
outputs->pos,
|
||||||
|
"while evaluating the 'outputs' attribute of a derivation"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto [idx, elem] : enumerate(outputs->value->listItems())) {
|
||||||
|
// NOTE(Qyriad): This error should be *extremely* rare in practice.
|
||||||
|
// It is impossible to construct with `stdenv.mkDerivation`,
|
||||||
|
// `builtins.derivation`, or even `derivationStrict`. As far as we can tell,
|
||||||
|
// it is only possible by overriding a derivation attrset already created by
|
||||||
|
// one of those with `//` to introduce the failing `outputs` entry.
|
||||||
|
auto errMsg = fmt("while evaluating output %d of a derivation", idx);
|
||||||
|
std::string_view outputName = state->forceStringNoCtx(
|
||||||
|
*elem,
|
||||||
|
outputs->pos,
|
||||||
|
errMsg
|
||||||
|
);
|
||||||
|
|
||||||
|
if (withPaths) {
|
||||||
|
// Find the attr with this output's name...
|
||||||
|
Attr * out = this->attrs->get(this->state->symbols.create(outputName));
|
||||||
|
if (out == nullptr) {
|
||||||
|
// FIXME: throw error?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meanwhile we couldn't figure out any circumstances
|
||||||
|
// that cause this to error.
|
||||||
|
state->forceAttrs(*out->value, outputs->pos, errMsg);
|
||||||
|
|
||||||
|
// ...and evaluate its `outPath` attribute.
|
||||||
|
Attr * outPath = out->value->attrs->get(this->state->sOutPath);
|
||||||
|
if (outPath == nullptr) {
|
||||||
|
continue;
|
||||||
|
// FIXME: throw error?
|
||||||
|
}
|
||||||
|
|
||||||
|
NixStringContext context;
|
||||||
|
// And idk what could possibly cause this one to error
|
||||||
|
// that wouldn't error before here.
|
||||||
|
auto storePath = state->coerceToStorePath(
|
||||||
|
outPath->pos,
|
||||||
|
*outPath->value,
|
||||||
|
context,
|
||||||
|
errMsg
|
||||||
|
);
|
||||||
|
this->outputs.emplace(outputName, storePath);
|
||||||
|
} else {
|
||||||
|
this->outputs.emplace(outputName, std::nullopt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall)
|
DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall)
|
||||||
{
|
{
|
||||||
|
// If we haven't already cached the outputs set, then do so now.
|
||||||
if (outputs.empty()) {
|
if (outputs.empty()) {
|
||||||
/* Get the ‘outputs’ list. */
|
// FIXME: this behavior seems kind of busted, since whether or not this
|
||||||
Bindings::iterator i;
|
// DrvInfo will have paths is forever determined by the *first* call to
|
||||||
if (attrs && (i = attrs->find(state->sOutputs)) != attrs->end()) {
|
// this function??
|
||||||
state->forceList(*i->value, i->pos, "while evaluating the 'outputs' attribute of a derivation");
|
fillOutputs(withPaths);
|
||||||
|
|
||||||
/* For each output... */
|
|
||||||
for (auto elem : i->value->listItems()) {
|
|
||||||
std::string output(state->forceStringNoCtx(*elem, i->pos, "while evaluating the name of an output of a derivation"));
|
|
||||||
|
|
||||||
if (withPaths) {
|
|
||||||
/* Evaluate the corresponding set. */
|
|
||||||
Bindings::iterator out = attrs->find(state->symbols.create(output));
|
|
||||||
if (out == attrs->end()) continue; // FIXME: throw error?
|
|
||||||
state->forceAttrs(*out->value, i->pos, "while evaluating an output of a derivation");
|
|
||||||
|
|
||||||
/* And evaluate its ‘outPath’ attribute. */
|
|
||||||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
|
||||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
|
||||||
NixStringContext context;
|
|
||||||
outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context, "while evaluating an output path of a derivation"));
|
|
||||||
} else
|
|
||||||
outputs.emplace(output, std::nullopt);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
outputs.emplace("out", withPaths ? std::optional{queryOutPath()} : std::nullopt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Things that operate on derivations like packages, like `nix-env` and `nix build`,
|
||||||
|
// allow derivations to specify which outputs should be used in those user-facing
|
||||||
|
// cases if the user didn't specify an output explicitly.
|
||||||
|
// If the caller just wanted all the outputs for this derivation, though,
|
||||||
|
// then we're done here.
|
||||||
if (!onlyOutputsToInstall || !attrs)
|
if (!onlyOutputsToInstall || !attrs)
|
||||||
return outputs;
|
return outputs;
|
||||||
|
|
||||||
Bindings::iterator i;
|
// Regardless of `meta.outputsToInstall`, though, you can select into a derivation
|
||||||
if (attrs && (i = attrs->find(state->sOutputSpecified)) != attrs->end() && state->forceBool(*i->value, i->pos, "while evaluating the 'outputSpecified' attribute of a derivation")) {
|
// output by its attribute, e.g. `pkgs.lix.dev`, which (lol?) sets the magic
|
||||||
Outputs result;
|
// attribute `outputSpecified = true`, and changes the `outputName` attr to the
|
||||||
auto out = outputs.find(queryOutputName());
|
// explicitly selected-into output.
|
||||||
if (out == outputs.end())
|
if (Attr * outSpecAttr = attrs->get(state->sOutputSpecified)) {
|
||||||
throw Error("derivation does not have output '%s'", queryOutputName());
|
bool outputSpecified = this->state->forceBool(
|
||||||
result.insert(*out);
|
*outSpecAttr->value,
|
||||||
return result;
|
outSpecAttr->pos,
|
||||||
|
"while evaluating the 'outputSpecified' attribute of a derivation"
|
||||||
|
);
|
||||||
|
if (outputSpecified) {
|
||||||
|
auto maybeOut = outputs.find(queryOutputName());
|
||||||
|
if (maybeOut == outputs.end()) {
|
||||||
|
throw Error("derivation does not have output '%s'", queryOutputName());
|
||||||
|
}
|
||||||
|
return Outputs{*maybeOut};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
||||||
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
const Value * outTI = queryMeta("outputsToInstall");
|
||||||
const Value * outTI = queryMeta("outputsToInstall");
|
if (!outTI) return outputs;
|
||||||
if (!outTI) return outputs;
|
auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
||||||
auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
||||||
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
if (!outTI->isList()) throw errMsg;
|
||||||
if (!outTI->isList()) throw errMsg;
|
Outputs result;
|
||||||
Outputs result;
|
for (auto elem : outTI->listItems()) {
|
||||||
for (auto elem : outTI->listItems()) {
|
if (elem->type() != nString) throw errMsg;
|
||||||
if (elem->type() != nString) throw errMsg;
|
auto out = outputs.find(elem->string.s);
|
||||||
auto out = outputs.find(elem->string.s);
|
if (out == outputs.end()) throw errMsg;
|
||||||
if (out == outputs.end()) throw errMsg;
|
result.insert(*out);
|
||||||
result.insert(*out);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ private:
|
||||||
|
|
||||||
bool checkMeta(Value & v);
|
bool checkMeta(Value & v);
|
||||||
|
|
||||||
|
void fillOutputs(bool withPaths = true);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* path towards the derivation
|
* path towards the derivation
|
||||||
|
|
Loading…
Reference in a new issue