* Big cleanup of the semantics of paths, strings, contexts, string
concatenation and string coercion.  This was a big mess (see
  e.g. NIX-67).  Contexts are now folded into strings, so that they
  don't cause evaluation errors when they're not expected.  The
  semantics of paths has been clarified (see nixexpr-ast.def).
  toString() and coerceToString() have been merged.
  Semantic change: paths are now copied to the store when they're in a
  concatenation (and in most other situations - that's the
  formalisation of the meaning of a path).  So
    "foo " + ./bla
  evaluates to "foo /nix/store/hash...-bla", not "foo
  /path/to/current-dir/bla".  This prevents accidental impurities, and
  is more consistent with the treatment of derivation outputs, e.g.,
  `"foo " + bla' where `bla' is a derivation.  (Here `bla' would be
  replaced by the output path of `bla'.)
			
			
This commit is contained in:
		
							parent
							
								
									4c9aa821b9
								
							
						
					
					
						commit
						d7efd76394
					
				
					 17 changed files with 331 additions and 396 deletions
				
			
		|  | @ -47,6 +47,7 @@ print HEADER "#endif\n\n\n"; | ||||||
| print IMPL "namespace nix {\n"; | print IMPL "namespace nix {\n"; | ||||||
| 
 | 
 | ||||||
| while (<STDIN>) { | while (<STDIN>) { | ||||||
|  |     s/\#.*//; | ||||||
|     next if (/^\s*$/); |     next if (/^\s*$/); | ||||||
|      |      | ||||||
|     if (/^\s*(\w*)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) { |     if (/^\s*(\w*)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) { | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| #include "hash.hh" | #include "hash.hh" | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| #include "store.hh" | #include "store.hh" | ||||||
|  | #include "derivations.hh" | ||||||
| #include "nixexpr-ast.hh" | #include "nixexpr-ast.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -157,23 +158,24 @@ static Expr updateAttrs(Expr e1, Expr e2) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| string evalString(EvalState & state, Expr e) | string evalString(EvalState & state, Expr e, PathSet & context) | ||||||
| { | { | ||||||
|     e = evalExpr(state, e); |     e = evalExpr(state, e); | ||||||
|     ATerm s; |     string s; | ||||||
|     if (!matchStr(e, s)) |     if (!matchStr(e, s, context)) | ||||||
|         throw TypeError(format("value is %1% while a string was expected") % showType(e)); |         throw TypeError(format("value is %1% while a string was expected") % showType(e)); | ||||||
|     return aterm2String(s); |     return s; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Path evalPath(EvalState & state, Expr e) | string evalStringNoCtx(EvalState & state, Expr e) | ||||||
| { | { | ||||||
|     e = evalExpr(state, e); |     PathSet context; | ||||||
|     ATerm s; |     string s = evalString(state, e, context); | ||||||
|     if (!matchPath(e, s)) |     if (!context.empty()) | ||||||
|         throw TypeError(format("value is %1% while a path was expected") % showType(e)); |         throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')") | ||||||
|     return aterm2String(s); |             % s % *(context.begin())); | ||||||
|  |     return s; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -206,76 +208,84 @@ ATermList evalList(EvalState & state, Expr e) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* String concatenation and context nodes: in order to allow users to
 | static void flattenList(EvalState & state, Expr e, ATermList & result) | ||||||
|    write things like |  | ||||||
| 
 |  | ||||||
|      "--with-freetype2-library=" + freetype + "/lib" |  | ||||||
| 
 |  | ||||||
|    where `freetype' is a derivation, we automatically coerce |  | ||||||
|    derivations into their output path (e.g., |  | ||||||
|    /nix/store/hashcode-freetype) in concatenations.  However, if we do |  | ||||||
|    this naively, we could introduce an undeclared dependency: when the |  | ||||||
|    string is used in another derivation, that derivation would not |  | ||||||
|    have an explicitly dependency on `freetype' in its inputDrvs |  | ||||||
|    field.  Thus `freetype' would not necessarily be built. |  | ||||||
| 
 |  | ||||||
|    To prevent this, we wrap the string resulting from the |  | ||||||
|    concatenation in a *context node*, like this: |  | ||||||
| 
 |  | ||||||
|      Context([freetype], |  | ||||||
|        Str("--with-freetype2-library=/nix/store/hashcode-freetype/lib")) |  | ||||||
| 
 |  | ||||||
|    Thus the context is the list of all derivations used in the |  | ||||||
|    computation of a value.  These contexts are propagated through |  | ||||||
|    further concatenations.  In processBinding() in primops.cc, context |  | ||||||
|    nodes are unwrapped and added to inputDrvs. |  | ||||||
| 
 |  | ||||||
|    !!! Should the ordering of the context list have a canonical form? |  | ||||||
| 
 |  | ||||||
