aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nix/command.hh6
-rw-r--r--src/nix/diff-closures.cc100
-rw-r--r--src/nix/profile.cc43
3 files changed, 104 insertions, 45 deletions
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 1c7413300..856721ebf 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -244,4 +244,10 @@ void completeFlakeRefWithFragment(
const Strings & defaultFlakeAttrPaths,
std::string_view prefix);
+void printClosureDiff(
+ ref<Store> store,
+ const StorePath & beforePath,
+ const StorePath & afterPath,
+ std::string_view indent);
+
}
diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc
index 56ddb575b..4199dae0f 100644
--- a/src/nix/diff-closures.cc
+++ b/src/nix/diff-closures.cc
@@ -6,7 +6,7 @@
#include <regex>
-using namespace nix;
+namespace nix {
struct Info
{
@@ -52,6 +52,60 @@ std::string showVersions(const std::set<std::string> & versions)
return concatStringsSep(", ", versions2);
}
+void printClosureDiff(
+ ref<Store> store,
+ const StorePath & beforePath,
+ const StorePath & afterPath,
+ std::string_view indent)
+{
+ auto beforeClosure = getClosureInfo(store, beforePath);
+ auto afterClosure = getClosureInfo(store, afterPath);
+
+ std::set<std::string> allNames;
+ for (auto & [name, _] : beforeClosure) allNames.insert(name);
+ for (auto & [name, _] : afterClosure) allNames.insert(name);
+
+ for (auto & name : allNames) {
+ auto & beforeVersions = beforeClosure[name];
+ auto & afterVersions = afterClosure[name];
+
+ auto totalSize = [&](const std::map<std::string, std::map<StorePath, Info>> & versions)
+ {
+ uint64_t sum = 0;
+ for (auto & [_, paths] : versions)
+ for (auto & [path, _] : paths)
+ sum += store->queryPathInfo(path)->narSize;
+ return sum;
+ };
+
+ auto beforeSize = totalSize(beforeVersions);
+ auto afterSize = totalSize(afterVersions);
+ auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize;
+ auto showDelta = abs(sizeDelta) >= 8 * 1024;
+
+ std::set<std::string> removed, unchanged;
+ for (auto & [version, _] : beforeVersions)
+ if (!afterVersions.count(version)) removed.insert(version); else unchanged.insert(version);
+
+ std::set<std::string> added;
+ for (auto & [version, _] : afterVersions)
+ if (!beforeVersions.count(version)) added.insert(version);
+
+ if (showDelta || !removed.empty() || !added.empty()) {
+ std::vector<std::string> items;
+ if (!removed.empty() || !added.empty())
+ items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added)));
+ if (showDelta)
+ items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0));
+ std::cout << fmt("%s%s: %s\n", indent, name, concatStringsSep(", ", items));
+ }
+ }
+}
+
+}
+
+using namespace nix;
+
struct CmdDiffClosures : SourceExprCommand
{
std::string _before, _after;
@@ -85,49 +139,7 @@ struct CmdDiffClosures : SourceExprCommand
auto beforePath = toStorePath(store, Realise::Outputs, operateOn, before);
auto after = parseInstallable(store, _after);
auto afterPath = toStorePath(store, Realise::Outputs, operateOn, after);
-
- auto beforeClosure = getClosureInfo(store, beforePath);
- auto afterClosure = getClosureInfo(store, afterPath);
-
- std::set<std::string> allNames;
- for (auto & [name, _] : beforeClosure) allNames.insert(name);
- for (auto & [name, _] : afterClosure) allNames.insert(name);
-
- for (auto & name : allNames) {
- auto & beforeVersions = beforeClosure[name];
- auto & afterVersions = afterClosure[name];
-
- auto totalSize = [&](const std::map<std::string, std::map<StorePath, Info>> & versions)
- {
- uint64_t sum = 0;
- for (auto & [_, paths] : versions)
- for (auto & [path, _] : paths)
- sum += store->queryPathInfo(path)->narSize;
- return sum;
- };
-
- auto beforeSize = totalSize(beforeVersions);
- auto afterSize = totalSize(afterVersions);
- auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize;
- auto showDelta = abs(sizeDelta) >= 8 * 1024;
-
- std::set<std::string> removed, unchanged;
- for (auto & [version, _] : beforeVersions)
- if (!afterVersions.count(version)) removed.insert(version); else unchanged.insert(version);
-
- std::set<std::string> added;
- for (auto & [version, _] : afterVersions)
- if (!beforeVersions.count(version)) added.insert(version);
-
- if (showDelta || !removed.empty() || !added.empty()) {
- std::vector<std::string> items;
- if (!removed.empty() || !added.empty())
- items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added)));
- if (showDelta)
- items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0));
- std::cout << fmt("%s: %s\n", name, concatStringsSep(", ", items));
- }
- }
+ printClosureDiff(store, beforePath, afterPath, "");
}
};
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 307e236d8..729924e3a 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -7,6 +7,7 @@
#include "builtins/buildenv.hh"
#include "flake/flakeref.hh"
#include "../nix-env/user-env.hh"
+#include "profiles.hh"
#include <nlohmann/json.hpp>
#include <regex>
@@ -394,6 +395,46 @@ struct CmdProfileInfo : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
}
};
+struct CmdProfileDiffClosures : virtual EvalCommand, virtual StoreCommand, MixDefaultProfile
+{
+ std::string description() override
+ {
+ return "show the closure difference between each generation of a profile";
+ }
+
+ Examples examples() override
+ {
+ return {
+ Example{
+ "To show what changed between each generation of the NixOS system profile:",
+ "nix profile diff-closure --profile /nix/var/nix/profiles/system"
+ },
+ };
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto [gens, curGen] = findGenerations(*profile);
+
+ std::optional<Generation> prevGen;
+ bool first = true;
+
+ for (auto & gen : gens) {
+ if (prevGen) {
+ if (!first) std::cout << "\n";
+ first = false;
+ std::cout << fmt("Generation %d -> %d:\n", prevGen->number, gen.number);
+ printClosureDiff(store,
+ store->followLinksToStorePath(prevGen->path),
+ store->followLinksToStorePath(gen.path),
+ " ");
+ }
+
+ prevGen = gen;
+ }
+ }
+};
+
struct CmdProfile : virtual MultiCommand, virtual Command
{
CmdProfile()
@@ -402,6 +443,7 @@ struct CmdProfile : virtual MultiCommand, virtual Command
{"remove", []() { return make_ref<CmdProfileRemove>(); }},
{"upgrade", []() { return make_ref<CmdProfileUpgrade>(); }},
{"info", []() { return make_ref<CmdProfileInfo>(); }},
+ {"diff-closures", []() { return make_ref<CmdProfileDiffClosures>(); }},
})
{ }
@@ -425,4 +467,3 @@ struct CmdProfile : virtual MultiCommand, virtual Command
};
static auto r1 = registerCommand<CmdProfile>("profile");
-