diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index 87190b6209..6aa342c1da 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -1,5 +1,3 @@ -#include - #include "profiles.hh" #include "names.hh" #include "globals.hh" @@ -9,6 +7,9 @@ #include "eval.hh" #include "help.txt.hh" +#include +#include + struct Globals { @@ -460,9 +461,9 @@ static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) - throw UsageError(format("unknown flags `%1%'") % opFlags.front()); + throw UsageError(format("unknown flag `%1%'") % opFlags.front()); if (opArgs.size() != 1) - throw UsageError(format("`--profile' takes exactly one argument")); + throw UsageError(format("exactly one argument expected")); Path profile = opArgs.front(); Path profileLink = getHomeDir() + "/.nix-profile"; @@ -471,13 +472,34 @@ static void opSwitchProfile(Globals & globals, } +static void opListGenerations(Globals & globals, + Strings opFlags, Strings opArgs) +{ + if (opFlags.size() > 0) + throw UsageError(format("unknown flag `%1%'") % opFlags.front()); + if (opArgs.size() != 0) + throw UsageError(format("no arguments expected")); + + Generations gens = findGenerations(globals.profile); + + for (Generations::iterator i = gens.begin(); i != gens.end(); ++i) { + tm t; + if (!localtime_r(&i->creationTime, &t)) throw Error("cannot convert time"); + cout << format("%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02|\n") + % i->number + % (t.tm_year + 1900) % (t.tm_mon + 1) % t.tm_mday + % t.tm_hour % t.tm_min % t.tm_sec; + } +} + + static void opDefaultExpr(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) throw UsageError(format("unknown flags `%1%'") % opFlags.front()); if (opArgs.size() != 1) - throw UsageError(format("`--import' takes exactly one argument")); + throw UsageError(format("exactly one argument expected")); Path defNixExpr = absPath(opArgs.front()); Path defNixExprLink = getDefNixExprPath(); @@ -526,6 +548,8 @@ void run(Strings args) } else if (arg == "--switch-profile" || arg == "-S") op = opSwitchProfile; + else if (arg == "--list-generations") + op = opListGenerations; else if (arg[0] == '-') opFlags.push_back(arg); else diff --git a/src/nix-env/profiles.cc b/src/nix-env/profiles.cc index 5b9c004066..22da6336bd 100644 --- a/src/nix-env/profiles.cc +++ b/src/nix-env/profiles.cc @@ -1,13 +1,23 @@ #include "profiles.hh" +#include +#include +#include -Path createGeneration(Path profile, Path outPath, Path drvPath) + +static bool cmpGensByNumber(const Generation & a, const Generation & b) { + return a.number < b.number; +} + + +Generations findGenerations(Path profile) +{ + Generations gens; + Path profileDir = dirOf(profile); string profileName = baseNameOf(profile); - unsigned int num = 0; - Strings names = readDirectory(profileDir); for (Strings::iterator i = names.begin(); i != names.end(); ++i) { if (string(*i, 0, profileName.size() + 1) != profileName + "-") continue; @@ -16,9 +26,32 @@ Path createGeneration(Path profile, Path outPath, Path drvPath) if (p == string::npos) continue; istringstream str(string(s, 0, p)); unsigned int n; - if (str >> n && str.eof() && n >= num) num = n + 1; + if (str >> n && str.eof()) { + Generation gen; + gen.path = profileDir + "/" + *i; + gen.number = n; + struct stat st; + if (lstat(gen.path.c_str(), &st) != 0) + throw SysError(format("statting `%1%'") % gen.path); + gen.creationTime = st.st_mtime; + gens.push_back(gen); + } } + gens.sort(cmpGensByNumber); + + return gens; +} + + +Path createGeneration(Path profile, Path outPath, Path drvPath) +{ + /* The new generation number should be higher than old the + previous ones. */ + Generations gens = findGenerations(profile); + unsigned int num = gens.size() > 0 ? gens.front().number : 0; + + /* Create the new generation. */ Path generation, gcrootSrc; while (1) { diff --git a/src/nix-env/profiles.hh b/src/nix-env/profiles.hh index 3d3c86e50b..f9480ed3f3 100644 --- a/src/nix-env/profiles.hh +++ b/src/nix-env/profiles.hh @@ -6,6 +6,20 @@ #include "util.hh" +struct Generation +{ + int number; + Path path; + time_t creationTime; +}; + +typedef list Generations; + + +/* Returns the list of currently present generations for the specified + profile, sorted by generation number. */ +Generations findGenerations(Path profile); + Path createGeneration(Path profile, Path outPath, Path drvPath); void switchLink(Path link, Path target);