Split OutputsSpec::merge
into OuputsSpec::{union_, isSubsetOf}
Additionally get rid of the evil time we made an empty `OutputSpec::Names()`.
This commit is contained in:
parent
0faf5326bd
commit
31875bcfb7
4 changed files with 56 additions and 30 deletions
|
@ -469,20 +469,14 @@ struct InstallableAttrPath : InstallableValue
|
||||||
|
|
||||||
// Backward compatibility hack: group results by drvPath. This
|
// Backward compatibility hack: group results by drvPath. This
|
||||||
// helps keep .all output together.
|
// helps keep .all output together.
|
||||||
std::map<StorePath, DerivedPath::Built> byDrvPath;
|
std::map<StorePath, OutputsSpec> byDrvPath;
|
||||||
|
|
||||||
for (auto & drvInfo : drvInfos) {
|
for (auto & drvInfo : drvInfos) {
|
||||||
auto drvPath = drvInfo.queryDrvPath();
|
auto drvPath = drvInfo.queryDrvPath();
|
||||||
if (!drvPath)
|
if (!drvPath)
|
||||||
throw Error("'%s' is not a derivation", what());
|
throw Error("'%s' is not a derivation", what());
|
||||||
|
|
||||||
auto derivedPath = byDrvPath.emplace(*drvPath, DerivedPath::Built {
|
auto newOutputs = std::visit(overloaded {
|
||||||
.drvPath = *drvPath,
|
|
||||||
// Not normally legal, but we will merge right below
|
|
||||||
.outputs = OutputsSpec::Names { StringSet { } },
|
|
||||||
}).first;
|
|
||||||
|
|
||||||
derivedPath->second.outputs.merge(std::visit(overloaded {
|
|
||||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||||
std::set<std::string> outputsToInstall;
|
std::set<std::string> outputsToInstall;
|
||||||
for (auto & output : drvInfo.queryOutputs(false, true))
|
for (auto & output : drvInfo.queryOutputs(false, true))
|
||||||
|
@ -492,12 +486,22 @@ struct InstallableAttrPath : InstallableValue
|
||||||
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
||||||
return e;
|
return e;
|
||||||
},
|
},
|
||||||
}, extendedOutputsSpec.raw()));
|
}, extendedOutputsSpec.raw());
|
||||||
|
|
||||||
|
auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
|
||||||
|
|
||||||
|
if (!didInsert)
|
||||||
|
iter->second = iter->second.union_(newOutputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPathsWithInfo res;
|
DerivedPathsWithInfo res;
|
||||||
for (auto & [_, info] : byDrvPath)
|
for (auto & [drvPath, outputs] : byDrvPath)
|
||||||
res.push_back({ .path = { info } });
|
res.push_back({
|
||||||
|
.path = DerivedPath::Built {
|
||||||
|
.drvPath = drvPath,
|
||||||
|
.outputs = outputs,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,10 @@ void DerivationGoal::work()
|
||||||
|
|
||||||
void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
|
void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
|
||||||
{
|
{
|
||||||
bool newOutputs = wantedOutputs.merge(outputs);
|
auto newWanted = wantedOutputs.union_(outputs);
|
||||||
if (newOutputs)
|
if (!newWanted.isSubsetOf(wantedOutputs))
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
|
wantedOutputs = newWanted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,24 +96,20 @@ std::string ExtendedOutputsSpec::to_string() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OutputsSpec::merge(const OutputsSpec & that)
|
OutputsSpec OutputsSpec::union_(const OutputsSpec & that) const
|
||||||
{
|
{
|
||||||
return std::visit(overloaded {
|
return std::visit(overloaded {
|
||||||
[&](OutputsSpec::All &) {
|
[&](const OutputsSpec::All &) -> OutputsSpec {
|
||||||
/* If we already refer to all outputs, there is nothing to do. */
|
return OutputsSpec::All { };
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
[&](OutputsSpec::Names & theseNames) {
|
[&](const OutputsSpec::Names & theseNames) -> OutputsSpec {
|
||||||
return std::visit(overloaded {
|
return std::visit(overloaded {
|
||||||
[&](const OutputsSpec::All &) {
|
[&](const OutputsSpec::All &) -> OutputsSpec {
|
||||||
*this = OutputsSpec::All {};
|
return OutputsSpec::All {};
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
[&](const OutputsSpec::Names & thoseNames) {
|
[&](const OutputsSpec::Names & thoseNames) -> OutputsSpec {
|
||||||
bool ret = false;
|
OutputsSpec::Names ret = theseNames;
|
||||||
for (auto & i : thoseNames)
|
ret.insert(thoseNames.begin(), thoseNames.end());
|
||||||
if (theseNames.insert(i).second)
|
|
||||||
ret = true;
|
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
}, that.raw());
|
}, that.raw());
|
||||||
|
@ -121,6 +117,30 @@ bool OutputsSpec::merge(const OutputsSpec & that)
|
||||||
}, raw());
|
}, raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OutputsSpec::isSubsetOf(const OutputsSpec & that) const
|
||||||
|
{
|
||||||
|
return std::visit(overloaded {
|
||||||
|
[&](const OutputsSpec::All &) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[&](const OutputsSpec::Names & thoseNames) {
|
||||||
|
return std::visit(overloaded {
|
||||||
|
[&](const OutputsSpec::All &) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[&](const OutputsSpec::Names & theseNames) {
|
||||||
|
bool ret = true;
|
||||||
|
for (auto & o : theseNames)
|
||||||
|
if (thoseNames.count(o) == 0)
|
||||||
|
ret = false;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
}, raw());
|
||||||
|
},
|
||||||
|
}, that.raw());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nlohmann {
|
namespace nlohmann {
|
||||||
|
|
|
@ -49,10 +49,11 @@ struct OutputsSpec : _OutputsSpecRaw {
|
||||||
|
|
||||||
bool contains(const std::string & output) const;
|
bool contains(const std::string & output) const;
|
||||||
|
|
||||||
/* Modify the receiver outputs spec so it is the union of it's old value
|
/* Create a new OutputsSpec which is the union of this and that. */
|
||||||
and the argument. Return whether the output spec needed to be modified
|
OutputsSpec union_(const OutputsSpec & that) const;
|
||||||
--- if it didn't it was already "large enough". */
|
|
||||||
bool merge(const OutputsSpec & outputs);
|
/* Whether this OutputsSpec is a subset of that. */
|
||||||
|
bool isSubsetOf(const OutputsSpec & outputs) const;
|
||||||
|
|
||||||
/* Parse a string of the form 'output1,...outputN' or
|
/* Parse a string of the form 'output1,...outputN' or
|
||||||
'*', returning the outputs spec. */
|
'*', returning the outputs spec. */
|
||||||
|
|
Loading…
Reference in a new issue