about summary refs log tree commit diff
path: root/src/nix-collect-garbage/nix-collect-garbage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-collect-garbage/nix-collect-garbage.cc')
-rw-r--r--src/nix-collect-garbage/nix-collect-garbage.cc92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc
new file mode 100644
index 000000000000..cc663a96924d
--- /dev/null
+++ b/src/nix-collect-garbage/nix-collect-garbage.cc
@@ -0,0 +1,92 @@
+#include "store-api.hh"
+#include "profiles.hh"
+#include "shared.hh"
+#include "globals.hh"
+
+#include <iostream>
+#include <cerrno>
+
+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(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") != string::npos) {
+                printInfo(format("removing old generations of profile %1%") % path);
+                if (deleteOlderThan != "")
+                    deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
+                else
+                    deleteOldGenerations(path, dryRun);
+            }
+        } else if (type == DT_DIR) {
+            removeOldGenerations(path);
+        }
+    }
+}
+
+int main(int argc, char * * argv)
+{
+    bool removeOld = false;
+
+    return handleExceptions(argv[0], [&]() {
+        initNix();
+
+        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") {
+                long long 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);
+        }
+    });
+}