aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/gc.cc27
-rw-r--r--src/libstore/gc.hh5
-rw-r--r--src/nix-store/help.txt1
-rw-r--r--src/nix-store/main.cc23
4 files changed, 45 insertions, 11 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index cb808b6d1..c02f59f2c 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -303,8 +303,8 @@ static Paths topoSort(const PathSet & paths)
}
-void collectGarbage(GCAction action, PathSet & result,
- unsigned long long & bytesFreed)
+void collectGarbage(GCAction action, const PathSet & pathsToDelete,
+ PathSet & result, unsigned long long & bytesFreed)
{
result.clear();
bytesFreed = 0;
@@ -398,17 +398,26 @@ void collectGarbage(GCAction action, PathSet & result,
/* Read the Nix store directory to find all currently existing
paths. */
- Paths storePaths = readDirectory(nixStore);
- PathSet storePaths2;
- for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i)
- storePaths2.insert(canonPath(nixStore + "/" + *i));
+ PathSet storePathSet;
+ if (action != gcDeleteSpecific) {
+ Paths entries = readDirectory(nixStore);
+ for (Paths::iterator i = entries.begin(); i != entries.end(); ++i)
+ storePathSet.insert(canonPath(nixStore + "/" + *i));
+ } else {
+ for (PathSet::iterator i = pathsToDelete.begin();
+ i != pathsToDelete.end(); ++i)
+ {
+ assertStorePath(*i);
+ storePathSet.insert(*i);
+ }
+ }
/* Topologically sort them under the `referrers' relation. That
is, a < b iff a is in referrers(b). This gives us the order in
which things can be deleted safely. */
/* !!! when we have multiple output paths per derivation, this
will not work anymore because we get cycles. */
- storePaths = topoSort(storePaths2);
+ Paths storePaths = topoSort(storePathSet);
/* Try to delete store paths in the topologically sorted order. */
for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i) {
@@ -416,6 +425,8 @@ void collectGarbage(GCAction action, PathSet & result,
debug(format("considering deletion of `%1%'") % *i);
if (livePaths.find(*i) != livePaths.end()) {
+ if (action == gcDeleteSpecific)
+ throw Error(format("cannot delete path `%1%' since it is still alive") % *i);
debug(format("live path `%1%'") % *i);
continue;
}
@@ -430,7 +441,7 @@ void collectGarbage(GCAction action, PathSet & result,
AutoCloseFD fdLock;
- if (action == gcDeleteDead) {
+ if (action == gcDeleteDead || action == gcDeleteSpecific) {
/* Only delete a lock file if we can acquire a write lock
on it. That means that it's either stale, or the
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index eb1858729..b05d88f93 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -10,6 +10,7 @@ typedef enum {
gcReturnLive,
gcReturnDead,
gcDeleteDead,
+ gcDeleteSpecific,
} GCAction;
/* If `action' is set to `gcReturnRoots', find and return the set of
@@ -19,8 +20,8 @@ typedef enum {
closure of) the roots. If `action' is `gcReturnDead', return the
set of paths not reachable from the roots. If `action' is
`gcDeleteDead', actually delete the latter set. */
-void collectGarbage(GCAction action, PathSet & result,
- unsigned long long & bytesFreed);
+void collectGarbage(GCAction action, const PathSet & pathsToDelete,
+ PathSet & result, unsigned long long & bytesFreed);
/* Register a temporary GC root. This root will automatically
disappear when this process exits. WARNING: this function should
diff --git a/src/nix-store/help.txt b/src/nix-store/help.txt
index 628805835..074745813 100644
--- a/src/nix-store/help.txt
+++ b/src/nix-store/help.txt
@@ -7,6 +7,7 @@ Operations:
--realise / -r: ensure path validity; if a derivation, ensure that
validity of the outputs
--add / -A: copy a path to the Nix store
+ --delete: safely delete paths from the Nix store
--query / -q: query information
--register-substitutes: register a substitute expression (dangerous!)
diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc
index 8bb1b1254..6f1fab13d 100644
--- a/src/nix-store/main.cc
+++ b/src/nix-store/main.cc
@@ -518,7 +518,7 @@ static void opGC(Strings opFlags, Strings opArgs)
PathSet result;
PrintFreed freed(action == gcDeleteDead);
- collectGarbage(action, result, freed.bytesFreed);
+ collectGarbage(action, PathSet(), result, freed.bytesFreed);
if (action != gcDeleteDead) {
for (PathSet::iterator i = result.begin(); i != result.end(); ++i)
@@ -527,6 +527,25 @@ static void opGC(Strings opFlags, Strings opArgs)
}
+/* Remove paths from the Nix store if possible (i.e., if they do not
+ have any remaining referrers and are not reachable from any GC
+ roots). */
+static void opDelete(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+
+ PathSet pathsToDelete;
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); ++i)
+ pathsToDelete.insert(fixPath(*i));
+
+ PathSet dummy;
+ PrintFreed freed(true);
+ collectGarbage(gcDeleteSpecific, pathsToDelete,
+ dummy, freed.bytesFreed);
+}
+
+
/* A sink that writes dump output to stdout. */
struct StdoutSink : DumpSink
{
@@ -621,6 +640,8 @@ void run(Strings args)
op = opAddFixed;
else if (arg == "--print-fixed-path")
op = opPrintFixedPath;
+ else if (arg == "--delete")
+ op = opDelete;
else if (arg == "--query" || arg == "-q")
op = opQuery;
else if (arg == "--register-substitutes")