Skip to content

Commit

Permalink
profile: convert Matcher to abstract class
Browse files Browse the repository at this point in the history
  • Loading branch information
bobvanderlinden committed Mar 8, 2024
1 parent 4741d3e commit 3d628d1
Showing 1 changed file with 69 additions and 49 deletions.
118 changes: 69 additions & 49 deletions src/nix/profile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -453,65 +453,85 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
}
};

enum MatcherType
struct Matcher
{
Regex,
StorePath,
Name,
All,
virtual std::string getTitle() = 0;
virtual bool matches(const std::string & name, const ProfileElement & element) = 0;
};

struct Matcher
struct RegexMatcher : public Matcher
{
MatcherType type;
std::string title;
std::function<bool(const std::string & name, const ProfileElement & element)> matches;
std::regex regex;
std::string pattern;

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);
}
};

Matcher createRegexMatcher(const std::string & pattern)
struct StorePathMatcher : public Matcher
{
std::regex reg(pattern, std::regex::extended | std::regex::icase);
return {
.type = MatcherType::Regex,
.title = fmt("Regex '%s'", pattern),
.matches = [reg](const std::string &name, const ProfileElement & element) {
return std::regex_match(element.identifier(), reg);
},
};
}
nix::StorePath storePath;

StorePathMatcher(const nix::StorePath & storePath) : storePath(storePath)
{ }

std::string getTitle() override
{
return fmt("Store path '%s'", storePath.to_string());
}

bool matches(const std::string & name, const ProfileElement & element) override
{
return element.storePaths.count(storePath);
}
};

Matcher createStorePathMatcher(const nix::StorePath & storePath)
struct NameMatcher : public Matcher
{
return {
.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);
}
};
}
std::string name;

Matcher createNameMatcher(const std::string & name) {
return {
.type = MatcherType::Name,
.title = fmt("Package name '%s'", name),
.matches = [name](const std::string &elementName, const ProfileElement & element) {
return elementName == name;
}
};
}
NameMatcher(const std::string & name) : name(name)
{ }

std::string getTitle() override
{
return fmt("Package name '%s'", name);
}

Matcher all = {
.type = MatcherType::All,
.title = "--all",
.matches = [](const std::string &name, const ProfileElement & element) {
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;
}
};

AllMatcher all;

class MixProfileElementMatchers : virtual Args, virtual StoreCommand
{
std::vector<Matcher> _matchers;
std::vector<ref<Matcher>> _matchers;

public:

Expand All @@ -521,15 +541,15 @@ class MixProfileElementMatchers : virtual Args, virtual StoreCommand
.longName = "all",
.description = "Match all packages in the profile.",
.handler = {[this]() {
_matchers.push_back(all);
_matchers.push_back(ref<AllMatcher>(std::shared_ptr<AllMatcher>(&all, [](AllMatcher*) {})));
}},
});
addFlag({
.longName = "regex",
.description = "A regular expression to match one or more packages in the profile.",
.labels = {"pattern"},
.handler = {[this](std::string arg) {
_matchers.push_back(createRegexMatcher(arg));
_matchers.push_back(make_ref<RegexMatcher>(arg));
}},
});
expectArgs({
Expand All @@ -540,9 +560,9 @@ class MixProfileElementMatchers : virtual Args, virtual StoreCommand
if (auto n = string2Int<size_t>(arg)) {
throw Error("'nix profile' no longer supports indices ('%d')", *n);
} else if (getStore()->isStorePath(arg)) {
_matchers.push_back(createStorePathMatcher(getStore()->parseStorePath(arg)));
_matchers.push_back(make_ref<StorePathMatcher>(getStore()->parseStorePath(arg)));
} else {
_matchers.push_back(createNameMatcher(arg));
_matchers.push_back(make_ref<NameMatcher>(arg));
}
}
}}
Expand All @@ -554,7 +574,7 @@ class MixProfileElementMatchers : virtual Args, virtual StoreCommand
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.");
}

Expand All @@ -567,13 +587,13 @@ class MixProfileElementMatchers : virtual Args, virtual StoreCommand
for (auto & matcher : _matchers) {
bool foundMatch = false;
for (auto & [name, element] : manifest.elements) {
if (matcher.matches(name, element)) {
if (matcher->matches(name, element)) {
result.insert(name);
foundMatch = true;
}
}
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;
Expand Down

0 comments on commit 3d628d1

Please sign in to comment.