{
name = pool_id2str(pool, s->name);
evr = pool_id2str(pool, s->evr);
- arch = pool_id2str(pool, s->arch);
+ arch = s->arch ? pool_id2str(pool, s->arch) : "-";
release = strrchr(evr, '-');
if (!release)
release = evr + strlen(evr);
}
if (s->vendor)
fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
+ if (solvable_lookup_idarray(s, SOLVABLE_BUILDFLAVOR, &q))
+ {
+ int i;
+ for (i = 0; i < q.count; i++)
+ fprintf(fp, "=Flv: %s\n", pool_id2str(pool, q.elements[i]));
+ }
ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
if (ti)
fprintf(fp, "=Tim: %u\n", ti);
if (sp[2] && !(sp[2][0] == '-' && !sp[2][1]))
sp[2][-1] = '-';
s->evr = makeevr(pool, sp[1]);
- s->arch = pool_str2id(pool, sp[3], 1);
+ s->arch = strcmp(sp[3], "-") ? pool_str2id(pool, sp[3], 1) : 0;
continue;
default:
break;
repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id);
break;
}
+ case 'F' << 16 | 'l' << 8 | 'v':
+ repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_BUILDFLAVOR, line + 6);
+ break;
default:
break;
}
lowscore = pool->id2arch[i];
}
}
- cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0);
+ cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "-", 0);
for (i = 0; disttype2str[i].str != 0; i++)
if (pool->disttype == disttype2str[i].type)
break;
missing_features = 1;
}
}
- if (strcmp(pieces[1], "unset") == 0)
+ if (strcmp(pieces[1], "unset") == 0 || strcmp(pieces[1], "-") == 0)
pool_setarch(pool, 0);
else if (pieces[1][0] == ':')
pool_setarchpolicy(pool, pieces[1] + 1);
}
static int
-regexmatch(const char *evr, const char *version, size_t versionlen)
+regexmatch(const char *evr, const char *version, size_t versionlen, int icase)
{
regex_t reg;
char *buf = solv_malloc(versionlen + 1);
memcpy(buf, version, versionlen);
buf[versionlen] = 0;
- if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB))
+ if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
return 0;
r = regexec(®, evr, 0, NULL, 0);
regfree(®);
}
static int
-globmatch(const char *evr, const char *version, size_t versionlen)
+globmatch(const char *evr, const char *version, size_t versionlen, int icase)
{
regex_t reg;
char *buf = solv_malloc(2 * versionlen + 3);
}
buf[j++] = '$';
buf[j] = 0;
- if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB))
+ if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
return 0;
r = regexec(®, evr, 0, NULL, 0);
regfree(®);
return 1; /* matches every version */
evr = pool_id2str(s->repo->pool, s->evr);
if (versionlen >= 2 && version[0] == '^' && version[versionlen - 1] == '$')
- return regexmatch(evr, version, versionlen);
+ return regexmatch(evr, version, versionlen, 0);
if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
{
int flags = 0;
if (version[i] != '*')
break;
if (i < versionlen)
- return globmatch(evr, version, versionlen);
+ return globmatch(evr, version, versionlen, 1);
}
if (versionlen > 1 && version[versionlen - 1] == '*')
}
}
+static int
+solvable_conda_matchbuild(Solvable *s, const char *build, const char *buildend)
+{
+ const char *bp;
+ const char *flavor = solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR);
+
+ if (!flavor)
+ flavor = "";
+ if (build == buildend)
+ return *flavor ? 0 : 1;
+ if (build + 1 == buildend && *build == '*')
+ return 1;
+ if (*build == '^' && buildend[-1] == '$')
+ return regexmatch(flavor, build, buildend - build, 0);
+ for (bp = build; bp < buildend; bp++)
+ if (*bp == '*')
+ return globmatch(flavor, build, buildend - build, 0);
+ return strncmp(flavor, build, buildend - build) == 0 && flavor[buildend - build] == 0 ? 1 : 0;
+}
+
/* return true if solvable s matches the version */
/* see conda/models/match_spec.py */
int
r = solvable_conda_matchversion_rec(s, &version, versionend);
if (r != 1 || version != versionend)
return 0;
+ if (build && !solvable_conda_matchbuild(s, build, build + strlen(build)))
+ return 0;
return r;
}
+static Id
+pool_addrelproviders_conda_slow(Pool *pool, const char *namestr, Id evr, Queue *plist, int mode)
+{
+ size_t namestrlen = strlen(namestr);
+ const char *evrstr = evr == 0 || evr == 1 ? 0 : pool_id2str(pool, evr);
+ Id p;
+
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!pool_installable(pool, s))
+ continue;
+ if (mode == 1 && !globmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
+ continue;
+ if (mode == 2 && !regexmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
+ continue;
+ if (!evrstr || solvable_conda_matchversion(s, evrstr))
+ queue_push(plist, p);
+ }
+ return 0;
+}
+
+/* called from pool_addrelproviders, plist is an empty queue
+ * it can either return an offset into the whatprovides array
+ * or fill the plist queue and return zero */
+Id
+pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist)
+{
+ const char *namestr = pool_id2str(pool, name), *np;
+ size_t l, nuc = 0;
+ Id wp, p, *pp;
+
+ /* is this a regex? */
+ if (*namestr && *namestr == '^')
+ {
+ l = strlen(namestr);
+ if (namestr[l - 1] == '$')
+ return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 2);
+ }
+ /* is this '*'? */
+ if (*namestr && *namestr == '*' && namestr[1] == 0)
+ return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 0);
+ /* does the string contain '*' or uppercase? */
+ for (np = namestr; *np; np++)
+ {
+ if (*np == '*')
+ return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 1);
+ else if (*np >= 'A' && *np <= 'Z')
+ nuc++;
+ }
+ if (nuc)
+ {
+ char *nbuf = solv_strdup(namestr), *nbufp;
+ for (nbufp = nbuf; *nbufp; nbufp++)
+ *nbufp = *nbufp >= 'A' && *nbufp <= 'Z' ? *nbufp + ('a' - 'A') : *nbufp;
+ name = pool_str2id(pool, nbuf, 0);
+ wp = name ? pool_whatprovides(pool, name) : 0;
+ solv_free(nbuf);
+ }
+ else
+ wp = pool_whatprovides(pool, name);
+ if (wp && evr && evr != 1)
+ {
+ const char *evrstr = pool_id2str(pool, evr);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ if (solvable_conda_matchversion(pool->solvables + p, evrstr))
+ queue_push(plist, p);
+ else
+ wp = 0;
+ }
+ }
+ return wp;
+}
+
+/* create a CONDA_REL relation from a matchspec */
+Id
+pool_conda_matchspec(Pool *pool, const char *name)
+{
+ const char *p2;
+ char *name2;
+ char *p, *pp;
+ char *build, *buildend, *version, *versionend;
+ Id nameid, evrid = 1;
+
+ /* ignore channel and namespace for now */
+ if ((p2 = strrchr(name, ':')))
+ name = p2 + 1;
+ name2 = solv_strdup(name);
+ /* find end of name */
+ for (p = name2; *p && *p != ' ' && *p != '=' && *p != '<' && *p != '>' && *p != '!' && *p != '~'; p++)
+ if (*p >= 'A' && *p <= 'Z')
+ *(char *)p += 'a' - 'A'; /* lower case the name */
+ if (p == name2)
+ {
+ solv_free(name2);
+ return 0; /* error: no package name */
+ }
+ nameid = pool_strn2id(pool, name2, p - name2, 1);
+ while (*p == ' ')
+ p++;
+ if (!*p)
+ {
+ solv_free(name2);
+ return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
+ }
+ /* have version */
+ version = p;
+ versionend = p + strlen(p);
+ while (versionend > version && versionend[-1] == ' ')
+ versionend--;
+ build = buildend = 0;
+ /* split of build */
+ p = versionend;
+ for (;;)
+ {
+ while (p > version && p[-1] != ' ' && p[-1] != '-' && p[-1] != '=' && p[-1] != ',' && p[-1] != '|' && p[-1] != '<' && p[-1] != '>' && p[-1] != '~')
+ p--;
+ if (p <= version + 1 || (p[-1] != ' ' && p[-1] != '='))
+ break; /* no build */
+ /* check char before delimiter */
+ if (p[-2] == '=' || p[-2] == '!' || p[-2] == '|' || p[-2] == ',' || p[-2] == '<' || p[-2] == '>' || p[-2] == '~')
+ {
+ /* illegal combination */
+ if (p[-1] == ' ')
+ {
+ p--;
+ continue; /* special case space: it may be in the build */
+ }
+ break; /* no build */
+ }
+ if (p < versionend)
+ {
+ build = p;
+ buildend = versionend;
+ versionend = p - 1;
+ }
+ break;
+ }
+ /* do weird version translation */
+ if (versionend > version && version[0] == '=')
+ {
+ if (versionend - version >= 2 && version[1] == '=')
+ {
+ if (!build)
+ version += 2;
+ }
+ else if (build)
+ version += 1;
+ else
+ {
+ for (p = version + 1; p < versionend; p++)
+ if (*p == '=' || *p == ',' || *p == '|')
+ break;
+ if (p == versionend)
+ {
+ memmove(version, version + 1, versionend - version - 1);
+ versionend[-1] = '*';
+ }
+ }
+ }
+#if 0
+ printf("version: >%.*s<\n", (int)(versionend - version), version);
+ if (build) printf("build: >%.*s<\n", (int)(buildend - build), build);
+#endif
+ /* strip spaces from version */
+ for (p = pp = version; pp < versionend; pp++)
+ if (*pp != ' ')
+ *p++ = *pp;
+ if (build)
+ {
+ *p++ = ' ';
+ memcpy(p, build, buildend - build);
+ p += buildend - build;
+ }
+ evrid = pool_strn2id(pool, version, p - version, 1);
+ solv_free(name2);
+ return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
+}
+
KNOWNID(SIGNATURE_DATA, "signature:data"),
/* 'content' of patch, usually list of modules */
-KNOWNID(UPDATE_MODULE, "update:module"), /* "name stream version context arch" */
-KNOWNID(UPDATE_MODULE_NAME, "update:module:name"), /* name */
-KNOWNID(UPDATE_MODULE_STREAM, "update:module:stream"), /* stream */
-KNOWNID(UPDATE_MODULE_VERSION, "update:module:version"), /* version */
-KNOWNID(UPDATE_MODULE_CONTEXT, "update:module:context"), /* context */
-KNOWNID(UPDATE_MODULE_ARCH, "update:module:arch"), /* architecture */
+KNOWNID(UPDATE_MODULE, "update:module"), /* "name stream version context arch" */
+KNOWNID(UPDATE_MODULE_NAME, "update:module:name"), /* name */
+KNOWNID(UPDATE_MODULE_STREAM, "update:module:stream"), /* stream */
+KNOWNID(UPDATE_MODULE_VERSION, "update:module:version"), /* version */
+KNOWNID(UPDATE_MODULE_CONTEXT, "update:module:context"), /* context */
+KNOWNID(UPDATE_MODULE_ARCH, "update:module:arch"), /* architecture */
+
+KNOWNID(SOLVABLE_BUILDVERSION, "solvable:buildversion"), /* conda */
+KNOWNID(SOLVABLE_BUILDFLAVOR, "solvable:buildflavor"), /* conda */
KNOWNID(ID_NUM_INTERNAL, 0)