Optionally ignore null-valued derivation attributes

This allows adding attributes like

  attr = if stdenv.system == "bla" then something else null;

without changing the resulting derivation on non-<bla> platforms.

We once considered adding a special "ignore" value for this purpose,
but using null seems more elegant.
This commit is contained in:
Eelco Dolstra 2012-11-27 15:01:32 +01:00
parent 8b8ee53bc7
commit 6c98e6a5de
3 changed files with 24 additions and 11 deletions

View file

@ -139,6 +139,7 @@ EvalState::EvalState()
, sSystem(symbols.create("system")) , sSystem(symbols.create("system"))
, sOverrides(symbols.create("__overrides")) , sOverrides(symbols.create("__overrides"))
, sOutputName(symbols.create("outputName")) , sOutputName(symbols.create("outputName"))
, sIgnoreNulls(symbols.create("__ignoreNulls"))
, baseEnv(allocEnv(128)) , baseEnv(allocEnv(128))
, baseEnvDispl(0) , baseEnvDispl(0)
, staticBaseEnv(false, 0) , staticBaseEnv(false, 0)

View file

@ -93,7 +93,7 @@ public:
SymbolTable symbols; SymbolTable symbols;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
sSystem, sOverrides, sOutputName; sSystem, sOverrides, sOutputName, sIgnoreNulls;
/* If set, force copying files to the Nix store even if they /* If set, force copying files to the Nix store even if they
already exist there. */ already exist there. */

View file

@ -310,16 +310,22 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
throw EvalError("required attribute `name' missing"); throw EvalError("required attribute `name' missing");
string drvName; string drvName;
Pos & posDrvName(*attr->pos); Pos & posDrvName(*attr->pos);
try { try {
drvName = state.forceStringNoCtx(*attr->value); drvName = state.forceStringNoCtx(*attr->value);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName); e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName);
throw; throw;
} }
/* Check whether null attributes should be ignored. */
bool ignoreNulls = false;
attr = args[0]->attrs->find(state.sIgnoreNulls);
if (attr != args[0]->attrs->end())
ignoreNulls = state.forceBool(*attr->value);
/* Build the derivation expression by processing the attributes. */ /* Build the derivation expression by processing the attributes. */
Derivation drv; Derivation drv;
PathSet context; PathSet context;
string outputHash, outputHashAlgo; string outputHash, outputHashAlgo;
@ -329,11 +335,17 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
outputs.insert("out"); outputs.insert("out");
foreach (Bindings::iterator, i, *args[0]->attrs) { foreach (Bindings::iterator, i, *args[0]->attrs) {
if (i->name == state.sIgnoreNulls) continue;
string key = i->name; string key = i->name;
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
try { try {
if (ignoreNulls) {
state.forceValue(*i->value);
if (i->value->type == tNull) continue;
}
/* The `args' attribute is special: it supplies the /* The `args' attribute is special: it supplies the
command-line arguments to the builder. */ command-line arguments to the builder. */
if (key == "args") { if (key == "args") {
@ -358,7 +370,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
else if (key == "outputHash") outputHash = s; else if (key == "outputHash") outputHash = s;
else if (key == "outputHashAlgo") outputHashAlgo = s; else if (key == "outputHashAlgo") outputHashAlgo = s;
else if (key == "outputHashMode") { else if (key == "outputHashMode") {
if (s == "recursive") outputHashRecursive = true; if (s == "recursive") outputHashRecursive = true;
else if (s == "flat") outputHashRecursive = false; else if (s == "flat") outputHashRecursive = false;
else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s); else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s);
} }
@ -390,13 +402,13 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
throw; throw;
} }
} }
/* Everything in the context of the strings in the derivation /* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting attributes should be added as dependencies of the resulting
derivation. */ derivation. */
foreach (PathSet::iterator, i, context) { foreach (PathSet::iterator, i, context) {
Path path = *i; Path path = *i;
/* Paths marked with `=' denote that the path of a derivation /* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the is explicitly passed to the builder. Since that allows the
builder to gain access to every path in the dependency builder to gain access to every path in the dependency
@ -433,7 +445,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
else else
drv.inputSrcs.insert(path); drv.inputSrcs.insert(path);
} }
/* Do we have all required attributes? */ /* Do we have all required attributes? */
if (drv.builder == "") if (drv.builder == "")
throw EvalError("required attribute `builder' missing"); throw EvalError("required attribute `builder' missing");
@ -450,14 +462,14 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* Handle fixed-output derivations. */ /* Handle fixed-output derivations. */
if (outputs.size() != 1 || *(outputs.begin()) != "out") if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error("multiple outputs are not supported in fixed-output derivations"); throw Error("multiple outputs are not supported in fixed-output derivations");
HashType ht = parseHashType(outputHashAlgo); HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown) if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo); throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
Hash h = parseHash16or32(ht, outputHash); Hash h = parseHash16or32(ht, outputHash);
outputHash = printHash(h); outputHash = printHash(h);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo; if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName); Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
drv.env["out"] = outPath; drv.env["out"] = outPath;
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash); drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
@ -477,7 +489,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* Use the masked derivation expression to compute the output /* Use the masked derivation expression to compute the output
path. */ path. */
Hash h = hashDerivationModulo(*store, drv); Hash h = hashDerivationModulo(*store, drv);
foreach (DerivationOutputs::iterator, i, drv.outputs) foreach (DerivationOutputs::iterator, i, drv.outputs)
if (i->second.path == "") { if (i->second.path == "") {
Path outPath = makeOutputPath(i->first, h, drvName); Path outPath = makeOutputPath(i->first, h, drvName);