From 4ca5a9dcfd577487f8a5b192e8ec525c5baad8cb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 21 May 2015 16:26:03 +0200 Subject: nix-collect-garbage: Don't call nix-env Also, make sure --delete-older-than doesn't delete the current generation. --- src/libstore/profiles.cc | 82 ++++++++++++++++++++++++++ src/libstore/profiles.hh | 10 +++- src/nix-collect-garbage/nix-collect-garbage.cc | 14 ++--- src/nix-env/nix-env.cc | 73 ++++------------------- 4 files changed, 110 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index 5b7a533df290..da3f7da9d19d 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -129,6 +129,88 @@ void deleteGeneration(const Path & profile, unsigned int gen) } +static void deleteGeneration2(const Path & profile, unsigned int gen, bool dryRun) +{ + if (dryRun) + printMsg(lvlInfo, format("would remove generation %1%") % gen); + else { + printMsg(lvlInfo, format("removing generation %1%") % gen); + deleteGeneration(profile, gen); + } +} + + +void deleteGenerations(const Path & profile, const std::set & gensToDelete, bool dryRun) +{ + PathLocks lock; + lockProfile(lock, profile); + + int curGen; + Generations gens = findGenerations(profile, curGen); + + if (gensToDelete.find(curGen) != gensToDelete.end()) + throw Error(format("cannot delete current generation of profile %1%’") % profile); + + for (auto & i : gens) { + if (gensToDelete.find(i.number) == gensToDelete.end()) continue; + deleteGeneration2(profile, i.number, dryRun); + } +} + + +void deleteOldGenerations(const Path & profile, bool dryRun) +{ + PathLocks lock; + lockProfile(lock, profile); + + int curGen; + Generations gens = findGenerations(profile, curGen); + + for (auto & i : gens) + if (i.number != curGen) + deleteGeneration2(profile, i.number, dryRun); +} + + +void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun) +{ + PathLocks lock; + lockProfile(lock, profile); + + int curGen; + Generations gens = findGenerations(profile, curGen); + + bool canDelete = false; + for (auto i = gens.rbegin(); i != gens.rend(); ++i) + if (canDelete) { + assert(i->creationTime < t); + if (i->number != curGen) + deleteGeneration2(profile, i->number, dryRun); + } else if (i->creationTime < t) { + /* We may now start deleting generations, but we don't + delete this generation yet, because this generation was + still the one that was active at the requested point in + time. */ + canDelete = true; + } +} + + +void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun) +{ + time_t curTime = time(0); + string strDays = string(timeSpec, 0, timeSpec.size() - 1); + int days; + + if (!string2Int(strDays, days) || days < 1) + throw Error(format("invalid number of days specifier ‘%1%’") % timeSpec); + + time_t oldTime = curTime - days * 24 * 3600; + + deleteGenerationsOlderThan(profile, oldTime, dryRun); +} + + void switchLink(Path link, Path target) { /* Hacky. */ diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh index 30d2376d998c..e99bbf398a86 100644 --- a/src/libstore/profiles.hh +++ b/src/libstore/profiles.hh @@ -30,11 +30,19 @@ typedef list Generations; /* Returns the list of currently present generations for the specified profile, sorted by generation number. */ Generations findGenerations(Path profile, int & curGen); - + Path createGeneration(Path profile, Path outPath); void deleteGeneration(const Path & profile, unsigned int gen); +void deleteGenerations(const Path & profile, const std::set & gensToDelete, bool dryRun); + +void deleteOldGenerations(const Path & profile, bool dryRun); + +void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun); + +void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun); + void switchLink(Path link, Path target); /* Ensure exclusive access to a profile. Any command that modifies diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc index 740ef88f5395..b671e6cb82dd 100644 --- a/src/nix-collect-garbage/nix-collect-garbage.cc +++ b/src/nix-collect-garbage/nix-collect-garbage.cc @@ -1,5 +1,5 @@ #include "store-api.hh" -#include "hash.hh" +#include "profiles.hh" #include "shared.hh" #include "globals.hh" @@ -7,7 +7,7 @@ using namespace nix; -std::string gen = "old"; +std::string deleteOlderThan; bool dryRun = false; void runProgramSimple(Path program, const Strings & args) @@ -49,10 +49,10 @@ void removeOldGenerations(std::string dir) auto link = readLink(path); if (link.find("link") != string::npos) { printMsg(lvlInfo, format("removing old generations of profile %1%") % path); - - auto args = Strings{"-p", path, "--delete-generations", gen}; - if (dryRun) args.push_back("--dry-run"); - runProgramSimple(settings.nixBinDir + "/nix-env", args); + if (deleteOlderThan != "") + deleteGenerationsOlderThan(path, deleteOlderThan, dryRun); + else + deleteOldGenerations(path, dryRun); } } else if (type == DT_DIR) { removeOldGenerations(path); @@ -76,7 +76,7 @@ int main(int argc, char * * argv) else if (*arg == "--delete-old" || *arg == "-d") removeOld = true; else if (*arg == "--delete-older-than") { removeOld = true; - gen = getArg(*arg, arg, end); + deleteOlderThan = getArg(*arg, arg, end); } else if (*arg == "--dry-run") dryRun = true; else diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 5cf41e844e83..3f82345ce43b 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1262,73 +1262,24 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs } -static void deleteGeneration2(Globals & globals, unsigned int gen) -{ - if (globals.dryRun) - printMsg(lvlInfo, format("would remove generation %1%") % gen); - else { - printMsg(lvlInfo, format("removing generation %1%") % gen); - deleteGeneration(globals.profile, gen); - } - -} - - static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) throw UsageError(format("unknown flag ‘%1%’") % opFlags.front()); - PathLocks lock; - lockProfile(lock, globals.profile); - - int curGen; - Generations gens = findGenerations(globals.profile, curGen); - - for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i) { - - if (*i == "old") { - for (Generations::iterator j = gens.begin(); j != gens.end(); ++j) - if (j->number != curGen) - deleteGeneration2(globals, j->number); - } else if (i->size() >= 2 && tolower(*i->rbegin()) == 'd') { - time_t curTime = time(NULL); - time_t oldTime; - string strDays = string(*i, 0, i->size() - 1); - int days; - - if (!string2Int(strDays, days) || days < 1) - throw UsageError(format("invalid number of days specifier ‘%1%’") % *i); - - oldTime = curTime - days * 24 * 3600; - - bool canDelete = false; - for (Generations::reverse_iterator j = gens.rbegin(); j != gens.rend(); ++j) { - if (canDelete) { - assert(j->creationTime < oldTime); - deleteGeneration2(globals, j->number); - } else if (j->creationTime < oldTime) { - /* We may now start deleting generations, but we don't delete - this generation yet, because this generation was still the - one that was active at the requested point in time. */ - canDelete = true; - } - } - } else { - int n; - if (!string2Int(*i, n) || n < 0) - throw UsageError(format("invalid generation specifier ‘%1%’") % *i); - bool found = false; - for (Generations::iterator j = gens.begin(); j != gens.end(); ++j) { - if (j->number == n) { - deleteGeneration2(globals, j->number); - found = true; - break; - } - } - if (!found) - printMsg(lvlError, format("generation %1% does not exist") % n); + if (opArgs.size() == 1 && opArgs.front() == "old") { + deleteOldGenerations(globals.profile, globals.dryRun); + } else if (opArgs.size() == 1 && opArgs.front().find('d') != string::npos) { + deleteGenerationsOlderThan(globals.profile, opArgs.front(), globals.dryRun); + } else { + std::set gens; + for (auto & i : opArgs) { + unsigned int n; + if (!string2Int(i, n) || n < 0) + throw UsageError(format("invalid generation number ‘%1%’") % i); + gens.insert(n); } + deleteGenerations(globals.profile, gens, globals.dryRun); } } -- cgit 1.4.1