* nix-env now maintains meta info (from the `meta' derivation
attribute) about installed packages in user environments. Thus, an operation like `nix-env -q --description' shows useful information not only on available packages but also on installed packages. * nix-env now passes the entire manifest as an argument to the Nix expression of the user environment builder (not just a list of paths), so that in particular the user environment builder has access to the meta attributes. * New operation `--set-flag' in nix-env to change meta info of installed packages. This will be useful to pass per-package policies to the user environment builder (e.g., how to resolve collision or whether to disable a package (NIX-80)) or upgrade policies in nix-env (e.g., that a package should be "masked", that is, left untouched by upgrade actions). Example: $ nix-env --set-flag enabled false ghc-6.4
This commit is contained in:
parent
f52de527c7
commit
451dbf687f
6 changed files with 105 additions and 16 deletions
|
@ -14,6 +14,14 @@
|
||||||
|
|
||||||
<listitem><para>TODO: multi-user support.</para></listitem>
|
<listitem><para>TODO: multi-user support.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem><para><command>nix-prefetch-url</command> now by default
|
||||||
|
computes the SHA-256 hash of the file instead of the MD5 hash. In
|
||||||
|
calls to <function>fetchurl</function> you should pass an
|
||||||
|
<literal>sha256</literal> attribute instead of
|
||||||
|
<literal>md5</literal>. You can pass either a hexadecimal or a
|
||||||
|
base-32 encoding of the hash.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
<listitem><para><command>nix-store</command> has a new operation
|
<listitem><para><command>nix-store</command> has a new operation
|
||||||
<option>--read-log</option> (<option>-l</option>)
|
<option>--read-log</option> (<option>-l</option>)
|
||||||
|
@ -51,6 +59,14 @@
|
||||||
|
|
||||||
|
|
||||||
<listitem><para>TODO: <option>--argstr</option>.</para></listitem>
|
<listitem><para>TODO: <option>--argstr</option>.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem><para>TODO: <command>nix-env</command> now maintains meta
|
||||||
|
info about installed packages in user
|
||||||
|
environments.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>TODO: <command>nix-env</command>
|
||||||
|
<option>--set-flag</option>.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
<listitem><para>TODO: new built-ins
|
<listitem><para>TODO: new built-ins
|
||||||
|
|
|
@ -60,6 +60,16 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DrvInfo::setMetaInfo(const MetaInfo & meta)
|
||||||
|
{
|
||||||
|
ATermMap metaAttrs;
|
||||||
|
for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i)
|
||||||
|
metaAttrs.set(toATerm(i->first),
|
||||||
|
makeAttrRHS(makeStr(i->second), makeNoPos()));
|
||||||
|
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Cache for already evaluated derivations. Usually putting ATerms in
|
/* Cache for already evaluated derivations. Usually putting ATerms in
|
||||||
a STL container is unsafe (they're not scanning for GC roots), but
|
a STL container is unsafe (they're not scanning for GC roots), but
|
||||||
here it doesn't matter; everything in this set is reachable from
|
here it doesn't matter; everything in this set is reachable from
|
||||||
|
|
|
@ -26,6 +26,9 @@ public:
|
||||||
string attrPath; /* path towards the derivation */
|
string attrPath; /* path towards the derivation */
|
||||||
string system;
|
string system;
|
||||||
|
|
||||||
|
/* !!! these should really be hidden, and setMetaInfo() should
|
||||||
|
make a copy since the ATermMap can be shared between multiple
|
||||||
|
DrvInfos. */
|
||||||
boost::shared_ptr<ATermMap> attrs;
|
boost::shared_ptr<ATermMap> attrs;
|
||||||
|
|
||||||
string queryDrvPath(EvalState & state) const;
|
string queryDrvPath(EvalState & state) const;
|
||||||
|
@ -41,6 +44,8 @@ public:
|
||||||
{
|
{
|
||||||
outPath = s;
|
outPath = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMetaInfo(const MetaInfo & meta);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -319,7 +319,7 @@ struct Canonicalise : TermFun
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Expr canonicaliseExpr(Expr & e)
|
Expr canonicaliseExpr(Expr e)
|
||||||
{
|
{
|
||||||
Canonicalise canonicalise;
|
Canonicalise canonicalise;
|
||||||
return bottomupRewrite(canonicalise, e);
|
return bottomupRewrite(canonicalise, e);
|
||||||
|
|
|
@ -96,7 +96,7 @@ void checkVarDefs(const ATermMap & def, Expr e);
|
||||||
|
|
||||||
/* Canonicalise a Nix expression by sorting attributes and removing
|
/* Canonicalise a Nix expression by sorting attributes and removing
|
||||||
location information. */
|
location information. */
|
||||||
Expr canonicaliseExpr(Expr & e);
|
Expr canonicaliseExpr(Expr e);
|
||||||
|
|
||||||
|
|
||||||
/* Create an expression representing a boolean. */
|
/* Create an expression representing a boolean. */
|
||||||
|
|
|
@ -164,7 +164,11 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
|
||||||
for (DrvInfos::const_iterator i = elems.begin();
|
for (DrvInfos::const_iterator i = elems.begin();
|
||||||
i != elems.end(); ++i)
|
i != elems.end(); ++i)
|
||||||
{
|
{
|
||||||
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
|
output path, and optionally the derivation path, as well as
|
||||||
|
the meta attributes. */
|
||||||
Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
|
Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
|
||||||
|
|
||||||
ATermList as = ATmakeList4(
|
ATermList as = ATmakeList4(
|
||||||
makeBind(toATerm("type"),
|
makeBind(toATerm("type"),
|
||||||
makeStr("derivation"), makeNoPos()),
|
makeStr("derivation"), makeNoPos()),
|
||||||
|
@ -174,10 +178,18 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
|
||||||
makeStr(i->system), makeNoPos()),
|
makeStr(i->system), makeNoPos()),
|
||||||
makeBind(toATerm("outPath"),
|
makeBind(toATerm("outPath"),
|
||||||
makeStr(i->queryOutPath(state)), makeNoPos()));
|
makeStr(i->queryOutPath(state)), makeNoPos()));
|
||||||
|
|
||||||
if (drvPath != "") as = ATinsert(as,
|
if (drvPath != "") as = ATinsert(as,
|
||||||
makeBind(toATerm("drvPath"),
|
makeBind(toATerm("drvPath"),
|
||||||
makeStr(drvPath), makeNoPos()));
|
makeStr(drvPath), makeNoPos()));
|
||||||
|
|
||||||
|
if (i->attrs->get(toATerm("meta"))) as = ATinsert(as,
|
||||||
|
makeBind(toATerm("meta"),
|
||||||
|
strictEvalExpr(state, i->attrs->get(toATerm("meta"))),
|
||||||
|
makeNoPos()));
|
||||||
|
|
||||||
manifest = ATinsert(manifest, makeAttrs(as));
|
manifest = ATinsert(manifest, makeAttrs(as));
|
||||||
|
|
||||||
inputs = ATinsert(inputs, makeStr(i->queryOutPath(state)));
|
inputs = ATinsert(inputs, makeStr(i->queryOutPath(state)));
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
|
@ -192,13 +204,13 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
|
||||||
/* 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 manifestFile = store->addTextToStore("env-manifest",
|
Path manifestFile = store->addTextToStore("env-manifest",
|
||||||
atPrint(makeList(ATreverse(manifest))), references);
|
atPrint(canonicaliseExpr(makeList(ATreverse(manifest)))), references);
|
||||||
|
|
||||||
Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
|
Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
|
||||||
makeBind(toATerm("system"),
|
makeBind(toATerm("system"),
|
||||||
makeStr(thisSystem), makeNoPos()),
|
makeStr(thisSystem), makeNoPos()),
|
||||||
makeBind(toATerm("derivations"),
|
makeBind(toATerm("derivations"),
|
||||||
makeList(ATreverse(inputs)), makeNoPos()),
|
makeList(ATreverse(manifest)), makeNoPos()),
|
||||||
makeBind(toATerm("manifest"),
|
makeBind(toATerm("manifest"),
|
||||||
makeStr(manifestFile, singleton<PathSet>(manifestFile)), makeNoPos())
|
makeStr(manifestFile, singleton<PathSet>(manifestFile)), makeNoPos())
|
||||||
)));
|
)));
|
||||||
|
@ -506,8 +518,7 @@ typedef enum { utLt, utLeq, utEq, utAlways } UpgradeType;
|
||||||
|
|
||||||
|
|
||||||
static void upgradeDerivations(Globals & globals,
|
static void upgradeDerivations(Globals & globals,
|
||||||
const Strings & args, const Path & profile,
|
const Strings & args, UpgradeType upgradeType)
|
||||||
UpgradeType upgradeType)
|
|
||||||
{
|
{
|
||||||
debug(format("upgrading derivations"));
|
debug(format("upgrading derivations"));
|
||||||
|
|
||||||
|
@ -518,8 +529,8 @@ static void upgradeDerivations(Globals & globals,
|
||||||
|
|
||||||
/* Load the currently installed derivations. */
|
/* Load the currently installed derivations. */
|
||||||
PathLocks lock;
|
PathLocks lock;
|
||||||
lockProfile(lock, profile);
|
lockProfile(lock, globals.profile);
|
||||||
DrvInfos installedElems = queryInstalled(globals.state, profile);
|
DrvInfos installedElems = queryInstalled(globals.state, globals.profile);
|
||||||
|
|
||||||
/* Fetch all derivations from the input file. */
|
/* Fetch all derivations from the input file. */
|
||||||
DrvInfos availElems;
|
DrvInfos availElems;
|
||||||
|
@ -577,7 +588,7 @@ static void upgradeDerivations(Globals & globals,
|
||||||
}
|
}
|
||||||
|
|
||||||
createUserEnv(globals.state, newElems,
|
createUserEnv(globals.state, newElems,
|
||||||
profile, globals.keepDerivations);
|
globals.profile, globals.keepDerivations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -593,7 +604,55 @@ 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);
|
||||||
|
|
||||||
upgradeDerivations(globals, opArgs, globals.profile, upgradeType);
|
upgradeDerivations(globals, opArgs, upgradeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
||||||
|
const string & name, const string & value)
|
||||||
|
{
|
||||||
|
MetaInfo meta = drv.queryMetaInfo(state);
|
||||||
|
meta[name] = value;
|
||||||
|
drv.setMetaInfo(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void opSetFlag(Globals & globals,
|
||||||
|
Strings opFlags, Strings opArgs)
|
||||||
|
{
|
||||||
|
if (opFlags.size() > 0)
|
||||||
|
throw UsageError(format("unknown flag `%1%'") % opFlags.front());
|
||||||
|
if (opArgs.size() < 2)
|
||||||
|
throw UsageError("not enough arguments to `--set-flag'");
|
||||||
|
|
||||||
|
Strings::iterator arg = opArgs.begin();
|
||||||
|
string flagName = *arg++;
|
||||||
|
string flagValue = *arg++;
|
||||||
|
DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end()));
|
||||||
|
|
||||||
|
/* Load the currently installed derivations. */
|
||||||
|
PathLocks lock;
|
||||||
|
lockProfile(lock, globals.profile);
|
||||||
|
DrvInfos installedElems = queryInstalled(globals.state, globals.profile);
|
||||||
|
|
||||||
|
/* Update all matching derivations. */
|
||||||
|
for (DrvInfos::iterator i = installedElems.begin();
|
||||||
|
i != installedElems.end(); ++i)
|
||||||
|
{
|
||||||
|
DrvName drvName(i->name);
|
||||||
|
for (DrvNames::iterator j = selectors.begin();
|
||||||
|
j != selectors.end(); ++j)
|
||||||
|
if (j->matches(drvName)) {
|
||||||
|
printMsg(lvlInfo,
|
||||||
|
format("setting flag on `%1%'") % i->name);
|
||||||
|
setMetaFlag(globals.state, *i, flagName, flagValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the new user environment. */
|
||||||
|
createUserEnv(globals.state, installedElems,
|
||||||
|
globals.profile, globals.keepDerivations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1167,18 +1226,18 @@ void run(Strings args)
|
||||||
op = opUninstall;
|
op = opUninstall;
|
||||||
else if (arg == "--upgrade" || arg == "-u")
|
else if (arg == "--upgrade" || arg == "-u")
|
||||||
op = opUpgrade;
|
op = opUpgrade;
|
||||||
|
else if (arg == "--set-flag")
|
||||||
|
op = opSetFlag;
|
||||||
else if (arg == "--set")
|
else if (arg == "--set")
|
||||||
op = opSet;
|
op = opSet;
|
||||||
else if (arg == "--query" || arg == "-q")
|
else if (arg == "--query" || arg == "-q")
|
||||||
op = opQuery;
|
op = opQuery;
|
||||||
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")
|
||||||
globals.profile = absPath(needArg(i, args, arg));
|
globals.profile = absPath(needArg(i, args, arg));
|
||||||
}
|
else if (arg == "--file" || arg == "-f")
|
||||||
else if (arg == "--file" || arg == "-f") {
|
|
||||||
globals.instSource.nixExprPath = absPath(needArg(i, args, arg));
|
globals.instSource.nixExprPath = absPath(needArg(i, args, arg));
|
||||||
}
|
|
||||||
else if (arg == "--switch-profile" || arg == "-S")
|
else if (arg == "--switch-profile" || arg == "-S")
|
||||||
op = opSwitchProfile;
|
op = opSwitchProfile;
|
||||||
else if (arg == "--switch-generation" || arg == "-G")
|
else if (arg == "--switch-generation" || arg == "-G")
|
||||||
|
@ -1195,9 +1254,8 @@ 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")
|
||||||
globals.instSource.systemFilter = needArg(i, args, arg);
|
globals.instSource.systemFilter = needArg(i, args, arg);
|
||||||
}
|
|
||||||
else if (arg[0] == '-')
|
else if (arg[0] == '-')
|
||||||
opFlags.push_back(arg);
|
opFlags.push_back(arg);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue