2013-11-22 15:41:48 +00:00
|
|
|
#include "user-env.hh"
|
2010-04-19 10:47:56 +00:00
|
|
|
#include "util.hh"
|
2010-04-21 15:08:58 +00:00
|
|
|
#include "derivations.hh"
|
|
|
|
#include "store-api.hh"
|
2021-03-02 03:50:41 +00:00
|
|
|
#include "path-with-outputs.hh"
|
2020-10-09 20:18:08 +00:00
|
|
|
#include "local-fs-store.hh"
|
2010-04-21 15:08:58 +00:00
|
|
|
#include "globals.hh"
|
|
|
|
#include "shared.hh"
|
|
|
|
#include "eval.hh"
|
2013-11-19 13:09:03 +00:00
|
|
|
#include "eval-inline.hh"
|
2010-04-21 15:08:58 +00:00
|
|
|
#include "profiles.hh"
|
2010-04-19 10:47:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
|
|
|
|
DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
|
|
|
{
|
2010-04-19 12:10:04 +00:00
|
|
|
DrvInfos elems;
|
2020-04-02 09:54:48 +00:00
|
|
|
if (pathExists(userEnv + "/manifest.json"))
|
|
|
|
throw Error("profile '%s' is incompatible with 'nix-env'; please use 'nix profile' instead", userEnv);
|
2010-04-21 15:08:58 +00:00
|
|
|
Path manifestFile = userEnv + "/manifest.nix";
|
|
|
|
if (pathExists(manifestFile)) {
|
|
|
|
Value v;
|
2011-08-06 13:02:55 +00:00
|
|
|
state.evalFile(manifestFile, v);
|
2014-09-19 14:49:41 +00:00
|
|
|
Bindings & bindings(*state.allocBindings(0));
|
2012-10-04 19:22:25 +00:00
|
|
|
getDerivations(state, v, "", bindings, elems, false);
|
2013-11-19 10:18:13 +00:00
|
|
|
}
|
2010-04-19 10:47:56 +00:00
|
|
|
return elems;
|
2010-04-19 12:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-21 15:08:58 +00:00
|
|
|
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|
|
|
const Path & profile, bool keepDerivations,
|
|
|
|
const string & lockToken)
|
|
|
|
{
|
|
|
|
/* Build the components in the user environment, if they don't
|
|
|
|
exist already. */
|
2019-12-05 18:11:09 +00:00
|
|
|
std::vector<StorePathWithOutputs> drvsToBuild;
|
2015-07-17 17:24:28 +00:00
|
|
|
for (auto & i : elems)
|
|
|
|
if (i.queryDrvPath() != "")
|
2019-12-05 18:11:09 +00:00
|
|
|
drvsToBuild.push_back({state.store->parseStorePath(i.queryDrvPath())});
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
debug(format("building user environment dependencies"));
|
2021-03-02 03:50:41 +00:00
|
|
|
state.store->buildPaths(
|
2021-04-05 13:48:18 +00:00
|
|
|
toDerivedPaths(drvsToBuild),
|
2021-03-02 03:50:41 +00:00
|
|
|
state.repair ? bmRepair : bmNormal);
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
/* Construct the whole top level derivation. */
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet references;
|
2010-04-21 15:08:58 +00:00
|
|
|
Value manifest;
|
|
|
|
state.mkList(manifest, elems.size());
|
2022-01-04 16:39:16 +00:00
|
|
|
size_t n = 0;
|
2015-07-17 17:24:28 +00:00
|
|
|
for (auto & i : elems) {
|
2010-04-21 15:08:58 +00:00
|
|
|
/* Create a pseudo-derivation containing the name, system,
|
2012-12-04 13:20:36 +00:00
|
|
|
output paths, and optionally the derivation path, as well
|
|
|
|
as the meta attributes. */
|
2015-07-17 17:24:28 +00:00
|
|
|
Path drvPath = keepDerivations ? i.queryDrvPath() : "";
|
2020-12-30 20:20:03 +00:00
|
|
|
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
|
|
|
StringSet metaNames = i.queryMetaNames();
|
2010-04-21 15:08:58 +00:00
|
|
|
|
2022-01-04 16:39:16 +00:00
|
|
|
auto attrs = state.buildBindings(7 + outputs.size());
|
2010-04-21 15:08:58 +00:00
|
|
|
|
2022-01-04 16:39:16 +00:00
|
|
|
attrs.alloc(state.sType).mkString("derivation");
|
|
|
|
attrs.alloc(state.sName).mkString(i.queryName());
|
2017-07-17 17:02:56 +00:00
|
|
|
auto system = i.querySystem();
|
|
|
|
if (!system.empty())
|
2022-01-04 16:39:16 +00:00
|
|
|
attrs.alloc(state.sSystem).mkString(system);
|
|
|
|
attrs.alloc(state.sOutPath).mkString(i.queryOutPath());
|
2010-04-21 15:08:58 +00:00
|
|
|
if (drvPath != "")
|
2022-01-04 16:39:16 +00:00
|
|
|
attrs.alloc(state.sDrvPath).mkString(i.queryDrvPath());
|
2010-10-24 19:52:33 +00:00
|
|
|
|
2016-02-23 13:19:14 +00:00
|
|
|
// Copy each output meant for installation.
|
2022-01-04 16:39:16 +00:00
|
|
|
auto & vOutputs = attrs.alloc(state.sOutputs);
|
2012-12-04 13:20:36 +00:00
|
|
|
state.mkList(vOutputs, outputs.size());
|
2022-01-04 16:39:16 +00:00
|
|
|
for (const auto & [m, j] : enumerate(outputs)) {
|
|
|
|
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
|
|
|
auto outputAttrs = state.buildBindings(2);
|
|
|
|
outputAttrs.alloc(state.sOutPath).mkString(j.second);
|
|
|
|
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
2012-12-04 13:20:36 +00:00
|
|
|
|
|
|
|
/* This is only necessary when installing store paths, e.g.,
|
|
|
|
`nix-env -i /nix/store/abcd...-foo'. */
|
2019-12-05 18:11:09 +00:00
|
|
|
state.store->addTempRoot(state.store->parseStorePath(j.second));
|
|
|
|
state.store->ensurePath(state.store->parseStorePath(j.second));
|
2012-12-04 13:20:36 +00:00
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
references.insert(state.store->parseStorePath(j.second));
|
2012-12-04 13:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the meta attributes.
|
2022-01-04 16:39:16 +00:00
|
|
|
auto meta = state.buildBindings(metaNames.size());
|
2015-07-17 17:24:28 +00:00
|
|
|
for (auto & j : metaNames) {
|
|
|
|
Value * v = i.queryMeta(j);
|
2013-11-19 13:29:39 +00:00
|
|
|
if (!v) continue;
|
2022-01-04 16:39:16 +00:00
|
|
|
meta.insert(state.symbols.create(j), v);
|
2010-04-21 15:08:58 +00:00
|
|
|
}
|
2022-01-04 16:39:16 +00:00
|
|
|
|
|
|
|
attrs.alloc(state.sMeta).mkAttrs(meta);
|
|
|
|
|
|
|
|
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
2012-12-03 17:19:49 +00:00
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
|
2010-04-21 15:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Also write a copy of the list of user environment elements to
|
|
|
|
the store; we need it for future modifications of the
|
|
|
|
environment. */
|
2019-12-05 18:11:09 +00:00
|
|
|
auto manifestFile = state.store->addTextToStore("env-manifest.nix",
|
|
|
|
fmt("%s", manifest), references);
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
/* Get the environment builder expression. */
|
|
|
|
Value envBuilder;
|
2020-03-11 15:41:22 +00:00
|
|
|
state.eval(state.parseExprFromString(
|
|
|
|
#include "buildenv.nix.gen.hh"
|
|
|
|
, "/"), envBuilder);
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
/* Construct a Nix expression that calls the user environment
|
|
|
|
builder with the manifest as argument. */
|
2022-01-04 16:39:16 +00:00
|
|
|
auto attrs = state.buildBindings(3);
|
|
|
|
attrs.alloc("manifest").mkString(
|
|
|
|
state.store->printStorePath(manifestFile),
|
|
|
|
{state.store->printStorePath(manifestFile)});
|
|
|
|
attrs.insert(state.symbols.create("derivations"), &manifest);
|
|
|
|
Value args;
|
|
|
|
args.mkAttrs(attrs);
|
|
|
|
|
|
|
|
Value topLevel;
|
|
|
|
topLevel.mkApp(&envBuilder, &args);
|
2012-12-03 17:19:49 +00:00
|
|
|
|
2010-04-21 15:08:58 +00:00
|
|
|
/* Evaluate it. */
|
|
|
|
debug("evaluating user environment builder");
|
2021-11-27 17:40:24 +00:00
|
|
|
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
2013-11-19 13:09:03 +00:00
|
|
|
PathSet context;
|
2014-04-04 20:19:33 +00:00
|
|
|
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
2021-08-30 07:52:26 +00:00
|
|
|
auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context));
|
2014-04-04 20:19:33 +00:00
|
|
|
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
2021-08-30 07:52:26 +00:00
|
|
|
Path topLevelOut = state.coerceToPath(*aOutPath.pos, *aOutPath.value, context);
|
2012-12-03 17:19:49 +00:00
|
|
|
|
2010-04-21 15:08:58 +00:00
|
|
|
/* Realise the resulting store expression. */
|
|
|
|
debug("building user environment");
|
2019-12-05 18:11:09 +00:00
|
|
|
std::vector<StorePathWithOutputs> topLevelDrvs;
|
2020-06-16 20:20:18 +00:00
|
|
|
topLevelDrvs.push_back({topLevelDrv});
|
2021-03-02 03:50:41 +00:00
|
|
|
state.store->buildPaths(
|
2021-04-05 13:48:18 +00:00
|
|
|
toDerivedPaths(topLevelDrvs),
|
2021-03-02 03:50:41 +00:00
|
|
|
state.repair ? bmRepair : bmNormal);
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
/* Switch the current user environment to the output path. */
|
2016-06-02 11:33:49 +00:00
|
|
|
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
|
2010-04-21 15:08:58 +00:00
|
|
|
|
2016-06-02 11:33:49 +00:00
|
|
|
if (store2) {
|
|
|
|
PathLocks lock;
|
|
|
|
lockProfile(lock, profile);
|
|
|
|
|
|
|
|
Path lockTokenCur = optimisticLockProfile(profile);
|
|
|
|
if (lockToken != lockTokenCur) {
|
2020-05-13 15:52:36 +00:00
|
|
|
printInfo("profile '%1%' changed while we were busy; restarting", profile);
|
2016-06-02 11:33:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-03 17:19:49 +00:00
|
|
|
|
2016-06-02 11:33:49 +00:00
|
|
|
debug(format("switching to new user environment"));
|
2020-09-03 09:06:56 +00:00
|
|
|
Path generation = createGeneration(ref<LocalFSStore>(store2), profile,
|
|
|
|
store2->parseStorePath(topLevelOut));
|
2016-06-02 11:33:49 +00:00
|
|
|
switchLink(profile, generation);
|
|
|
|
}
|
2010-04-21 15:08:58 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-19 10:47:56 +00:00
|
|
|
}
|