From: Michael Schroeder Date: Wed, 3 Apr 2019 13:02:02 +0000 (+0200) Subject: More conda work X-Git-Tag: 0.7.5~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c9d978dfbd600584ae56ebeba0c955e3acc274b6;p=thirdparty%2Flibsolv.git More conda work - add pool_conda_matchspec() to create a REL_CONDA dep from a string - add name globbing for REL_CONDA - support build flavor matching --- diff --git a/ext/testcase.c b/ext/testcase.c index 5c54bbf9..57919067 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -1258,7 +1258,7 @@ testcase_write_testtags(Repo *repo, FILE *fp) { 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); @@ -1284,6 +1284,12 @@ testcase_write_testtags(Repo *repo, FILE *fp) } 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); @@ -1412,7 +1418,7 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) 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; @@ -1502,6 +1508,9 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) 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; } @@ -2239,7 +2248,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha 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; @@ -2721,7 +2730,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res 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); diff --git a/src/conda.c b/src/conda.c index 5b134dd4..63da8f87 100644 --- a/src/conda.c +++ b/src/conda.c @@ -226,7 +226,7 @@ pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode } 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); @@ -234,7 +234,7 @@ regexmatch(const char *evr, const char *version, size_t versionlen) 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(®); @@ -242,7 +242,7 @@ regexmatch(const char *evr, const char *version, size_t versionlen) } 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); @@ -259,7 +259,7 @@ globmatch(const char *evr, const char *version, size_t versionlen) } 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(®); @@ -279,7 +279,7 @@ solvable_conda_matchversion_single(Solvable *s, const char *version, size_t vers 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; @@ -361,7 +361,7 @@ solvable_conda_matchversion_single(Solvable *s, const char *version, size_t vers if (version[i] != '*') break; if (i < versionlen) - return globmatch(evr, version, versionlen); + return globmatch(evr, version, versionlen, 1); } if (versionlen > 1 && version[versionlen - 1] == '*') @@ -430,6 +430,26 @@ solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char * } } +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 @@ -449,6 +469,189 @@ solvable_conda_matchversion(Solvable *s, const char *version) 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); +} + diff --git a/src/conda.h b/src/conda.h index 7233f17b..3bcfa2d1 100644 --- a/src/conda.h +++ b/src/conda.h @@ -15,6 +15,8 @@ int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode); int solvable_conda_matchversion(Solvable *s, const char *version); +Id pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist); +Id pool_conda_matchspec(Pool *pool, const char *name); #endif /* LIBSOLV_CONDA_H */ diff --git a/src/knownid.h b/src/knownid.h index b5b41d6a..9d7f157e 100644 --- a/src/knownid.h +++ b/src/knownid.h @@ -251,12 +251,15 @@ KNOWNID(SIGNATURE_EXPIRES, "signature:expires"), 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) diff --git a/src/libsolv.ver b/src/libsolv.ver index 58bc957e..d983b541 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -291,7 +291,6 @@ SOLV_1.0 { solv_realloc; solv_realloc2; solv_replacebadutf8; - solv_setcloexec; solv_sort; solv_strdup; solv_timems; @@ -449,4 +448,5 @@ SOLV_1.2 { SOLV_1.3 { repodata_set_kv; + solv_setcloexec; } SOLV_1.2; diff --git a/src/pool.c b/src/pool.c index 09354ef6..a263e9cf 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1289,19 +1289,7 @@ pool_addrelproviders(Pool *pool, Id d) break; #ifdef ENABLE_CONDA case REL_CONDA: - wp = pool_whatprovides(pool, name); - if (evr) - { - 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; - } - } + wp = pool_addrelproviders_conda(pool, name, evr, &plist); break; #endif default: diff --git a/src/selection.c b/src/selection.c index a160122a..ef5c1f8a 100644 --- a/src/selection.c +++ b/src/selection.c @@ -21,6 +21,9 @@ #include "selection.h" #include "solver.h" #include "evr.h" +#ifdef ENABLE_CONDA +#include "conda.h" +#endif static int @@ -1149,6 +1152,19 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags) flags |= SELECTION_NAME; flags &= ~SELECTION_PROVIDES; +#ifdef ENABLE_CONDA + if (pool->disttype == DISTTYPE_CONDA) + { + Id *wp, id = pool_conda_matchspec(pool, name); + if (!id) + return 0; + wp = pool_whatprovides_ptr(pool, id); /* check if there is a match */ + if (!wp || !*wp) + return 0; + queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); + return SELECTION_CANON; + } +#endif if (pool->disttype == DISTTYPE_DEB) { if ((r = strchr(name, '_')) == 0) diff --git a/src/solvable.c b/src/solvable.c index 331f290f..3c4e0bff 100644 --- a/src/solvable.c +++ b/src/solvable.c @@ -126,7 +126,7 @@ solvable_lookup_str(Solvable *s, Id keyname) if (!s->repo) return 0; str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname); - if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP)) + if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP || keyname == SOLVABLE_BUILDFLAVOR)) str = solvable_lookup_str_joinarray(s, keyname, ", "); return str; }