diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2011-08-06T16·05+0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2011-08-06T16·05+0000 |
commit | 1ecc97b6bdb27e56d832ca48cdafd3dbb5185a04 (patch) | |
tree | 4de27ee42f04bb50766f33a58d830677bd8fa80b /src/libexpr | |
parent | 54945a2950174ded83d58336061b4a9990cdbbfd (diff) |
* Add a Nix expression search path feature. Paths between angle
brackets, e.g. import <nixpkgs/pkgs/lib> are resolved by looking them up relative to the elements listed in the search path. This allows us to get rid of hacks like import "${builtins.getEnv "NIXPKGS_ALL"}/pkgs/lib" The search path can be specified through the ‘-I’ command-line flag and through the colon-separated ‘NIX_PATH’ environment variable, e.g., $ nix-build -I /etc/nixos ... If a file is not found in the search path, an error message is lazily thrown.
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/common-opts.cc | 12 | ||||
-rw-r--r-- | src/libexpr/common-opts.hh | 3 | ||||
-rw-r--r-- | src/libexpr/eval.cc | 6 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 8 | ||||
-rw-r--r-- | src/libexpr/lexer.l | 2 | ||||
-rw-r--r-- | src/libexpr/parser.y | 47 |
6 files changed, 72 insertions, 6 deletions
diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index bab31f4935db..d029d2ec35b9 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -33,5 +33,15 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, return true; } - + +bool parseSearchPathArg(const string & arg, Strings::iterator & i, + const Strings::iterator & argsEnd, EvalState & state) +{ + if (arg != "-I") return false; + if (i == argsEnd) throw UsageError(format("`%1%' requires an argument") % arg);; + state.addToSearchPath(*i++); + return true; +} + + } diff --git a/src/libexpr/common-opts.hh b/src/libexpr/common-opts.hh index 80298ce55d1b..6b7247fc3d89 100644 --- a/src/libexpr/common-opts.hh +++ b/src/libexpr/common-opts.hh @@ -11,6 +11,9 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, const Strings::iterator & argsEnd, EvalState & state, Bindings & autoArgs); +bool parseSearchPathArg(const string & arg, Strings::iterator & i, + const Strings::iterator & argsEnd, EvalState & state); + } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5701452f94f1..674fa96f0bc0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -181,6 +181,12 @@ EvalState::EvalState() gcInitialised = true; } #endif + + /* Initialise the Nix expression search path. */ + searchPathInsertionPoint = searchPath.end(); + Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":"); + foreach (Strings::iterator, i, paths) addToSearchPath(*i); + searchPathInsertionPoint = searchPath.begin(); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e900217fa457..1583665bad19 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -213,11 +213,16 @@ private: std::map<Path, Expr *> parseTrees; + Paths searchPath; + Paths::iterator searchPathInsertionPoint; + public: EvalState(); ~EvalState(); + void addToSearchPath(const string & s); + /* Parse a Nix expression from the specified file. If `path' refers to a directory, then "/default.nix" is appended. */ Expr * parseExprFromFile(Path path); @@ -229,6 +234,9 @@ public: form. */ void evalFile(const Path & path, Value & v); + /* Look up a file in the search path. */ + Path findFile(const string & path); + /* Evaluate an expression to normal form, storing the result in value `v'. */ void eval(Expr * e, Value & v); diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l index 330c2bd54d3a..d46b66d9ff7c 100644 --- a/src/libexpr/lexer.l +++ b/src/libexpr/lexer.l @@ -81,6 +81,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s) ID [a-zA-Z\_][a-zA-Z0-9\_\']* INT [0-9]+ PATH [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+ +SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\> URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+ @@ -153,6 +154,7 @@ or { return OR_KW; } <IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */ {PATH} { yylval->path = strdup(yytext); return PATH; } +{SPATH} { yylval->path = strdup(yytext); return SPATH; } {URI} { yylval->uri = strdup(yytext); return URI; } [ \t\r\n]+ /* eat up whitespace */ diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index a64d327b454b..cd63666dc5f0 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -17,19 +17,22 @@ #include "util.hh" #include "nixexpr.hh" +#include "eval.hh" namespace nix { struct ParseData { + EvalState & state; SymbolTable & symbols; Expr * result; Path basePath; Path path; string error; Symbol sLetBody; - ParseData(SymbolTable & symbols) - : symbols(symbols) + ParseData(EvalState & state) + : state(state) + , symbols(state.symbols) , sLetBody(symbols.create("<let-body>")) { }; }; @@ -253,7 +256,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err %token <id> ID ATTRPATH %token <e> STR IND_STR %token <n> INT -%token <path> PATH +%token <path> PATH SPATH %token <uri> URI %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW %token DOLLAR_CURLY /* == ${ */ @@ -350,6 +353,20 @@ expr_simple $$ = stripIndentation(data->symbols, *$2); } | 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 + ‘abort’. */ + $$ = path2 == "" + ? (Expr * ) new ExprApp( + new ExprVar(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)); } | '(' expr ')' { $$ = $2; } /* Let expressions `let {..., body = ...}' are just desugared @@ -454,7 +471,7 @@ Expr * EvalState::parse(const char * text, const Path & path, const Path & basePath) { yyscan_t scanner; - ParseData data(symbols); + ParseData data(*this); data.basePath = basePath; data.path = path; @@ -510,5 +527,25 @@ Expr * EvalState::parseExprFromString(const string & s, const Path & basePath) return parse(s.c_str(), "(string)", basePath); } - + +void EvalState::addToSearchPath(const string & s) +{ + Path path = absPath(s); + if (pathExists(path)) { + debug(format("adding path `%1%' to the search path") % path); + searchPath.insert(searchPathInsertionPoint, path); + } +} + + +Path EvalState::findFile(const string & path) +{ + foreach (Paths::iterator, i, searchPath) { + Path res = *i + "/" + path; + if (pathExists(res)) return canonPath(res); + } + return ""; +} + + } |