Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This command makes it easier to see what changed between two closures, i.e. what packages/versions got added or removed, and whether there were any notable changes in path size. For example: $ nix diff-closures /nix/var/nix/profiles/system-655-link /nix/var/nix/profiles/system-658-link blender-bin: 2.83.0 → 2.83.2, -294.2 KiB curl: 7.68.0 → 7.70.0, +19.1 KiB firmware-linux-nonfree: 2020-01-22 → 2020-05-19, +30827.7 KiB ibus: -21.8 KiB initrd-linux: 5.4.46 → 5.4.51, +16.9 KiB libexif: 0.6.21 → 0.6.22, +497.6 KiB linux: 5.4.46 → 5.4.51, +13.2 KiB mesa: 19.3.3 → 19.3.5, -183.9 KiB nix: 2.4pre20200701_6ff9aa8 → 2.4pre20200708_9223603, +9.7 KiB nix-bash-completions: 0.6.8 → ∅, -57.6 KiB nixos-system-hagbard: 20.03.20200615.a84b797 → 20.03.20200713.add5529 nvidia-persistenced: 440.82 → 440.100 nvidia-settings: 440.82 → 440.100 nvidia-x11: 440.82-5.4.46 → 440.100-5.4.51, +664.7 KiB pcre: 8.43 → 8.44 php: 7.3.16 → 7.3.20, -26.2 KiB python3.7-youtube-dl: 2020.06.06 → 2020.06.16.1, +8.4 KiB samba: 4.11.5 → 4.11.9, +30.1 KiB sane-backends: 1.0.28 → 1.0.30, +680.5 KiB source: -182.0 KiB zfs-kernel: 0.8.3-5.4.46 → 0.8.4-5.4.51, +9.9 KiB zfs-user: 0.8.3 → 0.8.4, +20.1 KiB
- Loading branch information
Showing
1 changed file
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#include "command.hh" | ||
#include "shared.hh" | ||
#include "store-api.hh" | ||
#include "common-args.hh" | ||
#include "names.hh" | ||
|
||
#include <regex> | ||
|
||
using namespace nix; | ||
|
||
struct Info | ||
{ | ||
std::string outputName; | ||
}; | ||
|
||
// name -> version -> store paths | ||
typedef std::map<std::string, std::map<std::string, std::map<StorePath, Info>>> GroupedPaths; | ||
|
||
GroupedPaths getClosureInfo(ref<Store> store, const StorePath & toplevel) | ||
{ | ||
StorePathSet closure; | ||
store->computeFSClosure({toplevel}, closure); | ||
|
||
GroupedPaths groupedPaths; | ||
|
||
for (auto & path : closure) { | ||
/* Strip the output name. Unfortunately this is ambiguous (we | ||
can't distinguish between output names like "bin" and | ||
version suffixes like "unstable"). */ | ||
static std::regex regex("(.*)-([a-z]+|lib32|lib64)"); | ||
std::smatch match; | ||
std::string name(path.name()); | ||
std::string outputName; | ||
if (std::regex_match(name, match, regex)) { | ||
name = match[1]; | ||
outputName = match[2]; | ||
} | ||
|
||
DrvName drvName(name); | ||
groupedPaths[drvName.name][drvName.version].emplace(path, Info { .outputName = outputName }); | ||
} | ||
|
||
return groupedPaths; | ||
} | ||
|
||
std::string showVersions(const std::set<std::string> & versions) | ||
{ | ||
if (versions.empty()) return "∅"; | ||
std::set<std::string> versions2; | ||
for (auto & version : versions) | ||
versions2.insert(version.empty() ? "ε" : version); | ||
return concatStringsSep(", ", versions2); | ||
} | ||
|
||
struct CmdDiffClosures : SourceExprCommand | ||
{ | ||
std::string _before, _after; | ||
|
||
CmdDiffClosures() | ||
{ | ||
expectArg("before", &_before); | ||
expectArg("after", &_after); | ||
} | ||
|
||
std::string description() override | ||
{ | ||
return "show what packages and versions were added and removed between two closures"; | ||
} | ||
|
||
Category category() override { return catSecondary; } | ||
|
||
Examples examples() override | ||
{ | ||
return { | ||
{ | ||
"To show what got added and removed between two versions of the NixOS system profile:", | ||
"nix diff-closures /nix/var/nix/profiles/system-655-link /nix/var/nix/profiles/system-658-link", | ||
}, | ||
}; | ||
} | ||
|
||
void run(ref<Store> store) override | ||
{ | ||
auto before = parseInstallable(*this, store, _before, false); | ||
auto beforePath = toStorePath(store, Build, before); | ||
auto after = parseInstallable(*this, store, _after, false); | ||
auto afterPath = toStorePath(store, NoBuild, 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)); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
static auto r1 = registerCommand<CmdDiffClosures>("diff-closures"); |