#include #include #include "regex-combinators.hh" #include "outputs-spec.hh" #include "path-regex.hh" #include "strings.hh" namespace nix { bool OutputsSpec::contains(const std::string & outputName) const { return std::visit(overloaded { [&](const OutputsSpec::All &) { return true; }, [&](const OutputsSpec::Names & outputNames) { return outputNames.count(outputName) > 0; }, }, raw); } static std::string outputSpecRegexStr = regex::either( regex::group(R"(\*)"), regex::group(regex::list(nameRegexStr))); std::optional OutputsSpec::parseOpt(std::string_view s) { static std::regex regex(std::string { outputSpecRegexStr }); std::smatch match; 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) return OutputsSpec::Names { tokenizeString(match[2].str(), ",") }; assert(false); } OutputsSpec OutputsSpec::parse(std::string_view s) { std::optional spec = parseOpt(s); if (!spec) throw Error("invalid outputs specifier '%s'", s); return std::move(*spec); } std::optional> ExtendedOutputsSpec::parseOpt(std::string_view s) { auto found = s.rfind('^'); if (found == std::string::npos) 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) } }; } std::pair ExtendedOutputsSpec::parse(std::string_view s) { std::optional spec = parseOpt(s); if (!spec) throw Error("invalid extended outputs specifier '%s'", s); return *spec; } 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); } std::string ExtendedOutputsSpec::to_string() const { return std::visit(overloaded { [&](const ExtendedOutputsSpec::Default &) -> std::string { return ""; }, [&](const ExtendedOutputsSpec::Explicit & outputSpec) -> std::string { return "^" + outputSpec.to_string(); }, }, raw); } OutputsSpec OutputsSpec::union_(const OutputsSpec & that) const { return std::visit(overloaded { [&](const OutputsSpec::All &) -> OutputsSpec { return OutputsSpec::All { }; }, [&](const OutputsSpec::Names & theseNames) -> OutputsSpec { return std::visit(overloaded { [&](const OutputsSpec::All &) -> OutputsSpec { return OutputsSpec::All {}; }, [&](const OutputsSpec::Names & thoseNames) -> OutputsSpec { OutputsSpec::Names ret = theseNames; ret.insert(thoseNames.begin(), thoseNames.end()); return ret; }, }, that.raw); }, }, raw); } 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); } } namespace nlohmann { using namespace nix; OutputsSpec adl_serializer::from_json(const json & json) { auto names = json.get(); if (names == StringSet({"*"})) return OutputsSpec::All {}; else return OutputsSpec::Names { std::move(names) }; } void adl_serializer::to_json(json & json, OutputsSpec t) { std::visit(overloaded { [&](const OutputsSpec::All &) { json = std::vector({"*"}); }, [&](const OutputsSpec::Names & names) { json = names; }, }, t.raw); } ExtendedOutputsSpec adl_serializer::from_json(const json & json) { if (json.is_null()) return ExtendedOutputsSpec::Default {}; else { return ExtendedOutputsSpec::Explicit { json.get() }; } } void adl_serializer::to_json(json & json, ExtendedOutputsSpec t) { std::visit(overloaded { [&](const ExtendedOutputsSpec::Default &) { json = nullptr; }, [&](const ExtendedOutputsSpec::Explicit & e) { adl_serializer::to_json(json, e); }, }, t.raw); } }