* 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); | ||||||
|         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 |  | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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,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 | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue