forked from lix-project/lix
* 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
|
@ -155,10 +155,8 @@ static void initAndRun(int argc, char * * argv)
|
||||||
else if (arg == "--max-jobs" || arg == "-j") {
|
else if (arg == "--max-jobs" || arg == "-j") {
|
||||||
++i;
|
++i;
|
||||||
if (i == args.end()) throw UsageError("`--max-jobs' requires an argument");
|
if (i == args.end()) throw UsageError("`--max-jobs' requires an argument");
|
||||||
istringstream str(*i);
|
|
||||||
int n;
|
int n;
|
||||||
str >> n;
|
if (!string2Int(*i, n) || n < 0)
|
||||||
if (!str || !str.eof() || n < 0)
|
|
||||||
throw UsageError(format("`--max-jobs' requires a non-negative integer"));
|
throw UsageError(format("`--max-jobs' requires a non-negative integer"));
|
||||||
maxBuildJobs = n;
|
maxBuildJobs = n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -616,3 +616,11 @@ bool statusOk(int status)
|
||||||
{
|
{
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
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);
|
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
|
/* !!! HACK HACK HACK - this should be in shared.hh, but it's to
|
||||||
facilitate a quick hack - will remove this eventually (famous last
|
facilitate a quick hack - will remove this eventually (famous last
|
||||||
words). */
|
words). */
|
||||||
|
|
|
@ -643,10 +643,8 @@ static void opSwitchGeneration(Globals & globals,
|
||||||
if (opArgs.size() != 1)
|
if (opArgs.size() != 1)
|
||||||
throw UsageError(format("exactly one argument expected"));
|
throw UsageError(format("exactly one argument expected"));
|
||||||
|
|
||||||
istringstream str(opArgs.front());
|
|
||||||
int dstGen;
|
int dstGen;
|
||||||
str >> dstGen;
|
if (!string2Int(opArgs.front(), dstGen))
|
||||||
if (!str || !str.eof())
|
|
||||||
throw UsageError(format("expected a generation number"));
|
throw UsageError(format("expected a generation number"));
|
||||||
|
|
||||||
switchGeneration(globals, dstGen);
|
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,
|
static void opDefaultExpr(Globals & globals,
|
||||||
Strings opFlags, Strings opArgs)
|
Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
|
@ -750,6 +791,8 @@ void run(Strings args)
|
||||||
op = opRollback;
|
op = opRollback;
|
||||||
else if (arg == "--list-generations")
|
else if (arg == "--list-generations")
|
||||||
op = opListGenerations;
|
op = opListGenerations;
|
||||||
|
else if (arg == "--delete-generations")
|
||||||
|
op = opDeleteGenerations;
|
||||||
else if (arg == "--dry-run") {
|
else if (arg == "--dry-run") {
|
||||||
printMsg(lvlInfo, "(dry run; not doing anything)");
|
printMsg(lvlInfo, "(dry run; not doing anything)");
|
||||||
globals.dryRun = true;
|
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)
|
static bool componentsLT(const string & c1, const string & c2)
|
||||||
{
|
{
|
||||||
int n1, n2;
|
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;
|
if (c1Num && c2Num) return n1 < n2;
|
||||||
else if (c1 == "" && c2Num) return true;
|
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);
|
string s = string(name, profileName.size() + 1);
|
||||||
int p = s.find("-link");
|
int p = s.find("-link");
|
||||||
if (p == string::npos) return -1;
|
if (p == string::npos) return -1;
|
||||||
istringstream str(string(s, 0, p));
|
int n;
|
||||||
unsigned int n;
|
if (string2Int(string(s, 0, p), n) && n >= 0)
|
||||||
if (str >> n && str.eof()) return n; else return -1;
|
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 createGeneration(Path profile, Path outPath,
|
||||||
Path drvPath, Path clrPath)
|
Path drvPath, Path clrPath)
|
||||||
{
|
{
|
||||||
|
@ -72,10 +84,7 @@ Path createGeneration(Path profile, Path outPath,
|
||||||
Path generation, gcrootDrv, gcrootClr;
|
Path generation, gcrootDrv, gcrootClr;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
Path prefix = (format("%1%-%2%") % profile % num).str();
|
makeNames(profile, num, generation, gcrootDrv, gcrootClr);
|
||||||
generation = prefix + "-link";
|
|
||||||
gcrootDrv = prefix + "-drv.gcroot";
|
|
||||||
gcrootClr = prefix + "-clr.gcroot";
|
|
||||||
if (symlink(outPath.c_str(), generation.c_str()) == 0) break;
|
if (symlink(outPath.c_str(), generation.c_str()) == 0) break;
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
throw SysError(format("creating symlink `%1%'") % generation);
|
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)
|
void switchLink(Path link, Path target)
|
||||||
{
|
{
|
||||||
/* Hacky. */
|
/* Hacky. */
|
||||||
|
|
|
@ -31,6 +31,8 @@ Generations findGenerations(Path profile, int & curGen);
|
||||||
Path createGeneration(Path profile, Path outPath,
|
Path createGeneration(Path profile, Path outPath,
|
||||||
Path drvPath, Path clrPath);
|
Path drvPath, Path clrPath);
|
||||||
|
|
||||||
|
void deleteGeneration(const Path & profile, unsigned int gen);
|
||||||
|
|
||||||
void switchLink(Path link, Path target);
|
void switchLink(Path link, Path target);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "normalise.hh"
|
#include "normalise.hh"
|
||||||
|
@ -171,10 +170,8 @@ static void opSubstitute(Strings opFlags, Strings opArgs)
|
||||||
getline(cin, sub.program);
|
getline(cin, sub.program);
|
||||||
string s;
|
string s;
|
||||||
getline(cin, s);
|
getline(cin, s);
|
||||||
istringstream st(s);
|
|
||||||
int n;
|
int n;
|
||||||
st >> n;
|
if (!string2Int(s, n)) throw Error("number expected");
|
||||||
if (!st) throw Error("number expected");
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
getline(cin, s);
|
getline(cin, s);
|
||||||
sub.args.push_back(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 == "--print-dead") subOp = soPrintDead;
|
||||||
else if (*i == "--delete") subOp = soDelete;
|
else if (*i == "--delete") subOp = soDelete;
|
||||||
else if (*i == "--min-age") {
|
else if (*i == "--min-age") {
|
||||||
if (opArgs.size() == 0)
|
int n;
|
||||||
throw UsageError("`--min-age' requires an argument");
|
if (opArgs.size() == 0 || !string2Int(opArgs.front(), n))
|
||||||
istringstream st(opArgs.front());
|
throw UsageError("`--min-age' requires an integer argument");
|
||||||
st >> minAge;
|
minAge = n;
|
||||||
if (!st) throw Error("number expected");
|
|
||||||
}
|
}
|
||||||
else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
|
else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue