diff --git a/src/libmain/include/nix/main/shared.hh b/src/libmain/include/nix/main/shared.hh index 9554a51d587..9aa67ae0dae 100644 --- a/src/libmain/include/nix/main/shared.hh +++ b/src/libmain/include/nix/main/shared.hh @@ -89,19 +89,7 @@ extern volatile ::sig_atomic_t blockInt; struct GCResults; -struct PrintFreed -{ - bool show; - const GCResults & results; - - PrintFreed(bool show, const GCResults & results) - : show(show) - , results(results) - { - } - - ~PrintFreed(); -}; +void printFreed(bool dryRun, const GCResults & results); #ifndef _WIN32 /** diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index fd56e3f1e21..fd0af9b66fd 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -391,9 +391,12 @@ RunPager::~RunPager() } } -PrintFreed::~PrintFreed() +void printFreed(bool dryRun, const GCResults & results) { - if (show) + /* bytesFreed cannot be reliably computed without actually deleting store paths because of hardlinking. */ + if (dryRun) + std::cout << fmt("%d store paths would be deleted\n", results.paths.size()); + else std::cout << fmt("%d store paths deleted, %s freed\n", results.paths.size(), renderSize(results.bytesFreed)); } diff --git a/src/libstore/include/nix/store/gc-store.hh b/src/libstore/include/nix/store/gc-store.hh index 7f04ed5a2c2..d5617d6d5c4 100644 --- a/src/libstore/include/nix/store/gc-store.hh +++ b/src/libstore/include/nix/store/gc-store.hh @@ -69,8 +69,7 @@ struct GCResults PathSet paths; /** - * For `gcReturnDead`, `gcDeleteDead` and `gcDeleteSpecific`, the - * number of bytes that would be or was freed. + * For `gcDeleteDead` and `gcDeleteSpecific`, the number of bytes that were freed. */ uint64_t bytesFreed = 0; }; diff --git a/src/nix/nix-collect-garbage/nix-collect-garbage.cc b/src/nix/nix-collect-garbage/nix-collect-garbage.cc index 29ca17a5de2..6cff8df6891 100644 --- a/src/nix/nix-collect-garbage/nix-collect-garbage.cc +++ b/src/nix/nix-collect-garbage/nix-collect-garbage.cc @@ -1,5 +1,6 @@ #include "nix/util/file-system.hh" #include "nix/util/signals.hh" +#include "nix/util/error.hh" #include "nix/store/store-open.hh" #include "nix/store/store-cast.hh" #include "nix/store/gc-store.hh" @@ -87,6 +88,9 @@ static int main_nix_collect_garbage(int argc, char ** argv) return true; }); + if (options.maxFreed != std::numeric_limits::max() && dryRun) + throw UsageError("options --max-freed and --dry-run cannot be combined"); + if (removeOld) { std::set dirsToClean = { profilesDir(), @@ -97,15 +101,12 @@ static int main_nix_collect_garbage(int argc, char ** argv) removeOldGenerations(dir); } - // Run the actual garbage collector. - if (!dryRun) { - auto store = openStore(); - auto & gcStore = require(*store); - options.action = GCOptions::gcDeleteDead; - GCResults results; - PrintFreed freed(true, results); - gcStore.collectGarbage(options, results); - } + auto store = openStore(); + auto & gcStore = require(*store); + options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead; + GCResults results; + Finally printer([&] { printFreed(dryRun, results); }); + gcStore.collectGarbage(options, results); return 0; } diff --git a/src/nix/nix-store/nix-store.cc b/src/nix/nix-store/nix-store.cc index f9c32ee063b..45fb8e58177 100644 --- a/src/nix/nix-store/nix-store.cc +++ b/src/nix/nix-store/nix-store.cc @@ -18,6 +18,8 @@ #include "nix/store/export-import.hh" #include "nix/util/strings.hh" #include "nix/store/posix-fs-canonicalise.hh" +#include "nix/util/error.hh" +#include "nix/store/gc-store.hh" #include "man-pages.hh" @@ -679,6 +681,10 @@ static void opGC(Strings opFlags, Strings opArgs) if (!opArgs.empty()) throw UsageError("no arguments expected"); + if (options.maxFreed != std::numeric_limits::max() + && (options.action == GCOptions::gcReturnDead || options.action == GCOptions::gcReturnLive || printRoots)) + throw UsageError("option --max-freed cannot be combined with --print-live, --print-dead, or --print-roots"); + auto & gcStore = require(*store); if (printRoots) { @@ -693,12 +699,14 @@ static void opGC(Strings opFlags, Strings opArgs) } else { - PrintFreed freed(options.action == GCOptions::gcDeleteDead, results); + Finally printer([&] { + if (options.action != GCOptions::gcDeleteDead) + for (auto & i : results.paths) + cout << i << std::endl; + else + printFreed(false, results); + }); gcStore.collectGarbage(options, results); - - if (options.action != GCOptions::gcDeleteDead) - for (auto & i : results.paths) - cout << i << std::endl; } } @@ -722,7 +730,7 @@ static void opDelete(Strings opFlags, Strings opArgs) auto & gcStore = require(*store); GCResults results; - PrintFreed freed(true, results); + Finally printer([&] { printFreed(false, results); }); gcStore.collectGarbage(options, results); } diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index 42517c8828e..3e2e0f2ba51 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/store-delete.cc @@ -40,7 +40,7 @@ struct CmdStoreDelete : StorePathsCommand options.pathsToDelete.insert(path); GCResults results; - PrintFreed freed(true, results); + Finally printer([&] { printFreed(false, results); }); gcStore.collectGarbage(options, results); } }; diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc index b0a627837ce..971be26be5b 100644 --- a/src/nix/store-gc.cc +++ b/src/nix/store-gc.cc @@ -4,6 +4,8 @@ #include "nix/store/store-api.hh" #include "nix/store/store-cast.hh" #include "nix/store/gc-store.hh" +#include "nix/util/error.hh" +#include "nix/util/logging.hh" using namespace nix; @@ -15,7 +17,7 @@ struct CmdStoreGC : StoreCommand, MixDryRun { addFlag({ .longName = "max", - .description = "Stop after freeing *n* bytes of disk space.", + .description = "Stop after freeing *n* bytes of disk space. Cannot be combined with --dry-run.", .labels = {"n"}, .handler = {&options.maxFreed}, }); @@ -35,11 +37,14 @@ struct CmdStoreGC : StoreCommand, MixDryRun void run(ref store) override { + if (options.maxFreed != std::numeric_limits::max() && dryRun) + throw UsageError("options --max and --dry-run cannot be combined"); + auto & gcStore = require(*store); options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead; GCResults results; - PrintFreed freed(options.action == GCOptions::gcDeleteDead, results); + Finally printer([&] { printFreed(dryRun, results); }); gcStore.collectGarbage(options, results); } };