* Implemented derivations.
This commit is contained in:
parent
5187678913
commit
3d94be61ea
6 changed files with 183 additions and 192 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
if (v.type != tAttrs) return true;
|
||||||
|
|
||||||
ATermList es;
|
Bindings::iterator i = v.attrs->find(toATerm("type"));
|
||||||
e = evalExpr(state, e);
|
if (i == v.attrs->end() || state.forceStringNoCtx(i->second) != "derivation") return true;
|
||||||
if (!matchAttrs(e, es)) return true;
|
|
||||||
|
|
||||||
boost::shared_ptr<ATermMap> attrs(new ATermMap());
|
|
||||||
queryAllAttrs(e, *attrs, false);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,21 +283,18 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -620,10 +608,11 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
|
||||||
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;
|
|
||||||
list = evalList(state, args[0]);
|
|
||||||
for (ATermIterator i(list); i; ++i){
|
|
||||||
// *i should now contain a pointer to the list item expression
|
|
||||||
ATermList attrs;
|
|
||||||
Expr evaledExpr = evalExpr(state, *i);
|
|
||||||
if (matchAttrs(evaledExpr, attrs)){
|
|
||||||
Expr e = evalExpr(state, makeSelect(evaledExpr, toATerm("name")));
|
|
||||||
string attr = evalStringNoCtx(state,e);
|
|
||||||
Expr r = makeSelect(evaledExpr, toATerm("value"));
|
|
||||||
res.set(toATerm(attr), makeAttrRHS(r, makeNoPos()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw TypeError(format("list element in `listToAttrs' is %s, expected a set { name = \"<name>\"; value = <value>; }")
|
|
||||||
% showType(evaledExpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
return makeAttrs(res);
|
state.mkAttrs(v);
|
||||||
|
|
||||||
} catch (Error & e) {
|
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
|
||||||
e.addPrefix(format("in `listToAttrs':\n"));
|
Value & v2(args[0]->list.elems[i]);
|
||||||
throw;
|
state.forceAttrs(v2);
|
||||||
|
|
||||||
|
Bindings::iterator j = v2.attrs->find(toATerm("name"));
|
||||||
|
if (j == v2.attrs->end())
|
||||||
|
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
||||||
|
string name = state.forceStringNoCtx(j->second);
|
||||||
|
|
||||||
|
j = v2.attrs->find(toATerm("value"));
|
||||||
|
if (j == v2.attrs->end())
|
||||||
|
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
||||||
|
|
||||||
|
(*v.attrs)[toATerm(name)] = j->second; // !!! sharing?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue