* In string contexts containing derivations

(e.g. "${somePkg}/bin/foo"), store the original derivation
  expression in the context.
This commit is contained in:
Eelco Dolstra 2010-01-31 20:08:57 +00:00
parent 25fc95d56d
commit 6d1abdc6d9
12 changed files with 123 additions and 101 deletions

View File

@ -242,7 +242,7 @@ LocalNoInline(Expr updateAttrs(Expr e1, Expr e2))
}
string evalString(EvalState & state, Expr e, PathSet & context)
string evalString(EvalState & state, Expr e, ATermList & context)
{
e = evalExpr(state, e);
string s;
@ -254,11 +254,10 @@ string evalString(EvalState & state, Expr e, PathSet & context)
string evalStringNoCtx(EvalState & state, Expr e)
{
PathSet context;
ATermList context;
string s = evalString(state, e, context);
if (!context.empty())
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
% s % *(context.begin()));
if (context != ATempty)
throw EvalError(format("the string `%1%' is not allowed to refer to a store path") % s);
return s;
}
@ -312,7 +311,7 @@ ATermList flattenList(EvalState & state, Expr e)
}
string coerceToString(EvalState & state, Expr e, PathSet & context,
string coerceToString(EvalState & state, Expr e, Context & context,
bool coerceMore, bool copyToStore)
{
e = evalExpr(state, e);
@ -343,7 +342,7 @@ string coerceToString(EvalState & state, Expr e, PathSet & context,
% path % dstPath);
}
context.insert(dstPath);
context.set(toATerm(dstPath), makeNull());
return dstPath;
}
@ -351,6 +350,7 @@ string coerceToString(EvalState & state, Expr e, PathSet & context,
if (matchAttrs(e, es)) {
Expr e2 = queryAttr(e, "outPath");
if (!e2) throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
/* XXX handle derivation */
return coerceToString(state, e2, context, coerceMore, copyToStore);
}
@ -385,9 +385,9 @@ string coerceToString(EvalState & state, Expr e, PathSet & context,
static ATerm concatStrings(EvalState & state, ATermVector & args,
string separator = "")
{
if (args.empty()) return makeStr("", PathSet());
if (args.empty()) return makeStr("", ATempty);
PathSet context;
Context context;
std::ostringstream s;
/* If the first element is a path, then the result will also be a
@ -403,7 +403,7 @@ static ATerm concatStrings(EvalState & state, ATermVector & args,
s << coerceToString(state, *i, context, false, !isPath);
}
if (isPath && !context.empty())
if (isPath && context.size() != 0)
throw EvalError(format("a string that refers to a store path cannot be appended to a path, in `%1%'")
% s.str());
@ -413,7 +413,7 @@ static ATerm concatStrings(EvalState & state, ATermVector & args,
}
Path coerceToPath(EvalState & state, Expr e, PathSet & context)
Path coerceToPath(EvalState & state, Expr e, Context & context)
{
string path = coerceToString(state, e, context, false, false);
if (path == "" || path[0] != '/')
@ -600,7 +600,7 @@ LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e))
"concatenation of a derivation and a path is deprecated; "
"you should write `drv + \"%1%\"' instead of `drv + %1%'")
% aterm2String(p));
PathSet context;
Context context;
return makeStr(
coerceToString(state, makeSelect(e1, toATerm("outPath")), context)
+ aterm2String(p), context);

View File

@ -61,7 +61,7 @@ Expr evalFile(EvalState & state, const Path & path);
Expr strictEvalExpr(EvalState & state, Expr e);
/* Specific results. */
string evalString(EvalState & state, Expr e, PathSet & context);
string evalString(EvalState & state, Expr e, ATermList & context);
string evalStringNoCtx(EvalState & state, Expr e);
int evalInt(EvalState & state, Expr e);
bool evalBool(EvalState & state, Expr e);
@ -74,13 +74,13 @@ ATermList flattenList(EvalState & state, Expr e);
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. */
string coerceToString(EvalState & state, Expr e, PathSet & context,
string coerceToString(EvalState & state, Expr e, Context & context,
bool coerceMore = false, bool copyToStore = true);
/* Path coercion. Converts strings, paths and derivations to a path.
The result is guaranteed to be an canonicalised, absolute path.
Nothing is copied to the store. */
Path coerceToPath(EvalState & state, Expr e, PathSet & context);
Path coerceToPath(EvalState & state, Expr e, Context & context);
/* Automatically call a function for which each argument has a default
value or has a binding in the `args' map. Note: result is a call,

View File

@ -23,12 +23,12 @@ static XMLAttrs singletonAttrs(const string & name, const string & value)
typedef set<Expr> ExprSet;
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
static void printTermAsXML(Expr e, XMLWriter & doc, Context & context,
ExprSet & drvsSeen);
static void showAttrs(const ATermMap & attrs, XMLWriter & doc,
PathSet & context, ExprSet & drvsSeen)
Context & context, ExprSet & drvsSeen)
{
StringSet names;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
@ -65,7 +65,7 @@ static void printPatternAsXML(Pattern pat, XMLWriter & doc)
}
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
static void printTermAsXML(Expr e, XMLWriter & doc, Context & context,
ExprSet & drvsSeen)
{
XMLAttrs attrs;
@ -144,7 +144,7 @@ static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
}
void printTermAsXML(Expr e, std::ostream & out, PathSet & context)
void printTermAsXML(Expr e, std::ostream & out, Context & context)
{
XMLWriter doc(true, out);
XMLOpenElement root(doc, "expr");

View File

@ -9,7 +9,7 @@
namespace nix {
void printTermAsXML(Expr e, std::ostream & out, PathSet & context);
void printTermAsXML(Expr e, std::ostream & out, Context & context);
}

View File

@ -17,7 +17,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const
if (a && matchPath(evalExpr(state, a), t))
return aterm2String(t);
PathSet context;
Context context;
(string &) drvPath = a ? coerceToPath(state, a, context) : "";
}
return drvPath;
@ -29,7 +29,7 @@ string DrvInfo::queryOutPath(EvalState & state) const
if (outPath == "") {
Expr a = attrs->get(toATerm("outPath"));
if (!a) throw TypeError("output path missing");
PathSet context;
Context context;
(string &) outPath = coerceToPath(state, a, context);
}
return outPath;
@ -49,7 +49,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
Expr e = evalExpr(state, i->value);
string s;
PathSet context;
ATermList context;
MetaValue value;
int n;
ATermList es;

View File

@ -45,6 +45,8 @@ Int | int | Expr |
Str | string ATermList | Expr |
Str | string | Expr | ObsoleteStr
ContextElem | string Expr | ContextElem |
# Internal to the parser, doesn't occur in ASTs.
IndStr | string | Expr |

View File

@ -336,25 +336,47 @@ Expr makeBool(bool b)
}
bool matchStr(Expr e, string & s, PathSet & context)
bool matchStr(Expr e, string & s, ATermList & context)
{
ATermList l;
ATerm s_;
if (!matchStr(e, s_, l)) return false;
if (!matchStr(e, s_, context)) return false;
s = aterm2String(s_);
for (ATermIterator i(l); i; ++i)
context.insert(aterm2String(*i));
return true;
}
Expr makeStr(const string & s, const PathSet & context)
bool matchStr(Expr e, string & s, Context & context)
{
return makeStr(toATerm(s), toATermList(context));
ATermList c;
if (!matchStr(e, s, c)) return false;
matchContext(c, context);
return true;
}
Expr makeStr(const string & s, ATermList context)
{
return makeStr(toATerm(s), context);
}
Expr makeStr(const string & s, const Context & context)
{
ATermList l = ATempty;
/* !!! should define a canonical ordering of context elements. */
foreach (Context::const_iterator, i, context)
l = ATinsert(l, makeContextElem(i->key, i->value));
return makeStr(s, l);
}
void matchContext(ATermList context, Context & result)
{
for (ATermIterator i(context); i; ++i) {
ATerm s, e;
if (!matchContextElem(*i, s, e)) abort();
result.set(s, e);
}
}
@ -380,7 +402,7 @@ string showType(Expr e)
string showValue(Expr e)
{
PathSet context;
ATermList context;
string s;
ATerm s2;
int i;

View File

@ -26,6 +26,7 @@ typedef ATerm DefaultValue;
typedef ATerm Pos;
typedef ATerm Pattern;
typedef ATerm ATermBool;
typedef ATerm ContextElem;
/* A STL vector of ATerms. Should be used with great care since it's
@ -104,11 +105,18 @@ Expr canonicaliseExpr(Expr e);
Expr makeBool(bool b);
/* Manipulation of Str() nodes. Note: matchStr() does not clear
context! */
bool matchStr(Expr e, string & s, PathSet & context);
/* Manipulation of Str() nodes. */
typedef ATermMap Context;
Expr makeStr(const string & s, const PathSet & context = PathSet());
bool matchStr(Expr e, string & s, ATermList & context);
bool matchStr(Expr e, string & s, Context & context);
Expr makeStr(const string & s, ATermList context = ATempty);
Expr makeStr(const string & s, const Context & context);
void matchContext(ATermList context, Context & result);
/* Showing types, values. */

View File

@ -93,16 +93,17 @@ static Expr prim_currentTime(EvalState & state, const ATermVector & args)
argument. */
static Expr prim_import(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Path path = coerceToPath(state, args[0], context);
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
assert(isStorePath(*i));
if (!store->isValidPath(*i))
foreach (Context::const_iterator, i, context) {
Path p = aterm2String(i->key);
assert(isStorePath(p));
if (!store->isValidPath(p))
throw EvalError(format("cannot import `%1%', since path `%2%' is not valid")
% path % *i);
if (isDerivation(*i))
store->buildDerivations(singleton<PathSet>(*i));
% path % p);
if (isDerivation(p))
store->buildDerivations(singleton<PathSet>(p));
}
return evalFile(state, path);
@ -136,8 +137,8 @@ static Expr prim_isInt(EvalState & state, const ATermVector & args)
static Expr prim_isString(EvalState & state, const ATermVector & args)
{
string s;
PathSet l;
return makeBool(matchStr(evalExpr(state, args[0]), s, l));
ATermList context;
return makeBool(matchStr(evalExpr(state, args[0]), s, context));
}
/* Determine whether the argument is an Bool. */
@ -197,7 +198,7 @@ static Expr prim_genericClosure(EvalState & state, const ATermVector & args)
static Expr prim_abort(EvalState & state, const ATermVector & args)
{
PathSet context;
ATermList context;
throw Abort(format("evaluation aborted with the following error message: `%1%'") %
evalString(state, args[0], context));
}
@ -205,7 +206,7 @@ static Expr prim_abort(EvalState & state, const ATermVector & args)
static Expr prim_throw(EvalState & state, const ATermVector & args)
{
PathSet context;
ATermList context;
throw ThrownError(format("user-thrown exception: %1%") %
evalString(state, args[0], context));
}
@ -213,7 +214,7 @@ static Expr prim_throw(EvalState & state, const ATermVector & args)
static Expr prim_addErrorContext(EvalState & state, const ATermVector & args)
{
PathSet context;
ATermList context;
try {
return evalExpr(state, args[1]);
} catch (Error & e) {
@ -257,7 +258,7 @@ static Expr prim_trace(EvalState & state, const ATermVector & args)
{
Expr e = evalExpr(state, args[0]);
string s;
PathSet context;
ATermList context;
if (matchStr(e, s, context))
printMsg(lvlError, format("trace: %1%") % s);
else
@ -360,7 +361,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
/* Build the derivation expression by processing the attributes. */
Derivation drv;
PathSet context;
Context context;
string outputHash, outputHashAlgo;
bool outputHashRecursive = false;
@ -421,8 +422,8 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
/* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting
derivation. */
foreach (PathSet::iterator, i, context) {
Path path = *i;
foreach (Context::const_iterator, i, context) {
Path path = aterm2String(i->key);
/* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the
@ -523,11 +524,12 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
state.drvHashes[drvPath] = hashDerivationModulo(state, drv);
/* !!! assumes a single output */
/* XXX makeNull? */
ATermMap outAttrs(2);
outAttrs.set(toATerm("outPath"),
makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
makeAttrRHS(makeStr(outPath, ATmakeList1(makeContextElem(toATerm(drvPath), makeNull()))), makeNoPos()));
outAttrs.set(toATerm("drvPath"),
makeAttrRHS(makeStr(drvPath, singleton<PathSet>("=" + drvPath)), makeNoPos()));
makeAttrRHS(makeStr(drvPath, ATmakeList1(makeContextElem(toATerm("=" + drvPath), makeNull()))), makeNoPos()));
return makeAttrs(outAttrs);
}
@ -561,7 +563,7 @@ static Expr prim_derivationLazy(EvalState & state, const ATermVector & args)
/* Convert the argument to a path. !!! obsolete? */
static Expr prim_toPath(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
string path = coerceToPath(state, args[0], context);
return makeStr(canonPath(path), context);
}
@ -577,23 +579,23 @@ static Expr prim_toPath(EvalState & state, const ATermVector & args)
corner cases. */
static Expr prim_storePath(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Path path = canonPath(coerceToPath(state, args[0], context));
if (!isInStore(path))
throw EvalError(format("path `%1%' is not in the Nix store") % path);
Path path2 = toStorePath(path);
if (!store->isValidPath(path2))
throw EvalError(format("store path `%1%' is not valid") % path2);
context.insert(path2);
context.set(toATerm(path2), makeNull());
return makeStr(path, context);
}
static Expr prim_pathExists(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Path path = coerceToPath(state, args[0], context);
if (!context.empty())
if (context.size() != 0)
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
return makeBool(pathExists(path));
}
@ -603,7 +605,7 @@ static Expr prim_pathExists(EvalState & state, const ATermVector & args)
following the last slash. */
static Expr prim_baseNameOf(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
return makeStr(baseNameOf(coerceToString(state, args[0], context)), context);
}
@ -613,7 +615,7 @@ static Expr prim_baseNameOf(EvalState & state, const ATermVector & args)
of the argument. */
static Expr prim_dirOf(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Expr e = evalExpr(state, args[0]); ATerm dummy;
bool isPath = matchPath(e, dummy);
Path dir = dirOf(coerceToPath(state, e, context));
@ -624,9 +626,9 @@ static Expr prim_dirOf(EvalState & state, const ATermVector & args)
/* Return the contents of a file as a string. */
static Expr prim_readFile(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Path path = coerceToPath(state, args[0], context);
if (!context.empty())
if (context.size() != 0)
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
return makeStr(readFile(path));
}
@ -643,7 +645,7 @@ static Expr prim_readFile(EvalState & state, const ATermVector & args)
static Expr prim_toXML(EvalState & state, const ATermVector & args)
{
std::ostringstream out;
PathSet context;
Context context;
printTermAsXML(strictEvalExpr(state, args[0]), out, context);
return makeStr(out.str(), context);
}
@ -653,14 +655,15 @@ static Expr prim_toXML(EvalState & state, const ATermVector & args)
as an input by derivations. */
static Expr prim_toFile(EvalState & state, const ATermVector & args)
{
PathSet context;
ATermList context;
string name = evalStringNoCtx(state, args[0]);
string contents = evalString(state, args[1], context);
PathSet refs;
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
Path path = *i;
Context context2; matchContext(context, context2);
foreach (Context::const_iterator, i, context2) {
Path path = aterm2String(i->key);
if (path.at(0) == '=') path = string(path, 1);
if (isDerivation(path))
throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name);
@ -675,7 +678,7 @@ static Expr prim_toFile(EvalState & state, const ATermVector & args)
result, since `storePath' itself has references to the paths
used in args[1]. */
return makeStr(storePath, singleton<PathSet>(storePath));
return makeStr(storePath, ATmakeList1(makeContextElem(toATerm(storePath), makeNull())));
}
@ -712,9 +715,9 @@ struct FilterFromExpr : PathFilter
static Expr prim_filterSource(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
Path path = coerceToPath(state, args[1], context);
if (!context.empty())
if (context.size() != 0)
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
FilterFromExpr filter(state, args[0]);
@ -723,7 +726,7 @@ static Expr prim_filterSource(EvalState & state, const ATermVector & args)
? computeStorePathForPath(path, true, htSHA256, filter).first
: store->addToStore(path, true, htSHA256, filter);
return makeStr(dstPath, singleton<PathSet>(dstPath));
return makeStr(dstPath, ATmakeList1(makeContextElem(toATerm(dstPath), makeNull())));
}
@ -746,7 +749,7 @@ static Expr prim_attrNames(EvalState & state, const ATermVector & args)
ATermList list = ATempty;
for (StringSet::const_reverse_iterator i = names.rbegin();
i != names.rend(); ++i)
list = ATinsert(list, makeStr(*i, PathSet()));
list = ATinsert(list, makeStr(*i));
return makeList(list);
}
@ -1001,7 +1004,7 @@ static Expr prim_lessThan(EvalState & state, const ATermVector & args)
`"/nix/store/whatever..."'. */
static Expr prim_toString(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
string s = coerceToString(state, args[0], context, true, false);
return makeStr(s, context);
}
@ -1015,7 +1018,7 @@ static Expr prim_substring(EvalState & state, const ATermVector & args)
{
int start = evalInt(state, args[0]);
int len = evalInt(state, args[1]);
PathSet context;
Context context;
string s = coerceToString(state, args[2], context);
if (start < 0) throw EvalError("negative start position in `substring'");
@ -1026,7 +1029,7 @@ static Expr prim_substring(EvalState & state, const ATermVector & args)
static Expr prim_stringLength(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
string s = coerceToString(state, args[0], context);
return makeInt(s.size());
}
@ -1034,9 +1037,9 @@ static Expr prim_stringLength(EvalState & state, const ATermVector & args)
static Expr prim_unsafeDiscardStringContext(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
string s = coerceToString(state, args[0], context);
return makeStr(s, PathSet());
return makeStr(s);
}
@ -1048,14 +1051,14 @@ static Expr prim_unsafeDiscardStringContext(EvalState & state, const ATermVector
drv.inputDrvs. */
static Expr prim_unsafeDiscardOutputDependency(EvalState & state, const ATermVector & args)
{
PathSet context;
Context context;
string s = coerceToString(state, args[0], context);
PathSet context2;
foreach (PathSet::iterator, i, context) {
Path p = *i;
Context context2;
foreach (Context::const_iterator, i, context) {
Path p = aterm2String(i->key);
if (p.at(0) == '=') p = "~" + string(p, 1);
context2.insert(p);
context2.set(toATerm(p), i->value);
}
return makeStr(s, context2);
@ -1072,18 +1075,6 @@ static Expr prim_exprToString(EvalState & state, const ATermVector & args)
}
static Expr prim_stringToExpr(EvalState & state, const ATermVector & args)
{
/* !!! this can introduce arbitrary garbage terms in the
evaluator! */;
string s;
PathSet l;
if (!matchStr(evalExpr(state, args[0]), s, l))
throw EvalError("stringToExpr needs string argument!");
return ATreadFromString(s.c_str());
}
/*************************************************************
* Versions
*************************************************************/
@ -1140,10 +1131,8 @@ void EvalState::addPrimOps()
addPrimOp("__getEnv", 1, prim_getEnv);
addPrimOp("__trace", 2, prim_trace);
// Expr <-> String
addPrimOp("__exprToString", 1, prim_exprToString);
addPrimOp("__stringToExpr", 1, prim_stringToExpr);
// Derivations
addPrimOp("derivation!", 1, prim_derivationStrict);

View File

@ -2,6 +2,7 @@
#define __ATERM_MAP_H
#include <aterm1.h>
#include <aterm2.h>
#include <assert.h>

View File

@ -327,7 +327,7 @@ static bool createUserEnv(EvalState & state, DrvInfos & elems,
makeBind(toATerm("derivations"),
makeList(ATreverse(manifest)), makeNoPos()),
makeBind(toATerm("manifest"),
makeStr(manifestFile, singleton<PathSet>(manifestFile)), makeNoPos())
makeStr(manifestFile, ATmakeList1(makeContextElem(toATerm(manifestFile), makeNull()))), makeNoPos())
)));
/* Instantiate it. */

View File

@ -40,7 +40,7 @@ static bool indirectRoot = false;
static void printResult(EvalState & state, Expr e,
bool evalOnly, bool xmlOutput, const ATermMap & autoArgs)
{
PathSet context;
Context context;
if (evalOnly)
if (xmlOutput)