|
Packit Service |
ff689b |
/*
|
|
Packit Service |
ff689b |
* Copyright (c) 2019, SUSE LLC
|
|
Packit Service |
ff689b |
*
|
|
Packit Service |
ff689b |
* This program is licensed under the BSD license, read LICENSE.BSD
|
|
Packit Service |
ff689b |
* for further information
|
|
Packit Service |
ff689b |
*/
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/*
|
|
Packit Service |
ff689b |
* conda.c
|
|
Packit Service |
ff689b |
*
|
|
Packit Service |
ff689b |
* evr comparison and package matching for conda
|
|
Packit Service |
ff689b |
*/
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
#include <stdio.h>
|
|
Packit Service |
ff689b |
#include <stdlib.h>
|
|
Packit Service |
ff689b |
#include <stdarg.h>
|
|
Packit Service |
ff689b |
#include <unistd.h>
|
|
Packit Service |
ff689b |
#include <string.h>
|
|
Packit Service |
ff689b |
#include <sys/types.h>
|
|
Packit Service |
ff689b |
#include <regex.h>
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
#include "pool.h"
|
|
Packit Service |
ff689b |
#include "repo.h"
|
|
Packit Service |
ff689b |
#include "util.h"
|
|
Packit Service |
ff689b |
#include "conda.h"
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
#ifdef _WIN32
|
|
Packit Service |
ff689b |
#include "strfncs.h"
|
|
Packit Service |
ff689b |
#endif
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static const char *
|
|
Packit Service |
ff689b |
endseg(const char *seg, const char *end)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (; seg < end; seg++)
|
|
Packit Service |
ff689b |
if (*seg == '.' || *seg == '-' || *seg == '_')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
return seg;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static const char *
|
|
Packit Service |
ff689b |
endpart(const char *seg, const char *end)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (seg == end)
|
|
Packit Service |
ff689b |
return seg;
|
|
Packit Service |
ff689b |
if (*seg >= '0' && *seg <= '9')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (seg++; seg < end; seg++)
|
|
Packit Service |
ff689b |
if (!(*seg >= '0' && *seg <= '9'))
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (*seg == '*')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (seg++; seg < end; seg++)
|
|
Packit Service |
ff689b |
if (*seg != '*')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (seg++; seg < end; seg++)
|
|
Packit Service |
ff689b |
if ((*seg >= '0' && *seg <= '9') || *seg == '*')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return seg;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* C implementation of the version comparison code in conda/models/version.py */
|
|
Packit Service |
ff689b |
/* startswith == 1 : check if s1 starts with s2 */
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
solv_vercmp_conda(const char *s1, const char *q1, const char *s2, const char *q2, int startswith)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *s1p, *s2p;
|
|
Packit Service |
ff689b |
const char *s1e, *s2e;
|
|
Packit Service |
ff689b |
int r, isfirst;
|
|
Packit Service |
ff689b |
const char *q2end = 0;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (startswith)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (q2end = q2; q2end > s2; q2end--)
|
|
Packit Service |
ff689b |
if (q2end[-1] != '.' && q2end[-1] != '-' && q2end[-1] != '_')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
for (;;)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
while (s1 < q1 && (*s1 == '.' || *s1 == '-' || *s1 == '_'))
|
|
Packit Service |
ff689b |
s1++;
|
|
Packit Service |
ff689b |
while (s2 < q2 && (*s2 == '.' || *s2 == '-' || *s2 == '_'))
|
|
Packit Service |
ff689b |
s2++;
|
|
Packit Service |
ff689b |
if (s1 == q1 && s2 == q2)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
if (startswith && s2 == q2)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
/* find end of component */
|
|
Packit Service |
ff689b |
s1e = endseg(s1, q1);
|
|
Packit Service |
ff689b |
s2e = endseg(s2, q2);
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
for (isfirst = 1; ; isfirst = 0)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (s1 == s1e && s2 == s2e)
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
if (s2 == q2end)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
s1p = endpart(s1, s1e);
|
|
Packit Service |
ff689b |
s2p = endpart(s2, s2e);
|
|
Packit Service |
ff689b |
/* prepend 0 if not numeric */
|
|
Packit Service |
ff689b |
if (isfirst)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (s1p != s1 && !(*s1 >= '0' && *s1 <= '9'))
|
|
Packit Service |
ff689b |
s1p = s1;
|
|
Packit Service |
ff689b |
if (s2p != s2 && !(*s2 >= '0' && *s2 <= '9'))
|
|
Packit Service |
ff689b |
s2p = s2;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* special case "post" */
|
|
Packit Service |
ff689b |
if (s1p - s1 == 4 && !strncasecmp(s1, "post", 4))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
s1 = s1p;
|
|
Packit Service |
ff689b |
s2 = s2p;
|
|
Packit Service |
ff689b |
continue;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (isfirst || ((s1 == s1p || (*s1 >= '0' && *s1 <= '9')) && (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
/* compare numbers */
|
|
Packit Service |
ff689b |
while (s1 < s1p && *s1 == '0')
|
|
Packit Service |
ff689b |
s1++;
|
|
Packit Service |
ff689b |
while (s2 < s2p && *s2 == '0')
|
|
Packit Service |
ff689b |
s2++;
|
|
Packit Service |
ff689b |
if (s1p - s1 < s2p - s2)
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
if (s1p - s1 > s2p - s2)
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
r = s1p - s1 ? strncmp(s1, s2, s1p - s1) : 0;
|
|
Packit Service |
ff689b |
if (r)
|
|
Packit Service |
ff689b |
return r;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (s1 == s1p || (*s1 >= '0' && *s1 <= '9'))
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
else if (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
/* special case "dev" */
|
|
Packit Service |
ff689b |
if (*s2 != '*' && s1p - s1 == 3 && !strncasecmp(s1, "dev", 3))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
s1 = s1p;
|
|
Packit Service |
ff689b |
s2 = s2p;
|
|
Packit Service |
ff689b |
continue;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (*s1 != '*' && s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
/* compare strings */
|
|
Packit Service |
ff689b |
r = s2p - s2 > s1p - s1 ? s1p - s1 : s2p - s2;
|
|
Packit Service |
ff689b |
if (r)
|
|
Packit Service |
ff689b |
r = strncasecmp(s1, s2, r);
|
|
Packit Service |
ff689b |
if (r)
|
|
Packit Service |
ff689b |
return r;
|
|
Packit Service |
ff689b |
if (s1p - s1 < s2p - s2)
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
if (s1p - s1 > s2p - s2)
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
s1 = s1p;
|
|
Packit Service |
ff689b |
s2 = s2p;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
pool_evrcmp_conda_int(const char *evr1, const char *evr1e, const char *evr2, const char *evr2e, int startswith)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
static char zero[2] = {'0', 0};
|
|
Packit Service |
ff689b |
const char *s1, *s2;
|
|
Packit Service |
ff689b |
const char *r1, *r2;
|
|
Packit Service |
ff689b |
int r;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* split and compare epoch */
|
|
Packit Service |
ff689b |
for (s1 = evr1; s1 < evr1e && *s1 >= '0' && *s1 <= '9'; s1++)
|
|
Packit Service |
ff689b |
;
|
|
Packit Service |
ff689b |
for (s2 = evr2; s2 < evr2e && *s2 >= '0' && *s2 <= '9'; s2++)
|
|
Packit Service |
ff689b |
;
|
|
Packit Service |
ff689b |
if (s1 == evr1 || s1 == evr1e || *s1 != '!')
|
|
Packit Service |
ff689b |
s1 = 0;
|
|
Packit Service |
ff689b |
if (s2 == evr1 || s2 == evr2e || *s2 != '!')
|
|
Packit Service |
ff689b |
s2 = 0;
|
|
Packit Service |
ff689b |
if (s1 || s2)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
r = solv_vercmp_conda(s1 ? evr1 : zero, s1 ? s1 : zero + 1,
|
|
Packit Service |
ff689b |
s2 ? evr2 : zero, s2 ? s2 : zero + 1, 0);
|
|
Packit Service |
ff689b |
if (r)
|
|
Packit Service |
ff689b |
return r;
|
|
Packit Service |
ff689b |
if (s1)
|
|
Packit Service |
ff689b |
evr1 = s1 + 1;
|
|
Packit Service |
ff689b |
if (s2)
|
|
Packit Service |
ff689b |
evr2 = s2 + 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* split into version/localversion */
|
|
Packit Service |
ff689b |
for (s1 = evr1, r1 = 0; s1 < evr1e; s1++)
|
|
Packit Service |
ff689b |
if (*s1 == '+')
|
|
Packit Service |
ff689b |
r1 = s1;
|
|
Packit Service |
ff689b |
for (s2 = evr2, r2 = 0; s2 < evr2e; s2++)
|
|
Packit Service |
ff689b |
if (*s2 == '+')
|
|
Packit Service |
ff689b |
r2 = s2;
|
|
Packit Service |
ff689b |
r = solv_vercmp_conda(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2, r2 ? 0 : startswith);
|
|
Packit Service |
ff689b |
if (r)
|
|
Packit Service |
ff689b |
return r;
|
|
Packit Service |
ff689b |
if (!r1 && !r2)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
if (!r1 && r2)
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
if (r1 && !r2)
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
return solv_vercmp_conda(r1 + 1, s1, r2 + 1, s2, startswith);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
int
|
|
Packit Service |
ff689b |
pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (evr1 == evr2)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
return pool_evrcmp_conda_int(evr1, evr1 + strlen(evr1), evr2, evr2 + strlen(evr2), 0);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
regexmatch(const char *evr, const char *version, size_t versionlen, int icase)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
regex_t reg;
|
|
Packit Service |
ff689b |
char *buf = solv_malloc(versionlen + 1);
|
|
Packit Service |
ff689b |
int r;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
memcpy(buf, version, versionlen);
|
|
Packit Service |
ff689b |
buf[versionlen] = 0;
|
|
Packit Service |
ff689b |
if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
solv_free(buf);
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
r = regexec(®, evr, 0, NULL, 0);
|
|
Packit Service |
ff689b |
regfree(®);
|
|
Packit Service |
ff689b |
solv_free(buf);
|
|
Packit Service |
ff689b |
return r == 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
globmatch(const char *evr, const char *version, size_t versionlen, int icase)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
regex_t reg;
|
|
Packit Service |
ff689b |
char *buf = solv_malloc(2 * versionlen + 3);
|
|
Packit Service |
ff689b |
size_t i, j;
|
|
Packit Service |
ff689b |
int r;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
buf[0] = '^';
|
|
Packit Service |
ff689b |
j = 1;
|
|
Packit Service |
ff689b |
for (i = 0, j = 1; i < versionlen; i++)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (version[i] == '.' || version[i] == '+' || version[i] == '*')
|
|
Packit Service |
ff689b |
buf[j++] = version[i] == '*' ? '.' : '\\';
|
|
Packit Service |
ff689b |
buf[j++] = version[i];
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
buf[j++] = '$';
|
|
Packit Service |
ff689b |
buf[j] = 0;
|
|
Packit Service |
ff689b |
if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
solv_free(buf);
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
r = regexec(®, evr, 0, NULL, 0);
|
|
Packit Service |
ff689b |
regfree(®);
|
|
Packit Service |
ff689b |
solv_free(buf);
|
|
Packit Service |
ff689b |
return r == 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* return true if solvable s matches the version */
|
|
Packit Service |
ff689b |
/* see conda/models/version.py */
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
solvable_conda_matchversion_single(Solvable *s, const char *version, size_t versionlen)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *evr;
|
|
Packit Service |
ff689b |
size_t i;
|
|
Packit Service |
ff689b |
int r;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (versionlen == 0 || (versionlen == 1 && *version == '*'))
|
|
Packit Service |
ff689b |
return 1; /* matches every version */
|
|
Packit Service |
ff689b |
evr = pool_id2str(s->repo->pool, s->evr);
|
|
Packit Service |
ff689b |
if (versionlen >= 2 && version[0] == '^' && version[versionlen - 1] == '$')
|
|
Packit Service |
ff689b |
return regexmatch(evr, version, versionlen, 0);
|
|
Packit Service |
ff689b |
if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
int flags = 0;
|
|
Packit Service |
ff689b |
int oplen;
|
|
Packit Service |
ff689b |
if (version[0] == '=')
|
|
Packit Service |
ff689b |
flags = version[1] == '=' ? REL_EQ : 8;
|
|
Packit Service |
ff689b |
else if (version[0] == '!' || version[0] == '~')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (version[1] != '=')
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
flags = version[0] == '!' ? REL_LT | REL_GT : 9;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (version[0] == '<' || version[0] == '>')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
flags = version[0] == '<' ? REL_LT : REL_GT;
|
|
Packit Service |
ff689b |
if (version[1] == '=')
|
|
Packit Service |
ff689b |
flags |= REL_EQ;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
oplen = flags == 8 || flags == REL_LT || flags == REL_GT ? 1 : 2;
|
|
Packit Service |
ff689b |
if (versionlen < oplen + 1)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
version += oplen;
|
|
Packit Service |
ff689b |
versionlen -= oplen;
|
|
Packit Service |
ff689b |
if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
|
|
Packit Service |
ff689b |
return 0; /* bad chars after op */
|
|
Packit Service |
ff689b |
if (versionlen >= 2 && version[versionlen - 2] == '.' && version[versionlen - 1] == '*')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (flags == 8 || flags == (REL_GT | REL_EQ))
|
|
Packit Service |
ff689b |
versionlen -= 2;
|
|
Packit Service |
ff689b |
else if (flags == (REL_LT | REL_GT))
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
versionlen -= 2;
|
|
Packit Service |
ff689b |
flags = 10;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (flags < 8)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
/* we now have an op and a version */
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
|
|
Packit Service |
ff689b |
if (r < 0)
|
|
Packit Service |
ff689b |
return (flags & REL_LT) ? 1 : 0;
|
|
Packit Service |
ff689b |
if (r == 0)
|
|
Packit Service |
ff689b |
return (flags & REL_EQ) ? 1 : 0;
|
|
Packit Service |
ff689b |
if (r > 0)
|
|
Packit Service |
ff689b |
return (flags & REL_GT) ? 1 : 0;
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (flags == 8 || flags == 10) /* startswith, not-startswith */
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
|
|
Packit Service |
ff689b |
return flags == 8 ? r == 0 : r != 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (flags == 9) /* compatible release op */
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
|
|
Packit Service |
ff689b |
if (r < 0)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
/* split off last component */
|
|
Packit Service |
ff689b |
while (versionlen > 0 && version[versionlen - 1] != '.')
|
|
Packit Service |
ff689b |
versionlen--;
|
|
Packit Service |
ff689b |
if (versionlen < 2)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
versionlen--;
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
|
|
Packit Service |
ff689b |
return r == 0 ? 1 : 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* do we have a '*' in the version */
|
|
Packit Service |
ff689b |
for (i = 0; i < versionlen; i++)
|
|
Packit Service |
ff689b |
if (version[i] == '*')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (i++; i < versionlen; i++)
|
|
Packit Service |
ff689b |
if (version[i] != '*')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
if (i < versionlen)
|
|
Packit Service |
ff689b |
return globmatch(evr, version, versionlen, 1);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (versionlen > 1 && version[versionlen - 1] == '*')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
/* startswith */
|
|
Packit Service |
ff689b |
while (versionlen > 0 && version[versionlen - 1] == '*')
|
|
Packit Service |
ff689b |
versionlen--;
|
|
Packit Service |
ff689b |
while (versionlen > 0 && version[versionlen - 1] == '.')
|
|
Packit Service |
ff689b |
versionlen--;
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
|
|
Packit Service |
ff689b |
return r == 0 ? 1 : 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* do we have a '@' in the version? */
|
|
Packit Service |
ff689b |
for (i = 0; i < versionlen; i++)
|
|
Packit Service |
ff689b |
if (version[i] == '@')
|
|
Packit Service |
ff689b |
return strncmp(evr, version, versionlen) == 0 && evr[versionlen] == 0;
|
|
Packit Service |
ff689b |
r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
|
|
Packit Service |
ff689b |
return r == 0 ? 1 : 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char *versionend)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *version = *versionp;
|
|
Packit Service |
ff689b |
int v, vor = 0, vand = -1; /* -1: doing OR, 0,1: doing AND */
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (version == versionend)
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
for (;;)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (*version == '(')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
version++;
|
|
Packit Service |
ff689b |
v = solvable_conda_matchversion_rec(s, &version, versionend);
|
|
Packit Service |
ff689b |
if (v == -1 || version == versionend || *version != ')')
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
version++;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (*version == ')' || *version == '|' || *version == ',')
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *vstart = version;
|
|
Packit Service |
ff689b |
while (version < versionend && *version != '(' && *version != ')' && *version != '|' && *version != ',')
|
|
Packit Service |
ff689b |
version++;
|
|
Packit Service |
ff689b |
if (vand >= 0 ? !vand : vor)
|
|
Packit Service |
ff689b |
v = 0; /* no need to call expensive matchversion if the result does not matter */
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
v = solvable_conda_matchversion_single(s, vstart, version - vstart) ? 1 : 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (version == versionend || *version == ')')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
*versionp = version;
|
|
Packit Service |
ff689b |
return vor | (vand >= 0 ? (vand & v) : v);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (*version == ',')
|
|
Packit Service |
ff689b |
vand = vand >= 0 ? (vand & v) : v;
|
|
Packit Service |
ff689b |
else if (*version == '|')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
vor |= vand >= 0 ? (vand & v) : v;
|
|
Packit Service |
ff689b |
vand = -1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
return -1;
|
|
Packit Service |
ff689b |
version++;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static int
|
|
Packit Service |
ff689b |
solvable_conda_matchbuild(Solvable *s, const char *build, const char *buildend)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *bp;
|
|
Packit Service |
ff689b |
const char *flavor = solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR);
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (!flavor)
|
|
Packit Service |
ff689b |
flavor = "";
|
|
Packit Service |
ff689b |
if (build == buildend)
|
|
Packit Service |
ff689b |
return *flavor ? 0 : 1;
|
|
Packit Service |
ff689b |
if (build + 1 == buildend && *build == '*')
|
|
Packit Service |
ff689b |
return 1;
|
|
Packit Service |
ff689b |
if (*build == '^' && buildend[-1] == '$')
|
|
Packit Service |
ff689b |
return regexmatch(flavor, build, buildend - build, 0);
|
|
Packit Service |
ff689b |
for (bp = build; bp < buildend; bp++)
|
|
Packit Service |
ff689b |
if (*bp == '*')
|
|
Packit Service |
ff689b |
return globmatch(flavor, build, buildend - build, 0);
|
|
Packit Service |
ff689b |
return strncmp(flavor, build, buildend - build) == 0 && flavor[buildend - build] == 0 ? 1 : 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* return true if solvable s matches the version */
|
|
Packit Service |
ff689b |
/* see conda/models/match_spec.py */
|
|
Packit Service |
ff689b |
int
|
|
Packit Service |
ff689b |
solvable_conda_matchversion(Solvable *s, const char *version)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *build, *versionend;
|
|
Packit Service |
ff689b |
int r;
|
|
Packit Service |
ff689b |
/* split off build */
|
|
Packit Service |
ff689b |
if ((build = strchr(version, ' ')) != 0)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
versionend = build++;
|
|
Packit Service |
ff689b |
while (*build == ' ')
|
|
Packit Service |
ff689b |
build++;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
versionend = version + strlen(version);
|
|
Packit Service |
ff689b |
r = solvable_conda_matchversion_rec(s, &version, versionend);
|
|
Packit Service |
ff689b |
if (r != 1 || version != versionend)
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
if (build && !solvable_conda_matchbuild(s, build, build + strlen(build)))
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
return r;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
static Id
|
|
Packit Service |
ff689b |
pool_addrelproviders_conda_slow(Pool *pool, const char *namestr, Id evr, Queue *plist, int mode)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
size_t namestrlen = strlen(namestr);
|
|
Packit Service |
ff689b |
const char *evrstr = evr == 0 || evr == 1 ? 0 : pool_id2str(pool, evr);
|
|
Packit Service |
ff689b |
Id p;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
FOR_POOL_SOLVABLES(p)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
Solvable *s = pool->solvables + p;
|
|
Packit Service |
ff689b |
if (!pool_installable(pool, s))
|
|
Packit Service |
ff689b |
continue;
|
|
Packit Service |
ff689b |
if (mode == 1 && !globmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
|
|
Packit Service |
ff689b |
continue;
|
|
Packit Service |
ff689b |
if (mode == 2 && !regexmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
|
|
Packit Service |
ff689b |
continue;
|
|
Packit Service |
ff689b |
if (!evrstr || solvable_conda_matchversion(s, evrstr))
|
|
Packit Service |
ff689b |
queue_push(plist, p);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* called from pool_addrelproviders, plist is an empty queue
|
|
Packit Service |
ff689b |
* it can either return an offset into the whatprovides array
|
|
Packit Service |
ff689b |
* or fill the plist queue and return zero */
|
|
Packit Service |
ff689b |
Id
|
|
Packit Service |
ff689b |
pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *namestr = pool_id2str(pool, name), *np;
|
|
Packit Service |
ff689b |
size_t l, nuc = 0;
|
|
Packit Service |
ff689b |
Id wp, p, *pp;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* is this a regex? */
|
|
Packit Service |
ff689b |
if (*namestr && *namestr == '^')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
l = strlen(namestr);
|
|
Packit Service |
ff689b |
if (namestr[l - 1] == '$')
|
|
Packit Service |
ff689b |
return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 2);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* is this '*'? */
|
|
Packit Service |
ff689b |
if (*namestr && *namestr == '*' && namestr[1] == 0)
|
|
Packit Service |
ff689b |
return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 0);
|
|
Packit Service |
ff689b |
/* does the string contain '*' or uppercase? */
|
|
Packit Service |
ff689b |
for (np = namestr; *np; np++)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (*np == '*')
|
|
Packit Service |
ff689b |
return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 1);
|
|
Packit Service |
ff689b |
else if (*np >= 'A' && *np <= 'Z')
|
|
Packit Service |
ff689b |
nuc++;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (nuc)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
char *nbuf = solv_strdup(namestr), *nbufp;
|
|
Packit Service |
ff689b |
for (nbufp = nbuf; *nbufp; nbufp++)
|
|
Packit Service |
ff689b |
*nbufp = *nbufp >= 'A' && *nbufp <= 'Z' ? *nbufp + ('a' - 'A') : *nbufp;
|
|
Packit Service |
ff689b |
name = pool_str2id(pool, nbuf, 0);
|
|
Packit Service |
ff689b |
wp = name ? pool_whatprovides(pool, name) : 0;
|
|
Packit Service |
ff689b |
solv_free(nbuf);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
wp = pool_whatprovides(pool, name);
|
|
Packit Service |
ff689b |
if (wp && evr && evr != 1)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *evrstr = pool_id2str(pool, evr);
|
|
Packit Service |
ff689b |
pp = pool->whatprovidesdata + wp;
|
|
Packit Service |
ff689b |
while ((p = *pp++) != 0)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (solvable_conda_matchversion(pool->solvables + p, evrstr))
|
|
Packit Service |
ff689b |
queue_push(plist, p);
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
wp = 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
return wp;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* create a CONDA_REL relation from a matchspec */
|
|
Packit Service |
ff689b |
Id
|
|
Packit Service |
ff689b |
pool_conda_matchspec(Pool *pool, const char *name)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
const char *p2;
|
|
Packit Service |
ff689b |
char *name2;
|
|
Packit Service |
ff689b |
char *p, *pp;
|
|
Packit Service |
ff689b |
char *build, *buildend, *version, *versionend;
|
|
Packit Service |
ff689b |
Id nameid, evrid;
|
|
Packit Service |
ff689b |
int haveglob = 0;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* ignore channel and namespace for now */
|
|
Packit Service |
ff689b |
if ((p2 = strrchr(name, ':')))
|
|
Packit Service |
ff689b |
name = p2 + 1;
|
|
Packit Service |
ff689b |
name2 = solv_strdup(name);
|
|
Packit Service |
ff689b |
/* find end of name */
|
|
Packit Service |
ff689b |
for (p = name2; *p && *p != ' ' && *p != '=' && *p != '<' && *p != '>' && *p != '!' && *p != '~'; p++)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (*p >= 'A' && *p <= 'Z')
|
|
Packit Service |
ff689b |
*(char *)p += 'a' - 'A'; /* lower case the name */
|
|
Packit Service |
ff689b |
else if (*p == '*')
|
|
Packit Service |
ff689b |
haveglob = 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (p == name2)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
solv_free(name2);
|
|
Packit Service |
ff689b |
return 0; /* error: empty package name */
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
nameid = pool_strn2id(pool, name2, p - name2, 1);
|
|
Packit Service |
ff689b |
while (*p == ' ')
|
|
Packit Service |
ff689b |
p++;
|
|
Packit Service |
ff689b |
if (!*p)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (*name2 != '^' && !haveglob)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
solv_free(name2);
|
|
Packit Service |
ff689b |
return nameid; /* return a simple dependency if no glob/regex */
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
evrid = pool_str2id(pool, "*", 1);
|
|
Packit Service |
ff689b |
solv_free(name2);
|
|
Packit Service |
ff689b |
return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* have version */
|
|
Packit Service |
ff689b |
version = p;
|
|
Packit Service |
ff689b |
versionend = p + strlen(p);
|
|
Packit Service |
ff689b |
while (versionend > version && versionend[-1] == ' ')
|
|
Packit Service |
ff689b |
versionend--;
|
|
Packit Service |
ff689b |
build = buildend = 0;
|
|
Packit Service |
ff689b |
/* split of build */
|
|
Packit Service |
ff689b |
p = versionend;
|
|
Packit Service |
ff689b |
for (;;)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
while (p > version && p[-1] != ' ' && p[-1] != '-' && p[-1] != '=' && p[-1] != ',' && p[-1] != '|' && p[-1] != '<' && p[-1] != '>' && p[-1] != '~')
|
|
Packit Service |
ff689b |
p--;
|
|
Packit Service |
ff689b |
if (p <= version + 1 || (p[-1] != ' ' && p[-1] != '='))
|
|
Packit Service |
ff689b |
break; /* no build */
|
|
Packit Service |
ff689b |
/* check char before delimiter */
|
|
Packit Service |
ff689b |
if (p[-2] == '=' || p[-2] == '!' || p[-2] == '|' || p[-2] == ',' || p[-2] == '<' || p[-2] == '>' || p[-2] == '~')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
/* illegal combination */
|
|
Packit Service |
ff689b |
if (p[-1] == ' ')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
p--;
|
|
Packit Service |
ff689b |
continue; /* special case space: it may be in the build */
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
break; /* no build */
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (p < versionend)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
build = p;
|
|
Packit Service |
ff689b |
buildend = versionend;
|
|
Packit Service |
ff689b |
versionend = p - 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
/* do weird version translation */
|
|
Packit Service |
ff689b |
if (versionend > version && version[0] == '=')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (versionend - version >= 2 && version[1] == '=')
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (!build)
|
|
Packit Service |
ff689b |
version += 2;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
else if (build)
|
|
Packit Service |
ff689b |
version += 1;
|
|
Packit Service |
ff689b |
else
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
for (p = version + 1; p < versionend; p++)
|
|
Packit Service |
ff689b |
if (*p == '=' || *p == ',' || *p == '|')
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
if (p == versionend)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
memmove(version, version + 1, versionend - version - 1);
|
|
Packit Service |
ff689b |
versionend[-1] = '*';
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
#if 0
|
|
Packit Service |
ff689b |
printf("version: >%.*s<\n", (int)(versionend - version), version);
|
|
Packit Service |
ff689b |
if (build) printf("build: >%.*s<\n", (int)(buildend - build), build);
|
|
Packit Service |
ff689b |
#endif
|
|
Packit Service |
ff689b |
/* strip spaces from version */
|
|
Packit Service |
ff689b |
for (p = pp = version; pp < versionend; pp++)
|
|
Packit Service |
ff689b |
if (*pp != ' ')
|
|
Packit Service |
ff689b |
*p++ = *pp;
|
|
Packit Service |
ff689b |
if (build)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
*p++ = ' ';
|
|
Packit Service |
ff689b |
memcpy(p, build, buildend - build);
|
|
Packit Service |
ff689b |
p += buildend - build;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
evrid = pool_strn2id(pool, version, p - version, 1);
|
|
Packit Service |
ff689b |
solv_free(name2);
|
|
Packit Service |
ff689b |
return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|