* 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).
This commit is contained in:
Eelco Dolstra 2009-06-30 15:53:39 +00:00
parent f2c3fc5191
commit 749dd97a54
3 changed files with 106 additions and 41 deletions

View file

@ -50,31 +50,55 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
Expr e = evalExpr(state, i->value); Expr e = evalExpr(state, i->value);
string s; string s;
PathSet context; PathSet context;
if (matchStr(e, s, context)) MetaValue value;
meta[aterm2String(i->key)] = s; int n;
/* For future compatibility, ignore attribute values that are ATermList es;
not strings. */ 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; 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 */ /* !!! evaluates all meta attributes => inefficient */
MetaInfo meta = queryMetaInfo(state); return queryMetaInfo(state)[name];
MetaInfo::iterator i = meta.find(name);
return i == meta.end() ? "" : i->second;
} }
void DrvInfo::setMetaInfo(const MetaInfo & meta) void DrvInfo::setMetaInfo(const MetaInfo & meta)
{ {
ATermMap metaAttrs; ATermMap metaAttrs;
for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i) foreach (MetaInfo::const_iterator, i, meta) {
metaAttrs.set(toATerm(i->first), Expr e;
makeAttrRHS(makeStr(i->second), makeNoPos())); 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)); attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
} }

View file

@ -12,7 +12,16 @@
namespace nix { 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 struct DrvInfo
@ -34,7 +43,7 @@ public:
string queryDrvPath(EvalState & state) const; string queryDrvPath(EvalState & state) const;
string queryOutPath(EvalState & state) const; string queryOutPath(EvalState & state) const;
MetaInfo queryMetaInfo(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) void setDrvPath(const string & s)
{ {

View file

@ -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 Path & profile, bool keepDerivations,
const string & lockToken) const string & lockToken)
{ {
/* Build the components in the user environment, if they don't /* Build the components in the user environment, if they don't
exist already. */ exist already. */
PathSet drvsToBuild; PathSet drvsToBuild;
for (DrvInfos::const_iterator i = elems.begin(); foreach (DrvInfos::const_iterator, i, elems)
i != elems.end(); ++i)
/* Call to `isDerivation' is for compatibility with Nix <= 0.7 /* Call to `isDerivation' is for compatibility with Nix <= 0.7
user environments. */ user environments. */
if (i->queryDrvPath(state) != "" && if (i->queryDrvPath(state) != "" &&
@ -277,19 +276,16 @@ static bool createUserEnv(EvalState & state, const DrvInfos & elems,
PathSet references; PathSet references;
ATermList manifest = ATempty; ATermList manifest = ATempty;
ATermList inputs = ATempty; ATermList inputs = ATempty;
for (DrvInfos::const_iterator i = elems.begin(); foreach (DrvInfos::iterator, i, elems) {
i != elems.end(); ++i)
{
/* Create a pseudo-derivation containing the name, system, /* Create a pseudo-derivation containing the name, system,
output path, and optionally the derivation path, as well as output path, and optionally the derivation path, as well as
the meta attributes. */ the meta attributes. */
Path drvPath = keepDerivations ? i->queryDrvPath(state) : ""; Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
/* Round trip to get rid of "bad" meta values (like
functions). */
MetaInfo meta = i->queryMetaInfo(state); MetaInfo meta = i->queryMetaInfo(state);
ATermList metaList = ATempty; i->setMetaInfo(meta);
foreach (MetaInfo::iterator, j, meta)
metaList = ATinsert(metaList,
makeBind(toATerm(j->first), makeStr(j->second), makeNoPos()));
ATermList as = ATmakeList5( ATermList as = ATmakeList5(
makeBind(toATerm("type"), makeBind(toATerm("type"),
@ -300,7 +296,8 @@ static bool createUserEnv(EvalState & state, const DrvInfos & elems,
makeStr(i->system), makeNoPos()), makeStr(i->system), makeNoPos()),
makeBind(toATerm("outPath"), makeBind(toATerm("outPath"),
makeStr(i->queryOutPath(state)), makeNoPos()), 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, if (drvPath != "") as = ATinsert(as,
makeBind(toATerm("drvPath"), 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, static int comparePriorities(EvalState & state,
const DrvInfo & drv1, const DrvInfo & drv2) const DrvInfo & drv1, const DrvInfo & drv2)
{ {
int prio1, prio2; return getPriority(state, drv2) - getPriority(state, drv1);
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 */
} }
@ -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, static void installDerivations(Globals & globals,
const Strings & args, const Path & profile) const Strings & args, const Path & profile)
{ {
@ -628,7 +642,7 @@ static void installDerivations(Globals & globals,
MetaInfo meta = i->queryMetaInfo(globals.state); MetaInfo meta = i->queryMetaInfo(globals.state);
if (!globals.preserveInstalled && if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() && newNames.find(drvName.name) != newNames.end() &&
meta["keep"] != "true") !keep(meta))
printMsg(lvlInfo, printMsg(lvlInfo,
format("replacing old `%1%'") % i->name); format("replacing old `%1%'") % i->name);
else else
@ -691,7 +705,7 @@ static void upgradeDerivations(Globals & globals,
DrvName drvName(i->name); DrvName drvName(i->name);
MetaInfo meta = i->queryMetaInfo(globals.state); MetaInfo meta = i->queryMetaInfo(globals.state);
if (meta["keep"] == "true") { if (keep(meta)) {
newElems.push_back(*i); newElems.push_back(*i);
continue; continue;
} }
@ -709,9 +723,9 @@ static void upgradeDerivations(Globals & globals,
if (newName.name == drvName.name) { if (newName.name == drvName.name) {
int d = comparePriorities(globals.state, *i, *j); int d = comparePriorities(globals.state, *i, *j);
if (d == 0) d = compareVersions(drvName.version, newName.version); if (d == 0) d = compareVersions(drvName.version, newName.version);
if (upgradeType == utLt && d < 0 || if ((upgradeType == utLt && d < 0) ||
upgradeType == utLeq && d <= 0 || (upgradeType == utLeq && d <= 0) ||
upgradeType == utEq && d == 0 || (upgradeType == utEq && d == 0) ||
upgradeType == utAlways) upgradeType == utAlways)
{ {
int d2 = -1; int d2 = -1;
@ -770,7 +784,10 @@ static void setMetaFlag(EvalState & state, DrvInfo & drv,
const string & name, const string & value) const string & name, const string & value)
{ {
MetaInfo meta = drv.queryMetaInfo(state); MetaInfo meta = drv.queryMetaInfo(state);
meta[name] = value; MetaValue v;
v.type = MetaValue::tpString;
v.stringValue = value;
meta[name] = v;
drv.setMetaInfo(meta); drv.setMetaInfo(meta);
} }
@ -1075,9 +1092,7 @@ static void opQuery(Globals & globals,
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy)); XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
XMLOpenElement xmlRoot(xml, "items"); XMLOpenElement xmlRoot(xml, "items");
for (vector<DrvInfo>::iterator i = elems2.begin(); foreach (vector<DrvInfo>::iterator, i, elems2) {
i != elems2.end(); ++i)
{
try { try {
/* For table output. */ /* For table output. */
@ -1164,7 +1179,8 @@ static void opQuery(Globals & globals,
if (printDescription) { if (printDescription) {
MetaInfo meta = i->queryMetaInfo(globals.state); 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 (xmlOutput) {
if (descr != "") attrs["description"] = descr; if (descr != "") attrs["description"] = descr;
} else } else
@ -1178,8 +1194,23 @@ static void opQuery(Globals & globals,
for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) {
XMLAttrs attrs2; XMLAttrs attrs2;
attrs2["name"] = j->first; attrs2["name"] = j->first;
attrs2["value"] = j->second; if (j->second.type == MetaValue::tpString) {
attrs2["type"] = "string";
attrs2["value"] = j->second.stringValue;
xml.writeEmptyElement("meta", attrs2); 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 else
@ -1230,12 +1261,13 @@ static void switchGeneration(Globals & globals, int dstGen)
(dstGen >= 0 && i->number == dstGen)) (dstGen >= 0 && i->number == dstGen))
dst = *i; dst = *i;
if (!dst) if (!dst) {
if (dstGen == prevGen) if (dstGen == prevGen)
throw Error(format("no generation older than the current (%1%) exists") throw Error(format("no generation older than the current (%1%) exists")
% curGen); % curGen);
else else
throw Error(format("generation %1% does not exist") % dstGen); throw Error(format("generation %1% does not exist") % dstGen);
}
printMsg(lvlInfo, format("switching from generation %1% to %2%") printMsg(lvlInfo, format("switching from generation %1% to %2%")
% curGen % dst.number); % curGen % dst.number);