about summary refs log tree commit diff
path: root/src/libexpr/primops.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/primops.cc')
-rw-r--r--src/libexpr/primops.cc101
1 files changed, 82 insertions, 19 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index c456e9b96a53..3b965f209bb2 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -477,7 +477,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
     bool ignoreNulls = false;
     attr = args[0]->attrs->find(state.sIgnoreNulls);
     if (attr != args[0]->attrs->end())
-        ignoreNulls = state.forceBool(*attr->value);
+        ignoreNulls = state.forceBool(*attr->value, pos);
 
     /* Build the derivation expression by processing the attributes. */
     Derivation drv;
@@ -673,6 +673,19 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 }
 
 
+/* Return a placeholder string for the specified output that will be
+   substituted by the corresponding output path at build time. For
+   example, ‘placeholder "out"’ returns the string
+   /1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9. At build
+   time, any occurence of this string in an derivation attribute will
+   be replaced with the concrete path in the Nix store of the output
+   ‘out’. */
+static void prim_placeholder(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+    mkString(v, hashPlaceholder(state.forceStringNoCtx(*args[0], pos)));
+}
+
+
 /*************************************************************
  * Paths
  *************************************************************/
@@ -912,9 +925,10 @@ struct FilterFromExpr : PathFilter
 {
     EvalState & state;
     Value & filter;
+    Pos pos;
 
-    FilterFromExpr(EvalState & state, Value & filter)
-        : state(state), filter(filter)
+    FilterFromExpr(EvalState & state, Value & filter, const Pos & pos)
+        : state(state), filter(filter), pos(pos)
     {
     }
 
@@ -942,7 +956,7 @@ struct FilterFromExpr : PathFilter
         Value res;
         state.callFunction(fun2, arg2, res, noPos);
 
-        return state.forceBool(res);
+        return state.forceBool(res, pos);
     }
 };
 
@@ -958,7 +972,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
     if (args[0]->type != tLambda)
         throw TypeError(format("first argument in call to ‘filterSource’ is not a function but %1%, at %2%") % showType(*args[0]) % pos);
 
-    FilterFromExpr filter(state, *args[0]);
+    FilterFromExpr filter(state, *args[0], pos);
 
     path = state.checkSourcePath(path);
 
@@ -1278,7 +1292,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
     for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
         Value res;
         state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
-        if (state.forceBool(res))
+        if (state.forceBool(res, pos))
             vs[k++] = args[1]->listElems()[n];
         else
             same = false;
@@ -1354,7 +1368,7 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg
     Value vTmp;
     for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
         state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos);
-        bool res = state.forceBool(vTmp);
+        bool res = state.forceBool(vTmp, pos);
         if (res == any) {
             mkBool(v, any);
             return;
@@ -1420,7 +1434,7 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
         Value vTmp1, vTmp2;
         state.callFunction(*args[0], *a, vTmp1, pos);
         state.callFunction(vTmp1, *b, vTmp2, pos);
-        return state.forceBool(vTmp2);
+        return state.forceBool(vTmp2, pos);
     };
 
     /* FIXME: std::sort can segfault if the comparator is not a strict
@@ -1430,6 +1444,40 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
 }
 
 
+static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+    state.forceFunction(*args[0], pos);
+    state.forceList(*args[1], pos);
+
+    auto len = args[1]->listSize();
+
+    ValueVector right, wrong;
+
+    for (unsigned int n = 0; n < len; ++n) {
+        auto vElem = args[1]->listElems()[n];
+        state.forceValue(*vElem);
+        Value res;
+        state.callFunction(*args[0], *vElem, res, pos);
+        if (state.forceBool(res, pos))
+            right.push_back(vElem);
+        else
+            wrong.push_back(vElem);
+    }
+
+    state.mkAttrs(v, 2);
+
+    Value * vRight = state.allocAttr(v, state.sRight);
+    state.mkList(*vRight, right.size());
+    memcpy(vRight->listElems(), right.data(), sizeof(Value *) * right.size());
+
+    Value * vWrong = state.allocAttr(v, state.sWrong);
+    state.mkList(*vWrong, wrong.size());
+    memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wrong.size());
+
+    v.attrs->sort();
+}
+
+
 /*************************************************************
  * Integer arithmetic
  *************************************************************/
