* Refactoring to support different installation sources in nix-env.

* Set the references for the user environment manifest properly.
* Don't copy the manifest (this was accidental).
* Don't store derivation paths in the manifest (maybe this should be
  made optional).  This cleans up the semantics of nix-env, which were
  weird.
* Hash on the output paths of activated components, not on derivation
  paths.  This is because we don't know the derivation path of already
  installed components anymore, and it allows the installation of
  components by store path (skipping Nix expressions entirely).
* Query options `--out-path' and `--drv-path' to show the output and
  derivation paths of components, respectively (the latter replaces
  the `--expr' query).
This commit is contained in:
Eelco Dolstra 2005-02-11 16:56:45 +00:00
parent 80870d9291
commit 20ce2642fc
5 changed files with 125 additions and 61 deletions

View file

@ -94,6 +94,7 @@ static void processBinding(EvalState & state, Expr e, Derivation & drv,
else if (matchAttrs(e, es)) { else if (matchAttrs(e, es)) {
Expr a = queryAttr(e, "type"); Expr a = queryAttr(e, "type");
if (a && evalString(state, a) == "derivation") { if (a && evalString(state, a) == "derivation") {
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
if (!a) throw Error("derivation name missing"); if (!a) throw Error("derivation name missing");
@ -104,12 +105,22 @@ static void processBinding(EvalState & state, Expr e, Derivation & drv,
/* !!! supports only single output path */ /* !!! supports only single output path */
Path outPath = evalPath(state, a); Path outPath = evalPath(state, a);
StringSet ids; drv.inputDrvs[drvPath] = singleton<StringSet>("out");
ids.insert("out");
drv.inputDrvs[drvPath] = ids;
ss.push_back(outPath); ss.push_back(outPath);
} else }
throw Error("invalid derivation attribute");
else if (a && evalString(state, a) == "storePath") {
a = queryAttr(e, "outPath");
if (!a) throw Error("output path missing");
/* !!! supports only single output path */
Path outPath = evalPath(state, a);
drv.inputSrcs.insert(outPath);
ss.push_back(outPath);
}
else throw Error("invalid derivation attribute");
} }
else if (matchPath(e, s)) { else if (matchPath(e, s)) {

View file

@ -112,6 +112,14 @@ Path createTempDir();
not already exist. */ not already exist. */
void writeStringToFile(const Path & path, const string & s); void writeStringToFile(const Path & path, const string & s);
template<class T, class A>
T singleton(const A & a)
{
T t;
t.insert(a);
return t;
}
/* Messages. */ /* Messages. */

View file

@ -37,7 +37,8 @@ Upgrade flags:
Query types: Query types:
--name: print derivation names (default) --name: print derivation names (default)
--expr: print derivation store expression --drv-path: print path of derivation
--out-path: print path of derivation output
--status / -s: print installed/present status --status / -s: print installed/present status
Query sources: Query sources:

View file

@ -12,14 +12,31 @@
#include <ctime> #include <ctime>
typedef enum {
srcNixExprDrvs,
srcNixExprs,
srcStorePaths,
srcProfile,
srcUnknown
} InstallSourceType;
struct InstallSourceInfo
{
InstallSourceType type;
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
Path profile; /* for srcProfile */
string systemFilter; /* for srcNixExprDrvs */
};
struct Globals struct Globals
{ {
InstallSourceInfo instSource;
Path profile; Path profile;
Path nixExprPath;
EvalState state; EvalState state;
bool dryRun; bool dryRun;
bool preserveInstalled; bool preserveInstalled;
string systemFilter;
}; };
@ -64,8 +81,7 @@ bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
drv.system = evalString(state, a); drv.system = evalString(state, a);
a = queryAttr(e, "drvPath"); a = queryAttr(e, "drvPath");
if (!a) throw badTerm("derivation path missing", e); if (a) drv.drvPath = evalPath(state, a);
drv.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);
@ -83,7 +99,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
e = evalExpr(state, e); e = evalExpr(state, e);
if (parseDerivation(state, e, drv)) if (parseDerivation(state, e, drv))
drvs[drv.drvPath] = drv; drvs[drv.outPath] = drv;
else if (matchAttrs(e, es)) { else if (matchAttrs(e, es)) {
ATermMap drvMap; ATermMap drvMap;
@ -91,7 +107,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
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), drv))
drvs[drv.drvPath] = drv; drvs[drv.outPath] = drv;
else else
parseDerivations(state, drvMap.get(*i), drvs); parseDerivations(state, drvMap.get(*i), drvs);
} }
@ -101,7 +117,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
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, drv))
drvs[drv.drvPath] = drv; drvs[drv.outPath] = drv;
else else
parseDerivations(state, *i, drvs); parseDerivations(state, *i, drvs);
} }
@ -111,10 +127,10 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
} }
void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs, static void loadDerivations(EvalState & state, Path nixExprPath,
string systemFilter) string systemFilter, DrvInfos & drvs)
{ {
Expr e = parseExprFromFile(state, absPath(nePath)); Expr e = parseExprFromFile(state, absPath(nixExprPath));
if (!parseDerivations(state, e, drvs)) if (!parseDerivations(state, e, drvs))
throw Error("set of derivations expected"); throw Error("set of derivations expected");
@ -128,6 +144,18 @@ void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs,
} }
static void queryInstSources(EvalState & state,
const InstallSourceInfo & instSource, DrvInfos & drvs)
{
switch (instSource.type) {
case srcUnknown:
loadDerivations(state, instSource.nixExprPath,
instSource.systemFilter, drvs);
break;
}
}
static Path getHomeDir() static Path getHomeDir()
{ {
Path homeDir(getEnv("HOME", "")); Path homeDir(getEnv("HOME", ""));
@ -177,43 +205,62 @@ void queryInstalled(EvalState & state, DrvInfos & drvs,
void createUserEnv(EvalState & state, const DrvInfos & drvs, void createUserEnv(EvalState & state, const DrvInfos & drvs,
const Path & profile) const Path & profile)
{ {
/* Build the components in the user environment, if they don't
exist already. */
PathSet drvsToBuild;
for (DrvInfos::const_iterator i = drvs.begin();
i != drvs.end(); ++i)
if (i->second.drvPath != "")
drvsToBuild.insert(i->second.drvPath);
debug(format("building user environment dependencies"));
buildDerivations(drvsToBuild);
/* Get the environment builder expression. */ /* Get the environment builder expression. */
Expr envBuilder = parseExprFromFile(state, Expr envBuilder = parseExprFromFile(state,
nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */ nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */
/* Construct the whole top level derivation. */ /* Construct the whole top level derivation. */
PathSet references;
ATermList manifest = ATempty;
ATermList inputs = ATempty; ATermList inputs = ATempty;
for (DrvInfos::const_iterator i = drvs.begin(); for (DrvInfos::const_iterator i = drvs.begin();
i != drvs.end(); ++i) i != drvs.end(); ++i)
{ {
ATerm t = makeAttrs(ATmakeList5( ATerm t = makeAttrs(ATmakeList4(
makeBind(toATerm("type"), makeBind(toATerm("type"),
makeStr(toATerm("derivation")), makeNoPos()), makeStr(toATerm("derivation")), makeNoPos()),
makeBind(toATerm("name"), makeBind(toATerm("name"),
makeStr(toATerm(i->second.name)), makeNoPos()), makeStr(toATerm(i->second.name)), makeNoPos()),
makeBind(toATerm("system"), makeBind(toATerm("system"),
makeStr(toATerm(i->second.system)), makeNoPos()), makeStr(toATerm(i->second.system)), makeNoPos()),
makeBind(toATerm("drvPath"),
makePath(toATerm(i->second.drvPath)), makeNoPos()),
makeBind(toATerm("outPath"), makeBind(toATerm("outPath"),
makePath(toATerm(i->second.outPath)), makeNoPos()) makePath(toATerm(i->second.outPath)), makeNoPos())
)); ));
inputs = ATinsert(inputs, t); manifest = ATinsert(manifest, t);
inputs = ATinsert(inputs, makeStr(toATerm(i->second.outPath)));
references.insert(i->second.outPath);
} }
ATerm inputs2 = makeList(ATreverse(inputs));
/* Also write a copy of the list of inputs to the store; we need /* Also write a copy of the list of inputs to the store; we need
it for future modifications of the environment. */ it for future modifications of the environment. */
Path inputsFile = addTextToStore("env-inputs", atPrint(inputs2), Path manifestFile = addTextToStore("env-manifest",
PathSet() /* !!! incorrect */); atPrint(makeList(ATreverse(manifest))), references);
printMsg(lvlError, format("manifest is %1%") % manifestFile);
Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
makeBind(toATerm("system"), makeBind(toATerm("system"),
makeStr(toATerm(thisSystem)), makeNoPos()), makeStr(toATerm(thisSystem)), makeNoPos()),
makeBind(toATerm("derivations"), inputs2, makeNoPos()), makeBind(toATerm("derivations"),
makeList(ATreverse(inputs)), makeNoPos()),
makeBind(toATerm("manifest"), makeBind(toATerm("manifest"),
makePath(toATerm(inputsFile)), makeNoPos()) makeAttrs(ATmakeList2(
makeBind(toATerm("type"),
makeStr(toATerm("storePath")), makeNoPos()),
makeBind(toATerm("outPath"),
makePath(toATerm(manifestFile)), makeNoPos())
)), makeNoPos())
))); )));
/* Instantiate it. */ /* Instantiate it. */
@ -224,9 +271,7 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
/* Realise the resulting store expression. */ /* Realise the resulting store expression. */
debug(format("building user environment")); debug(format("building user environment"));
PathSet drvPaths; buildDerivations(singleton<PathSet>(topLevelDrv.drvPath));
drvPaths.insert(topLevelDrv.drvPath);
buildDerivations(drvPaths);
/* 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"));
@ -237,14 +282,14 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
static void installDerivations(EvalState & state, static void installDerivations(EvalState & state,
Path nePath, DrvNames & selectors, const Path & profile, const InstallSourceInfo & instSource, DrvNames & selectors,
bool dryRun, bool preserveInstalled, string systemFilter) const Path & profile, bool dryRun, bool preserveInstalled)
{ {
debug(format("installing derivations from `%1%'") % nePath); debug(format("installing derivations"));
/* Fetch all derivations from the input file. */ /* Fetch all derivations from the input file. */
DrvInfos availDrvs; DrvInfos availDrvs;
loadDerivations(state, nePath, availDrvs, systemFilter); queryInstSources(state, instSource, availDrvs);
/* Filter out the ones we're not interested in. */ /* Filter out the ones we're not interested in. */
DrvInfos selectedDrvs; DrvInfos selectedDrvs;
@ -303,9 +348,9 @@ static void opInstall(Globals & globals,
DrvNames drvNames = drvNamesFromArgs(opArgs); DrvNames drvNames = drvNamesFromArgs(opArgs);
installDerivations(globals.state, globals.nixExprPath, installDerivations(globals.state, globals.instSource,
drvNames, globals.profile, globals.dryRun, drvNames, globals.profile, globals.dryRun,
globals.preserveInstalled, globals.systemFilter); globals.preserveInstalled);
} }
@ -313,10 +358,10 @@ typedef enum { utLt, utLeq, utAlways } UpgradeType;
static void upgradeDerivations(EvalState & state, static void upgradeDerivations(EvalState & state,
Path nePath, DrvNames & selectors, const Path & profile, const InstallSourceInfo & instSource, DrvNames & selectors, const Path & profile,
UpgradeType upgradeType, bool dryRun, string systemFilter) UpgradeType upgradeType, bool dryRun)
{ {
debug(format("upgrading derivations from `%1%'") % nePath); debug(format("upgrading derivations"));
/* Upgrade works as follows: we take all currently installed /* Upgrade works as follows: we take all currently installed
derivations, and for any derivation matching any selector, look derivations, and for any derivation matching any selector, look
@ -329,7 +374,7 @@ static void upgradeDerivations(EvalState & state,
/* Fetch all derivations from the input file. */ /* Fetch all derivations from the input file. */
DrvInfos availDrvs; DrvInfos availDrvs;
loadDerivations(state, nePath, availDrvs, systemFilter); // xxx loadDerivations(state, nePath, availDrvs, systemFilter);
/* Go through all installed derivations. */ /* Go through all installed derivations. */
DrvInfos newDrvs; DrvInfos newDrvs;
@ -414,9 +459,8 @@ static void opUpgrade(Globals & globals,
DrvNames drvNames = drvNamesFromArgs(opArgs); DrvNames drvNames = drvNamesFromArgs(opArgs);
upgradeDerivations(globals.state, globals.nixExprPath, upgradeDerivations(globals.state, globals.instSource,
drvNames, globals.profile, upgradeType, globals.dryRun, drvNames, globals.profile, upgradeType, globals.dryRun);
globals.systemFilter);
} }
@ -511,6 +555,7 @@ static void opQuery(Globals & globals,
bool printName = true; bool printName = true;
bool printSystem = false; bool printSystem = false;
bool printDrvPath = false; bool printDrvPath = false;
bool printOutPath = false;
enum { sInstalled, sAvailable } source = sInstalled; enum { sInstalled, sAvailable } source = sInstalled;
@ -521,7 +566,8 @@ static void opQuery(Globals & globals,
if (*i == "--status" || *i == "-s") printStatus = true; if (*i == "--status" || *i == "-s") printStatus = true;
else if (*i == "--no-name") printName = false; else if (*i == "--no-name") printName = false;
else if (*i == "--system") printSystem = true; else if (*i == "--system") printSystem = true;
else if (*i == "--expr") printDrvPath = true; else if (*i == "--drv-path") printDrvPath = true;
else if (*i == "--out-path") printOutPath = true;
else if (*i == "--installed") source = sInstalled; else if (*i == "--installed") source = sInstalled;
else if (*i == "--available" || *i == "-a") source = sAvailable; else if (*i == "--available" || *i == "-a") source = sAvailable;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
@ -536,8 +582,8 @@ static void opQuery(Globals & globals,
break; break;
case sAvailable: { case sAvailable: {
loadDerivations(globals.state, globals.nixExprPath, loadDerivations(globals.state, globals.instSource.nixExprPath,
drvs, globals.systemFilter); globals.instSource.systemFilter, drvs);
break; break;
} }
@ -554,17 +600,11 @@ static void opQuery(Globals & globals,
/* 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. */
PathSet installedPaths; /* output paths of installed drvs */ DrvInfos installed; /* installed paths */
if (printStatus) { if (printStatus)
DrvInfos installed;
queryInstalled(globals.state, installed, globals.profile); queryInstalled(globals.state, installed, globals.profile);
for (DrvInfos::iterator i = installed.begin();
i != installed.end(); ++i)
installedPaths.insert(i->second.outPath);
}
/* Print the desired columns. */ /* Print the desired columns. */
Table table; Table table;
@ -575,8 +615,8 @@ static void opQuery(Globals & globals,
if (printStatus) { if (printStatus) {
Substitutes subs = querySubstitutes(noTxn, i->drvPath); Substitutes subs = querySubstitutes(noTxn, i->drvPath);
columns.push_back( columns.push_back(
(string) (installedPaths.find(i->outPath) (string) (installed.find(i->outPath)
!= installedPaths.end() ? "I" : "-") != installed.end() ? "I" : "-")
+ (isValidPath(i->outPath) ? "P" : "-") + (isValidPath(i->outPath) ? "P" : "-")
+ (subs.size() > 0 ? "S" : "-")); + (subs.size() > 0 ? "S" : "-"));
} }
@ -585,7 +625,9 @@ static void opQuery(Globals & globals,
if (printSystem) columns.push_back(i->system); if (printSystem) columns.push_back(i->system);
if (printDrvPath) columns.push_back(i->drvPath); if (printDrvPath) columns.push_back(i->drvPath == "" ? "-" : i->drvPath);
if (printOutPath) columns.push_back(i->outPath);
table.push_back(columns); table.push_back(columns);
} }
@ -756,10 +798,12 @@ void run(Strings args)
Operation op = 0; Operation op = 0;
Globals globals; Globals globals;
globals.nixExprPath = getDefNixExprPath(); globals.instSource.type = srcUnknown;
globals.instSource.nixExprPath = getDefNixExprPath();
globals.instSource.systemFilter = thisSystem;
globals.dryRun = false; globals.dryRun = false;
globals.preserveInstalled = false; globals.preserveInstalled = false;
globals.systemFilter = thisSystem;
for (Strings::iterator i = args.begin(); i != args.end(); ++i) { for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
string arg = *i; string arg = *i;
@ -786,7 +830,7 @@ void run(Strings args)
++i; ++i;
if (i == args.end()) throw UsageError( if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg); format("`%1%' requires an argument") % arg);
globals.nixExprPath = absPath(*i); globals.instSource.nixExprPath = absPath(*i);
} }
else if (arg == "--switch-profile" || arg == "-S") else if (arg == "--switch-profile" || arg == "-S")
op = opSwitchProfile; op = opSwitchProfile;
@ -808,7 +852,7 @@ void run(Strings args)
++i; ++i;
if (i == args.end()) throw UsageError( if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg); format("`%1%' requires an argument") % arg);
globals.systemFilter = *i; globals.instSource.systemFilter = *i;
} }
else if (arg[0] == '-') else if (arg[0] == '-')
opFlags.push_back(arg); opFlags.push_back(arg);

View file

@ -65,7 +65,7 @@ static void makeNames(const Path & profile, unsigned int num,
Path & outLink, Path & drvLink) Path & outLink, Path & drvLink)
{ {
Path prefix = (format("%1%-%2%") % profile % num).str(); Path prefix = (format("%1%-%2%") % profile % num).str();
outLink = prefix + "-output"; outLink = prefix + "-link";
drvLink = prefix + "-drv"; drvLink = prefix + "-drv";
} }