about summary refs log tree commit diff
path: root/third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc')
-rw-r--r--third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc103
1 files changed, 103 insertions, 0 deletions
diff --git a/third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc b/third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc
new file mode 100644
index 0000000000..ac8c7d9399
--- /dev/null
+++ b/third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc
@@ -0,0 +1,103 @@
+#include <cerrno>
+#include <iostream>
+
+#include <glog/logging.h>
+
+#include "libmain/shared.hh"
+#include "libstore/globals.hh"
+#include "libstore/profiles.hh"
+#include "libstore/store-api.hh"
+#include "nix/legacy.hh"
+
+using namespace nix;
+
+std::string deleteOlderThan;
+bool dryRun = false;
+
+/* If `-d' was specified, remove all old generations of all profiles.
+ * Of course, this makes rollbacks to before this point in time
+ * impossible. */
+
+void removeOldGenerations(const std::string& dir) {
+  if (access(dir.c_str(), R_OK) != 0) {
+    return;
+  }
+
+  bool canWrite = access(dir.c_str(), W_OK) == 0;
+
+  for (auto& i : readDirectory(dir)) {
+    checkInterrupt();
+
+    auto path = dir + "/" + i.name;
+    auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
+
+    if (type == DT_LNK && canWrite) {
+      std::string link;
+      try {
+        link = readLink(path);
+      } catch (SysError& e) {
+        if (e.errNo == ENOENT) {
+          continue;
+        }
+      }
+      if (link.find("link") != std::string::npos) {
+        LOG(INFO) << "removing old generations of profile " << path;
+        if (!deleteOlderThan.empty()) {
+          deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
+        } else {
+          deleteOldGenerations(path, dryRun);
+        }
+      }
+    } else if (type == DT_DIR) {
+      removeOldGenerations(path);
+    }
+  }
+}
+
+static int _main(int argc, char** argv) {
+  {
+    bool removeOld = false;
+
+    GCOptions options;
+
+    parseCmdLine(argc, argv,
+                 [&](Strings::iterator& arg, const Strings::iterator& end) {
+                   if (*arg == "--help") {
+                     showManPage("nix-collect-garbage");
+                   } else if (*arg == "--version") {
+                     printVersion("nix-collect-garbage");
+                   } else if (*arg == "--delete-old" || *arg == "-d") {
+                     removeOld = true;
+                   } else if (*arg == "--delete-older-than") {
+                     removeOld = true;
+                     deleteOlderThan = getArg(*arg, arg, end);
+                   } else if (*arg == "--dry-run") {
+                     dryRun = true;
+                   } else if (*arg == "--max-freed") {
+                     auto maxFreed = getIntArg<long long>(*arg, arg, end, true);
+                     options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
+                   } else {
+                     return false;
+                   }
+                   return true;
+                 });
+
+    auto profilesDir = settings.nixStateDir + "/profiles";
+    if (removeOld) {
+      removeOldGenerations(profilesDir);
+    }
+
+    // Run the actual garbage collector.
+    if (!dryRun) {
+      auto store = openStore();
+      options.action = GCOptions::gcDeleteDead;
+      GCResults results;
+      PrintFreed freed(true, results);
+      store->collectGarbage(options, results);
+    }
+
+    return 0;
+  }
+}
+
+static RegisterLegacyCommand s1("nix-collect-garbage", _main);