Compare commits
2 Commits
flakes
...
diff-closu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0356f14459 | ||
|
|
cff2157185 |
@@ -1097,13 +1097,16 @@ StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
|
||||
{
|
||||
Path srcPath(absPath(_srcPath));
|
||||
|
||||
if (method != FileIngestionMethod::Recursive)
|
||||
return addToStoreFromDump(readFile(srcPath), name, method, hashAlgo, repair);
|
||||
|
||||
/* For computing the NAR hash. */
|
||||
auto sha256Sink = std::make_unique<HashSink>(htSHA256);
|
||||
|
||||
/* For computing the store path. In recursive SHA-256 mode, this
|
||||
is the same as the NAR hash, so no need to do it again. */
|
||||
std::unique_ptr<HashSink> hashSink =
|
||||
method == FileIngestionMethod::Recursive && hashAlgo == htSHA256
|
||||
hashAlgo == htSHA256
|
||||
? nullptr
|
||||
: std::make_unique<HashSink>(hashAlgo);
|
||||
|
||||
@@ -1136,10 +1139,7 @@ StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
|
||||
if (!inMemory) sink(buf, len);
|
||||
});
|
||||
|
||||
if (method == FileIngestionMethod::Recursive)
|
||||
dumpPath(srcPath, sink2, filter);
|
||||
else
|
||||
readFile(srcPath, sink2);
|
||||
dumpPath(srcPath, sink2, filter);
|
||||
});
|
||||
|
||||
std::unique_ptr<AutoDelete> delTempDir;
|
||||
@@ -1155,10 +1155,7 @@ StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
|
||||
delTempDir = std::make_unique<AutoDelete>(tempDir);
|
||||
tempPath = tempDir + "/x";
|
||||
|
||||
if (method == FileIngestionMethod::Recursive)
|
||||
restorePath(tempPath, *source);
|
||||
else
|
||||
writeFile(tempPath, *source);
|
||||
restorePath(tempPath, *source);
|
||||
|
||||
} catch (EndOfFile &) {
|
||||
if (!inMemory) throw;
|
||||
@@ -1191,10 +1188,7 @@ StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
|
||||
if (inMemory) {
|
||||
/* Restore from the NAR in memory. */
|
||||
StringSource source(nar);
|
||||
if (method == FileIngestionMethod::Recursive)
|
||||
restorePath(realPath, source);
|
||||
else
|
||||
writeFile(realPath, source);
|
||||
restorePath(realPath, source);
|
||||
} else {
|
||||
/* Move the temporary path we restored above. */
|
||||
if (rename(tempPath.c_str(), realPath.c_str()))
|
||||
|
||||
134
src/nix/diff-closures.cc
Normal file
134
src/nix/diff-closures.cc
Normal file
@@ -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");
|
||||
Reference in New Issue
Block a user