about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/get-drvs.cc46
-rw-r--r--src/libexpr/get-drvs.hh13
-rw-r--r--src/nix-env/nix-env.cc88
3 files changed, 106 insertions, 41 deletions
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 84f8ddf9bfb1..1442d7988b8b 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -50,31 +50,55 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
         Expr e = evalExpr(state, i->value);
         string s;
         PathSet context;
-        if (matchStr(e, s, context))
-            meta[aterm2String(i->key)] = s;
-        /* For future compatibility, ignore attribute values that are
-           not strings. */
+        MetaValue value;
+        int n;
+        ATermList es;
+        if (matchStr(e, s, context)) {
+            value.type = MetaValue::tpString;
+            value.stringValue = s;
+            meta[aterm2String(i->key)] = value;
+        } else if (matchInt(e, n)) {
+            value.type = MetaValue::tpInt;
+            value.intValue = n;
+            meta[aterm2String(i->key)] = value;
+        } else if (matchList(e, es)) {
+            value.type = MetaValue::tpStrings;
+            for (ATermIterator j(es); j; ++j)
+                value.stringValues.push_back(evalStringNoCtx(state, *j));
+            meta[aterm2String(i->key)] = value;
+        }
     }
 
     return meta;
 }
 
 
-string DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
+MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
 {
     /* !!! evaluates all meta attributes => inefficient */
-    MetaInfo meta = queryMetaInfo(state);
-    MetaInfo::iterator i = meta.find(name);
-    return i == meta.end() ? "" : i->second;
+    return queryMetaInfo(state)[name];
 }
 
 
 void DrvInfo::setMetaInfo(const MetaInfo & meta)
 {
     ATermMap metaAttrs;
-    for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i)
-        metaAttrs.set(toATerm(i->first),
-            makeAttrRHS(makeStr(i->second), makeNoPos()));
+    foreach (MetaInfo::const_iterator, i, meta) {
+        Expr e;
+        switch (i->second.type) {
+            case MetaValue::tpInt: e = makeInt(i->second.intValue); break;
+            case MetaValue::tpString: e = makeStr(i->second.stringValue); break;
+            case MetaValue::tpStrings: {
+                ATermList es = ATempty;
+                foreach (Strings::const_iterator, j, i->second.stringValues)
+                    es = ATinsert(es, makeStr(*j));
+                e = makeList(ATreverse(es));
+                break;
+            }
+            default: abort();
+        }
+        metaAttrs.set(toATerm(i->first), makeAttrRHS(e, makeNoPos()));
+    }
     attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
 }
 
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index 46dc51a568af..b56f54711899 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -12,7 +12,16 @@
 namespace nix {
 
 
-typedef std::map<string, string> MetaInfo;
+struct MetaValue
+{
+    enum { tpNone, tpString, tpStrings, tpInt } type;
+    string stringValue;
+    Strings stringValues;
+    int intValue;
+};
+
+
+typedef std::map<string, MetaValue> MetaInfo;
 
 
 struct DrvInfo
@@ -34,7 +43,7 @@ public:
     string queryDrvPath(EvalState & state) const;
     string queryOutPath(EvalState & state) const;
     MetaInfo queryMetaInfo(EvalState & state) const;
-    string queryMetaInfo(EvalState & state, const string & name) const;
+    MetaValue queryMetaInfo(EvalState & state, const string & name) const;
 
     void setDrvPath(const string & s)
     {
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 67bdfb66f7f3..87887a7bd570 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -251,15 +251,14 @@ static string optimisticLockProfile(const Path & profile)
 }
 
 
-static bool createUserEnv(EvalState & state, const DrvInfos & elems,
+static bool createUserEnv(EvalState & state, DrvInfos & elems,
     const Path & profile, bool keepDerivations,
     const string & lockToken)
 {
     /* Build the components in the user environment, if they don't
        exist already. */
     PathSet drvsToBuild;
-    for (DrvInfos::const_iterator i = elems.begin(); 
-         i != elems.end(); ++i)
+    foreach (DrvInfos::const_iterator, i, elems)
         /* Call to `isDerivation' is for compatibility with Nix <= 0.7
            user environments. */
         if (i->queryDrvPath(state) != "" &&
@@ -277,19 +276,16 @@ static bool createUserEnv(EvalState & state, const DrvInfos & elems,
     PathSet references;
     ATermList manifest = ATempty;
     ATermList inputs = ATempty;
-    for (DrvInfos::const_iterator i = elems.begin(); 
-         i != elems.end(); ++i)
-    {
+    foreach (DrvInfos::iterator, i, elems) {
         /* Create a pseudo-derivation containing the name, system,
            output path, and optionally the derivation path, as well as
            the meta attributes. */
         Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
 
+        /* Round trip to get rid of "bad" meta values (like
+           functions). */
         MetaInfo meta = i->queryMetaInfo(state);
-        ATermList metaList = ATempty;
-        foreach (MetaInfo::iterator, j, meta)
-            metaList = ATinsert(metaList,
-                makeBind(toATerm(j->first), makeStr(j->second), makeNoPos()));
+        i->setMetaInfo(meta);
         
         ATermList as = ATmakeList5(
             makeBind(toATerm("type"),
@@ -300,7 +296,8 @@ static bool createUserEnv(EvalState & state, const DrvInfos & elems,
                 makeStr(i->system), makeNoPos()),
             makeBind(toATerm("outPath"),
                 makeStr(i->queryOutPath(state)), makeNoPos()), 
-            makeBind(toATerm("meta"), makeAttrs(metaList), makeNoPos()));
+            makeBind(toATerm("meta"),
+                i->attrs->get(toATerm("meta")), makeNoPos()));
         
         if (drvPath != "") as = ATinsert(as, 
             makeBind(toATerm("drvPath"),
@@ -361,13 +358,23 @@ static bool createUserEnv(EvalState & state, const DrvInfos & elems,
 }
 
 
+static int getPriority(EvalState & state, const DrvInfo & drv)
+{
+    MetaValue value = drv.queryMetaInfo(state, "priority");
+    int prio = 0;
+    if (value.type == MetaValue::tpInt) prio = value.intValue;
+    else if (value.type == MetaValue::tpString)
+        /* Backwards compatibility.  Priorities used to be strings
+           before we had support for integer meta field. */
+        string2Int(value.stringValue, prio);
+    return prio;
+}
+
+
 static int comparePriorities(EvalState & state,
     const DrvInfo & drv1, const DrvInfo & drv2)
 {
-    int prio1, prio2;
-    if (!string2Int(drv1.queryMetaInfo(state, "priority"), prio1)) prio1 = 0;
-    if (!string2Int(drv2.queryMetaInfo(state, "priority"), prio2)) prio2 = 0;
-    return prio2 - prio1; /* higher number = lower priority, so negate */
+    return getPriority(state, drv2) - getPriority(state, drv1);
 }
 
 
@@ -594,6 +601,13 @@ static void printMissing(EvalState & state, const DrvInfos & elems)
 }
 
 
+static bool keep(MetaInfo & meta)
+{
+    MetaValue value = meta["keep"];
+    return value.type == MetaValue::tpString && value.stringValue == "true";
+}
+
+
 static void installDerivations(Globals & globals,
     const Strings & args, const Path & profile)
 {
@@ -628,7 +642,7 @@ static void installDerivations(Globals & globals,
             MetaInfo meta = i->queryMetaInfo(globals.state);
             if (!globals.preserveInstalled &&
                 newNames.find(drvName.name) != newNames.end() &&
-                meta["keep"] != "true")
+                !keep(meta))
                 printMsg(lvlInfo,
                     format("replacing old `%1%'") % i->name);
             else
@@ -691,7 +705,7 @@ static void upgradeDerivations(Globals & globals,
             DrvName drvName(i->name);
 
             MetaInfo meta = i->queryMetaInfo(globals.state);
-            if (meta["keep"] == "true") {
+            if (keep(meta)) {
                 newElems.push_back(*i);
                 continue;
             }
@@ -709,9 +723,9 @@ static void upgradeDerivations(Globals & globals,
                 if (newName.name == drvName.name) {
                     int d = comparePriorities(globals.state, *i, *j);
                     if (d == 0) d = compareVersions(drvName.version, newName.version);
-                    if (upgradeType == utLt && d < 0 ||
-                        upgradeType == utLeq && d <= 0 ||
-                        upgradeType == utEq && d == 0 ||
+                    if ((upgradeType == utLt && d < 0) ||
+                        (upgradeType == utLeq && d <= 0) ||
+                        (upgradeType == utEq && d == 0) ||
                         upgradeType == utAlways)
                     {
                         int d2 = -1;
@@ -770,7 +784,10 @@ static void setMetaFlag(EvalState & state, DrvInfo & drv,
     const string & name, const string & value)
 {
     MetaInfo meta = drv.queryMetaInfo(state);
-    meta[name] = value;
+    MetaValue v;
+    v.type = MetaValue::tpString;
+    v.stringValue = value;
+    meta[name] = v;
     drv.setMetaInfo(meta);
 }
 
@@ -1075,9 +1092,7 @@ static void opQuery(Globals & globals,
     XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
     XMLOpenElement xmlRoot(xml, "items");
     
-    for (vector<DrvInfo>::iterator i = elems2.begin();
-         i != elems2.end(); ++i)
-    {
+    foreach (vector<DrvInfo>::iterator, i, elems2) {
         try {
 
             /* For table output. */
@@ -1164,7 +1179,8 @@ static void opQuery(Globals & globals,
 
             if (printDescription) {
                 MetaInfo meta = i->queryMetaInfo(globals.state);
-                string descr = meta["description"];
+                MetaValue value = meta["description"];
+                string descr = value.type == MetaValue::tpString ? value.stringValue : "";
                 if (xmlOutput) {
                     if (descr != "") attrs["description"] = descr;
                 } else
@@ -1178,8 +1194,23 @@ static void opQuery(Globals & globals,
                     for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) {
                         XMLAttrs attrs2;
                         attrs2["name"] = j->first;
-                        attrs2["value"] = j->second;
-                        xml.writeEmptyElement("meta", attrs2);
+                        if (j->second.type == MetaValue::tpString) {
+                            attrs2["type"] = "string";
+                            attrs2["value"] = j->second.stringValue;
+                            xml.writeEmptyElement("meta", attrs2);
+                        } else if (j->second.type == MetaValue::tpInt) {
+                            attrs2["type"] = "int";
+                            attrs2["value"] = (format("%1%") % j->second.intValue).str();
+                            xml.writeEmptyElement("meta", attrs2);
+                        } else if (j->second.type == MetaValue::tpStrings) {
+                            attrs2["type"] = "strings";
+                            XMLOpenElement m(xml, "meta", attrs2);
+                            foreach (Strings::iterator, k, j->second.stringValues) { 
+                                XMLAttrs attrs3;
+                                attrs3["value"] = *k;
+                                xml.writeEmptyElement("string", attrs3);
+                           }
+                        }
                     }
                 }
                 else
@@ -1230,12 +1261,13 @@ static void switchGeneration(Globals & globals, int dstGen)
             (dstGen >= 0 && i->number == dstGen))
             dst = *i;
 
-    if (!dst)
+    if (!dst) {
         if (dstGen == prevGen)
             throw Error(format("no generation older than the current (%1%) exists")
                 % curGen);
         else
             throw Error(format("generation %1% does not exist") % dstGen);
+    }
 
     printMsg(lvlInfo, format("switching from generation %1% to %2%")
         % curGen % dst.number);