mirror of
https://github.com/NixOS/nix
synced 2025-06-27 16:51:15 +02:00
The short answer for why we need to do this is so we can consistently do `#include "nix/..."`. Without this change, there are ways to still make that work, but they are hacky, and they have downsides such as making it harder to make sure headers from the wrong Nix library (e..g. `libnixexpr` headers in `libnixutil`) aren't being used. The C API alraedy used `nix_api_*`, so its headers are *not* put in subdirectories accordingly. Progress on #7876 We resisted doing this for a while because it would be annoying to not have the header source file pairs close by / easy to change file path/name from one to the other. But I am ameliorating that with symlinks in the next commit.
108 lines
3 KiB
C++
108 lines
3 KiB
C++
#include "nix/util.hh"
|
|
#include "nix/value/context.hh"
|
|
|
|
#include <optional>
|
|
|
|
namespace nix {
|
|
|
|
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 '!': {
|
|
// 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 std::visit(
|
|
[&](auto x) -> NixStringContextElem { return std::move(x); },
|
|
parseRest());
|
|
}
|
|
case '=': {
|
|
return NixStringContextElem::DrvDeep {
|
|
.drvPath = StorePath { s.substr(1) },
|
|
};
|
|
}
|
|
default: {
|
|
// 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
|
|
{
|
|
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) {
|
|
res += '!';
|
|
toStringRest(b);
|
|
},
|
|
[&](const NixStringContextElem::Opaque & o) {
|
|
toStringRest(o);
|
|
},
|
|
[&](const NixStringContextElem::DrvDeep & d) {
|
|
res += '=';
|
|
res += d.drvPath.to_string();
|
|
},
|
|
}, raw);
|
|
|
|
return res;
|
|
}
|
|
|
|
}
|