From 20ce2642fc0052a9f70faf194cc0c31d3f88926e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Feb 2005 16:56:45 +0000 Subject: [PATCH] * 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). --- src/libexpr/primops.cc | 21 ++++-- src/libutil/util.hh | 8 +++ src/nix-env/help.txt | 3 +- src/nix-env/main.cc | 152 ++++++++++++++++++++++++++-------------- src/nix-env/profiles.cc | 2 +- 5 files changed, 125 insertions(+), 61 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 013eba594..da9d1e635 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -94,6 +94,7 @@ static void processBinding(EvalState & state, Expr e, Derivation & drv, else if (matchAttrs(e, es)) { Expr a = queryAttr(e, "type"); + if (a && evalString(state, a) == "derivation") { a = queryAttr(e, "drvPath"); 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 */ Path outPath = evalPath(state, a); - StringSet ids; - ids.insert("out"); - drv.inputDrvs[drvPath] = ids; + drv.inputDrvs[drvPath] = singleton("out"); 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)) { diff --git a/src/libutil/util.hh b/src/libutil/util.hh index b67913862..2577f79e1 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -112,6 +112,14 @@ Path createTempDir(); not already exist. */ void writeStringToFile(const Path & path, const string & s); +template +T singleton(const A & a) +{ + T t; + t.insert(a); + return t; +} + /* Messages. */ diff --git a/src/nix-env/help.txt b/src/nix-env/help.txt index fe9eca79e..4fc160284 100644 --- a/src/nix-env/help.txt +++ b/src/nix-env/help.txt @@ -37,7 +37,8 @@ Upgrade flags: Query types: --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 Query sources: diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index da77e2428..d45dd2bd8 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -12,14 +12,31 @@ #include +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 { + InstallSourceInfo instSource; Path profile; - Path nixExprPath; EvalState state; bool dryRun; bool preserveInstalled; - string systemFilter; }; @@ -64,8 +81,7 @@ bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv) drv.system = evalString(state, a); a = queryAttr(e, "drvPath"); - if (!a) throw badTerm("derivation path missing", e); - drv.drvPath = evalPath(state, a); + if (a) drv.drvPath = evalPath(state, a); a = queryAttr(e, "outPath"); if (!a) throw badTerm("output path missing", e); @@ -83,7 +99,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) e = evalExpr(state, e); if (parseDerivation(state, e, drv)) - drvs[drv.drvPath] = drv; + drvs[drv.outPath] = drv; else if (matchAttrs(e, es)) { ATermMap drvMap; @@ -91,7 +107,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) for (ATermIterator i(drvMap.keys()); i; ++i) { debug(format("evaluating attribute `%1%'") % *i); if (parseDerivation(state, drvMap.get(*i), drv)) - drvs[drv.drvPath] = drv; + drvs[drv.outPath] = drv; else parseDerivations(state, drvMap.get(*i), drvs); } @@ -101,7 +117,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) for (ATermIterator i(es); i; ++i) { debug(format("evaluating list element")); if (parseDerivation(state, *i, drv)) - drvs[drv.drvPath] = drv; + drvs[drv.outPath] = drv; else parseDerivations(state, *i, drvs); } @@ -111,10 +127,10 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) } -void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs, - string systemFilter) +static void loadDerivations(EvalState & state, Path nixExprPath, + string systemFilter, DrvInfos & drvs) { - Expr e = parseExprFromFile(state, absPath(nePath)); + Expr e = parseExprFromFile(state, absPath(nixExprPath)); if (!parseDerivations(state, e, drvs)) 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() { Path homeDir(getEnv("HOME", "")); @@ -177,43 +205,62 @@ void queryInstalled(EvalState & state, DrvInfos & drvs, void createUserEnv(EvalState & state, const DrvInfos & drvs, 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. */ Expr envBuilder = parseExprFromFile(state, nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */ /* Construct the whole top level derivation. */ + PathSet references; + ATermList manifest = ATempty; ATermList inputs = ATempty; for (DrvInfos::const_iterator i = drvs.begin(); i != drvs.end(); ++i) { - ATerm t = makeAttrs(ATmakeList5( + ATerm t = makeAttrs(ATmakeList4( makeBind(toATerm("type"), makeStr(toATerm("derivation")), makeNoPos()), makeBind(toATerm("name"), makeStr(toATerm(i->second.name)), makeNoPos()), makeBind(toATerm("system"), makeStr(toATerm(i->second.system)), makeNoPos()), - makeBind(toATerm("drvPath"), - makePath(toATerm(i->second.drvPath)), makeNoPos()), makeBind(toATerm("outPath"), 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 it for future modifications of the environment. */ - Path inputsFile = addTextToStore("env-inputs", atPrint(inputs2), - PathSet() /* !!! incorrect */); + Path manifestFile = addTextToStore("env-manifest", + atPrint(makeList(ATreverse(manifest))), references); + + printMsg(lvlError, format("manifest is %1%") % manifestFile); Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( makeBind(toATerm("system"), makeStr(toATerm(thisSystem)), makeNoPos()), - makeBind(toATerm("derivations"), inputs2, makeNoPos()), + makeBind(toATerm("derivations"), + makeList(ATreverse(inputs)), makeNoPos()), 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. */ @@ -224,9 +271,7 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, /* Realise the resulting store expression. */ debug(format("building user environment")); - PathSet drvPaths; - drvPaths.insert(topLevelDrv.drvPath); - buildDerivations(drvPaths); + buildDerivations(singleton(topLevelDrv.drvPath)); /* Switch the current user environment to the output path. */ debug(format("switching to new user environment")); @@ -237,14 +282,14 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, static void installDerivations(EvalState & state, - Path nePath, DrvNames & selectors, const Path & profile, - bool dryRun, bool preserveInstalled, string systemFilter) + const InstallSourceInfo & instSource, DrvNames & selectors, + 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. */ DrvInfos availDrvs; - loadDerivations(state, nePath, availDrvs, systemFilter); + queryInstSources(state, instSource, availDrvs); /* Filter out the ones we're not interested in. */ DrvInfos selectedDrvs; @@ -303,9 +348,9 @@ static void opInstall(Globals & globals, DrvNames drvNames = drvNamesFromArgs(opArgs); - installDerivations(globals.state, globals.nixExprPath, + installDerivations(globals.state, globals.instSource, 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, - Path nePath, DrvNames & selectors, const Path & profile, - UpgradeType upgradeType, bool dryRun, string systemFilter) + const InstallSourceInfo & instSource, DrvNames & selectors, const Path & profile, + UpgradeType upgradeType, bool dryRun) { - debug(format("upgrading derivations from `%1%'") % nePath); + debug(format("upgrading derivations")); /* Upgrade works as follows: we take all currently installed 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. */ DrvInfos availDrvs; - loadDerivations(state, nePath, availDrvs, systemFilter); + // xxx loadDerivations(state, nePath, availDrvs, systemFilter); /* Go through all installed derivations. */ DrvInfos newDrvs; @@ -414,9 +459,8 @@ static void opUpgrade(Globals & globals, DrvNames drvNames = drvNamesFromArgs(opArgs); - upgradeDerivations(globals.state, globals.nixExprPath, - drvNames, globals.profile, upgradeType, globals.dryRun, - globals.systemFilter); + upgradeDerivations(globals.state, globals.instSource, + drvNames, globals.profile, upgradeType, globals.dryRun); } @@ -511,6 +555,7 @@ static void opQuery(Globals & globals, bool printName = true; bool printSystem = false; bool printDrvPath = false; + bool printOutPath = false; enum { sInstalled, sAvailable } source = sInstalled; @@ -521,7 +566,8 @@ static void opQuery(Globals & globals, if (*i == "--status" || *i == "-s") printStatus = true; else if (*i == "--no-name") printName = false; 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 == "--available" || *i == "-a") source = sAvailable; else throw UsageError(format("unknown flag `%1%'") % *i); @@ -536,8 +582,8 @@ static void opQuery(Globals & globals, break; case sAvailable: { - loadDerivations(globals.state, globals.nixExprPath, - drvs, globals.systemFilter); + loadDerivations(globals.state, globals.instSource.nixExprPath, + globals.instSource.systemFilter, drvs); break; } @@ -554,16 +600,10 @@ static void opQuery(Globals & globals, /* We only need to know the installed paths when we are querying the status of the derivation. */ - PathSet installedPaths; /* output paths of installed drvs */ + DrvInfos installed; /* installed paths */ - if (printStatus) { - DrvInfos installed; + if (printStatus) 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. */ Table table; @@ -575,8 +615,8 @@ static void opQuery(Globals & globals, if (printStatus) { Substitutes subs = querySubstitutes(noTxn, i->drvPath); columns.push_back( - (string) (installedPaths.find(i->outPath) - != installedPaths.end() ? "I" : "-") + (string) (installed.find(i->outPath) + != installed.end() ? "I" : "-") + (isValidPath(i->outPath) ? "P" : "-") + (subs.size() > 0 ? "S" : "-")); } @@ -585,7 +625,9 @@ static void opQuery(Globals & globals, 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); } @@ -756,10 +798,12 @@ void run(Strings args) Operation op = 0; Globals globals; - globals.nixExprPath = getDefNixExprPath(); + globals.instSource.type = srcUnknown; + globals.instSource.nixExprPath = getDefNixExprPath(); + globals.instSource.systemFilter = thisSystem; + globals.dryRun = false; globals.preserveInstalled = false; - globals.systemFilter = thisSystem; for (Strings::iterator i = args.begin(); i != args.end(); ++i) { string arg = *i; @@ -786,7 +830,7 @@ void run(Strings args) ++i; if (i == args.end()) throw UsageError( format("`%1%' requires an argument") % arg); - globals.nixExprPath = absPath(*i); + globals.instSource.nixExprPath = absPath(*i); } else if (arg == "--switch-profile" || arg == "-S") op = opSwitchProfile; @@ -808,7 +852,7 @@ void run(Strings args) ++i; if (i == args.end()) throw UsageError( format("`%1%' requires an argument") % arg); - globals.systemFilter = *i; + globals.instSource.systemFilter = *i; } else if (arg[0] == '-') opFlags.push_back(arg); diff --git a/src/nix-env/profiles.cc b/src/nix-env/profiles.cc index abfdf9fed..20aaded77 100644 --- a/src/nix-env/profiles.cc +++ b/src/nix-env/profiles.cc @@ -65,7 +65,7 @@ static void makeNames(const Path & profile, unsigned int num, Path & outLink, Path & drvLink) { Path prefix = (format("%1%-%2%") % profile % num).str(); - outLink = prefix + "-output"; + outLink = prefix + "-link"; drvLink = prefix + "-drv"; }