lix/src/libexpr/get-drvs.cc

228 lines
7.1 KiB
C++
Raw Normal View History

#include "get-drvs.hh"
#include "nixexpr-ast.hh"
#include "util.hh"
namespace nix {
string DrvInfo::queryDrvPath(EvalState & state) const
{
if (drvPath == "") {
2010-03-31 15:38:03 +00:00
Bindings::iterator i = attrs->find(toATerm("drvPath"));
PathSet context;
2010-03-31 15:38:03 +00:00
(string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
}
return drvPath;
}
string DrvInfo::queryOutPath(EvalState & state) const
{
if (outPath == "") {
2010-03-31 19:12:08 +00:00
Bindings::iterator i = attrs->find(toATerm("outPath"));
PathSet context;
2010-03-31 19:12:08 +00:00
(string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
}
return outPath;
}
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
{
MetaInfo meta;
2010-03-31 19:12:08 +00:00
Bindings::iterator a = attrs->find(toATerm("meta"));
if (a == attrs->end()) return meta; /* fine, empty meta information */
2010-03-31 19:12:08 +00:00
state.forceAttrs(a->second);
2010-03-31 19:12:08 +00:00
foreach (Bindings::iterator, i, *a->second.attrs) {
MetaValue value;
2010-03-31 19:12:08 +00:00
state.forceValue(i->second);
if (i->second.type == tString) {
value.type = MetaValue::tpString;
2010-03-31 19:12:08 +00:00
value.stringValue = i->second.string.s;
} else if (i->second.type == tInt) {
value.type = MetaValue::tpInt;
2010-03-31 19:12:08 +00:00
value.intValue = i->second.integer;
} else if (i->second.type == tList) {
value.type = MetaValue::tpStrings;
2010-03-31 19:12:08 +00:00
for (unsigned int j = 0; j < i->second.list.length; ++j)
value.stringValues.push_back(state.forceStringNoCtx(i->second.list.elems[j]));
} else continue;
meta[aterm2String(i->first)] = value;
}
return meta;
}
MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
{
/* !!! evaluates all meta attributes => inefficient */
return queryMetaInfo(state)[name];
}
void DrvInfo::setMetaInfo(const MetaInfo & meta)
{
2010-03-31 19:12:08 +00:00
throw Error("not implemented");
#if 0
ATermMap metaAttrs;
foreach (MetaInfo::const_iterator, i, meta) {
Expr e;
switch (i->second.type) {
case MetaValue::tpInt: e = makeInt(i->second.intValue); break;
case MetaValue::tpString: e = makeStr(i->second.stringValue); break;
case MetaValue::tpStrings: {
ATermList es = ATempty;
foreach (Strings::const_iterator, j, i->second.stringValues)
es = ATinsert(es, makeStr(*j));
e = makeList(ATreverse(es));
break;
}
default: abort();
}
metaAttrs.set(toATerm(i->first), makeAttrRHS(e, makeNoPos()));
}
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
2010-03-31 15:38:03 +00:00
#endif
2010-03-31 19:12:08 +00:00
}
2010-04-01 12:04:57 +00:00
/* Cache for already considered attrsets. */
typedef set<Bindings *> Done;
2010-03-31 15:38:03 +00:00
/* Evaluate value `v'. If it evaluates to an attribute set of type
`derivation', then put information about it in `drvs' (unless it's
already in `doneExprs'). The result boolean indicates whether it
makes sense for the caller to recursively search for derivations in
`v'. */
static bool getDerivation(EvalState & state, Value & v,
2010-04-01 12:04:57 +00:00
const string & attrPath, DrvInfos & drvs, Done & done)
{
try {
2010-03-31 15:38:03 +00:00
state.forceValue(v);
if (!state.isDerivation(v)) return true;
/* Remove spurious duplicates (e.g., an attribute set like
`rec { x = derivation {...}; y = x;}'. */
2010-04-01 12:04:57 +00:00
if (done.find(v.attrs) != done.end()) return false;
done.insert(v.attrs);
DrvInfo drv;
Bindings::iterator i = v.attrs->find(toATerm("name"));
/* !!! We really would like to have a decent back trace here. */
2010-03-31 15:38:03 +00:00
if (i == v.attrs->end()) throw TypeError("derivation name missing");
drv.name = state.forceStringNoCtx(i->second);
2010-03-31 15:38:03 +00:00
i = v.attrs->find(toATerm("system"));
if (i == v.attrs->end())
drv.system = "unknown";
else
2010-03-31 15:38:03 +00:00
drv.system = state.forceStringNoCtx(i->second);
2010-03-31 15:38:03 +00:00
drv.attrs = v.attrs;
drv.attrPath = attrPath;
drvs.push_back(drv);
return false;
} catch (AssertionError & e) {
return false;
}
}
2010-03-31 15:38:03 +00:00
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
{
2010-04-01 12:04:57 +00:00
Done done;
DrvInfos drvs;
2010-04-01 12:04:57 +00:00
getDerivation(state, v, "", drvs, done);
if (drvs.size() != 1) return false;
drv = drvs.front();
return true;
}
static string addToPath(const string & s1, const string & s2)
{
return s1.empty() ? s2 : s1 + "." + s2;
}
static void getDerivations(EvalState & state, Value & vIn,
const string & pathPrefix, const Bindings & autoArgs,
2010-04-01 12:04:57 +00:00
DrvInfos & drvs, Done & done)
{
Value v;
state.autoCallFunction(autoArgs, vIn, v);
2010-03-31 15:38:03 +00:00
/* Process the expression. */
DrvInfo drv;
2010-04-01 12:04:57 +00:00
if (!getDerivation(state, v, pathPrefix, drvs, done)) ;
2010-03-31 15:38:03 +00:00
else if (v.type == tAttrs) {
/* !!! undocumented hackery to support combining channels in
nix-env.cc. */
2010-03-31 15:38:03 +00:00
bool combineChannels = v.attrs->find(toATerm("_combineChannels")) != v.attrs->end();
2008-08-25 14:15:56 +00:00
/* Consider the attributes in sorted order to get more
deterministic behaviour in nix-env operations (e.g. when
there are names clashes between derivations, the derivation
bound to the attribute with the "lower" name should take
precedence). */
2010-03-31 15:38:03 +00:00
StringSet attrs;
foreach (Bindings::iterator, i, *v.attrs)
attrs.insert(aterm2String(i->first));
foreach (StringSet::iterator, i, attrs) {
startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i);
string pathPrefix2 = addToPath(pathPrefix, *i);
Value & v2((*v.attrs)[toATerm(*i)]);
2008-08-25 14:15:56 +00:00
if (combineChannels)
2010-04-01 12:04:57 +00:00
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
/* If the value of this attribute is itself an
attribute set, should we recurse into it? => Only
if it has a `recurseForDerivations = true'
attribute. */
2010-03-31 15:38:03 +00:00
if (v2.type == tAttrs) {
Bindings::iterator j = v2.attrs->find(toATerm("recurseForDerivations"));
if (j != v2.attrs->end() && state.forceBool(j->second))
2010-04-01 12:04:57 +00:00
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
}
}
}
}
2010-03-31 15:38:03 +00:00
else if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n) {
startNest(nest, lvlDebug,
format("evaluating list element"));
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
2010-04-01 12:04:57 +00:00
if (getDerivation(state, v.list.elems[n], pathPrefix2, drvs, done))
getDerivations(state, v.list.elems[n], pathPrefix2, autoArgs, drvs, done);
}
}
2010-03-31 15:38:03 +00:00
else throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
}
2010-03-31 15:38:03 +00:00
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
const Bindings & autoArgs, DrvInfos & drvs)
{
2010-04-01 12:04:57 +00:00
Done done;
getDerivations(state, v, pathPrefix, autoArgs, drvs, done);
}
}