From dcc433de47d4bf4a27fe63bc8996e946164ae885 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 10 Sep 2004 13:32:08 +0000 Subject: [PATCH] * Operation `--delete-generations' to delete generations of a profile. Arguments are either generation number, or `old' to delete all non-current generations. Typical use: $ nix-env --delete-generations old $ nix-collect-garbage * istringstream -> string2Int. --- src/libmain/shared.cc | 4 +--- src/libutil/util.cc | 8 +++++++ src/libutil/util.hh | 4 ++++ src/nix-env/main.cc | 49 ++++++++++++++++++++++++++++++++++++++--- src/nix-env/names.cc | 12 +--------- src/nix-env/profiles.cc | 40 +++++++++++++++++++++++++++------ src/nix-env/profiles.hh | 2 ++ src/nix-store/main.cc | 14 +++++------- 8 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 5affce77e..24f6ec4df 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -155,10 +155,8 @@ static void initAndRun(int argc, char * * argv) else if (arg == "--max-jobs" || arg == "-j") { ++i; if (i == args.end()) throw UsageError("`--max-jobs' requires an argument"); - istringstream str(*i); int n; - str >> n; - if (!str || !str.eof() || n < 0) + if (!string2Int(*i, n) || n < 0) throw UsageError(format("`--max-jobs' requires a non-negative integer")); maxBuildJobs = n; } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index a25665e4a..5a41c0986 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -616,3 +616,11 @@ bool statusOk(int status) { return WIFEXITED(status) && WEXITSTATUS(status) == 0; } + + +bool string2Int(const string & s, int & n) +{ + istringstream str(s); + str >> n; + return str && str.eof(); +} diff --git a/src/libutil/util.hh b/src/libutil/util.hh index ae5b4882e..a79c07305 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -246,6 +246,10 @@ string statusToString(int status); bool statusOk(int status); +/* Parse a string into an integer. */ +bool string2Int(const string & s, int & n); + + /* !!! HACK HACK HACK - this should be in shared.hh, but it's to facilitate a quick hack - will remove this eventually (famous last words). */ diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index 14aa13b86..cf4ac8fc4 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -643,10 +643,8 @@ static void opSwitchGeneration(Globals & globals, if (opArgs.size() != 1) throw UsageError(format("exactly one argument expected")); - istringstream str(opArgs.front()); int dstGen; - str >> dstGen; - if (!str || !str.eof()) + if (!string2Int(opArgs.front(), dstGen)) throw UsageError(format("expected a generation number")); switchGeneration(globals, dstGen); @@ -688,6 +686,49 @@ static void opListGenerations(Globals & globals, } +static void deleteGeneration2(const Path & profile, unsigned int gen) +{ + printMsg(lvlInfo, format("removing generation %1%") % gen); + deleteGeneration(profile, gen); +} + + +static void opDeleteGenerations(Globals & globals, + Strings opFlags, Strings opArgs) +{ + if (opFlags.size() > 0) + throw UsageError(format("unknown flag `%1%'") % opFlags.front()); + + 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.profile, j->number); + } + + 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.profile, j->number); + found = true; + break; + } + } + if (!found) + printMsg(lvlError, format("generation %1% does not exist") % n); + } + } +} + + static void opDefaultExpr(Globals & globals, Strings opFlags, Strings opArgs) { @@ -750,6 +791,8 @@ void run(Strings args) op = opRollback; else if (arg == "--list-generations") op = opListGenerations; + else if (arg == "--delete-generations") + op = opDeleteGenerations; else if (arg == "--dry-run") { printMsg(lvlInfo, "(dry run; not doing anything)"); globals.dryRun = true; diff --git a/src/nix-env/names.cc b/src/nix-env/names.cc index c6054d6c1..93bcfda24 100644 --- a/src/nix-env/names.cc +++ b/src/nix-env/names.cc @@ -56,20 +56,10 @@ static string nextComponent(string::const_iterator & p, } -#include - -static bool parseInt(const string & s, int & n) -{ - istringstream st(s); - st >> n; - return !st.fail(); -} - - static bool componentsLT(const string & c1, const string & c2) { int n1, n2; - bool c1Num = parseInt(c1, n1), c2Num = parseInt(c2, n2); + bool c1Num = string2Int(c1, n1), c2Num = string2Int(c2, n2); if (c1Num && c2Num) return n1 < n2; else if (c1 == "" && c2Num) return true; diff --git a/src/nix-env/profiles.cc b/src/nix-env/profiles.cc index 1eeddf332..c52ddc0b6 100644 --- a/src/nix-env/profiles.cc +++ b/src/nix-env/profiles.cc @@ -20,9 +20,11 @@ static int parseName(const string & profileName, const string & name) string s = string(name, profileName.size() + 1); int p = s.find("-link"); if (p == string::npos) return -1; - istringstream str(string(s, 0, p)); - unsigned int n; - if (str >> n && str.eof()) return n; else return -1; + int n; + if (string2Int(string(s, 0, p), n) && n >= 0) + return n; + else + return -1; } @@ -59,6 +61,16 @@ Generations findGenerations(Path profile, int & curGen) } +static void makeNames(const Path & profile, unsigned int num, + Path & generation, Path & gcrootDrv, Path & gcrootClr) +{ + Path prefix = (format("%1%-%2%") % profile % num).str(); + generation = prefix + "-link"; + gcrootDrv = prefix + "-drv.gcroot"; + gcrootClr = prefix + "-clr.gcroot"; +} + + Path createGeneration(Path profile, Path outPath, Path drvPath, Path clrPath) { @@ -72,10 +84,7 @@ Path createGeneration(Path profile, Path outPath, Path generation, gcrootDrv, gcrootClr; while (1) { - Path prefix = (format("%1%-%2%") % profile % num).str(); - generation = prefix + "-link"; - gcrootDrv = prefix + "-drv.gcroot"; - gcrootClr = prefix + "-clr.gcroot"; + makeNames(profile, num, generation, gcrootDrv, gcrootClr); if (symlink(outPath.c_str(), generation.c_str()) == 0) break; if (errno != EEXIST) throw SysError(format("creating symlink `%1%'") % generation); @@ -90,6 +99,23 @@ Path createGeneration(Path profile, Path outPath, } +static void removeFile(const Path & path) +{ + if (remove(path.c_str()) == -1) + throw SysError(format("cannot unlink `%1%'") % path); +} + + +void deleteGeneration(const Path & profile, unsigned int gen) +{ + Path generation, gcrootDrv, gcrootClr; + makeNames(profile, gen, generation, gcrootDrv, gcrootClr); + removeFile(generation); + if (pathExists(gcrootClr)) removeFile(gcrootClr); + if (pathExists(gcrootDrv)) removeFile(gcrootDrv); +} + + void switchLink(Path link, Path target) { /* Hacky. */ diff --git a/src/nix-env/profiles.hh b/src/nix-env/profiles.hh index 423134412..bcd882c34 100644 --- a/src/nix-env/profiles.hh +++ b/src/nix-env/profiles.hh @@ -31,6 +31,8 @@ Generations findGenerations(Path profile, int & curGen); Path createGeneration(Path profile, Path outPath, Path drvPath, Path clrPath); +void deleteGeneration(const Path & profile, unsigned int gen); + void switchLink(Path link, Path target); diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc index a8acd30c7..febe65e5c 100644 --- a/src/nix-store/main.cc +++ b/src/nix-store/main.cc @@ -1,5 +1,4 @@ #include -#include #include "globals.hh" #include "normalise.hh" @@ -171,10 +170,8 @@ static void opSubstitute(Strings opFlags, Strings opArgs) getline(cin, sub.program); string s; getline(cin, s); - istringstream st(s); int n; - st >> n; - if (!st) throw Error("number expected"); + if (!string2Int(s, n)) throw Error("number expected"); while (n--) { getline(cin, s); sub.args.push_back(s); @@ -224,11 +221,10 @@ static void opGC(Strings opFlags, Strings opArgs) else if (*i == "--print-dead") subOp = soPrintDead; else if (*i == "--delete") subOp = soDelete; else if (*i == "--min-age") { - if (opArgs.size() == 0) - throw UsageError("`--min-age' requires an argument"); - istringstream st(opArgs.front()); - st >> minAge; - if (!st) throw Error("number expected"); + int n; + if (opArgs.size() == 0 || !string2Int(opArgs.front(), n)) + throw UsageError("`--min-age' requires an integer argument"); + minAge = n; } else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);