|    !!! Contexts are not currently recognised in most places in the |  | ||||||
|    evaluator. */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Coerce a value to a string, keeping track of contexts. */ |  | ||||||
| string coerceToStringWithContext(EvalState & state, |  | ||||||
|     ATermList & context, Expr e, bool & isPath) |  | ||||||
| { | { | ||||||
|     isPath = false; |     ATermList es; | ||||||
|  |     e = evalExpr(state, e); | ||||||
|  |     if (matchList(e, es)) | ||||||
|  |         for (ATermIterator i(es); i; ++i) | ||||||
|  |             flattenList(state, *i, result); | ||||||
|  |     else | ||||||
|  |         result = ATinsert(result, e); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | ATermList flattenList(EvalState & state, Expr e) | ||||||
|  | { | ||||||
|  |     ATermList result = ATempty; | ||||||
|  |     flattenList(state, e, result); | ||||||
|  |     return ATreverse(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | string coerceToString(EvalState & state, Expr e, PathSet & context, | ||||||
|  |     bool coerceMore, bool copyToStore) | ||||||
|  | { | ||||||
|     e = evalExpr(state, e); |     e = evalExpr(state, e); | ||||||
| 
 | 
 | ||||||
|     bool isWrapped = false; |     string s; | ||||||
|  | 
 | ||||||
|  |     if (matchStr(e, s, context)) return s; | ||||||
|  | 
 | ||||||
|  |     ATerm s2; | ||||||
|  |     if (matchPath(e, s2)) { | ||||||
|  |         Path path(canonPath(aterm2String(s2))); | ||||||
|  | 
 | ||||||
|  |         if (!copyToStore) return path; | ||||||
|  |          | ||||||
|  |         if (isDerivation(path)) | ||||||
|  |             throw EvalError(format("file names are not allowed to end in `%1%'") | ||||||
|  |                 % drvExtension); | ||||||
|  | 
 | ||||||
|  |         Path dstPath; | ||||||
|  |         if (state.srcToStore[path] != "") | ||||||
|  |             dstPath = state.srcToStore[path]; | ||||||
|  |         else { | ||||||
|  |             dstPath = addToStore(path); | ||||||
|  |             state.srcToStore[path] = dstPath; | ||||||
|  |             printMsg(lvlChatty, format("copied source `%1%' -> `%2%'") | ||||||
|  |                 % path % dstPath); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         context.insert(dstPath); | ||||||
|  |         return dstPath; | ||||||
|  |     } | ||||||
|  |          | ||||||
|     ATermList es; |     ATermList es; | ||||||
|     ATerm e2; |     if (matchAttrs(e, es)) | ||||||
|     if (matchContext(e, es, e2)) { |         return coerceToString(state, makeSelect(e, toATerm("outPath")), | ||||||
|         isWrapped = true; |             context, coerceMore, copyToStore); | ||||||
|         e = e2; | 
 | ||||||
|         context = ATconcat(es, context); |     if (coerceMore) { | ||||||
|  | 
 | ||||||
|  |         /* Note that `false' is represented as an empty string for
 | ||||||
|  |            shell scripting convenience, just like `null'. */ | ||||||
|  |         if (e == eTrue) return "1"; | ||||||
|  |         if (e == eFalse) return ""; | ||||||
|  |         int n; | ||||||
|  |         if (matchInt(e, n)) return int2String(n); | ||||||
|  |         if (matchNull(e)) return ""; | ||||||
|  | 
 | ||||||
|  |         if (matchList(e, es)) { | ||||||
|  |             string result; | ||||||
|  |             es = flattenList(state, e); | ||||||
|  |             bool first = true; | ||||||
|  |             for (ATermIterator i(es); i; ++i) { | ||||||
|  |                 if (!first) result += " "; else first = false; | ||||||
|  |                 result += coerceToString(state, *i, | ||||||
|  |                     context, coerceMore, copyToStore); | ||||||
|             } |             } | ||||||
|      |             return result; | ||||||
|     ATerm s; |  | ||||||
|     if (matchStr(e, s)) return aterm2String(s); |  | ||||||
|      |  | ||||||
|     if (matchPath(e, s)) { |  | ||||||
|         isPath = true; |  | ||||||
|         Path path = aterm2String(s); |  | ||||||
|         if (isInStore(path) && !isWrapped) { |  | ||||||
|             context = ATinsert(context, makePath(toATerm(toStorePath(path)))); |  | ||||||
|         } |  | ||||||
|         return path; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (matchAttrs(e, es)) { |  | ||||||
|         ATermMap attrs(128); /* !!! */ |  | ||||||
|         queryAllAttrs(e, attrs, false); |  | ||||||
| 
 |  | ||||||
|         Expr a = attrs.get(toATerm("type")); |  | ||||||
|         if (a && evalString(state, a) == "derivation") { |  | ||||||
|             a = attrs.get(toATerm("outPath")); |  | ||||||
|             if (!a) throw TypeError("output path missing from derivation"); |  | ||||||
|             isPath = true; |  | ||||||
|             context = ATinsert(context, e); |  | ||||||
|             return evalPath(state, a); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  | @ -283,31 +293,41 @@ string coerceToStringWithContext(EvalState & state, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Wrap an expression in a context if the context is not empty. */ | /* Common implementation of `+', ConcatStrings and `~'. */ | ||||||
| Expr wrapInContext(ATermList context, Expr e) | static ATerm concatStrings(EvalState & state, const ATermVector & args, | ||||||
|  |     string separator = "") | ||||||
| { | { | ||||||
|     return context == ATempty ? e : makeContext(context, e); |     PathSet context; | ||||||
|  |     std::ostringstream s; | ||||||
|  | 
 | ||||||
|  |     /* If the first element is a path, then the result will also be a
 | ||||||
|  |        path, we don't copy anything (yet - that's done later, since | ||||||
|  |        paths are copied when they are used in a derivation), and none | ||||||
|  |        of the strings are allowed to have contexts. */ | ||||||
|  |     ATerm dummy; | ||||||
|  |     bool isPath = !args.empty() && matchPath(args.front(), dummy); | ||||||
|  | 
 | ||||||
|  |     for (ATermVector::const_iterator i = args.begin(); i != args.end(); ++i) { | ||||||
|  |         if (i != args.begin()) s << separator; | ||||||
|  |         s << coerceToString(state, *i, context, false, !isPath); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (isPath && !context.empty()) | ||||||
|  |         throw EvalError(format("a string that refers to a store path cannot be appended to a path, in `%1%'") | ||||||
|  |             % s.str()); | ||||||
|  |      | ||||||
|  |     return isPath | ||||||
|  |         ? makePath(toATerm(s.str())) | ||||||
|  |         : makeStr(s.str(), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static ATerm concatStrings(EvalState & state, const ATermVector & args) | Path coerceToPath(EvalState & state, Expr e, PathSet & context) | ||||||
| { | { | ||||||
|     ATermList context = ATempty; |     string path = coerceToString(state, e, context, false, false); | ||||||
|     std::ostringstream s; |     if (path == "" || path[0] != '/') | ||||||
|     bool isPath = false; |         throw EvalError(format("string `%1%' doesn't represent an absolute path") % path); | ||||||
| 
 |     return path; | ||||||
|     /* Note that if the first argument in the concatenation is a path,
 |  | ||||||
|        then the result is also a path. */ |  | ||||||
| 
 |  | ||||||
|     for (ATermVector::const_iterator i = args.begin(); i != args.end(); ++i) { |  | ||||||
|         bool isPath2; |  | ||||||
|         s << coerceToStringWithContext(state, context, *i, isPath2); |  | ||||||
|         if (i == args.begin()) isPath = isPath2; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return wrapInContext(context, isPath |  | ||||||
|         ? makePath(toATerm(canonPath(s.str()))) |  | ||||||
|         : makeStr(toATerm(s.str()))); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -352,8 +372,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|         sym == symFunction1 || |         sym == symFunction1 || | ||||||
|         sym == symAttrs || |         sym == symAttrs || | ||||||
|         sym == symList || |         sym == symList || | ||||||
|         sym == symPrimOp || |         sym == symPrimOp) | ||||||
|         sym == symContext) |  | ||||||
|         return e; |         return e; | ||||||
|      |      | ||||||
|     /* The `Closed' constructor is just a way to prevent substitutions
 |     /* The `Closed' constructor is just a way to prevent substitutions
 | ||||||
|  | @ -371,6 +390,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|         ATermBlob fun; |         ATermBlob fun; | ||||||
|         if (!matchPrimOpDef(primOp, arity, fun)) abort(); |         if (!matchPrimOpDef(primOp, arity, fun)) abort(); | ||||||
|         if (arity == 0) |         if (arity == 0) | ||||||
|  |             /* !!! backtrace for primop call */ | ||||||
|             return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector()); |             return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector()); | ||||||
|         else |         else | ||||||
|             return makePrimOp(arity, fun, ATempty); |             return makePrimOp(arity, fun, ATempty); | ||||||
|  | @ -397,6 +417,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|                 ATermVector args2(arity); |                 ATermVector args2(arity); | ||||||
|                 for (ATermIterator i(args); i; ++i) |                 for (ATermIterator i(args); i; ++i) | ||||||
|                     args2[--arity] = *i; |                     args2[--arity] = *i; | ||||||
|  |                 /* !!! backtrace for primop call */ | ||||||
|                 return ((PrimOp) ATgetBlobData((ATermBlob) fun)) |                 return ((PrimOp) ATgetBlobData((ATermBlob) fun)) | ||||||
|                     (state, args2); |                     (state, args2); | ||||||
|             } else |             } else | ||||||
|  | @ -550,11 +571,10 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|     if (matchSubPath(e, e1, e2)) { |     if (matchSubPath(e, e1, e2)) { | ||||||
|         static bool haveWarned = false; |         static bool haveWarned = false; | ||||||
|         warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead"); |         warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead"); | ||||||
|         ATermList context = ATempty; |         ATermVector args; | ||||||
|         bool dummy; |         args.push_back(e1); | ||||||
|         string s1 = coerceToStringWithContext(state, context, e1, dummy); |         args.push_back(e2); | ||||||
|         string s2 = coerceToStringWithContext(state, context, e2, dummy); |         return concatStrings(state, args, "/"); | ||||||
|         return wrapInContext(context, makePath(toATerm(canonPath(s1 + "/" + s2)))); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* List concatenation. */ |     /* List concatenation. */ | ||||||
|  |  | ||||||
|  | @ -60,17 +60,26 @@ Expr strictEvalExpr(EvalState & state, Expr e, | ||||||
|     bool canonicalise = false); |     bool canonicalise = false); | ||||||
| 
 | 
 | ||||||
| /* Specific results. */ | /* Specific results. */ | ||||||
| string evalString(EvalState & state, Expr e); | string evalString(EvalState & state, Expr e, PathSet & context); | ||||||
| Path evalPath(EvalState & state, Expr e); | string evalStringNoCtx(EvalState & state, Expr e); | ||||||
| int evalInt(EvalState & state, Expr e); | int evalInt(EvalState & state, Expr e); | ||||||
| bool evalBool(EvalState & state, Expr e); | bool evalBool(EvalState & state, Expr e); | ||||||
| ATermList evalList(EvalState & state, Expr e); | ATermList evalList(EvalState & state, Expr e); | ||||||
| ATerm coerceToString(Expr e); |  | ||||||
| 
 | 
 | ||||||
| /* Contexts. */ | /* Flatten nested lists into a single list (or expand a singleton into
 | ||||||
| string coerceToStringWithContext(EvalState & state, |    a list). */ | ||||||
|     ATermList & context, Expr e, bool & isPath); | ATermList flattenList(EvalState & state, Expr e); | ||||||
| Expr wrapInContext(ATermList context, 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, | ||||||
|  |     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); | ||||||
| 
 | 
 | ||||||
| /* Automatically call a function for which each argument has a default
 | /* 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, |    value or has a binding in the `args' map.  Note: result is a call, | ||||||
|  |  | ||||||
|  | @ -15,26 +15,20 @@ static XMLAttrs singletonAttrs(const string & name, const string & value) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context) | static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context) | ||||||
| { | { | ||||||
|     XMLAttrs attrs; |     XMLAttrs attrs; | ||||||
|     ATerm s; |     string s; | ||||||
|  |     ATerm s2; | ||||||
|     int i; |     int i; | ||||||
|     Expr e2; |  | ||||||
|     ATermList as, es, formals; |     ATermList as, es, formals; | ||||||
|     ATerm body, pos; |     ATerm body, pos; | ||||||
| 
 | 
 | ||||||
|     while (matchContext(e, es, e2)) { |     if (matchStr(e, s, context)) /* !!! show the context? */ | ||||||
|         e = e2; |         doc.writeEmptyElement("string", singletonAttrs("value", s)); | ||||||
|         for (ATermIterator i(es); i; ++i) |  | ||||||
|             context = ATinsert(context, *i); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (matchStr(e, s)) |     else if (matchPath(e, s2)) | ||||||
|         doc.writeEmptyElement("string", singletonAttrs("value", aterm2String(s))); |         doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s2))); | ||||||
| 
 |  | ||||||
|     else if (matchPath(e, s)) |  | ||||||
|         doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s))); |  | ||||||
| 
 | 
 | ||||||
|     else if (matchNull(e)) |     else if (matchNull(e)) | ||||||
|         doc.writeEmptyElement("null"); |         doc.writeEmptyElement("null"); | ||||||
|  | @ -90,7 +84,7 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void printTermAsXML(Expr e, std::ostream & out, ATermList & context) | void printTermAsXML(Expr e, std::ostream & out, PathSet & context) | ||||||
| { | { | ||||||
|     XMLWriter doc(true, out); |     XMLWriter doc(true, out); | ||||||
|     XMLOpenElement root(doc, "expr"); |     XMLOpenElement root(doc, "expr"); | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| void printTermAsXML(Expr e, std::ostream & out, ATermList & context); | void printTermAsXML(Expr e, std::ostream & out, PathSet & context); | ||||||
|      |      | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,8 @@ string DrvInfo::queryDrvPath(EvalState & state) const | ||||||
| { | { | ||||||
|     if (drvPath == "") { |     if (drvPath == "") { | ||||||
|         Expr a = attrs->get(toATerm("drvPath")); |         Expr a = attrs->get(toATerm("drvPath")); | ||||||
|         (string &) drvPath = a ? evalPath(state, a) : ""; |         PathSet context; | ||||||
|  |         (string &) drvPath = a ? coerceToPath(state, a, context) : ""; | ||||||
|     } |     } | ||||||
|     return drvPath; |     return drvPath; | ||||||
| } | } | ||||||
|  | @ -21,7 +22,8 @@ string DrvInfo::queryOutPath(EvalState & state) const | ||||||
|     if (outPath == "") { |     if (outPath == "") { | ||||||
|         Expr a = attrs->get(toATerm("outPath")); |         Expr a = attrs->get(toATerm("outPath")); | ||||||
|         if (!a) throw TypeError("output path missing"); |         if (!a) throw TypeError("output path missing"); | ||||||
|         (string &) outPath = evalPath(state, a); |         PathSet context; | ||||||
|  |         (string &) outPath = coerceToPath(state, a, context); | ||||||
|     } |     } | ||||||
|     return outPath; |     return outPath; | ||||||
| } | } | ||||||
|  | @ -38,9 +40,11 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const | ||||||
|     queryAllAttrs(evalExpr(state, a), attrs2); |     queryAllAttrs(evalExpr(state, a), attrs2); | ||||||
| 
 | 
 | ||||||
|     for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) { |     for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) { | ||||||
|         ATerm s = coerceToString(evalExpr(state, i->value)); |         Expr e = evalExpr(state, i->value); | ||||||
|         if (s) |         string s; | ||||||
|             meta[aterm2String(i->key)] = aterm2String(s); |         PathSet context; | ||||||
|  |         if (matchStr(e, s, context)) | ||||||
|  |             meta[aterm2String(i->key)] = s; | ||||||
|         /* For future compatibility, ignore attribute values that are
 |         /* For future compatibility, ignore attribute values that are
 | ||||||
|            not strings. */ |            not strings. */ | ||||||
|     } |     } | ||||||
|  | @ -74,7 +78,7 @@ static bool getDerivation(EvalState & state, Expr e, | ||||||
|         queryAllAttrs(e, *attrs, false); |         queryAllAttrs(e, *attrs, false); | ||||||
|      |      | ||||||
|         Expr a = attrs->get(toATerm("type")); |         Expr a = attrs->get(toATerm("type")); | ||||||
|         if (!a || evalString(state, a) != "derivation") return true; |         if (!a || evalStringNoCtx(state, a) != "derivation") return true; | ||||||
| 
 | 
 | ||||||
|         /* Remove spurious duplicates (e.g., an attribute set like
 |         /* Remove spurious duplicates (e.g., an attribute set like
 | ||||||
|            `rec { x = derivation {...}; y = x;}'. */ |            `rec { x = derivation {...}; y = x;}'. */ | ||||||
|  | @ -86,13 +90,13 @@ static bool getDerivation(EvalState & state, Expr e, | ||||||
|         a = attrs->get(toATerm("name")); |         a = attrs->get(toATerm("name")); | ||||||
|         /* !!! We really would like to have a decent back trace here. */ |         /* !!! We really would like to have a decent back trace here. */ | ||||||
|         if (!a) throw TypeError("derivation name missing"); |         if (!a) throw TypeError("derivation name missing"); | ||||||
|         drv.name = evalString(state, a); |         drv.name = evalStringNoCtx(state, a); | ||||||
| 
 | 
 | ||||||
|         a = attrs->get(toATerm("system")); |         a = attrs->get(toATerm("system")); | ||||||
|         if (!a) |         if (!a) | ||||||
|             drv.system = "unknown"; |             drv.system = "unknown"; | ||||||
|         else |         else | ||||||
|             drv.system = evalString(state, a); |             drv.system = evalStringNoCtx(state, a); | ||||||
| 
 | 
 | ||||||
|         drv.attrs = attrs; |         drv.attrs = attrs; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ static Expr unescapeStr(const char * s) | ||||||
|         } |         } | ||||||
|         else t += c; |         else t += c; | ||||||
|     } |     } | ||||||
|     return makeStr(toATerm(t)); |     return makeStr(toATerm(t), ATempty); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -24,8 +24,37 @@ Call | Expr Expr | Expr | | ||||||
| Select | Expr string | Expr | | Select | Expr string | Expr | | ||||||
| Var | string | Expr | | Var | string | Expr | | ||||||
| Int | int | Expr | | Int | int | Expr | | ||||||
| Str | string | Expr | | 
 | ||||||
|  | # Strings in the evaluator carry a so-called `context' (the ATermList) | ||||||
|  | # which is a list of strings representing store paths.  This is to | ||||||
|  | # allow users to write things like | ||||||
|  | # | ||||||
|  | #   "--with-freetype2-library=" + freetype + "/lib" | ||||||
|  | # | ||||||
|  | # where `freetype' is a derivation (or a source to be copied to the | ||||||
|  | # store).  If we just concatenated the strings without keeping track | ||||||
|  | # of the referenced store paths, then if the string is used as a | ||||||
|  | # derivation attribute, the derivation will not have the correct | ||||||
|  | # dependencies in its inputDrvs and inputSrcs. | ||||||
|  | # | ||||||
|  | # The semantics of the context is as follows: when a string with | ||||||
|  | # context C is used as a derivation attribute, then the derivations in | ||||||
|  | # C will be added to the inputDrvs of the derivation, and the other | ||||||
|  | # store paths in C will be added to the inputSrcs of the derivations. | ||||||
|  | # | ||||||
|  | # For canonicity, the store paths should be in sorted order. | ||||||
|  | Str | string ATermList | Expr | | ||||||
|  | 
 | ||||||
|  | # A path is a reference to a file system object that is to be copied | ||||||
|  | # to the Nix store when used as a derivation attribute.  When it is | ||||||
|  | # concatenated to a string (i.e., `str + path'), it is also copied and | ||||||
|  | # the resulting store path is concatenated to the string (with the | ||||||
|  | # store path in the context).  If a string or path is concatenated to | ||||||
|  | # a path (i.e., `path + str' or `path + path'), the result is a new | ||||||
|  | # path (if the right-hand side is a string, the context must be | ||||||
|  | # empty). | ||||||
| Path | string | Expr | | Path | string | Expr | | ||||||
|  | 
 | ||||||
| List | ATermList | Expr | | List | ATermList | Expr | | ||||||
| BlackHole | | Expr | | BlackHole | | Expr | | ||||||
| Undefined | | Expr | | Undefined | | Expr | | ||||||
|  | @ -36,7 +65,6 @@ Closed | Expr | Expr | | ||||||
| Rec | ATermList ATermList | Expr | | Rec | ATermList ATermList | Expr | | ||||||
| Bool | ATerm | Expr | | Bool | ATerm | Expr | | ||||||
| Null | | Expr | | Null | | Expr | | ||||||
| Context | ATermList Expr | Expr | |  | ||||||
| 
 | 
 | ||||||
| Bind | string Expr Pos | ATerm | | Bind | string Expr Pos | ATerm | | ||||||
| Bind | string Expr | ATerm | Bind2 | Bind | string Expr | ATerm | Bind2 | ||||||
|  |  | ||||||
|  | @ -293,13 +293,35 @@ Expr makeBool(bool b) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | bool matchStr(Expr e, string & s, PathSet & context) | ||||||
|  | { | ||||||
|  |     ATermList l; | ||||||
|  |     ATerm s_; | ||||||
|  | 
 | ||||||
|  |     if (!matchStr(e, s_, l)) 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) | ||||||
|  | { | ||||||
|  |     return makeStr(toATerm(s), toATermList(context)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| string showType(Expr e) | string showType(Expr e) | ||||||
| { | { | ||||||
|     ATerm t1, t2, t3; |     ATerm t1, t2, t3; | ||||||
|     ATermList l1; |     ATermList l1; | ||||||
|     ATermBlob b1; |     ATermBlob b1; | ||||||
|     int i1; |     int i1; | ||||||
|     if (matchStr(e, t1)) return "a string"; |     if (matchStr(e, t1, l1)) return "a string"; | ||||||
|     if (matchPath(e, t1)) return "a path"; |     if (matchPath(e, t1)) return "a path"; | ||||||
|     if (matchNull(e)) return "null"; |     if (matchNull(e)) return "null"; | ||||||
|     if (matchInt(e, i1)) return "an integer"; |     if (matchInt(e, i1)) return "an integer"; | ||||||
|  | @ -309,18 +331,19 @@ string showType(Expr e) | ||||||
|     if (matchAttrs(e, l1)) return "an attribute set"; |     if (matchAttrs(e, l1)) return "an attribute set"; | ||||||
|     if (matchList(e, l1)) return "a list"; |     if (matchList(e, l1)) return "a list"; | ||||||
|     if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function"; |     if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function"; | ||||||
|     if (matchContext(e, l1, t1)) return "a context containing " + showType(t1); |  | ||||||
|     return "an unknown type"; |     return "an unknown type"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| string showValue(Expr e) | string showValue(Expr e) | ||||||
| { | { | ||||||
|     ATerm s; |     PathSet context; | ||||||
|  |     string s; | ||||||
|  |     ATerm s2; | ||||||
|     int i; |     int i; | ||||||
|     if (matchStr(e, s)) { |     if (matchStr(e, s, context)) { | ||||||
|         string t = aterm2String(s), u; |         string u; | ||||||
|         for (string::iterator i = t.begin(); i != t.end(); ++i) |         for (string::iterator i = s.begin(); i != s.end(); ++i) | ||||||
|             if (*i == '\"' || *i == '\\') u += "\\" + *i; |             if (*i == '\"' || *i == '\\') u += "\\" + *i; | ||||||
|             else if (*i == '\n') u += "\\n"; |             else if (*i == '\n') u += "\\n"; | ||||||
|             else if (*i == '\r') u += "\\r"; |             else if (*i == '\r') u += "\\r"; | ||||||
|  | @ -328,7 +351,7 @@ string showValue(Expr e) | ||||||
|             else u += *i; |             else u += *i; | ||||||
|         return "\"" + u + "\""; |         return "\"" + u + "\""; | ||||||
|     } |     } | ||||||
|     if (matchPath(e, s)) return aterm2String(s); |     if (matchPath(e, s2)) return aterm2String(s2); | ||||||
|     if (matchNull(e)) return "null"; |     if (matchNull(e)) return "null"; | ||||||
|     if (matchInt(e, i)) return (format("%1%") % i).str(); |     if (matchInt(e, i)) return (format("%1%") % i).str(); | ||||||
|     if (e == eTrue) return "true"; |     if (e == eTrue) return "true"; | ||||||
|  |  | ||||||
|  | @ -71,6 +71,7 @@ struct TermFun | ||||||
| }; | }; | ||||||
| ATerm bottomupRewrite(TermFun & f, ATerm e); | ATerm bottomupRewrite(TermFun & f, ATerm e); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Query all attributes in an attribute set expression.  The
 | /* Query all attributes in an attribute set expression.  The
 | ||||||
|    expression must be in normal form. */ |    expression must be in normal form. */ | ||||||
| void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false); | void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false); | ||||||
|  | @ -83,16 +84,28 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos); | ||||||
| /* Create an attribute set expression from an Attrs value. */ | /* Create an attribute set expression from an Attrs value. */ | ||||||
| Expr makeAttrs(const ATermMap & attrs); | Expr makeAttrs(const ATermMap & attrs); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Perform a set of substitutions on an expression. */ | /* Perform a set of substitutions on an expression. */ | ||||||
| Expr substitute(const Substitution & subs, Expr e); | Expr substitute(const Substitution & subs, Expr e); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Check whether all variables are defined in the given expression.
 | /* Check whether all variables are defined in the given expression.
 | ||||||
|    Throw an exception if this isn't the case. */ |    Throw an exception if this isn't the case. */ | ||||||
| void checkVarDefs(const ATermMap & def, Expr e); | void checkVarDefs(const ATermMap & def, Expr e); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Create an expression representing a boolean. */ | /* Create an expression representing a boolean. */ | ||||||
| Expr makeBool(bool b); | Expr makeBool(bool b); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | /* Manipulation of Str() nodes.  Note: matchStr() does not clear
 | ||||||
|  |    context!  */ | ||||||
|  | bool matchStr(Expr e, string & s, PathSet & context); | ||||||
|  | 
 | ||||||
|  | Expr makeStr(const string & s, const PathSet & context = PathSet()); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* Showing types, values. */ | ||||||
| string showType(Expr e); | string showType(Expr e); | ||||||
| 
 | 
 | ||||||
| string showValue(Expr e); | string showValue(Expr e); | ||||||
|  |  | ||||||
|  | @ -195,12 +195,12 @@ expr_simple | ||||||
|   | INT { $$ = makeInt(ATgetInt((ATermInt) $1)); } |   | INT { $$ = makeInt(ATgetInt((ATermInt) $1)); } | ||||||
|   | '"' string_parts '"' { |   | '"' string_parts '"' { | ||||||
|       /* For efficiency, and to simplify parse trees a bit. */ |       /* For efficiency, and to simplify parse trees a bit. */ | ||||||
|       if ($2 == ATempty) $$ = makeStr(toATerm("")); |       if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty); | ||||||
|       else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2); |       else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2); | ||||||
|       else $$ = makeConcatStrings(ATreverse($2)); |       else $$ = makeConcatStrings(ATreverse($2)); | ||||||
|   } |   } | ||||||
|   | PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); } |   | PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); } | ||||||
|   | URI { $$ = makeStr($1); } |   | URI { $$ = makeStr($1, ATempty); } | ||||||
|   | '(' expr ')' { $$ = $2; } |   | '(' expr ')' { $$ = $2; } | ||||||
|   /* Let expressions `let {..., body = ...}' are just desugared |   /* Let expressions `let {..., body = ...}' are just desugared | ||||||
|      into `(rec {..., body = ...}).body'. */ |      into `(rec {..., body = ...}).body'. */ | ||||||
|  |  | ||||||
|  | @ -13,16 +13,6 @@ | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static Expr unwrapContext(EvalState & state, Expr e, ATermList & context) |  | ||||||
| { |  | ||||||
|     context = ATempty; |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     if (matchContext(e, context, e)) |  | ||||||
|         e = evalExpr(state, e); |  | ||||||
|     return e; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr primBuiltins(EvalState & state, const ATermVector & args) | static Expr primBuiltins(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     /* Return an attribute set containing all primops.  This allows
 |     /* Return an attribute set containing all primops.  This allows
 | ||||||
|  | @ -51,34 +41,10 @@ static Expr primBuiltins(EvalState & state, const ATermVector & args) | ||||||
|    argument. */  |    argument. */  | ||||||
| static Expr primImport(EvalState & state, const ATermVector & args) | static Expr primImport(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     ATermList es; |     PathSet context; | ||||||
|     Path path; |     Path path = coerceToPath(state, args[0], context); | ||||||
|     ATermList context; /* don't care the context */ |  | ||||||
|      |      | ||||||
|     Expr arg = unwrapContext(state, args[0], context), arg2; |     /* !!! build the derivations in context */ | ||||||
|      |  | ||||||
|     if (matchPath(arg, arg2)) |  | ||||||
|         path = aterm2String(arg2); |  | ||||||
| 
 |  | ||||||
|     else if (matchAttrs(arg, es)) { |  | ||||||
|         Expr a = queryAttr(arg, "type"); |  | ||||||
| 
 |  | ||||||
|         /* If it is a derivation, we have to realise it and load the
 |  | ||||||
|            Nix expression created at the derivation's output path. */ |  | ||||||
|         if (a && evalString(state, a) == "derivation") { |  | ||||||
|             a = queryAttr(arg, "drvPath"); |  | ||||||
|             if (!a) throw EvalError("bad derivation in import"); |  | ||||||
|             Path drvPath = evalPath(state, a); |  | ||||||
| 
 |  | ||||||
|             buildDerivations(singleton<PathSet>(drvPath)); |  | ||||||
|   |  | ||||||
|             a = queryAttr(arg, "outPath"); |  | ||||||
|             if (!a) throw EvalError("bad derivation in import"); |  | ||||||
|             path = evalPath(state, a); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     else throw TypeError(format("argument of `import' is %1% while a path or derivation is required") % showType(arg)); |  | ||||||
| 
 | 
 | ||||||
