Author: eelco
Date: Sat Aug 6 16:05:24 2011
New Revision: 28194
URL: https://svn.nixos.org/websvn/nix/?rev=28194&sc=1
Log:
* 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.
Added:
nix/trunk/tests/lang/dir1/
nix/trunk/tests/lang/dir1/a.nix
nix/trunk/tests/lang/dir2/
nix/trunk/tests/lang/dir2/a.nix
nix/trunk/tests/lang/dir2/b.nix
nix/trunk/tests/lang/dir3/
nix/trunk/tests/lang/dir3/a.nix
nix/trunk/tests/lang/dir3/b.nix
nix/trunk/tests/lang/dir3/c.nix
nix/trunk/tests/lang/dir4/
nix/trunk/tests/lang/dir4/a.nix
nix/trunk/tests/lang/dir4/c.nix
nix/trunk/tests/lang/eval-okay-search-path.exp
nix/trunk/tests/lang/eval-okay-search-path.flags
nix/trunk/tests/lang/eval-okay-search-path.nix
nix/trunk/tests/lang/eval-okay-search-path.nix~
nix/trunk/tests/lang/eval-okay-search-path.out
Modified:
nix/trunk/doc/manual/release-notes.xml
nix/trunk/scripts/nix-build.in
nix/trunk/src/libexpr/common-opts.cc
nix/trunk/src/libexpr/common-opts.hh
nix/trunk/src/libexpr/eval.cc
nix/trunk/src/libexpr/eval.hh
nix/trunk/src/libexpr/lexer.l
nix/trunk/src/libexpr/parser.y
nix/trunk/src/nix-env/nix-env.cc
nix/trunk/src/nix-instantiate/nix-instantiate.cc
nix/trunk/tests/lang.sh
Modified: nix/trunk/doc/manual/release-notes.xml
==============================================================================
--- nix/trunk/doc/manual/release-notes.xml Sat Aug 6 14:28:15 2011
(r28193)
+++ nix/trunk/doc/manual/release-notes.xml Sat Aug 6 16:05:24 2011
(r28194)
@@ -36,6 +36,10 @@
<para>TODO: “or” keyword.</para>
</listitem>
+ <listitem>
+ <para>TODO: Nix expression search path (<literal>import
<foo/bar.nix></literal>).</para>
+ </listitem>
+
</itemizedlist>
</section>
Modified: nix/trunk/scripts/nix-build.in
==============================================================================
--- nix/trunk/scripts/nix-build.in Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/scripts/nix-build.in Sat Aug 6 16:05:24 2011 (r28194)
@@ -76,10 +76,10 @@
$outLink = $ARGV[$n];
}
- elsif ($arg eq "--attr" or $arg eq "-A") {
+ elsif ($arg eq "--attr" or $arg eq "-A" or $arg eq "-I") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
- push @instArgs, ("--attr", $ARGV[$n]);
+ push @instArgs, ($arg, $ARGV[$n]);
}
elsif ($arg eq "--arg" || $arg eq "--argstr") {
Modified: nix/trunk/src/libexpr/common-opts.cc
==============================================================================
--- nix/trunk/src/libexpr/common-opts.cc Sat Aug 6 14:28:15 2011
(r28193)
+++ nix/trunk/src/libexpr/common-opts.cc Sat Aug 6 16:05:24 2011
(r28194)
@@ -33,5 +33,15 @@
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;
+}
+
+
}
Modified: nix/trunk/src/libexpr/common-opts.hh
==============================================================================
--- nix/trunk/src/libexpr/common-opts.hh Sat Aug 6 14:28:15 2011
(r28193)
+++ nix/trunk/src/libexpr/common-opts.hh Sat Aug 6 16:05:24 2011
(r28194)
@@ -11,6 +11,9 @@
const Strings::iterator & argsEnd, EvalState & state,
Bindings & autoArgs);
+bool parseSearchPathArg(const string & arg, Strings::iterator & i,
+ const Strings::iterator & argsEnd, EvalState & state);
+
}
Modified: nix/trunk/src/libexpr/eval.cc
==============================================================================
--- nix/trunk/src/libexpr/eval.cc Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/src/libexpr/eval.cc Sat Aug 6 16:05:24 2011 (r28194)
@@ -181,6 +181,12 @@
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();
}
Modified: nix/trunk/src/libexpr/eval.hh
==============================================================================
--- nix/trunk/src/libexpr/eval.hh Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/src/libexpr/eval.hh Sat Aug 6 16:05:24 2011 (r28194)
@@ -213,11 +213,16 @@
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 @@
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);
Modified: nix/trunk/src/libexpr/lexer.l
==============================================================================
--- nix/trunk/src/libexpr/lexer.l Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/src/libexpr/lexer.l Sat Aug 6 16:05:24 2011 (r28194)
@@ -81,6 +81,7 @@
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 @@
<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 */
Modified: nix/trunk/src/libexpr/parser.y
==============================================================================
--- nix/trunk/src/libexpr/parser.y Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/src/libexpr/parser.y Sat Aug 6 16:05:24 2011 (r28194)
@@ -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 @@
%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 @@
$$ = 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 @@
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 @@
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 "";
+}
+
+
}
Modified: nix/trunk/src/nix-env/nix-env.cc
==============================================================================
--- nix/trunk/src/nix-env/nix-env.cc Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/src/nix-env/nix-env.cc Sat Aug 6 16:05:24 2011 (r28194)
@@ -1253,6 +1253,8 @@
else if (parseOptionArg(arg, i, args.end(),
globals.state, globals.instSource.autoArgs))
;
+ else if (parseSearchPathArg(arg, i, args.end(), globals.state))
+ ;
else if (arg == "--force-name") // undocumented flag for
nix-install-package
globals.forceName = needArg(i, args, arg);
else if (arg == "--uninstall" || arg == "-e")
Modified: nix/trunk/src/nix-instantiate/nix-instantiate.cc
==============================================================================
--- nix/trunk/src/nix-instantiate/nix-instantiate.cc Sat Aug 6 14:28:15
2011 (r28193)
+++ nix/trunk/src/nix-instantiate/nix-instantiate.cc Sat Aug 6 16:05:24
2011 (r28194)
@@ -107,6 +107,8 @@
}
else if (parseOptionArg(arg, i, args.end(), state, autoArgs))
;
+ else if (parseSearchPathArg(arg, i, args.end(), state))
+ ;
else if (arg == "--add-root") {
if (i == args.end())
throw UsageError("`--add-root' requires an argument");
Modified: nix/trunk/tests/lang.sh
==============================================================================
--- nix/trunk/tests/lang.sh Sat Aug 6 14:28:15 2011 (r28193)
+++ nix/trunk/tests/lang.sh Sat Aug 6 16:05:24 2011 (r28194)
@@ -40,7 +40,7 @@
if test -e lang/$i.flags; then
flags=$(cat lang/$i.flags)
fi
- if ! $nixinstantiate $flags --eval-only --strict lang/$i.nix >
lang/$i.out; then
+ if ! NIX_PATH=lang/dir3:lang/dir4 $nixinstantiate $flags --eval-only
--strict lang/$i.nix > lang/$i.out; then
echo "FAIL: $i should evaluate"
fail=1
elif ! diff lang/$i.out lang/$i.exp; then
Added: nix/trunk/tests/lang/dir1/a.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir1/a.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"a"
Added: nix/trunk/tests/lang/dir2/a.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir2/a.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"X"
Added: nix/trunk/tests/lang/dir2/b.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir2/b.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"b"
Added: nix/trunk/tests/lang/dir3/a.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir3/a.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"X"
Added: nix/trunk/tests/lang/dir3/b.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir3/b.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"X"
Added: nix/trunk/tests/lang/dir3/c.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir3/c.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"c"
Added: nix/trunk/tests/lang/dir4/a.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir4/a.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"X"
Added: nix/trunk/tests/lang/dir4/c.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/dir4/c.nix Sat Aug 6 16:05:24 2011 (r28194)
@@ -0,0 +1 @@
+"X"
Added: nix/trunk/tests/lang/eval-okay-search-path.exp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-search-path.exp Sat Aug 6 16:05:24
2011 (r28194)
@@ -0,0 +1 @@
+"abc"
Added: nix/trunk/tests/lang/eval-okay-search-path.flags
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-search-path.flags Sat Aug 6 16:05:24
2011 (r28194)
@@ -0,0 +1 @@
+-I lang/dir1 -I lang/dir2
\ No newline at end of file
Added: nix/trunk/tests/lang/eval-okay-search-path.nix
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-search-path.nix Sat Aug 6 16:05:24
2011 (r28194)
@@ -0,0 +1,3 @@
+import <a.nix> + import <b.nix> + import <c.nix>
+
+
Added: nix/trunk/tests/lang/eval-okay-search-path.nix~
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-search-path.nix~ Sat Aug 6 16:05:24
2011 (r28194)
@@ -0,0 +1 @@
+(import <a.nix>)
\ No newline at end of file
Added: nix/trunk/tests/lang/eval-okay-search-path.out
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-search-path.out Sat Aug 6 16:05:24
2011 (r28194)
@@ -0,0 +1 @@
+"abc"
_______________________________________________
nix-commits mailing list
[email protected]
http://mail.cs.uu.nl/mailman/listinfo/nix-commits