* 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.
This commit is contained in:
		
							parent
							
								
									c16be6ac92
								
							
						
					
					
						commit
						dcc433de47
					
				
					 8 changed files with 100 additions and 33 deletions
				
			
		|  | @ -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; | ||||
|         } | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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). */ | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -56,20 +56,10 @@ static string nextComponent(string::const_iterator & p, | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| #include <fstream> | ||||
| 
 | ||||
| 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; | ||||
|  |  | |||
|  | @ -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. */ | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| #include <iostream> | ||||
| #include <sstream> | ||||
| 
 | ||||
| #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); | ||||
|          | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue