* Implemented derivations.

This commit is contained in:
Eelco Dolstra 2010-03-31 15:38:03 +00:00
parent 5187678913
commit 3d94be61ea
6 changed files with 183 additions and 192 deletions

View file

@ -261,6 +261,14 @@ void EvalState::mkAttrs(Value & v)
} }
void EvalState::cloneAttrs(Value & src, Value & dst)
{
mkAttrs(dst);
foreach (Bindings::iterator, i, *src.attrs)
(*dst.attrs)[i->first] = i->second; // !!! sharing?
}
void EvalState::evalFile(const Path & path, Value & v) void EvalState::evalFile(const Path & path, Value & v)
{ {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
@ -488,17 +496,14 @@ void EvalState::eval(Env & env, Expr e, Value & v)
/* Attribute set update (//). */ /* Attribute set update (//). */
else if (matchOpUpdate(e, e1, e2)) { else if (matchOpUpdate(e, e1, e2)) {
mkAttrs(v);
Value v2; Value v2;
eval(env, e1, v2);
cloneAttrs(v2, v);
eval(env, e2, v2); eval(env, e2, v2);
foreach (Bindings::iterator, i, *v2.attrs) foreach (Bindings::iterator, i, *v2.attrs)
(*v.attrs)[i->first] = i->second; (*v.attrs)[i->first] = i->second; // !!! sharing
eval(env, e1, v2);
foreach (Bindings::iterator, i, *v2.attrs)
if (v.attrs->find(i->first) == v.attrs->end())
(*v.attrs)[i->first] = i->second;
} }
/* Attribute existence test (?). */ /* Attribute existence test (?). */
@ -673,6 +678,15 @@ int EvalState::forceInt(Value & v)
} }
bool EvalState::forceBool(Value & v)
{
forceValue(v);
if (v.type != tBool)
throw TypeError(format("value is %1% while a Boolean was expected") % showType(v));
return v.boolean;
}
void EvalState::forceAttrs(Value & v) void EvalState::forceAttrs(Value & v)
{ {
forceValue(v); forceValue(v);
@ -697,15 +711,22 @@ void EvalState::forceFunction(Value & v)
} }
string EvalState::forceStringNoCtx(Value & v) string EvalState::forceString(Value & v)
{ {
forceValue(v); forceValue(v);
if (v.type != tString) if (v.type != tString)
throw TypeError(format("value is %1% while a string was expected") % showType(v)); throw TypeError(format("value is %1% while a string was expected") % showType(v));
return string(v.string.s);
}
string EvalState::forceStringNoCtx(Value & v)
{
string s = forceString(v);
if (v.string.context) if (v.string.context)
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')") throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
% v.string.s % v.string.context[0]); % v.string.s % v.string.context[0]);
return string(v.string.s); return s;
} }

View file

@ -109,7 +109,6 @@ void mkString(Value & v, const string & s, const PathSet & context = PathSet());
void mkPath(Value & v, const char * s); void mkPath(Value & v, const char * s);
typedef std::map<Path, PathSet> DrvRoots;
typedef std::map<Path, Hash> DrvHashes; typedef std::map<Path, Hash> DrvHashes;
/* Cache for calls to addToStore(); maps source paths to the store /* Cache for calls to addToStore(); maps source paths to the store
@ -124,8 +123,10 @@ std::ostream & operator << (std::ostream & str, Value & v);
class EvalState class EvalState
{ {
DrvRoots drvRoots; public:
DrvHashes drvHashes; /* normalised derivation hashes */ DrvHashes drvHashes; /* normalised derivation hashes */
private:
SrcToStore srcToStore; SrcToStore srcToStore;
unsigned long nrValues; unsigned long nrValues;
@ -164,9 +165,11 @@ public:
/* Force `v', and then verify that it has the expected type. */ /* Force `v', and then verify that it has the expected type. */
int forceInt(Value & v); int forceInt(Value & v);
bool forceBool(Value & v);
void forceAttrs(Value & v); void forceAttrs(Value & v);
void forceList(Value & v); void forceList(Value & v);
void forceFunction(Value & v); // either lambda or primop void forceFunction(Value & v); // either lambda or primop
string forceString(Value & v);
string forceStringNoCtx(Value & v); string forceStringNoCtx(Value & v);
/* String coercion. Converts strings, paths and derivations to a /* String coercion. Converts strings, paths and derivations to a
@ -209,6 +212,8 @@ public:
void mkList(Value & v, unsigned int length); void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v); void mkAttrs(Value & v);
void cloneAttrs(Value & src, Value & dst);
/* Print statistics. */ /* Print statistics. */
void printStats(); void printStats();
}; };

View file

@ -6,25 +6,18 @@
namespace nix { namespace nix {
#if 0
string DrvInfo::queryDrvPath(EvalState & state) const string DrvInfo::queryDrvPath(EvalState & state) const
{ {
if (drvPath == "") { if (drvPath == "") {
Expr a = attrs->get(toATerm("drvPath")); Bindings::iterator i = attrs->find(toATerm("drvPath"));
/* Backwards compatibility hack with user environments made by
Nix <= 0.10: these contain illegal Path("") expressions. */
ATerm t;
if (a && matchPath(evalExpr(state, a), t))
return aterm2String(t);
PathSet context; PathSet context;
(string &) drvPath = a ? coerceToPath(state, a, context) : ""; (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
} }
return drvPath; return drvPath;
} }
#if 0
string DrvInfo::queryOutPath(EvalState & state) const string DrvInfo::queryOutPath(EvalState & state) const
{ {
if (outPath == "") { if (outPath == "") {
@ -102,54 +95,47 @@ void DrvInfo::setMetaInfo(const MetaInfo & meta)
} }
attrs->set(toATerm("meta"), makeAttrs(metaAttrs)); attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
} }
#endif
/* Cache for already evaluated derivations. Usually putting ATerms in /* Cache for already considered values. */
a STL container is unsafe (they're not scanning for GC roots), but typedef set<Value *> Values;
here it doesn't matter; everything in this set is reachable from
the stack as well. */
typedef set<Expr> Exprs;
/* Evaluate expression `e'. If it evaluates to an attribute set of /* Evaluate value `v'. If it evaluates to an attribute set of type
type `derivation', then put information about it in `drvs' (unless `derivation', then put information about it in `drvs' (unless it's
it's already in `doneExprs'). The result boolean indicates whether already in `doneExprs'). The result boolean indicates whether it
it makes sense for the caller to recursively search for derivations makes sense for the caller to recursively search for derivations in
in `e'. */ `v'. */
static bool getDerivation(EvalState & state, Expr e, static bool getDerivation(EvalState & state, Value & v,
const string & attrPath, DrvInfos & drvs, Exprs & doneExprs) const string & attrPath, DrvInfos & drvs, Values & doneValues)
{ {
try { try {
state.forceValue(v);
ATermList es; if (v.type != tAttrs) return true;
e = evalExpr(state, e);
if (!matchAttrs(e, es)) return true;
boost::shared_ptr<ATermMap> attrs(new ATermMap()); Bindings::iterator i = v.attrs->find(toATerm("type"));
queryAllAttrs(e, *attrs, false); if (i == v.attrs->end() || state.forceStringNoCtx(i->second) != "derivation") return true;
Expr a = attrs->get(toATerm("type"));
if (!a || evalStringNoCtx(state, a) != "derivation") return true;
/* Remove spurious duplicates (e.g., an attribute set like /* Remove spurious duplicates (e.g., an attribute set like
`rec { x = derivation {...}; y = x;}'. */ `rec { x = derivation {...}; y = x;}'. */
if (doneExprs.find(e) != doneExprs.end()) return false; if (doneValues.find(&v) != doneValues.end()) return false;
doneExprs.insert(e); doneValues.insert(&v);
DrvInfo drv; DrvInfo drv;
a = attrs->get(toATerm("name")); i = v.attrs->find(toATerm("name"));
/* !!! We really would like to have a decent back trace here. */ /* !!! We really would like to have a decent back trace here. */
if (!a) throw TypeError("derivation name missing"); if (i == v.attrs->end()) throw TypeError("derivation name missing");
drv.name = evalStringNoCtx(state, a); drv.name = state.forceStringNoCtx(i->second);
a = attrs->get(toATerm("system")); i = v.attrs->find(toATerm("system"));
if (!a) if (i == v.attrs->end())
drv.system = "unknown"; drv.system = "unknown";
else else
drv.system = evalStringNoCtx(state, a); drv.system = state.forceStringNoCtx(i->second);
drv.attrs = attrs; drv.attrs = v.attrs;
drv.attrPath = attrPath; drv.attrPath = attrPath;
@ -162,11 +148,11 @@ static bool getDerivation(EvalState & state, Expr e,
} }
bool getDerivation(EvalState & state, Expr e, DrvInfo & drv) bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
{ {
Exprs doneExprs; Values doneValues;
DrvInfos drvs; DrvInfos drvs;
getDerivation(state, e, "", drvs, doneExprs); getDerivation(state, v, "", drvs, doneValues);
if (drvs.size() != 1) return false; if (drvs.size() != 1) return false;
drv = drvs.front(); drv = drvs.front();
return true; return true;
@ -179,85 +165,72 @@ static string addToPath(const string & s1, const string & s2)
} }
static void getDerivations(EvalState & state, Expr e, static void getDerivations(EvalState & state, Value & v,
const string & pathPrefix, const ATermMap & autoArgs, const string & pathPrefix, const ATermMap & autoArgs,
DrvInfos & drvs, Exprs & doneExprs) DrvInfos & drvs, Values & doneValues)
{ {
e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs)); // !!! autoCallFunction(evalExpr(state, e), autoArgs)
/* Process the expression. */ /* Process the expression. */
ATermList es;
DrvInfo drv; DrvInfo drv;
if (!getDerivation(state, e, pathPrefix, drvs, doneExprs)) if (!getDerivation(state, v, pathPrefix, drvs, doneValues)) ;
return;
if (matchAttrs(e, es)) { else if (v.type == tAttrs) {
ATermMap drvMap(ATgetLength(es));
queryAllAttrs(e, drvMap);
/* !!! undocumented hackery to support combining channels in /* !!! undocumented hackery to support combining channels in
nix-env.cc. */ nix-env.cc. */
bool combineChannels = drvMap.get(toATerm("_combineChannels")); bool combineChannels = v.attrs->find(toATerm("_combineChannels")) != v.attrs->end();
/* Consider the attributes in sorted order to get more /* Consider the attributes in sorted order to get more
deterministic behaviour in nix-env operations (e.g. when deterministic behaviour in nix-env operations (e.g. when
there are names clashes between derivations, the derivation there are names clashes between derivations, the derivation
bound to the attribute with the "lower" name should take bound to the attribute with the "lower" name should take
precedence). */ precedence). */
typedef std::map<string, Expr> AttrsSorted; StringSet attrs;
AttrsSorted attrsSorted; foreach (Bindings::iterator, i, *v.attrs)
foreach (ATermMap::const_iterator, i, drvMap) attrs.insert(aterm2String(i->first));
attrsSorted[aterm2String(i->key)] = i->value;
foreach (AttrsSorted::iterator, i, attrsSorted) { foreach (StringSet::iterator, i, attrs) {
startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first); startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i);
string pathPrefix2 = addToPath(pathPrefix, i->first); string pathPrefix2 = addToPath(pathPrefix, *i);
Value & v2((*v.attrs)[toATerm(*i)]);
if (combineChannels) if (combineChannels)
getDerivations(state, i->second, pathPrefix2, autoArgs, drvs, doneExprs); getDerivations(state, v2, pathPrefix2, autoArgs, drvs, doneValues);
else if (getDerivation(state, i->second, pathPrefix2, drvs, doneExprs)) { else if (getDerivation(state, v2, pathPrefix2, drvs, doneValues)) {
/* If the value of this attribute is itself an /* If the value of this attribute is itself an
attribute set, should we recurse into it? => Only attribute set, should we recurse into it? => Only
if it has a `recurseForDerivations = true' if it has a `recurseForDerivations = true'
attribute. */ attribute. */
ATermList es; if (v2.type == tAttrs) {
Expr e = evalExpr(state, i->second), e2; Bindings::iterator j = v2.attrs->find(toATerm("recurseForDerivations"));
if (matchAttrs(e, es)) { if (j != v2.attrs->end() && state.forceBool(j->second))
ATermMap attrs(ATgetLength(es)); getDerivations(state, v2, pathPrefix2, autoArgs, drvs, doneValues);
queryAllAttrs(e, attrs, false);
if (((e2 = attrs.get(toATerm("recurseForDerivations")))
&& evalBool(state, e2)))
getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
} }
} }
} }
return;
} }
if (matchList(e, es)) { else if (v.type == tList) {
int n = 0; for (unsigned int n = 0; n < v.list.length; ++n) {
for (ATermIterator i(es); i; ++i, ++n) {
startNest(nest, lvlDebug, startNest(nest, lvlDebug,
format("evaluating list element")); format("evaluating list element"));
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs)) if (getDerivation(state, v.list.elems[n], pathPrefix2, drvs, doneValues))
getDerivations(state, *i, pathPrefix2, autoArgs, drvs, doneExprs); getDerivations(state, v.list.elems[n], pathPrefix2, autoArgs, drvs, doneValues);
} }
return;
} }
throw TypeError("expression does not evaluate to a derivation (or a set or list of those)"); else throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
} }
void getDerivations(EvalState & state, Expr e, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
const ATermMap & autoArgs, DrvInfos & drvs) const ATermMap & autoArgs, DrvInfos & drvs)
{ {
Exprs doneExprs; Values doneValues;
getDerivations(state, e, pathPrefix, autoArgs, drvs, doneExprs); getDerivations(state, v, pathPrefix, autoArgs, drvs, doneValues);
} }
#endif
} }

View file

@ -35,10 +35,8 @@ 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 this private */
make a copy since the ATermMap can be shared between multiple Bindings * attrs;
DrvInfos. */
boost::shared_ptr<ATermMap> attrs;
string queryDrvPath(EvalState & state) const; string queryDrvPath(EvalState & state) const;
string queryOutPath(EvalState & state) const; string queryOutPath(EvalState & state) const;
@ -62,12 +60,11 @@ public:
typedef list<DrvInfo> DrvInfos; typedef list<DrvInfo> DrvInfos;
/* Evaluate expression `e'. If it evaluates to a derivation, store /* If value `v' denotes a derivation, store information about the
information about the derivation in `drv' and return true. derivation in `drv' and return true. Otherwise, return false. */
Otherwise, return false. */ bool getDerivation(EvalState & state, Value & v, DrvInfo & drv);
bool getDerivation(EvalState & state, Expr e, DrvInfo & drv);
void getDerivations(EvalState & state, Expr e, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
const ATermMap & autoArgs, DrvInfos & drvs); const ATermMap & autoArgs, DrvInfos & drvs);

View file

@ -207,6 +207,7 @@ static void prim_trace(EvalState & state, Value * * args, Value & v)
printMsg(lvlError, format("trace: %1%") % e); printMsg(lvlError, format("trace: %1%") % e);
return evalExpr(state, args[1]); return evalExpr(state, args[1]);
} }
#endif
/************************************************************* /*************************************************************
@ -282,24 +283,21 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
{ {
startNest(nest, lvlVomit, "evaluating derivation"); startNest(nest, lvlVomit, "evaluating derivation");
ATermMap attrs; state.forceAttrs(*args[0]);
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
/* Figure out the name already (for stack backtraces). */ /* Figure out the name first (for stack backtraces). */
ATerm posDrvName; Bindings::iterator attr = args[0]->attrs->find(toATerm("name"));
Expr eDrvName = attrs.get(toATerm("name")); if (attr == args[0]->attrs->end())
if (!eDrvName)
throw EvalError("required attribute `name' missing"); throw EvalError("required attribute `name' missing");
if (!matchAttrRHS(eDrvName, eDrvName, posDrvName)) abort();
string drvName; string drvName;
try { try {
drvName = evalStringNoCtx(state, eDrvName); drvName = state.forceStringNoCtx(attr->second);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") e.addPrefix(format("while evaluating the derivation attribute `name' at <SOMEWHERE>:\n"));
% showPos(posDrvName)); // !!! % showPos(posDrvName));
throw; throw;
} }
/* Build the derivation expression by processing the attributes. */ /* Build the derivation expression by processing the attributes. */
Derivation drv; Derivation drv;
@ -308,12 +306,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
string outputHash, outputHashAlgo; string outputHash, outputHashAlgo;
bool outputHashRecursive = false; bool outputHashRecursive = false;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { foreach (Bindings::iterator, i, *args[0]->attrs) {
string key = aterm2String(i->key); string key = aterm2String(i->first);
ATerm value;
Expr pos;
ATerm rhs = i->value;
if (!matchAttrRHS(rhs, value, pos)) abort();
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
try { try {
@ -321,15 +315,9 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* 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") {
ATermList es; state.forceList(i->second);
value = evalExpr(state, value); for (unsigned int n = 0; n < i->second.list.length; ++n) {
if (!matchList(value, es)) { string s = state.coerceToString(i->second.list.elems[n], context, true);
static bool haveWarned = false;
warnOnce(haveWarned, "the `args' attribute should evaluate to a list");
es = flattenList(state, value);
}
for (ATermIterator i(es); i; ++i) {
string s = coerceToString(state, *i, context, true);
drv.args.push_back(s); drv.args.push_back(s);
} }
} }
@ -337,7 +325,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* All other attributes are passed to the builder through /* All other attributes are passed to the builder through
the environment. */ the environment. */
else { else {
string s = coerceToString(state, value, context, true); string s = state.coerceToString(i->second, context, true);
drv.env[key] = s; drv.env[key] = s;
if (key == "builder") drv.builder = s; if (key == "builder") drv.builder = s;
else if (key == "system") drv.platform = s; else if (key == "system") drv.platform = s;
@ -352,13 +340,12 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
} }
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(format("while evaluating the derivation attribute `%1%' at %2%:\n") e.addPrefix(format("while evaluating the derivation attribute `%1%' at <SOMEWHERE>:\n")
% key % showPos(pos)); % key /* !!! % showPos(pos) */);
e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n") e.addPrefix(format("while instantiating the derivation named `%1%' at <SOMEWHERE>:\n")
% drvName % showPos(posDrvName)); % drvName /* !!! % showPos(posDrvName) */);
throw; throw;
} }
} }
/* Everything in the context of the strings in the derivation /* Everything in the context of the strings in the derivation
@ -466,25 +453,25 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
state.drvHashes[drvPath] = hashDerivationModulo(state, drv); state.drvHashes[drvPath] = hashDerivationModulo(state, drv);
/* !!! assumes a single output */ /* !!! assumes a single output */
ATermMap outAttrs(2); //state.mkAttrs(v);
outAttrs.set(toATerm("outPath"), state.cloneAttrs(*args[0], v);
makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos())); mkString((*v.attrs)[toATerm("outPath")], outPath, singleton<PathSet>(drvPath));
outAttrs.set(toATerm("drvPath"), mkString((*v.attrs)[toATerm("drvPath")], drvPath, singleton<PathSet>("=" + drvPath));
makeAttrRHS(makeStr(drvPath, singleton<PathSet>("=" + drvPath)), makeNoPos())); mkString((*v.attrs)[toATerm("type")], "derivation"); // !!! remove
return makeAttrs(outAttrs);
} }
static void prim_derivationLazy(EvalState & state, Value * * args, Value & v) static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
{ {
Expr eAttrs = evalExpr(state, args[0]); state.forceAttrs(*args[0]);
ATermMap attrs;
queryAllAttrs(eAttrs, attrs, true);
attrs.set(toATerm("type"), state.cloneAttrs(*args[0], v);
makeAttrRHS(makeStr("derivation"), makeNoPos()));
mkString((*v.attrs)[toATerm("type")], "derivation");
/* !!! */
#if 0
Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs); Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs);
attrs.set(toATerm("outPath"), attrs.set(toATerm("outPath"),
@ -493,8 +480,8 @@ static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos())); makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos()));
return makeAttrs(attrs); return makeAttrs(attrs);
}
#endif #endif
}
/************************************************************* /*************************************************************
@ -592,6 +579,7 @@ static void prim_toXML(EvalState & state, Value * * args, Value & v)
printTermAsXML(strictEvalExpr(state, args[0]), out, context); printTermAsXML(strictEvalExpr(state, args[0]), out, context);
return makeStr(out.str(), context); return makeStr(out.str(), context);
} }
#endif
/* Store a string in the Nix store as a source file that can be used /* Store a string in the Nix store as a source file that can be used
@ -599,12 +587,12 @@ static void prim_toXML(EvalState & state, Value * * args, Value & v)
static void prim_toFile(EvalState & state, Value * * args, Value & v) static void prim_toFile(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string name = evalStringNoCtx(state, args[0]); string name = state.forceStringNoCtx(*args[0]);
string contents = evalString(state, args[1], context); string contents = state.forceString(*args[1]); // !!! context
PathSet refs; PathSet refs;
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) { foreach (PathSet::iterator, i, context) {
Path path = *i; Path path = *i;
if (path.at(0) == '=') path = string(path, 1); if (path.at(0) == '=') path = string(path, 1);
if (isDerivation(path)) if (isDerivation(path))
@ -619,11 +607,12 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
/* Note: we don't need to add `context' to the context of the /* Note: we don't need to add `context' to the context of the
result, since `storePath' itself has references to the paths result, since `storePath' itself has references to the paths
used in args[1]. */ used in args[1]. */
return makeStr(storePath, singleton<PathSet>(storePath)); mkString(v, storePath, singleton<PathSet>(storePath));
} }
#if 0
struct FilterFromExpr : PathFilter struct FilterFromExpr : PathFilter
{ {
EvalState & state; EvalState & state;
@ -731,10 +720,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
state.forceAttrs(*args[0]); state.forceAttrs(*args[0]);
state.forceList(*args[1]); state.forceList(*args[1]);
state.mkAttrs(v); state.cloneAttrs(*args[0], v);
foreach (Bindings::iterator, i, *args[0]->attrs)
(*v.attrs)[i->first] = i->second;
for (unsigned int i = 0; i < args[1]->list.length; ++i) { for (unsigned int i = 0; i < args[1]->list.length; ++i) {
state.forceStringNoCtx(args[1]->list.elems[i]); state.forceStringNoCtx(args[1]->list.elems[i]);
@ -743,40 +729,32 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
} }
#if 0
/* Builds an attribute set from a list specifying (name, value) /* Builds an attribute set from a list specifying (name, value)
pairs. To be precise, a list [{name = "name1"; value = value1;} pairs. To be precise, a list [{name = "name1"; value = value1;}
... {name = "nameN"; value = valueN;}] is transformed to {name1 = ... {name = "nameN"; value = valueN;}] is transformed to {name1 =
value1; ... nameN = valueN;}. */ value1; ... nameN = valueN;}. */
static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
{ {
try { state.forceList(*args[0]);
ATermMap res = ATermMap();
ATermList list; state.mkAttrs(v);
list = evalList(state, args[0]);
for (ATermIterator i(list); i; ++i){ for (unsigned int i = 0; i < args[0]->list.length; ++i) {
// *i should now contain a pointer to the list item expression Value & v2(args[0]->list.elems[i]);
ATermList attrs; state.forceAttrs(v2);
Expr evaledExpr = evalExpr(state, *i);
if (matchAttrs(evaledExpr, attrs)){ Bindings::iterator j = v2.attrs->find(toATerm("name"));
Expr e = evalExpr(state, makeSelect(evaledExpr, toATerm("name"))); if (j == v2.attrs->end())
string attr = evalStringNoCtx(state,e); throw TypeError("`name' attribute missing in a call to `listToAttrs'");
Expr r = makeSelect(evaledExpr, toATerm("value")); string name = state.forceStringNoCtx(j->second);
res.set(toATerm(attr), makeAttrRHS(r, makeNoPos()));
} j = v2.attrs->find(toATerm("value"));
else if (j == v2.attrs->end())
throw TypeError(format("list element in `listToAttrs' is %s, expected a set { name = \"<name>\"; value = <value>; }") throw TypeError("`value' attribute missing in a call to `listToAttrs'");
% showType(evaledExpr));
} (*v.attrs)[toATerm(name)] = j->second; // !!! sharing?
return makeAttrs(res);
} catch (Error & e) {
e.addPrefix(format("in `listToAttrs':\n"));
throw;
} }
} }
#endif
#if 0 #if 0
@ -897,7 +875,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
static void prim_length(EvalState & state, Value * * args, Value & v) static void prim_length(EvalState & state, Value * * args, Value & v)
{ {
state.forceList(*args[0]); state.forceList(*args[0]);
mkInt(v, v.list.length); mkInt(v, args[0]->list.length);
} }
@ -1111,11 +1089,11 @@ void EvalState::createBaseEnv()
// Expr <-> String // Expr <-> String
addPrimOp("__exprToString", 1, prim_exprToString); addPrimOp("__exprToString", 1, prim_exprToString);
addPrimOp("__stringToExpr", 1, prim_stringToExpr); addPrimOp("__stringToExpr", 1, prim_stringToExpr);
#endif
// Derivations // Derivations
addPrimOp("derivation!", 1, prim_derivationStrict); addPrimOp("derivation", 1, prim_derivationStrict);
addPrimOp("derivation", 1, prim_derivationLazy); //addPrimOp("derivation", 1, prim_derivationLazy);
#endif
// Paths // Paths
addPrimOp("__toPath", 1, prim_toPath); addPrimOp("__toPath", 1, prim_toPath);
@ -1130,7 +1108,9 @@ void EvalState::createBaseEnv()
// Creating files // Creating files
#if 0 #if 0
addPrimOp("__toXML", 1, prim_toXML); addPrimOp("__toXML", 1, prim_toXML);
#endif
addPrimOp("__toFile", 2, prim_toFile); addPrimOp("__toFile", 2, prim_toFile);
#if 0
addPrimOp("__filterSource", 2, prim_filterSource); addPrimOp("__filterSource", 2, prim_filterSource);
#endif #endif
@ -1140,8 +1120,8 @@ void EvalState::createBaseEnv()
addPrimOp("__hasAttr", 2, prim_hasAttr); addPrimOp("__hasAttr", 2, prim_hasAttr);
addPrimOp("__isAttrs", 1, prim_isAttrs); addPrimOp("__isAttrs", 1, prim_isAttrs);
addPrimOp("removeAttrs", 2, prim_removeAttrs); addPrimOp("removeAttrs", 2, prim_removeAttrs);
#if 0
addPrimOp("__listToAttrs", 1, prim_listToAttrs); addPrimOp("__listToAttrs", 1, prim_listToAttrs);
#if 0
addPrimOp("__intersectAttrs", 2, prim_intersectAttrs); addPrimOp("__intersectAttrs", 2, prim_intersectAttrs);
addPrimOp("__functionArgs", 1, prim_functionArgs); addPrimOp("__functionArgs", 1, prim_functionArgs);
#endif #endif

View file

@ -75,8 +75,23 @@ void processExpr(EvalState & state, const Strings & attrPaths,
std::cout << format("%1%\n") % canonicaliseExpr(e); std::cout << format("%1%\n") % canonicaliseExpr(e);
else { else {
Value v; Value v;
state.strictEval(e, v); if (strict) state.strictEval(e, v); else state.eval(e, v);
std::cout << v << std::endl; if (evalOnly)
std::cout << v << std::endl;
else {
DrvInfos drvs;
getDerivations(state, v, "", autoArgs, drvs);
foreach (DrvInfos::iterator, i, drvs) {
Path drvPath = i->queryDrvPath(state);
if (gcRoot == "")
printGCWarning();
else
drvPath = addPermRoot(drvPath,
makeRootName(gcRoot, rootNr),
indirectRoot);
std::cout << format("%1%\n") % drvPath;
}
}
} }
#if 0 #if 0