mirror of
https://github.com/NixOS/nix.git
synced 2025-12-13 20:41:04 +01:00
This is an example of "Parse, don't validate" principle [1]. Before, we had a number of `StringSet`s in `DerivationOptions` that were not *actually* allowed to be arbitrary sets of strings. Instead, each set member had to be one of: - a store path - a CA "downstream placeholder" - an output name Only later, in the code that checks outputs, would these strings be further parsed to match these cases. (Actually, only 2 by that point, because the placeholders must be rewritten away by then.) Now, we fully parse everything up front, and have an "honest" data type that reflects these invariants: - store paths are parsed, stored as (opaque) deriving paths - CA "downstream placeholders" are rewritten to the output deriving paths they denote - output names are the only arbitrary strings left Since the first two cases both become deriving paths, that leaves us with a `std::variant<SingleDerivedPath, String>` data type, which we use in our sets instead. Getting rid of placeholders is especially nice because we are replacing them with something much more internally-structured / transparent. [1]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo> Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
94 lines
3.2 KiB
C++
94 lines
3.2 KiB
C++
#include "nix/store/downstream-placeholder.hh"
|
|
#include "nix/store/derivations.hh"
|
|
#include "nix/util/json-utils.hh"
|
|
|
|
namespace nix {
|
|
|
|
std::string DownstreamPlaceholder::render() const
|
|
{
|
|
return "/" + hash.to_string(HashFormat::Nix32, false);
|
|
}
|
|
|
|
DownstreamPlaceholder DownstreamPlaceholder::unknownCaOutput(
|
|
const StorePath & drvPath, OutputNameView outputName, const ExperimentalFeatureSettings & xpSettings)
|
|
{
|
|
xpSettings.require(Xp::CaDerivations);
|
|
auto drvNameWithExtension = drvPath.name();
|
|
auto drvName = drvNameWithExtension.substr(0, drvNameWithExtension.size() - 4);
|
|
auto clearText =
|
|
"nix-upstream-output:" + std::string{drvPath.hashPart()} + ":" + outputPathName(drvName, outputName);
|
|
return DownstreamPlaceholder{hashString(HashAlgorithm::SHA256, clearText)};
|
|
}
|
|
|
|
DownstreamPlaceholder DownstreamPlaceholder::unknownDerivation(
|
|
const DownstreamPlaceholder & placeholder,
|
|
OutputNameView outputName,
|
|
const ExperimentalFeatureSettings & xpSettings)
|
|
{
|
|
xpSettings.require(
|
|
Xp::DynamicDerivations, [&] { return fmt("placeholder for unknown derivation output '%s'", outputName); });
|
|
auto compressed = compressHash(placeholder.hash, 20);
|
|
auto clearText =
|
|
"nix-computed-output:" + compressed.to_string(HashFormat::Nix32, false) + ":" + std::string{outputName};
|
|
return DownstreamPlaceholder{hashString(HashAlgorithm::SHA256, clearText)};
|
|
}
|
|
|
|
DownstreamPlaceholder DownstreamPlaceholder::fromSingleDerivedPathBuilt(
|
|
const SingleDerivedPath::Built & b, const ExperimentalFeatureSettings & xpSettings)
|
|
{
|
|
return std::visit(
|
|
overloaded{
|
|
[&](const SingleDerivedPath::Opaque & o) {
|
|
return DownstreamPlaceholder::unknownCaOutput(o.path, b.output, xpSettings);
|
|
},
|
|
[&](const SingleDerivedPath::Built & b2) {
|
|
return DownstreamPlaceholder::unknownDerivation(
|
|
DownstreamPlaceholder::fromSingleDerivedPathBuilt(b2, xpSettings), b.output, xpSettings);
|
|
},
|
|
},
|
|
b.drvPath->raw());
|
|
}
|
|
|
|
} // namespace nix
|
|
|
|
namespace nlohmann {
|
|
|
|
using namespace nix;
|
|
|
|
template<typename Item>
|
|
DrvRef<Item> adl_serializer<DrvRef<Item>>::from_json(const json & json)
|
|
{
|
|
// OutputName case: { "drvPath": "self", "output": <output> }
|
|
if (json.type() == nlohmann::json::value_t::object) {
|
|
auto & obj = getObject(json);
|
|
if (auto * drvPath_ = get(obj, "drvPath")) {
|
|
auto & drvPath = *drvPath_;
|
|
if (drvPath.type() == nlohmann::json::value_t::string && getString(drvPath) == "self") {
|
|
return getString(valueAt(obj, "output"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Input case
|
|
return adl_serializer<Item>::from_json(json);
|
|
}
|
|
|
|
template<typename Item>
|
|
void adl_serializer<DrvRef<Item>>::to_json(json & json, const DrvRef<Item> & ref)
|
|
{
|
|
std::visit(
|
|
overloaded{
|
|
[&](const OutputName & outputName) {
|
|
json = nlohmann::json::object();
|
|
json["drvPath"] = "self";
|
|
json["output"] = outputName;
|
|
},
|
|
[&](const Item & item) { json = item; },
|
|
},
|
|
ref);
|
|
}
|
|
|
|
template struct adl_serializer<nix::DrvRef<StorePath>>;
|
|
template struct adl_serializer<nix::DrvRef<SingleDerivedPath>>;
|
|
|
|
} // namespace nlohmann
|