@@ -1620,13 +1668,18 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
     if (args[0]->listSize() != args[1]->listSize())
         throw EvalError(format("‘from’ and ‘to’ arguments to ‘replaceStrings’ have different lengths, at %1%") % pos);
 
-    Strings from;
+    vector<string> from;
+    from.reserve(args[0]->listSize());
     for (unsigned int n = 0; n < args[0]->listSize(); ++n)
-        from.push_back(state.forceStringNoCtx(*args[0]->listElems()[n], pos));
+        from.push_back(state.forceString(*args[0]->listElems()[n], pos));
 
-    Strings to;
-    for (unsigned int n = 0; n < args[1]->listSize(); ++n)
-        to.push_back(state.forceStringNoCtx(*args[1]->listElems()[n], pos));
+    vector<std::pair<string, PathSet>> to;
+    to.reserve(args[1]->listSize());
+    for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
+        PathSet ctx;
+        auto s = state.forceString(*args[1]->listElems()[n], ctx, pos);
+        to.push_back(std::make_pair(std::move(s), std::move(ctx)));
+    }
 
     PathSet context;
     auto s = state.forceString(*args[2], context, pos);
@@ -1634,11 +1687,16 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
     string res;
     for (size_t p = 0; p < s.size(); ) {
         bool found = false;
-        for (auto i = from.begin(), j = to.begin(); i != from.end(); ++i, ++j)
+        auto i = from.begin();
+        auto j = to.begin();
+        for (; i != from.end(); ++i, ++j)
             if (s.compare(p, i->size(), *i) == 0) {
                 found = true;
                 p += i->size();
-                res += *j;
+                res += j->first;
+                for (auto& path : j->second)
+                    context.insert(path);
+                j->second.clear();
                 break;
             }
         if (!found) res += s[p++];
@@ -1682,6 +1740,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
 {
     string url;
     Hash expectedHash;
+    string name;
 
     state.forceValue(*args[0]);
 
@@ -1690,11 +1749,13 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
         state.forceAttrs(*args[0], pos);
 
         for (auto & attr : *args[0]->attrs) {
-            string name(attr.name);
-            if (name == "url")
+            string n(attr.name);
+            if (n == "url")
                 url = state.forceStringNoCtx(*attr.value, *attr.pos);
-            else if (name == "sha256")
+            else if (n == "sha256")
                 expectedHash = parseHash16or32(htSHA256, state.forceStringNoCtx(*attr.value, *attr.pos));
+            else if (n == "name")
+                name = state.forceStringNoCtx(*attr.value, *attr.pos);
             else
                 throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
         }
@@ -1708,7 +1769,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
     if (state.restricted && !expectedHash)
         throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
 
-    Path res = makeDownloader()->downloadCached(state.store, url, unpack, expectedHash);
+    Path res = makeDownloader()->downloadCached(state.store, url, unpack, name, expectedHash);
     mkString(v, res, PathSet({res}));
 }
 
@@ -1855,6 +1916,7 @@ void EvalState::createBaseEnv()
     addPrimOp("__all", 2, prim_all);
     addPrimOp("__genList", 2, prim_genList);
     addPrimOp("__sort", 2, prim_sort);
+    addPrimOp("__partition", 2, prim_partition);
 
     // Integer arithmetic
     addPrimOp("__add", 2, prim_add);
@@ -1880,6 +1942,7 @@ void EvalState::createBaseEnv()
 
     // Derivations
     addPrimOp("derivationStrict", 1, prim_derivationStrict);
+    addPrimOp("placeholder", 1, prim_placeholder);
 
     // Networking
     addPrimOp("__fetchurl", 1, prim_fetchurl);