aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-10-22 13:06:32 +0200
committerEelco Dolstra <edolstra@gmail.com>2019-10-22 13:06:32 +0200
commite30a0155d47a2e8a2eb9d0801b8b1602f71c5fd7 (patch)
tree7fd019bf036fb7e38d37ddd67019914f97ac1f33
parent555ca59f2b34bb8f3e738789e9548895766609cf (diff)
Add "nix profile remove" command
-rw-r--r--src/libstore/builtins/buildenv.cc2
-rw-r--r--src/nix/profile.cc109
2 files changed, 108 insertions, 3 deletions
diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc
index c1c85d0bf..1b802d908 100644
--- a/src/libstore/builtins/buildenv.cc
+++ b/src/libstore/builtins/buildenv.cc
@@ -156,7 +156,7 @@ void buildProfile(const Path & out, Packages && pkgs)
addPkg(pkgDir, priorityCounter++);
}
- printError("created %d symlinks in user environment", state.symlinks);
+ debug("created %d symlinks in user environment", state.symlinks);
}
void builtinBuildenv(const BasicDerivation & drv)
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 2303900c0..c9a6a5355 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -8,6 +8,7 @@
#include "flake/flakeref.hh"
#include <nlohmann/json.hpp>
+#include <regex>
using namespace nix;
@@ -32,6 +33,8 @@ struct ProfileManifest
{
std::vector<ProfileElement> elements;
+ ProfileManifest() { }
+
ProfileManifest(const Path & profile)
{
auto manifestPath = profile + "/manifest.json";
@@ -173,11 +176,112 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
}
};
+class MixProfileElementMatchers : virtual Args
+{
+ std::vector<std::string> _matchers;
+
+public:
+
+ MixProfileElementMatchers()
+ {
+ expectArgs("elements", &_matchers);
+ }
+
+ typedef std::variant<size_t, Path, std::regex> Matcher;
+
+ std::vector<Matcher> getMatchers(ref<Store> store)
+ {
+ std::vector<Matcher> res;
+
+ for (auto & s : _matchers) {
+ size_t n;
+ if (string2Int(s, n))
+ res.push_back(n);
+ else if (store->isStorePath(s))
+ res.push_back(s);
+ else
+ res.push_back(std::regex(s, std::regex::extended | std::regex::icase));
+ }
+
+ return res;
+ }
+
+ bool matches(const ProfileElement & element, size_t pos, std::vector<Matcher> matchers)
+ {
+ for (auto & matcher : matchers) {
+ if (auto n = std::get_if<size_t>(&matcher)) {
+ if (*n == pos) return true;
+ } else if (auto path = std::get_if<Path>(&matcher)) {
+ if (element.storePaths.count(*path)) return true;
+ } else if (auto regex = std::get_if<std::regex>(&matcher)) {
+ if (element.source
+ && std::regex_match(element.source->attrPath, *regex))
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+struct CmdProfileRemove : virtual StoreCommand, MixDefaultProfile, MixProfileElementMatchers
+{
+ std::string description() override
+ {
+ return "remove packages from a profile";
+ }
+
+ Examples examples() override
+ {
+ return {
+ Example{
+ "To remove a package by attribute path:",
+ "nix profile remove packages.x86_64-linux.hello"
+ },
+ Example{
+ "To remove all package:",
+ "nix profile remove '.*'"
+ },
+ Example{
+ "To remove a package by store path:",
+ "nix profile remove /nix/store/rr3y0c6zyk7kjjl8y19s4lsrhn4aiq1z-hello-2.10"
+ },
+ Example{
+ "To remove a package by position:",
+ "nix profile remove 3"
+ },
+ };
+ }
+
+ void run(ref<Store> store) override
+ {
+ ProfileManifest oldManifest(*profile);
+
+ auto matchers = getMatchers(store);
+
+ ProfileManifest newManifest;
+
+ for (size_t i = 0; i < oldManifest.elements.size(); ++i) {
+ auto & element(oldManifest.elements[i]);
+ if (!matches(element, i, matchers))
+ newManifest.elements.push_back(element);
+ }
+
+ // FIXME: warn about unused matchers?
+
+ printInfo("removed %d packages, kept %d packages",
+ oldManifest.elements.size() - newManifest.elements.size(),
+ newManifest.elements.size());
+
+ updateProfile(newManifest.build(store));
+ }
+};
+
struct CmdProfileInfo : virtual StoreCommand, MixDefaultProfile
{
std::string description() override
{
- return "info";
+ return "list installed packages";
}
Examples examples() override
@@ -196,7 +300,7 @@ struct CmdProfileInfo : virtual StoreCommand, MixDefaultProfile
for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
- std::cout << fmt("%d %s %s\n", i,
+ std::cout << fmt("%d %s %s %s\n", i,
element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath : "-",
element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-",
concatStringsSep(" ", element.storePaths));
@@ -209,6 +313,7 @@ struct CmdProfile : virtual MultiCommand, virtual Command
CmdProfile()
: MultiCommand({
{"install", []() { return make_ref<CmdProfileInstall>(); }},
+ {"remove", []() { return make_ref<CmdProfileRemove>(); }},
{"info", []() { return make_ref<CmdProfileInfo>(); }},
})
{ }