From: Michael Schroeder Date: Fri, 29 Mar 2019 10:49:37 +0000 (+0100) Subject: Implement complex conda version matches X-Git-Tag: 0.7.4~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc0e369c03b7a75479c4e2332f4c2562be561b5f;p=thirdparty%2Flibsolv.git Implement complex conda version matches This turned out to be easier than expected. --- diff --git a/src/conda.c b/src/conda.c index 30b0f090..5b134dd4 100644 --- a/src/conda.c +++ b/src/conda.c @@ -382,22 +382,73 @@ solvable_conda_matchversion_single(Solvable *s, const char *version, size_t vers return r == 0 ? 1 : 0; } +static int +solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char *versionend) +{ + const char *version = *versionp; + int v, vor = 0, vand = -1; /* -1: doing OR, 0,1: doing AND */ + + if (version == versionend) + return -1; + for (;;) + { + if (*version == '(') + { + version++; + v = solvable_conda_matchversion_rec(s, &version, versionend); + if (v == -1 || version == versionend || *version != ')') + return -1; + version++; + } + else if (*version == ')' || *version == '|' || *version == ',') + return -1; + else + { + const char *vstart = version; + while (version < versionend && *version != '(' && *version != ')' && *version != '|' && *version != ',') + version++; + if (vand >= 0 ? !vand : vor) + v = 0; /* no need to call expensive matchversion if the result does not matter */ + else + v = solvable_conda_matchversion_single(s, vstart, version - vstart) ? 1 : 0; + } + if (version == versionend || *version == ')') + { + *versionp = version; + return vor | (vand >= 0 ? (vand & v) : v); + } + if (*version == ',') + vand = vand >= 0 ? (vand & v) : v; + else if (*version == '|') + { + vor |= vand >= 0 ? (vand & v) : v; + vand = -1; + } + else + return -1; + version++; + } +} /* return true if solvable s matches the version */ /* see conda/models/match_spec.py */ int solvable_conda_matchversion(Solvable *s, const char *version) { - const char *build; - size_t vl; + const char *build, *versionend; + int r; /* split off build */ if ((build = strchr(version, ' ')) != 0) { - vl = build - version; + versionend = build++; while (*build == ' ') build++; } else - vl = strlen(version); - return solvable_conda_matchversion_single(s, version, vl); + versionend = version + strlen(version); + r = solvable_conda_matchversion_rec(s, &version, versionend); + if (r != 1 || version != versionend) + return 0; + return r; } +