Make the Nix search path declarative
Nix search path lookups like <nixpkgs> are now desugared to ‘findFile
nixPath <nixpkgs>’, where ‘findFile’ is a new primop. Thus you can
override the search path simply by saying
  let
    nixPath = [ { prefix = "nixpkgs"; path = "/my-nixpkgs"; } ];
  in ... <nixpkgs> ...
In conjunction with ‘scopedImport’ (commit
c273c15cb1), the Nix search path can be
propagated across imports, e.g.
  let
    overrides = {
      nixPath = [ ... ] ++ builtins.nixPath;
      import = fn: scopedImport overrides fn;
      scopedImport = attrs: fn: scopedImport (overrides // attrs) fn;
      builtins = builtins // overrides;
    };
  in scopedImport overrides ./nixos
			
			
This commit is contained in:
		
							parent
							
								
									39d72640c2
								
							
						
					
					
						commit
						62a6eeb1f3
					
				
					 7 changed files with 51 additions and 17 deletions
				
			
		|  | @ -48,9 +48,7 @@ Path lookupFileArg(EvalState & state, string s) | |||
| { | ||||
|     if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { | ||||
|         Path p = s.substr(1, s.size() - 2); | ||||
|         Path p2 = state.findFile(p); | ||||
|         if (p2 == "") throw Error(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % p); | ||||
|         return p2; | ||||
|         return state.findFile(p); | ||||
|     } else | ||||
|         return absPath(s); | ||||
| } | ||||
|  |  | |||
|  | @ -86,6 +86,9 @@ typedef std::map<Path, Path> SrcToStore; | |||
| std::ostream & operator << (std::ostream & str, const Value & v); | ||||
| 
 | ||||
| 
 | ||||
| typedef list<std::pair<string, Path> > SearchPath; | ||||
| 
 | ||||
| 
 | ||||
| class EvalState | ||||
| { | ||||
| public: | ||||
|  | @ -111,7 +114,6 @@ private: | |||
| #endif | ||||
|     FileEvalCache fileEvalCache; | ||||
| 
 | ||||
|     typedef list<std::pair<string, Path> > SearchPath; | ||||
|     SearchPath searchPath; | ||||
| 
 | ||||
| public: | ||||
|  | @ -137,6 +139,7 @@ public: | |||
| 
 | ||||
|     /* Look up a file in the search path. */ | ||||
|     Path findFile(const string & path); | ||||
|     Path findFile(SearchPath & searchPath, const string & path); | ||||
| 
 | ||||
|     /* Evaluate an expression to normal form, storing the result in
 | ||||
|        value `v'. */ | ||||
|  |  | |||
|  | @ -142,6 +142,7 @@ struct ExprVar : Expr | |||
|     unsigned int level; | ||||
|     unsigned int displ; | ||||
| 
 | ||||
|     ExprVar(const Symbol & name) : name(name) { }; | ||||
|     ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; | ||||
|     COMMON_METHODS | ||||
|     Value * maybeThunk(EvalState & state, Env & env); | ||||
|  |  | |||
|  | @ -386,17 +386,10 @@ expr_simple | |||
|   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } | ||||
|   | SPATH { | ||||
|       string path($1 + 1, strlen($1) - 2); | ||||
|       Path path2 = data->state.findFile(path); | ||||
|       /* The file wasn't found in the search path.  However, we can't | ||||
|          throw an error here, because the expression might never be | ||||
|          evaluated.  So return an expression that lazily calls | ||||
|          ‘throw’. */ | ||||
|       $$ = path2 == "" | ||||
|           ? (Expr * ) new ExprApp( | ||||
|               new ExprBuiltin(data->symbols.create("throw")), | ||||
|               new ExprString(data->symbols.create( | ||||
|                       (format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str()))) | ||||
|           : (Expr * ) new ExprPath(path2); | ||||
|       $$ = new ExprApp(CUR_POS, | ||||
|           new ExprApp(new ExprVar(data->symbols.create("__findFile")), | ||||
|               new ExprVar(data->symbols.create("nixPath"))), | ||||
|           new ExprString(data->symbols.create(path))); | ||||
|   } | ||||
|   | URI { $$ = new ExprString(data->symbols.create($1)); } | ||||
|   | '(' expr ')' { $$ = $2; } | ||||
|  | @ -636,6 +629,12 @@ void EvalState::addToSearchPath(const string & s, bool warn) | |||
| 
 | ||||
| 
 | ||||
| Path EvalState::findFile(const string & path) | ||||
| { | ||||
|     return findFile(searchPath, path); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Path EvalState::findFile(SearchPath & searchPath, const string & path) | ||||
| { | ||||
|     foreach (SearchPath::iterator, i, searchPath) { | ||||
|         Path res; | ||||
|  | @ -650,7 +649,7 @@ Path EvalState::findFile(const string & path) | |||
|         } | ||||
|         if (pathExists(res)) return canonPath(res); | ||||
|     } | ||||
|     return ""; | ||||
|     throw ThrownError(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -654,6 +654,37 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Find a file in the Nix search path. Used to implement <x> paths,
 | ||||
|    which are desugared to ‘findFile nixPath "x"’. */ | ||||
| static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||
| { | ||||
|     state.forceList(*args[0], pos); | ||||
| 
 | ||||
|     SearchPath searchPath; | ||||
| 
 | ||||
|     for (unsigned int n = 0; n < args[0]->list.length; ++n) { | ||||
|         Value & v2(*args[0]->list.elems[n]); | ||||
|         state.forceAttrs(v2, pos); | ||||
| 
 | ||||
|         string prefix; | ||||
|         Bindings::iterator i = v2.attrs->find(state.symbols.create("prefix")); | ||||
|         if (i != v2.attrs->end()) | ||||
|             prefix = state.forceStringNoCtx(*i->value, pos); | ||||
| 
 | ||||
|         i = v2.attrs->find(state.symbols.create("path")); | ||||
|         if (i == v2.attrs->end()) | ||||
|             throw EvalError(format("attribute `path' missing, at %1%") % pos); | ||||
|         PathSet context; | ||||
|         string path = state.coerceToPath(pos, *i->value, context); | ||||
| 
 | ||||
|         searchPath.push_back(std::pair<string, Path>(prefix, path)); | ||||
|     } | ||||
| 
 | ||||
|     string path = state.forceStringNoCtx(*args[1], pos); | ||||
|     mkPath(v, state.findFile(searchPath, path).c_str()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*************************************************************
 | ||||
|  * Creating files | ||||
|  *************************************************************/ | ||||
|  | @ -1293,6 +1324,7 @@ void EvalState::createBaseEnv() | |||
|     addPrimOp("baseNameOf", 1, prim_baseNameOf); | ||||
|     addPrimOp("dirOf", 1, prim_dirOf); | ||||
|     addPrimOp("__readFile", 1, prim_readFile); | ||||
|     addPrimOp("__findFile", 2, prim_findFile); | ||||
| 
 | ||||
|     // Creating files
 | ||||
|     addPrimOp("__toXML", 1, prim_toXML); | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| "abcc" | ||||
| "abcca" | ||||
|  |  | |||
|  | @ -8,3 +8,4 @@ assert length (filter (x: x.prefix == "nix") nixPath) == 1; | |||
| assert length (filter (x: baseNameOf x.path == "dir4") nixPath) == 1; | ||||
| 
 | ||||
| import <a.nix> + import <b.nix> + import <c.nix> + import <dir5/c.nix> | ||||
|   + (let nixPath = [ { path = ./dir1; } { path = ./dir2; } ]; in import <a.nix>) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue