2023-01-19 05:26:06 +00:00
|
|
|
#include <regex>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
2023-01-11 06:51:14 +00:00
|
|
|
#include "util.hh"
|
2023-01-19 05:26:06 +00:00
|
|
|
#include "regex-combinators.hh"
|
2023-01-10 16:27:19 +00:00
|
|
|
#include "outputs-spec.hh"
|
2023-01-19 05:26:06 +00:00
|
|
|
#include "path-regex.hh"
|
2023-01-10 16:27:19 +00:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
2023-01-11 23:57:18 +00:00
|
|
|
bool OutputsSpec::contains(const std::string & outputName) const
|
2023-01-10 16:27:19 +00:00
|
|
|
{
|
2023-01-11 23:57:18 +00:00
|
|
|
return std::visit(overloaded {
|
|
|
|
[&](const OutputsSpec::All &) {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
[&](const OutputsSpec::Names & outputNames) {
|
|
|
|
return outputNames.count(outputName) > 0;
|
|
|
|
},
|
|
|
|
}, raw());
|
|
|
|
}
|
|
|
|
|
2023-01-19 05:26:06 +00:00
|
|
|
static std::string outputSpecRegexStr =
|
|
|
|
regex::either(
|
|
|
|
regex::group(R"(\*)"),
|
|
|
|
regex::group(regex::list(nameRegexStr)));
|
2023-01-11 23:57:18 +00:00
|
|
|
|
|
|
|
std::optional<OutputsSpec> OutputsSpec::parseOpt(std::string_view s)
|
|
|
|
{
|
2023-01-19 05:26:06 +00:00
|
|
|
static std::regex regex(std::string { outputSpecRegexStr });
|
2023-01-10 16:27:19 +00:00
|
|
|
|
|
|
|
std::smatch match;
|
2023-01-11 23:57:18 +00:00
|
|
|
std::string s2 { s }; // until some improves std::regex
|
|
|
|
if (!std::regex_match(s2, match, regex))
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
if (match[1].matched)
|
|
|
|
return { OutputsSpec::All {} };
|
|
|
|
|
|
|
|
if (match[2].matched)
|
2023-01-11 16:54:43 +00:00
|
|
|
return OutputsSpec::Names { tokenizeString<StringSet>(match[2].str(), ",") };
|
2023-01-11 23:57:18 +00:00
|
|
|
|
|
|
|
assert(false);
|
|
|
|
}
|
2023-01-10 16:27:19 +00:00
|
|
|
|
|
|
|
|
2023-01-11 23:57:18 +00:00
|
|
|
OutputsSpec OutputsSpec::parse(std::string_view s)
|
|
|
|
{
|
2023-01-11 22:31:32 +00:00
|
|
|
std::optional spec = parseOpt(s);
|
2023-01-11 23:57:18 +00:00
|
|
|
if (!spec)
|
2023-01-18 13:14:29 +00:00
|
|
|
throw Error("invalid outputs specifier '%s'", s);
|
2023-01-11 23:57:18 +00:00
|
|
|
return *spec;
|
2023-01-10 16:27:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-11 23:57:18 +00:00
|
|
|
|
2023-01-11 22:31:32 +00:00
|
|
|
std::optional<std::pair<std::string_view, ExtendedOutputsSpec>> ExtendedOutputsSpec::parseOpt(std::string_view s)
|
2023-01-11 23:57:18 +00:00
|
|
|
{
|
|
|
|
auto found = s.rfind('^');
|
|
|
|
|
|
|
|
if (found == std::string::npos)
|
2023-01-11 22:31:32 +00:00
|
|
|
return std::pair { s, ExtendedOutputsSpec::Default {} };
|
|
|
|
|
|
|
|
auto specOpt = OutputsSpec::parseOpt(s.substr(found + 1));
|
|
|
|
if (!specOpt)
|
|
|
|
return std::nullopt;
|
|
|
|
return std::pair { s.substr(0, found), ExtendedOutputsSpec::Explicit { *std::move(specOpt) } };
|
|
|
|
}
|
|
|
|
|
2023-01-11 23:57:18 +00:00
|
|
|
|
2023-01-11 22:31:32 +00:00
|
|
|
std::pair<std::string_view, ExtendedOutputsSpec> ExtendedOutputsSpec::parse(std::string_view s)
|
|
|
|
{
|
|
|
|
std::optional spec = parseOpt(s);
|
|
|
|
if (!spec)
|
2023-01-18 13:14:29 +00:00
|
|
|
throw Error("invalid extended outputs specifier '%s'", s);
|
2023-01-11 22:31:32 +00:00
|
|
|
return *spec;
|
2023-01-11 23:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string OutputsSpec::to_string() const
|
|
|
|
{
|
|
|
|
return std::visit(overloaded {
|
|
|
|
[&](const OutputsSpec::All &) -> std::string {
|
|
|
|
return "*";
|
|
|
|
},
|
|
|
|
[&](const OutputsSpec::Names & outputNames) -> std::string {
|
|
|
|
return concatStringsSep(",", outputNames);
|
|
|
|
},
|
|
|
|
}, raw());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-11 07:00:44 +00:00
|
|
|
std::string ExtendedOutputsSpec::to_string() const
|
2023-01-10 16:27:19 +00:00
|
|
|
{
|
2023-01-11 06:51:14 +00:00
|
|
|
return std::visit(overloaded {
|
2023-01-11 07:00:44 +00:00
|
|
|
[&](const ExtendedOutputsSpec::Default &) -> std::string {
|
2023-01-11 06:51:14 +00:00
|
|
|
return "";
|
|
|
|
},
|
2023-01-11 23:57:18 +00:00
|
|
|
[&](const ExtendedOutputsSpec::Explicit & outputSpec) -> std::string {
|
|
|
|
return "^" + outputSpec.to_string();
|
|
|
|
},
|
|
|
|
}, raw());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-13 01:20:27 +00:00
|
|
|
OutputsSpec OutputsSpec::union_(const OutputsSpec & that) const
|
2023-01-11 23:57:18 +00:00
|
|
|
{
|
|
|
|
return std::visit(overloaded {
|
2023-01-13 01:20:27 +00:00
|
|
|
[&](const OutputsSpec::All &) -> OutputsSpec {
|
|
|
|
return OutputsSpec::All { };
|
2023-01-11 06:51:14 +00:00
|
|
|
},
|
2023-01-13 01:20:27 +00:00
|
|
|
[&](const OutputsSpec::Names & theseNames) -> OutputsSpec {
|
2023-01-11 23:57:18 +00:00
|
|
|
return std::visit(overloaded {
|
2023-01-13 01:20:27 +00:00
|
|
|
[&](const OutputsSpec::All &) -> OutputsSpec {
|
|
|
|
return OutputsSpec::All {};
|
2023-01-11 23:57:18 +00:00
|
|
|
},
|
2023-01-13 01:20:27 +00:00
|
|
|
[&](const OutputsSpec::Names & thoseNames) -> OutputsSpec {
|
|
|
|
OutputsSpec::Names ret = theseNames;
|
|
|
|
ret.insert(thoseNames.begin(), thoseNames.end());
|
2023-01-11 23:57:18 +00:00
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
}, that.raw());
|
2023-01-11 06:51:14 +00:00
|
|
|
},
|
|
|
|
}, raw());
|
2023-01-10 16:27:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-13 01:20:27 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2023-01-11 21:32:30 +00:00
|
|
|
}
|
2023-01-11 23:57:18 +00:00
|
|
|
|
2023-01-11 21:32:30 +00:00
|
|
|
namespace nlohmann {
|
|
|
|
|
|
|
|
using namespace nix;
|
|
|
|
|
|
|
|
OutputsSpec adl_serializer<OutputsSpec>::from_json(const json & json) {
|
|
|
|
auto names = json.get<StringSet>();
|
|
|
|
if (names == StringSet({"*"}))
|
|
|
|
return OutputsSpec::All {};
|
|
|
|
else
|
|
|
|
return OutputsSpec::Names { std::move(names) };
|
|
|
|
}
|
|
|
|
|
|
|
|
void adl_serializer<OutputsSpec>::to_json(json & json, OutputsSpec t) {
|
2023-01-11 23:57:18 +00:00
|
|
|
std::visit(overloaded {
|
|
|
|
[&](const OutputsSpec::All &) {
|
|
|
|
json = std::vector<std::string>({"*"});
|
|
|
|
},
|
|
|
|
[&](const OutputsSpec::Names & names) {
|
|
|
|
json = names;
|
|
|
|
},
|
2023-01-17 14:14:17 +00:00
|
|
|
}, t.raw());
|
2023-01-11 23:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-11 21:32:30 +00:00
|
|
|
ExtendedOutputsSpec adl_serializer<ExtendedOutputsSpec>::from_json(const json & json) {
|
|
|
|
if (json.is_null())
|
|
|
|
return ExtendedOutputsSpec::Default {};
|
|
|
|
else {
|
|
|
|
return ExtendedOutputsSpec::Explicit { json.get<OutputsSpec>() };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void adl_serializer<ExtendedOutputsSpec>::to_json(json & json, ExtendedOutputsSpec t) {
|
2023-01-11 23:57:18 +00:00
|
|
|
std::visit(overloaded {
|
|
|
|
[&](const ExtendedOutputsSpec::Default &) {
|
|
|
|
json = nullptr;
|
|
|
|
},
|
|
|
|
[&](const ExtendedOutputsSpec::Explicit & e) {
|
2023-01-11 21:32:30 +00:00
|
|
|
adl_serializer<OutputsSpec>::to_json(json, e);
|
2023-01-11 23:57:18 +00:00
|
|
|
},
|
2023-01-17 14:14:17 +00:00
|
|
|
}, t.raw());
|
2023-01-10 16:27:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|