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) == '>') { |     if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { | ||||||
|         Path p = s.substr(1, s.size() - 2); |         Path p = s.substr(1, s.size() - 2); | ||||||
|         Path p2 = state.findFile(p); |         return 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; |  | ||||||
|     } else |     } else | ||||||
|         return absPath(s); |         return absPath(s); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -86,6 +86,9 @@ typedef std::map<Path, Path> SrcToStore; | ||||||
| std::ostream & operator << (std::ostream & str, const Value & v); | std::ostream & operator << (std::ostream & str, const Value & v); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | typedef list<std::pair<string, Path> > SearchPath; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class EvalState | class EvalState | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | @ -111,7 +114,6 @@ private: | ||||||
| #endif | #endif | ||||||
|     FileEvalCache fileEvalCache; |     FileEvalCache fileEvalCache; | ||||||
| 
 | 
 | ||||||
|     typedef list<std::pair<string, Path> > SearchPath; |  | ||||||
|     SearchPath searchPath; |     SearchPath searchPath; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | @ -137,6 +139,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /* Look up a file in the search path. */ |     /* Look up a file in the search path. */ | ||||||
|     Path findFile(const string & path); |     Path findFile(const string & path); | ||||||
|  |     Path findFile(SearchPath & searchPath, const string & path); | ||||||
| 
 | 
 | ||||||
|     /* Evaluate an expression to normal form, storing the result in
 |     /* Evaluate an expression to normal form, storing the result in
 | ||||||
|        value `v'. */ |        value `v'. */ | ||||||
|  |  | ||||||
|  | @ -142,6 +142,7 @@ struct ExprVar : Expr | ||||||
|     unsigned int level; |     unsigned int level; | ||||||
|     unsigned int displ; |     unsigned int displ; | ||||||
| 
 | 
 | ||||||
|  |     ExprVar(const Symbol & name) : name(name) { }; | ||||||
|     ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; |     ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
|     Value * maybeThunk(EvalState & state, Env & env); |     Value * maybeThunk(EvalState & state, Env & env); | ||||||
|  |  | ||||||
|  | @ -386,17 +386,10 @@ expr_simple | ||||||
|   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } |   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } | ||||||
|   | SPATH { |   | SPATH { | ||||||
|       string path($1 + 1, strlen($1) - 2); |       string path($1 + 1, strlen($1) - 2); | ||||||
|       Path path2 = data->state.findFile(path); |       $$ = new ExprApp(CUR_POS, | ||||||
|       /* The file wasn't found in the search path.  However, we can't |           new ExprApp(new ExprVar(data->symbols.create("__findFile")), | ||||||
|          throw an error here, because the expression might never be |               new ExprVar(data->symbols.create("nixPath"))), | ||||||
|          evaluated.  So return an expression that lazily calls |           new ExprString(data->symbols.create(path))); | ||||||
|          ‘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); |  | ||||||
|   } |   } | ||||||
|   | URI { $$ = new ExprString(data->symbols.create($1)); } |   | URI { $$ = new ExprString(data->symbols.create($1)); } | ||||||
|   | '(' expr ')' { $$ = $2; } |   | '(' expr ')' { $$ = $2; } | ||||||
|  | @ -636,6 +629,12 @@ void EvalState::addToSearchPath(const string & s, bool warn) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path EvalState::findFile(const string & path) | Path EvalState::findFile(const string & path) | ||||||
|  | { | ||||||
|  |     return findFile(searchPath, path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Path EvalState::findFile(SearchPath & searchPath, const string & path) | ||||||
| { | { | ||||||
|     foreach (SearchPath::iterator, i, searchPath) { |     foreach (SearchPath::iterator, i, searchPath) { | ||||||
|         Path res; |         Path res; | ||||||
|  | @ -650,7 +649,7 @@ Path EvalState::findFile(const string & path) | ||||||
|         } |         } | ||||||
|         if (pathExists(res)) return canonPath(res); |         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 |  * Creating files | ||||||
|  *************************************************************/ |  *************************************************************/ | ||||||
|  | @ -1293,6 +1324,7 @@ void EvalState::createBaseEnv() | ||||||
|     addPrimOp("baseNameOf", 1, prim_baseNameOf); |     addPrimOp("baseNameOf", 1, prim_baseNameOf); | ||||||
|     addPrimOp("dirOf", 1, prim_dirOf); |     addPrimOp("dirOf", 1, prim_dirOf); | ||||||
|     addPrimOp("__readFile", 1, prim_readFile); |     addPrimOp("__readFile", 1, prim_readFile); | ||||||
|  |     addPrimOp("__findFile", 2, prim_findFile); | ||||||
| 
 | 
 | ||||||
|     // Creating files
 |     // Creating files
 | ||||||
|     addPrimOp("__toXML", 1, prim_toXML); |     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; | assert length (filter (x: baseNameOf x.path == "dir4") nixPath) == 1; | ||||||
| 
 | 
 | ||||||
| import <a.nix> + import <b.nix> + import <c.nix> + import <dir5/c.nix> | 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