From 749dd97a54f50467d266dde2b833f272cb556145 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 30 Jun 2009 15:53:39 +0000 Subject: [PATCH] * Support integers and lists of strings in meta fields. This is useful for fields like meta.maintainers, meta.priority (which can be a proper integer now) and even meta.license (if there are multiple licenses). --- src/libexpr/get-drvs.cc | 46 +++++++++++++++------ src/libexpr/get-drvs.hh | 13 +++++- src/nix-env/nix-env.cc | 88 ++++++++++++++++++++++++++++------------- 3 files changed, 106 insertions(+), 41 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 84f8ddf9b..1442d7988 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 46dc51a56..b56f54711 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -12,7 +12,16 @@ namespace nix { -typedef std::map MetaInfo; +struct MetaValue +{ + enum { tpNone, tpString, tpStrings, tpInt } type; + string stringValue; + Strings stringValues; + int intValue; +}; + + +typedef std::map 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 67bdfb66f..87887a7bd 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::iterator i = elems2.begin(); - i != elems2.end(); ++i) - { + foreach (vector::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);