mirror of
https://github.com/NixOS/nix
synced 2025-06-28 05:21:16 +02:00
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`: `foo.drv^bar.drv` is the dynamic derivation (since it is itself a derivation output, `bar.drv` from `foo.drv`). To that end, we create `Single{Derivation,BuiltPath}` types, that are very similar except instead of having multiple outputs (in a set or map), they have a single one. This is for everything to the left of the rightmost `^`. `NixStringContextElem` has an analogous change, and now can reuse `SingleDerivedPath` at the top level. In fact, if we ever get rid of `DrvDeep`, `NixStringContextElem` could be replaced with `SingleDerivedPath` entirely! Important note: some JSON formats have changed. We already can *produce* dynamic derivations, but we can't refer to them directly. Today, we can merely express building or example at the top imperatively over time by building `foo.drv^bar.drv`, and then with a second nix invocation doing `<result-from-first>^baz`, but this is not declarative. The ethos of Nix of being able to write down the full plan everything you want to do, and then execute than plan with a single command, and for that we need the new inductive form of these types. Co-authored-by: Robert Hensing <roberth@users.noreply.github.com> Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
This commit is contained in:
parent
d00fe5f225
commit
60b7121d2c
48 changed files with 1136 additions and 267 deletions
|
@ -4,29 +4,52 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
NixStringContextElem NixStringContextElem::parse(std::string_view s0)
|
||||
NixStringContextElem NixStringContextElem::parse(
|
||||
std::string_view s0,
|
||||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
std::string_view s = s0;
|
||||
|
||||
std::function<SingleDerivedPath()> parseRest;
|
||||
parseRest = [&]() -> SingleDerivedPath {
|
||||
// Case on whether there is a '!'
|
||||
size_t index = s.find("!");
|
||||
if (index == std::string_view::npos) {
|
||||
return SingleDerivedPath::Opaque {
|
||||
.path = StorePath { s },
|
||||
};
|
||||
} else {
|
||||
std::string output { s.substr(0, index) };
|
||||
// Advance string to parse after the '!'
|
||||
s = s.substr(index + 1);
|
||||
auto drv = make_ref<SingleDerivedPath>(parseRest());
|
||||
drvRequireExperiment(*drv, xpSettings);
|
||||
return SingleDerivedPath::Built {
|
||||
.drvPath = std::move(drv),
|
||||
.output = std::move(output),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if (s.size() == 0) {
|
||||
throw BadNixStringContextElem(s0,
|
||||
"String context element should never be an empty string");
|
||||
}
|
||||
|
||||
switch (s.at(0)) {
|
||||
case '!': {
|
||||
s = s.substr(1); // advance string to parse after first !
|
||||
size_t index = s.find("!");
|
||||
// This makes index + 1 safe. Index can be the length (one after index
|
||||
// of last character), so given any valid character index --- a
|
||||
// successful find --- we can add one.
|
||||
if (index == std::string_view::npos) {
|
||||
// Advance string to parse after the '!'
|
||||
s = s.substr(1);
|
||||
|
||||
// Find *second* '!'
|
||||
if (s.find("!") == std::string_view::npos) {
|
||||
throw BadNixStringContextElem(s0,
|
||||
"String content element beginning with '!' should have a second '!'");
|
||||
}
|
||||
return NixStringContextElem::Built {
|
||||
.drvPath = StorePath { s.substr(index + 1) },
|
||||
.output = std::string(s.substr(0, index)),
|
||||
};
|
||||
|
||||
return std::visit(
|
||||
[&](auto x) -> NixStringContextElem { return std::move(x); },
|
||||
parseRest());
|
||||
}
|
||||
case '=': {
|
||||
return NixStringContextElem::DrvDeep {
|
||||
|
@ -34,33 +57,51 @@ NixStringContextElem NixStringContextElem::parse(std::string_view s0)
|
|||
};
|
||||
}
|
||||
default: {
|
||||
return NixStringContextElem::Opaque {
|
||||
.path = StorePath { s },
|
||||
};
|
||||
// Ensure no '!'
|
||||
if (s.find("!") != std::string_view::npos) {
|
||||
throw BadNixStringContextElem(s0,
|
||||
"String content element not beginning with '!' should not have a second '!'");
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto x) -> NixStringContextElem { return std::move(x); },
|
||||
parseRest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string NixStringContextElem::to_string() const {
|
||||
return std::visit(overloaded {
|
||||
std::string NixStringContextElem::to_string() const
|
||||
{
|
||||
std::string res;
|
||||
|
||||
std::function<void(const SingleDerivedPath &)> toStringRest;
|
||||
toStringRest = [&](auto & p) {
|
||||
std::visit(overloaded {
|
||||
[&](const SingleDerivedPath::Opaque & o) {
|
||||
res += o.path.to_string();
|
||||
},
|
||||
[&](const SingleDerivedPath::Built & o) {
|
||||
res += o.output;
|
||||
res += '!';
|
||||
toStringRest(*o.drvPath);
|
||||
},
|
||||
}, p.raw());
|
||||
};
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](const NixStringContextElem::Built & b) {
|
||||
std::string res;
|
||||
res += '!';
|
||||
res += b.output;
|
||||
res += '!';
|
||||
res += b.drvPath.to_string();
|
||||
return res;
|
||||
},
|
||||
[&](const NixStringContextElem::DrvDeep & d) {
|
||||
std::string res;
|
||||
res += '=';
|
||||
res += d.drvPath.to_string();
|
||||
return res;
|
||||
toStringRest(b);
|
||||
},
|
||||
[&](const NixStringContextElem::Opaque & o) {
|
||||
return std::string { o.path.to_string() };
|
||||
toStringRest(o);
|
||||
},
|
||||
[&](const NixStringContextElem::DrvDeep & d) {
|
||||
res += '=';
|
||||
res += d.drvPath.to_string();
|
||||
},
|
||||
}, raw());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue