profile: convert Matcher to abstract class

This commit is contained in:
Bob van der Linden 2024-03-07 21:40:18 +01:00
parent 4741d3e308
commit 3d628d1704
No known key found for this signature in database

View file

@ -453,65 +453,85 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
} }
}; };
enum MatcherType
{
Regex,
StorePath,
Name,
All,
};
struct Matcher struct Matcher
{ {
MatcherType type; virtual std::string getTitle() = 0;
std::string title; virtual bool matches(const std::string & name, const ProfileElement & element) = 0;
std::function<bool(const std::string & name, const ProfileElement & element)> matches;
}; };
Matcher createRegexMatcher(const std::string & pattern) struct RegexMatcher : public Matcher
{ {
std::regex reg(pattern, std::regex::extended | std::regex::icase); std::regex regex;
return { std::string pattern;
.type = MatcherType::Regex,
.title = fmt("Regex '%s'", pattern),
.matches = [reg](const std::string &name, const ProfileElement & element) {
return std::regex_match(element.identifier(), reg);
},
};
}
Matcher createStorePathMatcher(const nix::StorePath & storePath) RegexMatcher(const std::string & pattern) : regex(pattern, std::regex::extended | std::regex::icase), pattern(pattern)
{ }
std::string getTitle() override
{
return fmt("Regex '%s'", pattern);
}
bool matches(const std::string & name, const ProfileElement & element) override
{
return std::regex_match(element.identifier(), regex);
}
};
struct StorePathMatcher : public Matcher
{ {
return { nix::StorePath storePath;
.type = MatcherType::StorePath,
.title = fmt("Store path '%s'", storePath.to_string()),
.matches = [storePath](const std::string &name, const ProfileElement & element) {
return element.storePaths.count(storePath);
}
};
}
Matcher createNameMatcher(const std::string & name) { StorePathMatcher(const nix::StorePath & storePath) : storePath(storePath)
return { { }
.type = MatcherType::Name,
.title = fmt("Package name '%s'", name),
.matches = [name](const std::string &elementName, const ProfileElement & element) {
return elementName == name;
}
};
}
Matcher all = { std::string getTitle() override
.type = MatcherType::All, {
.title = "--all", return fmt("Store path '%s'", storePath.to_string());
.matches = [](const std::string &name, const ProfileElement & element) { }
bool matches(const std::string & name, const ProfileElement & element) override
{
return element.storePaths.count(storePath);
}
};
struct NameMatcher : public Matcher
{
std::string name;
NameMatcher(const std::string & name) : name(name)
{ }
std::string getTitle() override
{
return fmt("Package name '%s'", name);
}
bool matches(const std::string & name, const ProfileElement & element) override
{
return name == this->name;
}
};
struct AllMatcher : public Matcher
{
std::string getTitle() override
{
return "--all";
}
bool matches(const std::string & name, const ProfileElement & element) override
{
return true; return true;
} }
}; };
AllMatcher all;
class MixProfileElementMatchers : virtual Args, virtual StoreCommand class MixProfileElementMatchers : virtual Args, virtual StoreCommand
{ {
std::vector<Matcher> _matchers; std::vector<ref<Matcher>> _matchers;
public: public:
@ -521,7 +541,7 @@ public:
.longName = "all", .longName = "all",
.description = "Match all packages in the profile.", .description = "Match all packages in the profile.",
.handler = {[this]() { .handler = {[this]() {
_matchers.push_back(all); _matchers.push_back(ref<AllMatcher>(std::shared_ptr<AllMatcher>(&all, [](AllMatcher*) {})));
}}, }},
}); });
addFlag({ addFlag({
@ -529,7 +549,7 @@ public:
.description = "A regular expression to match one or more packages in the profile.", .description = "A regular expression to match one or more packages in the profile.",
.labels = {"pattern"}, .labels = {"pattern"},
.handler = {[this](std::string arg) { .handler = {[this](std::string arg) {
_matchers.push_back(createRegexMatcher(arg)); _matchers.push_back(make_ref<RegexMatcher>(arg));
}}, }},
}); });
expectArgs({ expectArgs({
@ -540,9 +560,9 @@ public:
if (auto n = string2Int<size_t>(arg)) { if (auto n = string2Int<size_t>(arg)) {
throw Error("'nix profile' no longer supports indices ('%d')", *n); throw Error("'nix profile' no longer supports indices ('%d')", *n);
} else if (getStore()->isStorePath(arg)) { } else if (getStore()->isStorePath(arg)) {
_matchers.push_back(createStorePathMatcher(getStore()->parseStorePath(arg))); _matchers.push_back(make_ref<StorePathMatcher>(getStore()->parseStorePath(arg)));
} else { } else {
_matchers.push_back(createNameMatcher(arg)); _matchers.push_back(make_ref<NameMatcher>(arg));
} }
} }
}} }}
@ -554,7 +574,7 @@ public:
throw UsageError("No packages specified."); throw UsageError("No packages specified.");
} }
if (std::find_if(_matchers.begin(), _matchers.end(), [](const Matcher & m) { return m.type == MatcherType::All; }) != _matchers.end() && _matchers.size() > 1) { if (std::find_if(_matchers.begin(), _matchers.end(), [](const ref<Matcher> & m) { return m.dynamic_pointer_cast<AllMatcher>(); }) != _matchers.end() && _matchers.size() > 1) {
throw UsageError("--all cannot be used with package names or regular expressions."); throw UsageError("--all cannot be used with package names or regular expressions.");
} }
@ -567,13 +587,13 @@ public:
for (auto & matcher : _matchers) { for (auto & matcher : _matchers) {
bool foundMatch = false; bool foundMatch = false;
for (auto & [name, element] : manifest.elements) { for (auto & [name, element] : manifest.elements) {
if (matcher.matches(name, element)) { if (matcher->matches(name, element)) {
result.insert(name); result.insert(name);
foundMatch = true; foundMatch = true;
} }
} }
if (!foundMatch) { if (!foundMatch) {
warn("%s does not match any packages in the profile.", matcher.title); warn("%s does not match any packages in the profile.", matcher->getTitle());
} }
} }
return result; return result;