Skip to content

Commit

Permalink
profile: add installable matcher
Browse files Browse the repository at this point in the history
This allows removing and upgrading packages using flake urls.
  • Loading branch information
bobvanderlinden committed Mar 8, 2024
1 parent a200ee6 commit 8fa98ca
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
40 changes: 40 additions & 0 deletions src/nix/profile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,43 @@ struct NameMatcher : public Matcher
}
};

std::regex defaultPackageFragmentPattern("(?:legacyPackages|packages)\\.(?:[^\\.]+)\\.default");
std::regex packageFragmentPattern("(?:legacyPackages|packages)\\.(?:[^\\.]+)\\.(.+)");
struct InstallableMatcher : public Matcher
{
const FlakeRef flakeRef;
const std::string fragment;

InstallableMatcher(const FlakeRef flakeRef, const std::string fragment) : flakeRef(flakeRef), fragment(fragment)
{ }

std::string getTitle() override
{
return fmt("Installable '%s#%s'", flakeRef.to_string(), fragment);
}

bool matches(const std::string & name, const ProfileElement & element) override
{
if (element.source->originalRef != flakeRef) {
return false;
}
// Match "#packages.{system}.default"
if (fragment == "") {
return std::regex_match(element.source->attrPath, defaultPackageFragmentPattern);
}
// Match "#{name}"
if (element.source->attrPath == fragment) {
return true;
}
// Match "#packages.{system}.{name}"
std::smatch match;
if (std::regex_match(element.source->attrPath, match, packageFragmentPattern)) {
return match.str(1) == fragment;
}
return false;
}
};

struct AllMatcher : public Matcher
{
std::string getTitle() override
Expand Down Expand Up @@ -587,6 +624,9 @@ class MixProfileElementMatchers : virtual Args, virtual StoreCommand
throw Error("'nix profile' no longer supports indices ('%d')", *n);
} else if (getStore()->isStorePath(arg)) {
_matchers.push_back(make_ref<StorePathMatcher>(getStore()->parseStorePath(arg)));
} else if (std::regex_match(arg, std::regex(".*[#:].*"))) {
auto pair = parseFlakeRefWithFragment(arg);
_matchers.push_back(make_ref<InstallableMatcher>(pair.first, pair.second));
} else {
_matchers.push_back(make_ref<NameMatcher>(arg));
}
Expand Down
21 changes: 20 additions & 1 deletion tests/functional/nix-profile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,28 @@ warning: No packages to upgrade. Use 'nix profile list' to see the current profi
EOF

# Test removing all packages using regular expression.
nix profile remove --regex '.*' 2>&1 | grep "removed 2 packages, kept 0 packages"
assertStderr nix --offline profile remove --regex '.*' << EOF
removing 'path:$flake1Dir#packages.$system.default'
removing 'foo'
removed 2 packages, kept 0 packages
EOF
nix profile rollback

# Test removing package using full url.
nix profile remove "path:$flake1Dir#packages.$system.default"
[[ ! -f $TEST_HOME/.nix-profile/bin/hello ]]
nix profile install $flake1Dir

# Test removing package using shorthand flake url.
nix profile remove path:$flake1Dir
[[ ! -f $TEST_HOME/.nix-profile/bin/hello ]]
nix profile install $flake1Dir

# Test removing package using shorthand package name.
nix profile remove path:$flake1Dir#default
[[ ! -f $TEST_HOME/.nix-profile/bin/hello ]]
nix profile install $flake1Dir

# Test 'history', 'diff-closures'.
nix profile diff-closures

Expand Down

0 comments on commit 8fa98ca

Please sign in to comment.