about summary refs log tree commit diff
path: root/src/nix-store
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-store')
-rw-r--r--src/nix-store/main.cc70
1 files changed, 57 insertions, 13 deletions
diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc
index e83f9133f61d..78599e30869c 100644
--- a/src/nix-store/main.cc
+++ b/src/nix-store/main.cc
@@ -3,6 +3,7 @@
 
 #include "globals.hh"
 #include "normalise.hh"
+#include "gc.hh"
 #include "archive.hh"
 #include "shared.hh"
 #include "dotgraph.hh"
@@ -32,17 +33,6 @@ static void opRealise(Strings opFlags, Strings opArgs)
 }
 
 
-/* Delete a path in the Nix store directory. */
-static void opDelete(Strings opFlags, Strings opArgs)
-{
-    if (!opFlags.empty()) throw UsageError("unknown flag");
-
-    for (Strings::iterator it = opArgs.begin();
-         it != opArgs.end(); it++)
-        deleteFromStore(*it);
-}
-
-
 /* Add paths to the Nix values directory and print the hashes of those
    paths. */
 static void opAdd(Strings opFlags, Strings opArgs)
@@ -220,6 +210,60 @@ static void opIsValid(Strings opFlags, Strings opArgs)
 }
 
 
+static void opGC(Strings opFlags, Strings opArgs)
+{
+    if (opFlags.size() != 1) throw UsageError("missing flag");
+    if (!opArgs.empty())
+        throw UsageError("no arguments expected");
+
+    /* Do what? */
+    string flag = opFlags.front();
+    enum { soPrintLive, soPrintDead, soDelete } subOp;
+    if (flag == "--print-live") subOp = soPrintLive;
+    else if (flag == "--print-dead") subOp = soPrintDead;
+    else if (flag == "--delete") subOp = soDelete;
+    else throw UsageError(format("bad sub-operation `%1% in GC") % flag);
+        
+    Paths roots;
+    while (1) {
+        Path root;
+        getline(cin, root);
+        if (cin.eof()) break;
+        roots.push_back(root);
+    }
+
+    PathSet live = findLivePaths(roots);
+
+    if (subOp == soPrintLive) {
+        for (PathSet::iterator i = live.begin(); i != live.end(); ++i)
+            cout << *i << endl;
+        return;
+    }
+
+    PathSet dead = findDeadPaths(live);
+
+    if (subOp == soPrintDead) {
+        for (PathSet::iterator i = dead.begin(); i != dead.end(); ++i)
+            cout << *i << endl;
+        return;
+    }
+
+    if (subOp == soDelete) {
+
+        /* !!! What happens if the garbage collector run is aborted
+           halfway through?  In particular, dead paths can always
+           become live again (through re-instantiation), and might
+           then refer to deleted paths. => check instantiation
+           invariants */
+
+        for (PathSet::iterator i = dead.begin(); i != dead.end(); ++i) {
+            printMsg(lvlInfo, format("deleting `%1%'") % *i);
+            deleteFromStore(*i);
+        }
+    }
+}
+
+
 /* A sink that writes dump output to stdout. */
 struct StdoutSink : DumpSink
 {
@@ -298,8 +342,6 @@ void run(Strings args)
 
         if (arg == "--realise" || arg == "-r")
             op = opRealise;
-        else if (arg == "--delete" || arg == "-d")
-            op = opDelete;
         else if (arg == "--add" || arg == "-A")
             op = opAdd;
         else if (arg == "--query" || arg == "-q")
@@ -312,6 +354,8 @@ void run(Strings args)
             op = opValidPath;
         else if (arg == "--isvalid")
             op = opIsValid;
+        else if (arg == "--gc")
+            op = opGC;
         else if (arg == "--dump")
             op = opDump;
         else if (arg == "--restore")