* Refactoring. Hope this doesn't break the semantics of `-u' ;-)

This commit is contained in:
Eelco Dolstra 2005-02-14 16:16:02 +00:00
parent a04a5de8f7
commit 0cb016c209
3 changed files with 170 additions and 162 deletions

View file

@ -45,7 +45,7 @@ typedef void (* Operation) (Globals & globals,
Strings opFlags, Strings opArgs); Strings opFlags, Strings opArgs);
struct DrvInfo struct UserEnvElem
{ {
string name; string name;
string system; string system;
@ -53,8 +53,7 @@ struct DrvInfo
Path outPath; Path outPath;
}; };
typedef map<Path, DrvInfo> DrvInfos; typedef map<Path, UserEnvElem> UserEnvElems;
typedef vector<DrvInfo> DrvInfoList;
void printHelp() void printHelp()
@ -63,7 +62,7 @@ void printHelp()
} }
bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv) static bool parseDerivation(EvalState & state, Expr e, UserEnvElem & elem)
{ {
ATermList es; ATermList es;
e = evalExpr(state, e); e = evalExpr(state, e);
@ -73,54 +72,54 @@ bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
a = queryAttr(e, "name"); a = queryAttr(e, "name");
if (!a) throw badTerm("derivation name missing", e); if (!a) throw badTerm("derivation name missing", e);
drv.name = evalString(state, a); elem.name = evalString(state, a);
a = queryAttr(e, "system"); a = queryAttr(e, "system");
if (!a) if (!a)
drv.system = "unknown"; elem.system = "unknown";
else else
drv.system = evalString(state, a); elem.system = evalString(state, a);
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
if (a) drv.drvPath = evalPath(state, a); if (a) elem.drvPath = evalPath(state, a);
a = queryAttr(e, "outPath"); a = queryAttr(e, "outPath");
if (!a) throw badTerm("output path missing", e); if (!a) throw badTerm("output path missing", e);
drv.outPath = evalPath(state, a); elem.outPath = evalPath(state, a);
return true; return true;
} }
bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) static bool parseDerivations(EvalState & state, Expr e, UserEnvElems & elems)
{ {
ATermList es; ATermList es;
DrvInfo drv; UserEnvElem elem;
e = evalExpr(state, e); e = evalExpr(state, e);
if (parseDerivation(state, e, drv)) if (parseDerivation(state, e, elem))
drvs[drv.outPath] = drv; elems[elem.outPath] = elem;
else if (matchAttrs(e, es)) { else if (matchAttrs(e, es)) {
ATermMap drvMap; ATermMap drvMap;
queryAllAttrs(e, drvMap); queryAllAttrs(e, drvMap);
for (ATermIterator i(drvMap.keys()); i; ++i) { for (ATermIterator i(drvMap.keys()); i; ++i) {
debug(format("evaluating attribute `%1%'") % *i); debug(format("evaluating attribute `%1%'") % *i);
if (parseDerivation(state, drvMap.get(*i), drv)) if (parseDerivation(state, drvMap.get(*i), elem))
drvs[drv.outPath] = drv; elems[elem.outPath] = elem;
else else
parseDerivations(state, drvMap.get(*i), drvs); parseDerivations(state, drvMap.get(*i), elems);
} }
} }
else if (matchList(e, es)) { else if (matchList(e, es)) {
for (ATermIterator i(es); i; ++i) { for (ATermIterator i(es); i; ++i) {
debug(format("evaluating list element")); debug(format("evaluating list element"));
if (parseDerivation(state, *i, drv)) if (parseDerivation(state, *i, elem))
drvs[drv.outPath] = drv; elems[elem.outPath] = elem;
else else
parseDerivations(state, *i, drvs); parseDerivations(state, *i, elems);
} }
} }
@ -129,30 +128,18 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
static void loadDerivations(EvalState & state, Path nixExprPath, static void loadDerivations(EvalState & state, Path nixExprPath,
string systemFilter, DrvInfos & drvs) string systemFilter, UserEnvElems & elems)
{ {
Expr e = parseExprFromFile(state, absPath(nixExprPath)); Expr e = parseExprFromFile(state, absPath(nixExprPath));
if (!parseDerivations(state, e, drvs)) if (!parseDerivations(state, e, elems))
throw Error("set of derivations expected"); throw Error("set of derivations expected");
/* Filter out all derivations not applicable to the current /* Filter out all derivations not applicable to the current
system. */ system. */
for (DrvInfos::iterator i = drvs.begin(), j; i != drvs.end(); i = j) { for (UserEnvElems::iterator i = elems.begin(), j; i != elems.end(); i = j) {
j = i; j++; j = i; j++;
if (systemFilter != "*" && i->second.system != systemFilter) if (systemFilter != "*" && i->second.system != systemFilter)
drvs.erase(i); elems.erase(i);
}
}
static void queryInstSources(EvalState & state,
const InstallSourceInfo & instSource, DrvInfos & drvs)
{
switch (instSource.type) {
case srcUnknown:
loadDerivations(state, instSource.nixExprPath,
instSource.systemFilter, drvs);
break;
} }
} }
@ -184,7 +171,7 @@ struct AddPos : TermFun
}; };
void queryInstalled(EvalState & state, DrvInfos & drvs, static void queryInstalled(EvalState & state, UserEnvElems & elems,
const Path & userEnv) const Path & userEnv)
{ {
Path path = userEnv + "/manifest"; Path path = userEnv + "/manifest";
@ -198,19 +185,19 @@ void queryInstalled(EvalState & state, DrvInfos & drvs,
AddPos addPos; AddPos addPos;
e = bottomupRewrite(addPos, e); e = bottomupRewrite(addPos, e);
if (!parseDerivations(state, e, drvs)) if (!parseDerivations(state, e, elems))
throw badTerm(format("set of derivations expected in `%1%'") % path, e); throw badTerm(format("set of derivations expected in `%1%'") % path, e);
} }
void createUserEnv(EvalState & state, const DrvInfos & drvs, static void createUserEnv(EvalState & state, const UserEnvElems & elems,
const Path & profile, bool keepDerivations) const Path & profile, bool keepDerivations)
{ {
/* Build the components in the user environment, if they don't /* Build the components in the user environment, if they don't
exist already. */ exist already. */
PathSet drvsToBuild; PathSet drvsToBuild;
for (DrvInfos::const_iterator i = drvs.begin(); for (UserEnvElems::const_iterator i = elems.begin();
i != drvs.end(); ++i) i != elems.end(); ++i)
if (i->second.drvPath != "") if (i->second.drvPath != "")
drvsToBuild.insert(i->second.drvPath); drvsToBuild.insert(i->second.drvPath);
@ -225,8 +212,8 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
PathSet references; PathSet references;
ATermList manifest = ATempty; ATermList manifest = ATempty;
ATermList inputs = ATempty; ATermList inputs = ATempty;
for (DrvInfos::const_iterator i = drvs.begin(); for (UserEnvElems::const_iterator i = elems.begin();
i != drvs.end(); ++i) i != elems.end(); ++i)
{ {
Path drvPath = keepDerivations ? i->second.drvPath : ""; Path drvPath = keepDerivations ? i->second.drvPath : "";
ATerm t = makeAttrs(ATmakeList5( ATerm t = makeAttrs(ATmakeList5(
@ -268,7 +255,7 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
/* Instantiate it. */ /* Instantiate it. */
debug(format("evaluating builder expression `%1%'") % topLevel); debug(format("evaluating builder expression `%1%'") % topLevel);
DrvInfo topLevelDrv; UserEnvElem topLevelDrv;
if (!parseDerivation(state, topLevel, topLevelDrv)) if (!parseDerivation(state, topLevel, topLevelDrv))
abort(); abort();
@ -278,37 +265,42 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
/* Switch the current user environment to the output path. */ /* Switch the current user environment to the output path. */
debug(format("switching to new user environment")); debug(format("switching to new user environment"));
Path generation = createGeneration(profile, Path generation = createGeneration(profile, topLevelDrv.outPath);
topLevelDrv.outPath, topLevelDrv.drvPath);
switchLink(profile, generation); switchLink(profile, generation);
} }
static void installDerivations(Globals & globals, static void queryInstSources(EvalState & state,
DrvNames & selectors, const Path & profile) const InstallSourceInfo & instSource, const Strings & args,
UserEnvElems & elems)
{ {
debug(format("installing derivations")); switch (instSource.type) {
/* Fetch all derivations from the input file. */ /* Get the available user environment elements from the
DrvInfos availDrvs; derivations specified in a Nix expression, including only
queryInstSources(globals.state, globals.instSource, availDrvs); those with names matching any of the names in `args'. */
case srcUnknown:
case srcNixExprDrvs: {
DrvNames selectors = drvNamesFromArgs(args);
/* Load the derivations from the (default or specified)
Nix expression. */
UserEnvElems allElems;
loadDerivations(state, instSource.nixExprPath,
instSource.systemFilter, allElems);
/* Filter out the ones we're not interested in. */ /* Filter out the ones we're not interested in. */
DrvInfos selectedDrvs; for (UserEnvElems::iterator i = allElems.begin();
StringSet selectedNames; i != allElems.end(); ++i)
for (DrvInfos::iterator i = availDrvs.begin();
i != availDrvs.end(); ++i)
{ {
DrvName drvName(i->second.name); DrvName drvName(i->second.name);
for (DrvNames::iterator j = selectors.begin(); for (DrvNames::iterator j = selectors.begin();
j != selectors.end(); ++j) j != selectors.end(); ++j)
{ {
if (j->matches(drvName)) { if (j->matches(drvName)) {
printMsg(lvlInfo,
format("installing `%1%'") % i->second.name);
j->hits++; j->hits++;
selectedDrvs.insert(*i); elems.insert(*i);
selectedNames.insert(drvName.name);
} }
} }
} }
@ -320,25 +312,57 @@ static void installDerivations(Globals & globals,
throw Error(format("selector `%1%' matches no derivations") throw Error(format("selector `%1%' matches no derivations")
% i->fullName); % i->fullName);
/* Add in the already installed derivations. */ break;
DrvInfos installedDrvs; }
queryInstalled(globals.state, installedDrvs, profile);
for (DrvInfos::iterator i = installedDrvs.begin(); case srcNixExprs:
i != installedDrvs.end(); ++i) break;
case srcStorePaths:
break;
case srcProfile:
break;
}
}
static void installDerivations(Globals & globals,
const Strings & args, const Path & profile)
{
debug(format("installing derivations"));
/* Get the set of user environment elements to be installed. */
UserEnvElems newElems;
queryInstSources(globals.state, globals.instSource, args, newElems);
StringSet newNames;
for (UserEnvElems::iterator i = newElems.begin(); i != newElems.end(); ++i) {
printMsg(lvlInfo,
format("installing `%1%'") % i->second.name);
newNames.insert(DrvName(i->second.name).name);
}
/* Add in the already installed derivations, unless they have the
same name as a to-be-installed element. */
UserEnvElems installedElems;
queryInstalled(globals.state, installedElems, profile);
for (UserEnvElems::iterator i = installedElems.begin();
i != installedElems.end(); ++i)
{ {
DrvName drvName(i->second.name); DrvName drvName(i->second.name);
if (!globals.preserveInstalled && if (!globals.preserveInstalled &&
selectedNames.find(drvName.name) != selectedNames.end()) newNames.find(drvName.name) != newNames.end())
printMsg(lvlInfo, printMsg(lvlInfo,
format("uninstalling `%1%'") % i->second.name); format("uninstalling `%1%'") % i->second.name);
else else
selectedDrvs.insert(*i); newElems.insert(*i);
} }
if (globals.dryRun) return; if (globals.dryRun) return;
createUserEnv(globals.state, selectedDrvs, createUserEnv(globals.state, newElems,
profile, globals.keepDerivations); profile, globals.keepDerivations);
} }
@ -349,9 +373,7 @@ static void opInstall(Globals & globals,
if (opFlags.size() > 0) if (opFlags.size() > 0)
throw UsageError(format("unknown flags `%1%'") % opFlags.front()); throw UsageError(format("unknown flags `%1%'") % opFlags.front());
DrvNames drvNames = drvNamesFromArgs(opArgs); installDerivations(globals, opArgs, globals.profile);
installDerivations(globals, drvNames, globals.profile);
} }
@ -359,7 +381,7 @@ typedef enum { utLt, utLeq, utAlways } UpgradeType;
static void upgradeDerivations(Globals & globals, static void upgradeDerivations(Globals & globals,
DrvNames & selectors, const Path & profile, const Strings & args, const Path & profile,
UpgradeType upgradeType) UpgradeType upgradeType)
{ {
debug(format("upgrading derivations")); debug(format("upgrading derivations"));
@ -370,47 +392,28 @@ static void upgradeDerivations(Globals & globals,
name and a higher version number. */ name and a higher version number. */
/* Load the currently installed derivations. */ /* Load the currently installed derivations. */
DrvInfos installedDrvs; UserEnvElems installedElems;
queryInstalled(globals.state, installedDrvs, profile); queryInstalled(globals.state, installedElems, profile);
/* Fetch all derivations from the input file. */ /* Fetch all derivations from the input file. */
DrvInfos availDrvs; UserEnvElems availElems;
queryInstSources(globals.state, globals.instSource, availDrvs); queryInstSources(globals.state, globals.instSource, args, availElems);
/* Go through all installed derivations. */ /* Go through all installed derivations. */
DrvInfos newDrvs; UserEnvElems newElems;
for (DrvInfos::iterator i = installedDrvs.begin(); for (UserEnvElems::iterator i = installedElems.begin();
i != installedDrvs.end(); ++i) i != installedElems.end(); ++i)
{ {
DrvName drvName(i->second.name); DrvName drvName(i->second.name);
DrvName selector;
/* Do we want to upgrade this derivation? */ /* Find the derivation in the input Nix expression with the
bool upgrade = false; same name and satisfying the version constraints specified
for (DrvNames::iterator j = selectors.begin(); by upgradeType. If there are multiple matches, take the
j != selectors.end(); ++j) one with highest version. */
{ UserEnvElems::iterator bestElem = availElems.end();
if (j->name == "*" || j->name == drvName.name) {
j->hits++;
selector = *j;
upgrade = true;
break;
}
}
if (!upgrade) {
newDrvs.insert(*i);
continue;
}
/* If yes, find the derivation in the input Nix expression
with the same name and satisfying the version constraints
specified by upgradeType. If there are multiple matches,
take the one with highest version. */
DrvInfos::iterator bestDrv = availDrvs.end();
DrvName bestName; DrvName bestName;
for (DrvInfos::iterator j = availDrvs.begin(); for (UserEnvElems::iterator j = availElems.begin();
j != availDrvs.end(); ++j) j != availElems.end(); ++j)
{ {
DrvName newName(j->second.name); DrvName newName(j->second.name);
if (newName.name == drvName.name) { if (newName.name == drvName.name) {
@ -419,31 +422,30 @@ static void upgradeDerivations(Globals & globals,
upgradeType == utLeq && d <= 0 || upgradeType == utLeq && d <= 0 ||
upgradeType == utAlways) upgradeType == utAlways)
{ {
if (selector.matches(newName) && if ((bestElem == availElems.end() ||
(bestDrv == availDrvs.end() ||
compareVersions( compareVersions(
bestName.version, newName.version) < 0)) bestName.version, newName.version) < 0))
{ {
bestDrv = j; bestElem = j;
bestName = newName; bestName = newName;
} }
} }
} }
} }
if (bestDrv != availDrvs.end() && if (bestElem != availElems.end() &&
i->second.drvPath != bestDrv->second.drvPath) i->second.outPath != bestElem->second.outPath)
{ {
printMsg(lvlInfo, printMsg(lvlInfo,
format("upgrading `%1%' to `%2%'") format("upgrading `%1%' to `%2%'")
% i->second.name % bestDrv->second.name); % i->second.name % bestElem->second.name);
newDrvs.insert(*bestDrv); newElems.insert(*bestElem);
} else newDrvs.insert(*i); } else newElems.insert(*i);
} }
if (globals.dryRun) return; if (globals.dryRun) return;
createUserEnv(globals.state, newDrvs, createUserEnv(globals.state, newElems,
profile, globals.keepDerivations); profile, globals.keepDerivations);
} }
@ -459,20 +461,18 @@ static void opUpgrade(Globals & globals,
else if (*i == "--always") upgradeType = utAlways; else if (*i == "--always") upgradeType = utAlways;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
DrvNames drvNames = drvNamesFromArgs(opArgs); upgradeDerivations(globals, opArgs, globals.profile, upgradeType);
upgradeDerivations(globals, drvNames, globals.profile, upgradeType);
} }
static void uninstallDerivations(Globals & globals, DrvNames & selectors, static void uninstallDerivations(Globals & globals, DrvNames & selectors,
Path & profile) Path & profile)
{ {
DrvInfos installedDrvs; UserEnvElems installedElems;
queryInstalled(globals.state, installedDrvs, profile); queryInstalled(globals.state, installedElems, profile);
for (DrvInfos::iterator i = installedDrvs.begin(); for (UserEnvElems::iterator i = installedElems.begin();
i != installedDrvs.end(); ++i) i != installedElems.end(); ++i)
{ {
DrvName drvName(i->second.name); DrvName drvName(i->second.name);
for (DrvNames::iterator j = selectors.begin(); for (DrvNames::iterator j = selectors.begin();
@ -480,13 +480,13 @@ static void uninstallDerivations(Globals & globals, DrvNames & selectors,
if (j->matches(drvName)) { if (j->matches(drvName)) {
printMsg(lvlInfo, printMsg(lvlInfo,
format("uninstalling `%1%'") % i->second.name); format("uninstalling `%1%'") % i->second.name);
installedDrvs.erase(i); installedElems.erase(i);
} }
} }
if (globals.dryRun) return; if (globals.dryRun) return;
createUserEnv(globals.state, installedDrvs, createUserEnv(globals.state, installedElems,
profile, globals.keepDerivations); profile, globals.keepDerivations);
} }
@ -510,7 +510,7 @@ static bool cmpChars(char a, char b)
} }
static bool cmpDrvByName(const DrvInfo & a, const DrvInfo & b) static bool cmpElemByName(const UserEnvElem & a, const UserEnvElem & b)
{ {
return lexicographical_compare( return lexicographical_compare(
a.name.begin(), a.name.end(), a.name.begin(), a.name.end(),
@ -575,17 +575,17 @@ static void opQuery(Globals & globals,
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
/* Obtain derivation information from the specified source. */ /* Obtain derivation information from the specified source. */
DrvInfos drvs; UserEnvElems elems;
switch (source) { switch (source) {
case sInstalled: case sInstalled:
queryInstalled(globals.state, drvs, globals.profile); queryInstalled(globals.state, elems, globals.profile);
break; break;
case sAvailable: { case sAvailable: {
loadDerivations(globals.state, globals.instSource.nixExprPath, loadDerivations(globals.state, globals.instSource.nixExprPath,
globals.instSource.systemFilter, drvs); globals.instSource.systemFilter, elems);
break; break;
} }
@ -595,14 +595,14 @@ static void opQuery(Globals & globals,
if (opArgs.size() != 0) throw UsageError("no arguments expected"); if (opArgs.size() != 0) throw UsageError("no arguments expected");
/* Sort them by name. */ /* Sort them by name. */
DrvInfoList drvs2; vector<UserEnvElem> elems2;
for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i) for (UserEnvElems::iterator i = elems.begin(); i != elems.end(); ++i)
drvs2.push_back(i->second); elems2.push_back(i->second);
sort(drvs2.begin(), drvs2.end(), cmpDrvByName); sort(elems2.begin(), elems2.end(), cmpElemByName);
/* We only need to know the installed paths when we are querying /* We only need to know the installed paths when we are querying
the status of the derivation. */ the status of the derivation. */
DrvInfos installed; /* installed paths */ UserEnvElems installed; /* installed paths */
if (printStatus) if (printStatus)
queryInstalled(globals.state, installed, globals.profile); queryInstalled(globals.state, installed, globals.profile);
@ -610,8 +610,9 @@ static void opQuery(Globals & globals,
/* Print the desired columns. */ /* Print the desired columns. */
Table table; Table table;
for (DrvInfoList::iterator i = drvs2.begin(); i != drvs2.end(); ++i) { for (vector<UserEnvElem>::iterator i = elems2.begin();
i != elems2.end(); ++i)
{
Strings columns; Strings columns;
if (printStatus) { if (printStatus) {
@ -794,6 +795,16 @@ static void opDefaultExpr(Globals & globals,
} }
static string needArg(Strings::iterator & i,
const Strings & args, const string & arg)
{
++i;
if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg);
return *i;
}
void run(Strings args) void run(Strings args)
{ {
Strings opFlags, opArgs; Strings opFlags, opArgs;
@ -818,6 +829,12 @@ void run(Strings args)
if (arg == "--install" || arg == "-i") if (arg == "--install" || arg == "-i")
op = opInstall; op = opInstall;
else if (arg == "--from-expression" || arg == "-E")
globals.instSource.type = srcNixExprs;
else if (arg == "--from-profile") {
globals.instSource.type = srcProfile;
globals.instSource.profile = needArg(i, args, arg);
}
else if (arg == "--uninstall" || arg == "-e") else if (arg == "--uninstall" || arg == "-e")
op = opUninstall; op = opUninstall;
else if (arg == "--upgrade" || arg == "-u") else if (arg == "--upgrade" || arg == "-u")
@ -827,16 +844,10 @@ void run(Strings args)
else if (arg == "--import" || arg == "-I") /* !!! bad name */ else if (arg == "--import" || arg == "-I") /* !!! bad name */
op = opDefaultExpr; op = opDefaultExpr;
else if (arg == "--profile" || arg == "-p") { else if (arg == "--profile" || arg == "-p") {
++i; globals.profile = absPath(needArg(i, args, arg));
if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg);
globals.profile = absPath(*i);
} }
else if (arg == "--file" || arg == "-f") { else if (arg == "--file" || arg == "-f") {
++i; globals.instSource.nixExprPath = absPath(needArg(i, args, arg));
if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg);
globals.instSource.nixExprPath = absPath(*i);
} }
else if (arg == "--switch-profile" || arg == "-S") else if (arg == "--switch-profile" || arg == "-S")
op = opSwitchProfile; op = opSwitchProfile;
@ -855,10 +866,7 @@ void run(Strings args)
else if (arg == "--preserve-installed" || arg == "-P") else if (arg == "--preserve-installed" || arg == "-P")
globals.preserveInstalled = true; globals.preserveInstalled = true;
else if (arg == "--system-filter") { else if (arg == "--system-filter") {
++i; globals.instSource.systemFilter = needArg(i, args, arg);
if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg);
globals.instSource.systemFilter = *i;
} }
else if (arg[0] == '-') else if (arg[0] == '-')
opFlags.push_back(arg); opFlags.push_back(arg);

View file

@ -69,7 +69,7 @@ static void makeName(const Path & profile, unsigned int num,
} }
Path createGeneration(Path profile, Path outPath, Path drvPath) Path createGeneration(Path profile, Path outPath)
{ {
/* The new generation number should be higher than old the /* The new generation number should be higher than old the
previous ones. */ previous ones. */

View file

@ -28,7 +28,7 @@ typedef list<Generation> Generations;
profile, sorted by generation number. */ profile, sorted by generation number. */
Generations findGenerations(Path profile, int & curGen); Generations findGenerations(Path profile, int & curGen);
Path createGeneration(Path profile, Path outPath, Path drvPath); Path createGeneration(Path profile, Path outPath);
void deleteGeneration(const Path & profile, unsigned int gen); void deleteGeneration(const Path & profile, unsigned int gen);