diff options
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/common-opts.cc | 2 | ||||
-rw-r--r-- | src/libexpr/common-opts.hh | 2 | ||||
-rw-r--r-- | src/libexpr/eval.cc | 13 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 12 | ||||
-rw-r--r-- | src/libexpr/lexer.l | 24 | ||||
-rw-r--r-- | src/libexpr/parser.y | 2 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 63 |
7 files changed, 70 insertions, 48 deletions
diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index 13760490d9c4..68ab4b5cdcbf 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -55,7 +55,7 @@ bool parseSearchPathArg(Strings::iterator & i, Path lookupFileArg(EvalState & state, string s) { if (isUri(s)) - return downloadFileCached(s, true); + return downloadFileCached(state.store, s, true); else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { Path p = s.substr(1, s.size() - 2); return state.findFile(p); diff --git a/src/libexpr/common-opts.hh b/src/libexpr/common-opts.hh index be0f40202430..cb2732d6fe7e 100644 --- a/src/libexpr/common-opts.hh +++ b/src/libexpr/common-opts.hh @@ -4,6 +4,8 @@ namespace nix { +class Store; + /* Some common option parsing between nix-env and nix-instantiate. */ bool parseAutoArgs(Strings::iterator & i, const Strings::iterator & argsEnd, std::map<string, string> & res); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index b951daacaf0c..8ce2f3dfa6af 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -248,7 +248,7 @@ static Strings parseNixPath(const string & in) } -EvalState::EvalState(const Strings & _searchPath) +EvalState::EvalState(const Strings & _searchPath, ref<Store> store) : sWith(symbols.create("<with>")) , sOutPath(symbols.create("outPath")) , sDrvPath(symbols.create("drvPath")) @@ -265,6 +265,8 @@ EvalState::EvalState(const Strings & _searchPath) , sLine(symbols.create("line")) , sColumn(symbols.create("column")) , sFunctor(symbols.create("__functor")) + , sToString(symbols.create("__toString")) + , store(store) , baseEnv(allocEnv(128)) , staticBaseEnv(false, 0) { @@ -1431,7 +1433,14 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } if (v.type == tAttrs) { - Bindings::iterator i = v.attrs->find(sOutPath); + auto i = v.attrs->find(sToString); + if (i != v.attrs->end()) { + forceValue(*i->value, pos); + Value v1; + callFunction(*i->value, v, v1, pos); + return coerceToString(pos, v1, context, coerceMore, copyToStore); + } + i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 13353a43f4e0..40e05712bab1 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -16,6 +16,7 @@ namespace nix { +class Store; class EvalState; @@ -69,7 +70,7 @@ public: const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, - sFile, sLine, sColumn, sFunctor; + sFile, sLine, sColumn, sFunctor, sToString; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they @@ -82,6 +83,8 @@ public: Value vEmptySet; + const ref<Store> store; + private: SrcToStore srcToStore; @@ -97,7 +100,7 @@ private: public: - EvalState(const Strings & _searchPath); + EvalState(const Strings & _searchPath, ref<Store> store); ~EvalState(); void addToSearchPath(const string & s, bool warn = false); @@ -241,6 +244,8 @@ public: /* Print statistics. */ void printStats(); + void realiseContext(const PathSet & context); + private: unsigned long nrEnvs = 0; @@ -291,7 +296,4 @@ struct InvalidPathError : EvalError #endif }; -/* Realise all paths in `context' */ -void realiseContext(const PathSet & context); - } diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l index 7a6e48215b34..701c01aff973 100644 --- a/src/libexpr/lexer.l +++ b/src/libexpr/lexer.l @@ -8,6 +8,7 @@ %x STRING %x IND_STRING +%x INSIDE_DOLLAR_CURLY %{ @@ -94,6 +95,8 @@ URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~ %% +<INITIAL,INSIDE_DOLLAR_CURLY>{ + if { return IF; } then { return THEN; } @@ -131,11 +134,15 @@ or { return OR_KW; } return FLOAT; } -\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; } -\{ { PUSH_STATE(INITIAL); return '{'; } -\} { POP_STATE(); return '}'; } +\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; } +} + +\} { return '}'; } +<INSIDE_DOLLAR_CURLY>\} { POP_STATE(); return '}'; } +\{ { return '{'; } +<INSIDE_DOLLAR_CURLY>\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return '{'; } -\" { PUSH_STATE(STRING); return '"'; } +<INITIAL,INSIDE_DOLLAR_CURLY>\" { PUSH_STATE(STRING); return '"'; } <STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)*\$/\" | <STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)+ { /* It is impossible to match strings ending with '$' with one @@ -144,11 +151,11 @@ or { return OR_KW; } yylval->e = unescapeStr(data->symbols, yytext); return STR; } -<STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; } +<STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; } <STRING>\" { POP_STATE(); return '"'; } <STRING>. return yytext[0]; /* just in case: shouldn't be reached */ -\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; } +<INITIAL,INSIDE_DOLLAR_CURLY>\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; } <IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ { yylval->e = new ExprIndStr(yytext); return IND_STR; @@ -165,7 +172,7 @@ or { return OR_KW; } yylval->e = unescapeStr(data->symbols, yytext + 2); return IND_STR; } -<IND_STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; } +<IND_STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; } <IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; } <IND_STRING>\' { yylval->e = new ExprIndStr("'"); @@ -173,6 +180,8 @@ or { return OR_KW; } } <IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */ +<INITIAL,INSIDE_DOLLAR_CURLY>{ + {PATH} { yylval->path = strdup(yytext); return PATH; } {HPATH} { yylval->path = strdup(yytext); return HPATH; } {SPATH} { yylval->path = strdup(yytext); return SPATH; } @@ -184,6 +193,7 @@ or { return OR_KW; } . return yytext[0]; +} %% diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 32c66c783328..f87aa261935b 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -606,7 +606,7 @@ void EvalState::addToSearchPath(const string & s, bool warn) } if (isUri(path)) - path = downloadFileCached(path, true); + path = downloadFileCached(store, path, true); path = absPath(path); if (pathExists(path)) { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ebc5ae143143..3c899d769253 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,15 +1,15 @@ +#include "archive.hh" +#include "derivations.hh" +#include "download.hh" +#include "eval-inline.hh" #include "eval.hh" -#include "misc.hh" #include "globals.hh" +#include "json-to-value.hh" +#include "names.hh" #include "store-api.hh" #include "util.hh" -#include "archive.hh" -#include "value-to-xml.hh" #include "value-to-json.hh" -#include "json-to-value.hh" -#include "names.hh" -#include "eval-inline.hh" -#include "download.hh" +#include "value-to-xml.hh" #include <sys/types.h> #include <sys/stat.h> @@ -43,7 +43,7 @@ std::pair<string, string> decodeContext(const string & s) InvalidPathError::InvalidPathError(const Path & path) : EvalError(format("path ‘%1%’ is not valid") % path), path(path) {} -void realiseContext(const PathSet & context) +void EvalState::realiseContext(const PathSet & context) { PathSet drvs; for (auto & i : context) { @@ -52,16 +52,14 @@ void realiseContext(const PathSet & context) assert(isStorePath(ctx)); if (!store->isValidPath(ctx)) throw InvalidPathError(ctx); - if (!decoded.second.empty() && isDerivation(ctx)) + if (!decoded.second.empty() && nix::isDerivation(ctx)) drvs.insert(decoded.first + "!" + decoded.second); } if (!drvs.empty()) { /* For performance, prefetch all substitute info. */ PathSet willBuild, willSubstitute, unknown; unsigned long long downloadSize, narSize; - queryMissing(*store, drvs, - willBuild, willSubstitute, unknown, downloadSize, narSize); - + store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize); store->buildPaths(drvs); } } @@ -75,7 +73,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[1], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -83,7 +81,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args path = state.checkSourcePath(path); - if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) { + if (isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) { Derivation drv = readDerivation(path); Value & w = *state.allocValue(); state.mkAttrs(w, 3 + drv.outputs.size()); @@ -145,7 +143,7 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -259,7 +257,7 @@ struct CompareValues if (v1->type == tInt && v2->type == tFloat) return v1->integer < v2->fpoint; if (v1->type != v2->type) - throw EvalError("cannot compare values of different types"); + throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2)); switch (v1->type) { case tInt: return v1->integer < v2->integer; @@ -573,11 +571,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * runs. */ if (path.at(0) == '=') { /* !!! This doesn't work if readOnlyMode is set. */ - PathSet refs; computeFSClosure(*store, string(path, 1), refs); + PathSet refs; + state.store->computeFSClosure(string(path, 1), refs); for (auto & j : refs) { drv.inputSrcs.insert(j); if (isDerivation(j)) - drv.inputDrvs[j] = store->queryDerivationOutputNames(j); + drv.inputDrvs[j] = state.store->queryDerivationOutputNames(j); } } @@ -594,7 +593,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Handle derivation contexts returned by ‘builtins.storePath’. */ else if (isDerivation(path)) - drv.inputDrvs[path] = store->queryDerivationOutputNames(path); + drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path); /* Otherwise it's a source file. */ else @@ -643,7 +642,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Use the masked derivation expression to compute the output path. */ - Hash h = hashDerivationModulo(*store, drv); + Hash h = hashDerivationModulo(*state.store, drv); for (auto & i : drv.outputs) if (i.second.path == "") { @@ -654,7 +653,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } /* Write the resulting term into the Nix store directory. */ - Path drvPath = writeDerivation(*store, drv, drvName, state.repair); + Path drvPath = writeDerivation(state.store, drv, drvName, state.repair); printMsg(lvlChatty, format("instantiated ‘%1%’ -> ‘%2%’") % drvName % drvPath); @@ -662,7 +661,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Optimisation, but required in read-only mode! because in that case we don't actually write store derivations, so we can't read them later. */ - drvHashes[drvPath] = hashDerivationModulo(*store, drv); + drvHashes[drvPath] = hashDerivationModulo(*state.store, drv); state.mkAttrs(v, 1 + drv.outputs.size()); mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath)); @@ -708,7 +707,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos); Path path2 = toStorePath(path); if (!settings.readOnlyMode) - store->ensurePath(path2); + state.store->ensurePath(path2); context.insert(path2); mkString(v, path, context); } @@ -758,7 +757,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va PathSet context; Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -799,7 +798,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va string path = state.forceStringNoCtx(*args[1], pos); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -814,7 +813,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val PathSet ctx; Path path = state.coerceToPath(pos, *args[0], ctx); try { - realiseContext(ctx); + state.realiseContext(ctx); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -892,13 +891,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu if (path.at(0) != '~') throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos); path = string(path, 1); - } + } refs.insert(path); } Path storePath = settings.readOnlyMode ? computeStorePathForText(name, contents, refs) - : store->addTextToStore(name, contents, refs, state.repair); + : state.store->addTextToStore(name, contents, refs, state.repair); /* Note: we don't need to add `context' to the context of the result, since `storePath' itself has references to the paths @@ -964,7 +963,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args Path dstPath = settings.readOnlyMode ? computeStorePathForPath(path, true, htSHA256, filter).first - : store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); + : state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); mkString(v, dstPath, singleton<PathSet>(dstPath)); } @@ -1167,7 +1166,7 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va /* Return a set containing the names of the formal arguments expected by the function `f'. The value of each attribute is a Boolean - denoting whether has a default value. For instance, + denoting whether the corresponding argument has a default value. For instance, functionArgs ({ x, y ? 123}: ...) => { x = false; y = true; } @@ -1387,7 +1386,7 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val state.mkList(v, len); - for (unsigned int n = 0; n < len; ++n) { + for (unsigned int n = 0; n < (unsigned int) len; ++n) { Value * arg = state.allocValue(); mkInt(*arg, n); mkApp(*(v.listElems()[n] = state.allocValue()), *args[0], *arg); @@ -1704,7 +1703,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, } else url = state.forceStringNoCtx(*args[0], pos); - Path res = downloadFileCached(url, unpack); + Path res = downloadFileCached(state.store, url, unpack); mkString(v, res, PathSet({res})); } |