Work on Values instead of Exprs
This prevents some duplicate evaluation in nix-env and nix-instantiate. Also, when traversing ~/.nix-defexpr, only read regular files with the extension .nix. Previously it was reading files like .../channels/binary-caches/<name>. The only reason this didn't cause problems is pure luck (namely, <name> shadows an actual Nix expression, the binary-caches files happen to be syntactically valid Nix expressions, and we iterate over the directory contents in just the right order).
This commit is contained in:
		
							parent
							
								
									06bb2d95b4
								
							
						
					
					
						commit
						ef4f5ba85e
					
				
					 4 changed files with 62 additions and 50 deletions
				
			
		|  | @ -6,9 +6,8 @@ | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // !!! Shouldn't we return a pointer to a Value?
 | Value * findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
| void findAlongAttrPath(EvalState & state, const string & attrPath, |     Bindings & autoArgs, Value & vIn) | ||||||
|     Bindings & autoArgs, Expr * e, Value & v) |  | ||||||
| { | { | ||||||
|     Strings tokens = tokenizeString<Strings>(attrPath, "."); |     Strings tokens = tokenizeString<Strings>(attrPath, "."); | ||||||
| 
 | 
 | ||||||
|  | @ -17,7 +16,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
| 
 | 
 | ||||||
|     string curPath; |     string curPath; | ||||||
| 
 | 
 | ||||||
|     state.mkThunk_(v, e); |     Value * v = &vIn; | ||||||
| 
 | 
 | ||||||
|     foreach (Strings::iterator, i, tokens) { |     foreach (Strings::iterator, i, tokens) { | ||||||
| 
 | 
 | ||||||
|  | @ -31,10 +30,10 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
|         if (string2Int(attr, attrIndex)) apType = apIndex; |         if (string2Int(attr, attrIndex)) apType = apIndex; | ||||||
| 
 | 
 | ||||||
|         /* Evaluate the expression. */ |         /* Evaluate the expression. */ | ||||||
|         Value vTmp; |         Value * vNew = state.allocValue(); | ||||||
|         state.autoCallFunction(autoArgs, v, vTmp); |         state.autoCallFunction(autoArgs, *v, *vNew); | ||||||
|         v = vTmp; |         v = vNew; | ||||||
|         state.forceValue(v); |         state.forceValue(*v); | ||||||
| 
 | 
 | ||||||
|         /* It should evaluate to either an attribute set or an
 |         /* It should evaluate to either an attribute set or an
 | ||||||
|            expression, according to what is specified in the |            expression, according to what is specified in the | ||||||
|  | @ -42,31 +41,33 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
| 
 | 
 | ||||||
|         if (apType == apAttr) { |         if (apType == apAttr) { | ||||||
| 
 | 
 | ||||||
|             if (v.type != tAttrs) |             if (v->type != tAttrs) | ||||||
|                 throw TypeError( |                 throw TypeError( | ||||||
|                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") |                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") | ||||||
|                     % curPath % showType(v)); |                     % curPath % showType(*v)); | ||||||
| 
 | 
 | ||||||
|             Bindings::iterator a = v.attrs->find(state.symbols.create(attr)); |             Bindings::iterator a = v->attrs->find(state.symbols.create(attr)); | ||||||
|             if (a == v.attrs->end()) |             if (a == v->attrs->end()) | ||||||
|                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); |                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); | ||||||
|             v = *a->value; |             v = &*a->value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         else if (apType == apIndex) { |         else if (apType == apIndex) { | ||||||
| 
 | 
 | ||||||
|             if (v.type != tList) |             if (v->type != tList) | ||||||
|                 throw TypeError( |                 throw TypeError( | ||||||
|                     format("the expression selected by the selection path `%1%' should be a list but is %2%") |                     format("the expression selected by the selection path `%1%' should be a list but is %2%") | ||||||
|                     % curPath % showType(v)); |                     % curPath % showType(*v)); | ||||||
| 
 | 
 | ||||||
|             if (attrIndex >= v.list.length) |             if (attrIndex >= v->list.length) | ||||||
|                 throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath); |                 throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath); | ||||||
| 
 | 
 | ||||||
|             v = *v.list.elems[attrIndex]; |             v = v->list.elems[attrIndex]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return v; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| void findAlongAttrPath(EvalState & state, const string & attrPath, | Value * findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
|     Bindings & autoArgs, Expr * e, Value & v); |     Bindings & autoArgs, Value & vIn); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -94,18 +94,14 @@ static bool parseInstallSourceOptions(Globals & globals, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static bool isNixExpr(const Path & path) | static bool isNixExpr(const Path & path, struct stat & st) | ||||||
| { | { | ||||||
|     struct stat st; |     return S_ISREG(st.st_mode) || (S_ISDIR(st.st_mode) && pathExists(path + "/default.nix")); | ||||||
|     if (stat(path.c_str(), &st) == -1) |  | ||||||
|         throw SysError(format("getting information about `%1%'") % path); |  | ||||||
| 
 |  | ||||||
|     return !S_ISDIR(st.st_mode) || pathExists(path + "/default.nix"); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void getAllExprs(EvalState & state, | static void getAllExprs(EvalState & state, | ||||||
|     const Path & path, ExprAttrs & attrs) |     const Path & path, Value & v) | ||||||
| { | { | ||||||
|     Strings names = readDirectory(path); |     Strings names = readDirectory(path); | ||||||
|     StringSet namesSorted(names.begin(), names.end()); |     StringSet namesSorted(names.begin(), names.end()); | ||||||
|  | @ -122,7 +118,7 @@ static void getAllExprs(EvalState & state, | ||||||
|         if (stat(path2.c_str(), &st) == -1) |         if (stat(path2.c_str(), &st) == -1) | ||||||
|             continue; // ignore dangling symlinks in ~/.nix-defexpr
 |             continue; // ignore dangling symlinks in ~/.nix-defexpr
 | ||||||
| 
 | 
 | ||||||
|         if (isNixExpr(path2)) { |         if (isNixExpr(path2, st) && (!S_ISREG(st.st_mode) || hasSuffix(path2, ".nix"))) { | ||||||
|             /* Strip off the `.nix' filename suffix (if applicable),
 |             /* Strip off the `.nix' filename suffix (if applicable),
 | ||||||
|                otherwise the attribute cannot be selected with the |                otherwise the attribute cannot be selected with the | ||||||
|                `-A' option.  Useful if you want to stick a Nix |                `-A' option.  Useful if you want to stick a Nix | ||||||
|  | @ -130,20 +126,28 @@ static void getAllExprs(EvalState & state, | ||||||
|             string attrName = *i; |             string attrName = *i; | ||||||
|             if (hasSuffix(attrName, ".nix")) |             if (hasSuffix(attrName, ".nix")) | ||||||
|                 attrName = string(attrName, 0, attrName.size() - 4); |                 attrName = string(attrName, 0, attrName.size() - 4); | ||||||
|             attrs.attrs[state.symbols.create(attrName)] = |             // FIXME: make loading lazy.
 | ||||||
|                 ExprAttrs::AttrDef(state.parseExprFromFile(resolveExprPath(absPath(path2))), noPos); |             Value & v2(*state.allocAttr(v, state.symbols.create(attrName))); | ||||||
|  |             state.evalFile(path2, v2); | ||||||
|         } |         } | ||||||
|         else |         else if (S_ISDIR(st.st_mode)) | ||||||
|             /* `path2' is a directory (with no default.nix in it);
 |             /* `path2' is a directory (with no default.nix in it);
 | ||||||
|                recurse into it. */ |                recurse into it. */ | ||||||
|             getAllExprs(state, path2, attrs); |             getAllExprs(state, path2, v); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static Expr * loadSourceExpr(EvalState & state, const Path & path) | static void loadSourceExpr(EvalState & state, const Path & path, Value & v) | ||||||
| { | { | ||||||
|     if (isNixExpr(path)) return state.parseExprFromFile(resolveExprPath(absPath(path))); |     struct stat st; | ||||||
|  |     if (stat(path.c_str(), &st) == -1) | ||||||
|  |         throw SysError(format("getting information about `%1%'") % path); | ||||||
|  | 
 | ||||||
|  |     if (isNixExpr(path, st)) { | ||||||
|  |         state.evalFile(path, v); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /* The path is a directory.  Put the Nix expressions in the
 |     /* The path is a directory.  Put the Nix expressions in the
 | ||||||
|        directory in an attribute set, with the file name of each |        directory in an attribute set, with the file name of each | ||||||
|  | @ -151,11 +155,12 @@ static Expr * loadSourceExpr(EvalState & state, const Path & path) | ||||||
|        (but keep the attribute set flat, not nested, to make it easier |        (but keep the attribute set flat, not nested, to make it easier | ||||||
|        for a user to have a ~/.nix-defexpr directory that includes |        for a user to have a ~/.nix-defexpr directory that includes | ||||||
|        some system-wide directory). */ |        some system-wide directory). */ | ||||||
|     ExprAttrs * attrs = new ExprAttrs; |     if (S_ISDIR(st.st_mode)) { | ||||||
|     attrs->attrs[state.symbols.create("_combineChannels")] = |         state.mkAttrs(v, 16); | ||||||
|         ExprAttrs::AttrDef(new ExprList(), noPos); |         state.mkList(*state.allocAttr(v, state.symbols.create("_combineChannels")), 0); | ||||||
|     getAllExprs(state, path, *attrs); |         getAllExprs(state, path, v); | ||||||
|     return attrs; |         v.attrs->sort(); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -163,8 +168,10 @@ static void loadDerivations(EvalState & state, Path nixExprPath, | ||||||
|     string systemFilter, Bindings & autoArgs, |     string systemFilter, Bindings & autoArgs, | ||||||
|     const string & pathPrefix, DrvInfos & elems) |     const string & pathPrefix, DrvInfos & elems) | ||||||
| { | { | ||||||
|     Value v; |     Value vRoot; | ||||||
|     findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v); |     loadSourceExpr(state, nixExprPath, vRoot); | ||||||
|  | 
 | ||||||
|  |     Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot)); | ||||||
| 
 | 
 | ||||||
|     getDerivations(state, v, pathPrefix, autoArgs, elems, true); |     getDerivations(state, v, pathPrefix, autoArgs, elems, true); | ||||||
| 
 | 
 | ||||||
|  | @ -356,13 +363,15 @@ static void queryInstSources(EvalState & state, | ||||||
|            (import ./foo.nix)' = `(import ./foo.nix).bar'. */ |            (import ./foo.nix)' = `(import ./foo.nix).bar'. */ | ||||||
|         case srcNixExprs: { |         case srcNixExprs: { | ||||||
| 
 | 
 | ||||||
|             Expr * e1 = loadSourceExpr(state, instSource.nixExprPath); |             Value vArg; | ||||||
|  |             loadSourceExpr(state, instSource.nixExprPath, vArg); | ||||||
| 
 | 
 | ||||||
|             foreach (Strings::const_iterator, i, args) { |             foreach (Strings::const_iterator, i, args) { | ||||||
|                 Expr * e2 = state.parseExprFromString(*i, absPath(".")); |                 Expr * eFun = state.parseExprFromString(*i, absPath(".")); | ||||||
|                 Expr * call = new ExprApp(e2, e1); |                 Value vFun, vTmp; | ||||||
|                 Value v; state.eval(call, v); |                 state.eval(eFun, vFun); | ||||||
|                 getDerivations(state, v, "", instSource.autoArgs, elems, true); |                 mkApp(vTmp, vFun, vArg); | ||||||
|  |                 getDerivations(state, vTmp, "", instSource.autoArgs, elems, true); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             break; |             break; | ||||||
|  | @ -413,10 +422,10 @@ static void queryInstSources(EvalState & state, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         case srcAttrPath: { |         case srcAttrPath: { | ||||||
|  |             Value vRoot; | ||||||
|  |             loadSourceExpr(state, instSource.nixExprPath, vRoot); | ||||||
|             foreach (Strings::const_iterator, i, args) { |             foreach (Strings::const_iterator, i, args) { | ||||||
|                 Value v; |                 Value & v(*findAlongAttrPath(state, *i, instSource.autoArgs, vRoot)); | ||||||
|                 findAlongAttrPath(state, *i, instSource.autoArgs, |  | ||||||
|                     loadSourceExpr(state, instSource.nixExprPath), v); |  | ||||||
|                 getDerivations(state, v, "", instSource.autoArgs, elems, true); |                 getDerivations(state, v, "", instSource.autoArgs, elems, true); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|  | @ -44,9 +44,11 @@ void processExpr(EvalState & state, const Strings & attrPaths, | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     Value vRoot; | ||||||
|  |     state.eval(e, vRoot); | ||||||
|  | 
 | ||||||
|     foreach (Strings::const_iterator, i, attrPaths) { |     foreach (Strings::const_iterator, i, attrPaths) { | ||||||
|         Value v; |         Value & v(*findAlongAttrPath(state, *i, autoArgs, vRoot)); | ||||||
|         findAlongAttrPath(state, *i, autoArgs, e, v); |  | ||||||
|         state.forceValue(v); |         state.forceValue(v); | ||||||
| 
 | 
 | ||||||
|         PathSet context; |         PathSet context; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue