Make it hard to construct an empty OutputsSpec::Names

This should be a non-empty set, and so we don't want people doing this
by accident. We remove the zero-0 constructor with a little inheritance
trickery.
This commit is contained in:
John Ericson 2023-01-11 11:54:43 -05:00
parent 8a3b1b7ced
commit 114a6e2b09
7 changed files with 26 additions and 11 deletions

View file

@ -479,7 +479,7 @@ struct InstallableAttrPath : InstallableValue
auto derivedPath = byDrvPath.emplace(*drvPath, DerivedPath::Built { auto derivedPath = byDrvPath.emplace(*drvPath, DerivedPath::Built {
.drvPath = *drvPath, .drvPath = *drvPath,
// Not normally legal, but we will merge right below // Not normally legal, but we will merge right below
.outputs = OutputsSpec::Names { }, .outputs = OutputsSpec::Names { StringSet { } },
}).first; }).first;
derivedPath->second.outputs.merge(std::visit(overloaded { derivedPath->second.outputs.merge(std::visit(overloaded {

View file

@ -990,7 +990,7 @@ void DerivationGoal::resolvedFinished()
return resolvedDrv.outputNames(); return resolvedDrv.outputNames();
}, },
[&](const OutputsSpec::Names & names) { [&](const OutputsSpec::Names & names) {
return names; return static_cast<std::set<std::string>>(names);
}, },
}, wantedOutputs.raw()); }, wantedOutputs.raw());
@ -1325,7 +1325,7 @@ std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
return StringSet {}; return StringSet {};
}, },
[&](const OutputsSpec::Names & names) { [&](const OutputsSpec::Names & names) {
return names; return static_cast<StringSet>(names);
}, },
}, wantedOutputs.raw()); }, wantedOutputs.raw());
DrvOutputs validOutputs; DrvOutputs validOutputs;

View file

@ -317,7 +317,7 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd,
return names; return names;
}, },
[&](const OutputsSpec::Names & names) { [&](const OutputsSpec::Names & names) {
return names; return static_cast<std::set<std::string>>(names);
}, },
}, bfd.outputs); }, bfd.outputs);
for (auto & output : outputNames) { for (auto & output : outputNames) {

View file

@ -32,7 +32,7 @@ std::optional<OutputsSpec> OutputsSpec::parseOpt(std::string_view s)
return { OutputsSpec::All {} }; return { OutputsSpec::All {} };
if (match[2].matched) if (match[2].matched)
return { tokenizeString<OutputsSpec::Names>(match[2].str(), ",") }; return OutputsSpec::Names { tokenizeString<StringSet>(match[2].str(), ",") };
assert(false); assert(false);
} }
@ -139,11 +139,11 @@ void to_json(nlohmann::json & json, const ExtendedOutputsSpec & extendedOutputsS
void from_json(const nlohmann::json & json, OutputsSpec & outputsSpec) void from_json(const nlohmann::json & json, OutputsSpec & outputsSpec)
{ {
auto names = json.get<OutputNames>(); auto names = json.get<StringSet>();
if (names == OutputNames({"*"})) if (names == StringSet({"*"}))
outputsSpec = OutputsSpec::All {}; outputsSpec = OutputsSpec::All {};
else else
outputsSpec = names; outputsSpec = OutputsSpec::Names { std::move(names) };
} }

View file

@ -8,7 +8,22 @@
namespace nix { namespace nix {
typedef std::set<std::string> OutputNames; struct OutputNames : std::set<std::string> {
using std::set<std::string>::set;
// These need to be "inherited manually"
OutputNames(const std::set<std::string> & s)
: std::set<std::string>(s)
{ }
OutputNames(std::set<std::string> && s)
: std::set<std::string>(s)
{ }
/* This set should always be non-empty, so we delete this
constructor in order make creating empty ones by mistake harder.
*/
OutputNames() = delete;
};
struct AllOutputs { struct AllOutputs {
bool operator < (const AllOutputs & _) const { return false; } bool operator < (const AllOutputs & _) const { return false; }

View file

@ -53,7 +53,7 @@ std::variant<StorePathWithOutputs, StorePath> StorePathWithOutputs::tryFromDeriv
return {}; return {};
}, },
[&](const OutputsSpec::Names & outputs) { [&](const OutputsSpec::Names & outputs) {
return outputs; return static_cast<StringSet>(outputs);
}, },
}, bfd.outputs.raw()), }, bfd.outputs.raw()),
}; };

View file

@ -421,7 +421,7 @@ static void main_nix_build(int argc, char * * argv)
{ {
pathsToBuild.push_back(DerivedPath::Built { pathsToBuild.push_back(DerivedPath::Built {
.drvPath = inputDrv, .drvPath = inputDrv,
.outputs = inputOutputs .outputs = OutputsSpec::Names { inputOutputs },
}); });
pathsToCopy.insert(inputDrv); pathsToCopy.insert(inputDrv);
} }