|     return evalFile(state, path); |     return evalFile(state, path); | ||||||
| } | } | ||||||
|  | @ -86,117 +52,11 @@ static Expr primImport(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
| static Expr primPathExists(EvalState & state, const ATermVector & args) | static Expr primPathExists(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     Expr arg = evalExpr(state, args[0]), arg2; |     PathSet context; | ||||||
|      |     Path path = coerceToPath(state, args[0], context); | ||||||
|     if (!matchPath(arg, arg2)) |     if (!context.empty()) | ||||||
|         throw TypeError("`pathExists' requires a path as its argument"); |         throw EvalError(format("string `%1%' cannot refer to other paths") % path); | ||||||
| 
 |     return makeBool(pathExists(path)); | ||||||
|     return makeBool(pathExists(aterm2String(arg2))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static void flattenList(EvalState & state, Expr e, ATermList & result) |  | ||||||
| { |  | ||||||
|     ATermList es; |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
|     if (matchList(e, es)) |  | ||||||
|         for (ATermIterator i(es); i; ++i) |  | ||||||
|             flattenList(state, *i, result); |  | ||||||
|     else |  | ||||||
|         result = ATinsert(result, e); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ATermList flattenList(EvalState & state, Expr e) |  | ||||||
| { |  | ||||||
|     ATermList result = ATempty; |  | ||||||
|     flattenList(state, e, result); |  | ||||||
|     return ATreverse(result); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void toString(EvalState & state, Expr e, |  | ||||||
|     ATermList & context, string & result) |  | ||||||
| { |  | ||||||
|     e = evalExpr(state, e); |  | ||||||
| 
 |  | ||||||
|     ATerm s; |  | ||||||
|     ATermList es; |  | ||||||
|     int n; |  | ||||||
|     Expr e2; |  | ||||||
| 
 |  | ||||||
|     bool isWrapped = false; |  | ||||||
|     while (matchContext(e, es, e2)) { |  | ||||||
|         isWrapped = true; |  | ||||||
|         e = e2; |  | ||||||
|         for (ATermIterator i(es); i; ++i) |  | ||||||
|             context = ATinsert(context, *i); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Note that `false' is represented as an empty string for shell
 |  | ||||||
|        scripting convenience, just like `null'. */ |  | ||||||
|      |  | ||||||
|     if (matchStr(e, s)) result += aterm2String(s); |  | ||||||
|     else if (e == eTrue) result += "1"; |  | ||||||
|     else if (e == eFalse) ;  |  | ||||||
|     else if (matchInt(e, n)) result += int2String(n); |  | ||||||
|     else if (matchNull(e)) ; |  | ||||||
|      |  | ||||||
|     else if (matchAttrs(e, es)) { |  | ||||||
|         Expr a = queryAttr(e, "type"); |  | ||||||
|          |  | ||||||
|         if (a && evalString(state, a) == "derivation") { |  | ||||||
|             Expr a2 = queryAttr(e, "outPath"); |  | ||||||
|             if (!a2) throw EvalError("output path missing"); |  | ||||||
|             result += evalPath(state, a2); |  | ||||||
|             context = ATinsert(context, e); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         else throw TypeError("cannot convert an attribute set to a string"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     else if (matchPath(e, s)) { |  | ||||||
|         Path path(canonPath(aterm2String(s))); |  | ||||||
| 
 |  | ||||||
|         if (isStorePath(path) || (isWrapped && isInStore(path))) { |  | ||||||
|             result += path; |  | ||||||
|             /* !!! smells hacky.  Check whether this is the Right
 |  | ||||||
|                Thing To Do. */ |  | ||||||
|             if (!isWrapped) |  | ||||||
|                 context = ATinsert(context, makePath(toATerm(toStorePath(path)))); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         else { |  | ||||||
|             if (isDerivation(path)) |  | ||||||
|                 throw EvalError(format("file names are not allowed to end in `%1%'") |  | ||||||
|                     % drvExtension); |  | ||||||
| 
 |  | ||||||
|             Path dstPath; |  | ||||||
|             if (state.srcToStore[path] != "") |  | ||||||
|                 dstPath = state.srcToStore[path]; |  | ||||||
|             else { |  | ||||||
|                 dstPath = addToStore(path); |  | ||||||
|                 state.srcToStore[path] = dstPath; |  | ||||||
|                 printMsg(lvlChatty, format("copied source `%1%' -> `%2%'") |  | ||||||
|                     % path % dstPath); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             result += dstPath; |  | ||||||
|             context = ATinsert(context, makePath(toATerm(dstPath))); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     else if (matchList(e, es)) { |  | ||||||
|         es = flattenList(state, e); |  | ||||||
|         bool first = true; |  | ||||||
|         for (ATermIterator i(es); i; ++i) { |  | ||||||
|             if (!first) result += " "; else first = false; |  | ||||||
|             toString(state, *i, context, result); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     else throw TypeError(format("cannot convert %1% to a string") % showType(e)); |  | ||||||
|      |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -275,11 +135,13 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
|         throw EvalError("required attribute `name' missing"); |         throw EvalError("required attribute `name' missing"); | ||||||
|     ATerm posDrvName; |     ATerm posDrvName; | ||||||
|     if (!matchAttrRHS(eDrvName, eDrvName, posDrvName)) abort(); |     if (!matchAttrRHS(eDrvName, eDrvName, posDrvName)) abort(); | ||||||
|     string drvName = evalString(state, eDrvName); |     string drvName = evalStringNoCtx(state, eDrvName); | ||||||
| 
 | 
 | ||||||
|     /* Build the derivation expression by processing the attributes. */ |     /* Build the derivation expression by processing the attributes. */ | ||||||
|     Derivation drv; |     Derivation drv; | ||||||
|      |      | ||||||
|  |     PathSet context; | ||||||
|  | 
 | ||||||
|     string outputHash; |     string outputHash; | ||||||
|     string outputHashAlgo; |     string outputHashAlgo; | ||||||
|     bool outputHashRecursive = false; |     bool outputHashRecursive = false; | ||||||
|  | @ -294,8 +156,6 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| 
 | 
 | ||||||
|             ATermList context = ATempty; |  | ||||||
| 
 |  | ||||||
|             /* The `args' attribute is special: it supplies the
 |             /* The `args' attribute is special: it supplies the
 | ||||||
|                command-line arguments to the builder. */ |                command-line arguments to the builder. */ | ||||||
|             if (key == "args") { |             if (key == "args") { | ||||||
|  | @ -307,8 +167,7 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
|                     es = flattenList(state, value); |                     es = flattenList(state, value); | ||||||
|                 } |                 } | ||||||
|                 for (ATermIterator i(es); i; ++i) { |                 for (ATermIterator i(es); i; ++i) { | ||||||
|                     string s; |                     string s = coerceToString(state, *i, context, true); | ||||||
|                     toString(state, *i, context, s); |  | ||||||
|                     drv.args.push_back(s); |                     drv.args.push_back(s); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -316,8 +175,7 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
|             /* All other attributes are passed to the builder through
 |             /* All other attributes are passed to the builder through
 | ||||||
|                the environment. */ |                the environment. */ | ||||||
|             else { |             else { | ||||||
|                 string s; |                 string s = coerceToString(state, value, context, true); | ||||||
|                 toString(state, value, context, s); |  | ||||||
|                 drv.env[key] = s; |                 drv.env[key] = s; | ||||||
|                 if (key == "builder") drv.builder = s; |                 if (key == "builder") drv.builder = s; | ||||||
|                 else if (key == "system") drv.platform = s; |                 else if (key == "system") drv.platform = s; | ||||||
|  | @ -331,32 +189,6 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /* Everything in the context of the expression should be
 |  | ||||||
|                added as dependencies of the resulting derivation. */ |  | ||||||
| 
 |  | ||||||
|             for (ATermIterator i(context); i; ++i) { |  | ||||||
| 
 |  | ||||||
|                 ATerm s; |  | ||||||
|                 ATermList as; |  | ||||||
|                  |  | ||||||
|                 if (matchPath(*i, s)) { |  | ||||||
|                     assert(isStorePath(aterm2String(s))); |  | ||||||
|                     drv.inputSrcs.insert(aterm2String(s)); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 else if (matchAttrs(*i, as)) { |  | ||||||
|                     Expr a = queryAttr(*i, "type"); |  | ||||||
|                     assert(a && evalString(state, a) == "derivation"); |  | ||||||
| 
 |  | ||||||
|                     Expr a2 = queryAttr(*i, "drvPath"); |  | ||||||
|                     if (!a2) throw EvalError("derivation path missing"); |  | ||||||
| 
 |  | ||||||
|                     drv.inputDrvs[evalPath(state, a2)] = singleton<StringSet>("out"); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 else abort(); |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|         } catch (Error & e) { |         } catch (Error & e) { | ||||||
|             e.addPrefix(format("while processing the derivation attribute `%1%' at %2%:\n") |             e.addPrefix(format("while processing the derivation attribute `%1%' at %2%:\n") | ||||||
|                 % key % showPos(pos)); |                 % key % showPos(pos)); | ||||||
|  | @ -367,6 +199,18 @@ static Expr primDerivationStrict(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. */ | ||||||
|  |     for (PathSet::iterator i = context.begin(); i != context.end(); ++i) { | ||||||
|  |         debug(format("derivation uses `%1%'") % *i); | ||||||
|  |         assert(isStorePath(*i)); | ||||||
|  |         if (isDerivation(*i)) | ||||||
|  |             drv.inputDrvs[*i] = singleton<StringSet>("out"); | ||||||
|  |         else | ||||||
|  |             drv.inputSrcs.insert(*i); | ||||||
|  |     } | ||||||
|  |              | ||||||
|     /* Do we have all required attributes? */ |     /* Do we have all required attributes? */ | ||||||
|     if (drv.builder == "") |     if (drv.builder == "") | ||||||
|         throw EvalError("required attribute `builder' missing"); |         throw EvalError("required attribute `builder' missing"); | ||||||
|  | @ -434,9 +278,9 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args) | ||||||
|     /* !!! assumes a single output */ |     /* !!! assumes a single output */ | ||||||
|     ATermMap outAttrs(2); |     ATermMap outAttrs(2); | ||||||
|     outAttrs.set(toATerm("outPath"), |     outAttrs.set(toATerm("outPath"), | ||||||
|         makeAttrRHS(makePath(toATerm(outPath)), makeNoPos())); |         makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos())); | ||||||
|     outAttrs.set(toATerm("drvPath"), |     outAttrs.set(toATerm("drvPath"), | ||||||
|         makeAttrRHS(makePath(toATerm(drvPath)), makeNoPos())); |         makeAttrRHS(makeStr(drvPath, singleton<PathSet>(drvPath)), makeNoPos())); | ||||||
| 
 | 
 | ||||||
|     return makeAttrs(outAttrs); |     return makeAttrs(outAttrs); | ||||||
| } | } | ||||||
|  | @ -449,7 +293,7 @@ static Expr primDerivationLazy(EvalState & state, const ATermVector & args) | ||||||
|     queryAllAttrs(eAttrs, attrs, true); |     queryAllAttrs(eAttrs, attrs, true); | ||||||
| 
 | 
 | ||||||
|     attrs.set(toATerm("type"), |     attrs.set(toATerm("type"), | ||||||
|         makeAttrRHS(makeStr(toATerm("derivation")), makeNoPos())); |         makeAttrRHS(makeStr("derivation"), makeNoPos())); | ||||||
| 
 | 
 | ||||||
|     Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs); |     Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs); | ||||||
| 
 | 
 | ||||||
|  | @ -466,7 +310,8 @@ static Expr primDerivationLazy(EvalState & state, const ATermVector & args) | ||||||
|    following the last slash. */ |    following the last slash. */ | ||||||
| static Expr primBaseNameOf(EvalState & state, const ATermVector & args) | static Expr primBaseNameOf(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     return makeStr(toATerm(baseNameOf(evalString(state, args[0])))); |     PathSet context; | ||||||
|  |     return makeStr(baseNameOf(coerceToPath(state, args[0], context)), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -474,39 +319,29 @@ static Expr primBaseNameOf(EvalState & state, const ATermVector & args) | ||||||
|    last slash. */ |    last slash. */ | ||||||
| static Expr primDirOf(EvalState & state, const ATermVector & args) | static Expr primDirOf(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     return makePath(toATerm(dirOf(evalPath(state, args[0])))); |     PathSet context; | ||||||
|  |     return makeStr(dirOf(coerceToPath(state, args[0], context)), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ATerm coerceToString(Expr e) | /* Convert the argument to a string. */ | ||||||
| { |  | ||||||
|     ATerm s; |  | ||||||
|     if (matchStr(e, s) || matchPath(e, s)) |  | ||||||
|         return s; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Convert the argument (which can be a path or a uri) to a string. */ |  | ||||||
| static Expr primToString(EvalState & state, const ATermVector & args) | static Expr primToString(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     ATermList context = ATempty; |     PathSet context; | ||||||
|     bool dummy; |     string s = coerceToString(state, args[0], context); | ||||||
|     string s = coerceToStringWithContext(state, context, args[0], dummy); |     /* !!! do lists etc */ | ||||||
|     return wrapInContext(context, makeStr(toATerm(s))); |     return makeStr(s, context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Convert the argument to a path. */ | /* Convert the argument to a path.  !!! obsolete? */ | ||||||
| static Expr primToPath(EvalState & state, const ATermVector & args) | static Expr primToPath(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     Expr e = evalExpr(state, args[0]); |     PathSet context; | ||||||
|     ATerm t = coerceToString(e); |     string path = evalString(state, args[0], context); | ||||||
|     if (!t) throw TypeError(format("cannot coerce %1% to a path in `toPath'") % showType(e)); |  | ||||||
|     Path path = aterm2String(t); |  | ||||||
|     if (path == "" || path[0] != '/') |     if (path == "" || path[0] != '/') | ||||||
|         throw EvalError("string doesn't represent an absolute path in `toPath'"); |         throw EvalError("string doesn't represent an absolute path in `toPath'"); | ||||||
|     return makePath(toATerm(canonPath(path))); |     return makeStr(canonPath(path), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -516,9 +351,9 @@ static Expr primToPath(EvalState & state, const ATermVector & args) | ||||||
| static Expr primToXML(EvalState & state, const ATermVector & args) | static Expr primToXML(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     std::ostringstream out; |     std::ostringstream out; | ||||||
|     ATermList context = ATempty; |     PathSet context; | ||||||
|     printTermAsXML(strictEvalExpr(state, args[0]), out, context); |     printTermAsXML(strictEvalExpr(state, args[0]), out, context); | ||||||
|     return wrapInContext(context, makeStr(toATerm(out.str()))); |     return makeStr(out.str(), context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -526,13 +361,14 @@ static Expr primToXML(EvalState & state, const ATermVector & args) | ||||||
|    as an input by derivations. */ |    as an input by derivations. */ | ||||||
| static Expr primToFile(EvalState & state, const ATermVector & args) | static Expr primToFile(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     ATermList context; |     PathSet context; | ||||||
|     string name = evalString(state, args[0]); |     string name = evalStringNoCtx(state, args[0]); | ||||||
|     string contents = evalString(state, |     string contents = evalString(state, args[1], context); | ||||||
|         unwrapContext(state, args[1], context)); |  | ||||||
| 
 | 
 | ||||||
|     PathSet refs; |     PathSet refs; | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
|  |     /* !!! */ | ||||||
|     for (ATermIterator i(context); i; ++i) { |     for (ATermIterator i(context); i; ++i) { | ||||||
|         ATerm s; |         ATerm s; | ||||||
|         if (matchPath(*i, s)) { |         if (matchPath(*i, s)) { | ||||||
|  | @ -541,13 +377,15 @@ static Expr primToFile(EvalState & state, const ATermVector & args) | ||||||
|         } |         } | ||||||
|         else throw EvalError("in `toFile': the file cannot contain references to derivation outputs"); |         else throw EvalError("in `toFile': the file cannot contain references to derivation outputs"); | ||||||
|     } |     } | ||||||
|  | #endif     | ||||||
|      |      | ||||||
|     Path storePath = addTextToStore(name, contents, refs); |     Path storePath = addTextToStore(name, contents, refs); | ||||||
| 
 | 
 | ||||||
|     /* Note: we don't need to wrap the result in a context, since
 |     /* Note: we don't need to add `context' to the context of the
 | ||||||
|        `storePath' itself has references to the paths used in |        result, since `storePath' itself has references to the paths | ||||||
|        args[1]. */ |        used in args[1]. */ | ||||||
|     return makePath(toATerm(storePath)); |      | ||||||
|  |     return makeStr(storePath, singleton<PathSet>(storePath)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -652,7 +490,8 @@ static Expr primDependencyClosure(EvalState & state, const ATermVector & args) | ||||||
|     Path pivot; |     Path pivot; | ||||||
|     PathSet workSet; |     PathSet workSet; | ||||||
|     for (ATermIterator i(startSet2); i; ++i) { |     for (ATermIterator i(startSet2); i; ++i) { | ||||||
|         Path p = evalPath(state, *i); |         PathSet context; /* !!! what to do? */ | ||||||
|  |         Path p = coerceToPath(state, *i, context); | ||||||
|         workSet.insert(p); |         workSet.insert(p); | ||||||
|         pivot = dirOf(p); |         pivot = dirOf(p); | ||||||
|     } |     } | ||||||
|  | @ -663,7 +502,8 @@ static Expr primDependencyClosure(EvalState & state, const ATermVector & args) | ||||||
|     if (e) { |     if (e) { | ||||||
|         ATermList list = evalList(state, e); |         ATermList list = evalList(state, e); | ||||||
|         for (ATermIterator i(list); i; ++i) { |         for (ATermIterator i(list); i; ++i) { | ||||||
|             Path p = evalPath(state, *i); |             PathSet context; /* !!! what to do? */ | ||||||
|  |             Path p = coerceToPath(state, *i, context); | ||||||
|             searchPath.insert(p); |             searchPath.insert(p); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -686,11 +526,11 @@ static Expr primDependencyClosure(EvalState & state, const ATermVector & args) | ||||||
|              |              | ||||||
|             /* Call the `scanner' function with `path' as argument. */ |             /* Call the `scanner' function with `path' as argument. */ | ||||||
|             debug(format("finding dependencies in `%1%'") % path); |             debug(format("finding dependencies in `%1%'") % path); | ||||||
|             ATermList deps = evalList(state, makeCall(scanner, makePath(toATerm(path)))); |             ATermList deps = evalList(state, makeCall(scanner, makeStr(path))); | ||||||
| 
 | 
 | ||||||
|             /* Try to find the dependencies relative to the `path'. */ |             /* Try to find the dependencies relative to the `path'. */ | ||||||
|             for (ATermIterator i(deps); i; ++i) { |             for (ATermIterator i(deps); i; ++i) { | ||||||
|                 string s = evalString(state, *i); |                 string s = evalStringNoCtx(state, *i); | ||||||
|                  |                  | ||||||
|                 Path dep = findDependency(dirOf(path), s); |                 Path dep = findDependency(dirOf(path), s); | ||||||
| 
 | 
 | ||||||
|  | @ -721,8 +561,8 @@ static Expr primDependencyClosure(EvalState & state, const ATermVector & args) | ||||||
|     /* Return a list of the dependencies we've just found. */ |     /* Return a list of the dependencies we've just found. */ | ||||||
|     ATermList deps = ATempty; |     ATermList deps = ATempty; | ||||||
|     for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) { |     for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) { | ||||||
|         deps = ATinsert(deps, makeStr(toATerm(relativise(pivot, *i)))); |         deps = ATinsert(deps, makeStr(relativise(pivot, *i))); | ||||||
|         deps = ATinsert(deps, makePath(toATerm(*i))); |         deps = ATinsert(deps, makeStr(*i)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     debug(format("dependency list is `%1%'") % makeList(deps)); |     debug(format("dependency list is `%1%'") % makeList(deps)); | ||||||
|  | @ -733,8 +573,9 @@ static Expr primDependencyClosure(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
| static Expr primAbort(EvalState & state, const ATermVector & args) | static Expr primAbort(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|  |     PathSet context; | ||||||
|     throw Abort(format("evaluation aborted with the following error message: `%1%'") % |     throw Abort(format("evaluation aborted with the following error message: `%1%'") % | ||||||
|         evalString(state, args[0])); |         evalString(state, args[0], context)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -762,8 +603,8 @@ static Expr primTail(EvalState & state, const ATermVector & args) | ||||||
| /* Return an environment variable.  Use with care. */ | /* Return an environment variable.  Use with care. */ | ||||||
| static Expr primGetEnv(EvalState & state, const ATermVector & args) | static Expr primGetEnv(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     string name = evalString(state, args[0]); |     string name = evalStringNoCtx(state, args[0]); | ||||||
|     return makeStr(toATerm(getEnv(name))); |     return makeStr(getEnv(name)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -787,7 +628,7 @@ static Expr primMap(EvalState & state, const ATermVector & args) | ||||||
|    platforms. */ |    platforms. */ | ||||||
| static Expr primCurrentSystem(EvalState & state, const ATermVector & args) | static Expr primCurrentSystem(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     return makeStr(toATerm(thisSystem)); |     return makeStr(thisSystem); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -800,7 +641,7 @@ static Expr primCurrentTime(EvalState & state, const ATermVector & args) | ||||||
| /* Dynamic version of the `.' operator. */ | /* Dynamic version of the `.' operator. */ | ||||||
| static Expr primGetAttr(EvalState & state, const ATermVector & args) | static Expr primGetAttr(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     string attr = evalString(state, args[0]); |     string attr = evalStringNoCtx(state, args[0]); | ||||||
|     return evalExpr(state, makeSelect(args[1], toATerm(attr))); |     return evalExpr(state, makeSelect(args[1], toATerm(attr))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -808,7 +649,7 @@ static Expr primGetAttr(EvalState & state, const ATermVector & args) | ||||||
| /* Dynamic version of the `?' operator. */ | /* Dynamic version of the `?' operator. */ | ||||||
| static Expr primHasAttr(EvalState & state, const ATermVector & args) | static Expr primHasAttr(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     string attr = evalString(state, args[0]); |     string attr = evalStringNoCtx(state, args[0]); | ||||||
|     return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr))); |     return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -822,7 +663,7 @@ static Expr primRemoveAttrs(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
|     for (ATermIterator i(list); i; ++i) |     for (ATermIterator i(list); i; ++i) | ||||||
|         /* It's not an error for *i not to exist. */ |         /* It's not an error for *i not to exist. */ | ||||||
|         attrs.remove(toATerm(evalString(state, *i))); |         attrs.remove(toATerm(evalStringNoCtx(state, *i))); | ||||||
| 
 | 
 | ||||||
|     return makeAttrs(attrs); |     return makeAttrs(attrs); | ||||||
| } | } | ||||||
|  | @ -830,9 +671,10 @@ static Expr primRemoveAttrs(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
| static Expr primRelativise(EvalState & state, const ATermVector & args) | static Expr primRelativise(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     Path pivot = evalPath(state, args[0]); |     PathSet context; /* !!! what to do? */ | ||||||
|     Path path = evalPath(state, args[1]); |     Path pivot = coerceToPath(state, args[0], context); | ||||||
|     return makeStr(toATerm(relativise(pivot, path))); |     Path path = coerceToPath(state, args[1], context); | ||||||
|  |     return makeStr(relativise(pivot, path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -113,16 +113,6 @@ Derivation parseDerivation(ATerm t) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static ATermList unparseStrings(const StringSet & paths) |  | ||||||
| { |  | ||||||
|     ATermList l = ATempty; |  | ||||||
|     for (PathSet::const_reverse_iterator i = paths.rbegin(); |  | ||||||
|          i != paths.rend(); ++i) |  | ||||||
|         l = ATinsert(l, toATerm(*i)); |  | ||||||
|     return l; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ATerm unparseDerivation(const Derivation & drv) | ATerm unparseDerivation(const Derivation & drv) | ||||||
| { | { | ||||||
|     ATermList outputs = ATempty; |     ATermList outputs = ATempty; | ||||||
|  | @ -141,7 +131,7 @@ ATerm unparseDerivation(const Derivation & drv) | ||||||
|         inDrvs = ATinsert(inDrvs, |         inDrvs = ATinsert(inDrvs, | ||||||
|             makeDerivationInput( |             makeDerivationInput( | ||||||
|                 toATerm(i->first), |                 toATerm(i->first), | ||||||
|                 unparseStrings(i->second))); |                 toATermList(i->second))); | ||||||
|      |      | ||||||
|     ATermList args = ATempty; |     ATermList args = ATempty; | ||||||
|     for (Strings::const_reverse_iterator i = drv.args.rbegin(); |     for (Strings::const_reverse_iterator i = drv.args.rbegin(); | ||||||
|  | @ -159,7 +149,7 @@ ATerm unparseDerivation(const Derivation & drv) | ||||||
|     return makeDerive( |     return makeDerive( | ||||||
|         outputs, |         outputs, | ||||||
|         inDrvs, |         inDrvs, | ||||||
|         unparseStrings(drv.inputSrcs), |         toATermList(drv.inputSrcs), | ||||||
|         toATerm(drv.platform), |         toATerm(drv.platform), | ||||||
|         toATerm(drv.builder), |         toATerm(drv.builder), | ||||||
|         args, |         args, | ||||||
|  |  | ||||||
|  | @ -41,3 +41,13 @@ ATerm nix::toATerm(const string & s) | ||||||
| { | { | ||||||
|     return toATerm(s.c_str()); |     return toATerm(s.c_str()); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ATermList nix::toATermList(const StringSet & ss) | ||||||
|  | { | ||||||
|  |     ATermList l = ATempty; | ||||||
|  |     for (StringSet::const_reverse_iterator i = ss.rbegin(); | ||||||
|  |          i != ss.rend(); ++i) | ||||||
|  |         l = ATinsert(l, toATerm(*i)); | ||||||
|  |     return l; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ Error badTerm(const format & f, ATerm t); | ||||||
| ATerm toATerm(const char * s); | ATerm toATerm(const char * s); | ||||||
| ATerm toATerm(const string & s); | ATerm toATerm(const string & s); | ||||||
| 
 | 
 | ||||||
|  | ATermList toATermList(const StringSet & ss); | ||||||
|   |   | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -167,18 +167,18 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems, | ||||||
|         Path drvPath = keepDerivations ? i->queryDrvPath(state) : ""; |         Path drvPath = keepDerivations ? i->queryDrvPath(state) : ""; | ||||||
|         ATerm t = makeAttrs(ATmakeList5( |         ATerm t = makeAttrs(ATmakeList5( | ||||||
|             makeBind(toATerm("type"), |             makeBind(toATerm("type"), | ||||||
|                 makeStr(toATerm("derivation")), makeNoPos()), |                 makeStr("derivation"), makeNoPos()), | ||||||
|             makeBind(toATerm("name"), |             makeBind(toATerm("name"), | ||||||
|                 makeStr(toATerm(i->name)), makeNoPos()), |                 makeStr(i->name), makeNoPos()), | ||||||
|             makeBind(toATerm("system"), |             makeBind(toATerm("system"), | ||||||
|                 makeStr(toATerm(i->system)), makeNoPos()), |                 makeStr(i->system), makeNoPos()), | ||||||
|             makeBind(toATerm("drvPath"), |             makeBind(toATerm("drvPath"), | ||||||
|                 makePath(toATerm(drvPath)), makeNoPos()), |                 makeStr(drvPath), makeNoPos()), | ||||||
|             makeBind(toATerm("outPath"), |             makeBind(toATerm("outPath"), | ||||||
|                 makePath(toATerm(i->queryOutPath(state))), makeNoPos()) |                 makeStr(i->queryOutPath(state)), makeNoPos()) | ||||||
|             )); |             )); | ||||||
|         manifest = ATinsert(manifest, t); |         manifest = ATinsert(manifest, t); | ||||||
|         inputs = ATinsert(inputs, makeStr(toATerm(i->queryOutPath(state)))); |         inputs = ATinsert(inputs, makeStr(i->queryOutPath(state))); | ||||||
| 
 | 
 | ||||||
|         /* This is only necessary when installing store paths, e.g.,
 |         /* This is only necessary when installing store paths, e.g.,
 | ||||||
|            `nix-env -i /nix/store/abcd...-foo'. */ |            `nix-env -i /nix/store/abcd...-foo'. */ | ||||||
|  | @ -196,11 +196,11 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems, | ||||||
| 
 | 
 | ||||||
|     Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( |     Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( | ||||||
|         makeBind(toATerm("system"), |         makeBind(toATerm("system"), | ||||||
|             makeStr(toATerm(thisSystem)), makeNoPos()), |             makeStr(thisSystem), makeNoPos()), | ||||||
|         makeBind(toATerm("derivations"), |         makeBind(toATerm("derivations"), | ||||||
|             makeList(ATreverse(inputs)), makeNoPos()), |             makeList(ATreverse(inputs)), makeNoPos()), | ||||||
|         makeBind(toATerm("manifest"), |         makeBind(toATerm("manifest"), | ||||||
|             makePath(toATerm(manifestFile)), makeNoPos()) |             makeStr(manifestFile), makeNoPos()) | ||||||
|         ))); |         ))); | ||||||
| 
 | 
 | ||||||
|     /* Instantiate it. */ |     /* Instantiate it. */ | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ static bool indirectRoot = false; | ||||||
| static void printResult(EvalState & state, Expr e, | static void printResult(EvalState & state, Expr e, | ||||||
|     bool evalOnly, bool xmlOutput, const ATermMap & autoArgs) |     bool evalOnly, bool xmlOutput, const ATermMap & autoArgs) | ||||||
| { | { | ||||||
|     ATermList context; |     PathSet context; | ||||||
|      |      | ||||||
|     if (evalOnly) |     if (evalOnly) | ||||||
|         if (xmlOutput) |         if (xmlOutput) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue