Backport: Add support for dpkg-style sorting of tilde in version/release

Original commit message:

- This allows much nicer handling some common scenarios such as
  upstream pre-releases where the pre-release version would normally
  appear newer than final release, eg 1.0-rc1 vs 1.0. Previously this
  required mapping the pre-release tag into the release tag to achieve
  desired sorting, with tilde this becomes simply 1.0~rc1 < 1.0.
- Add a rpmlib() tracking dependency to prevent older rpm versions
  from getting confused with packages relying on the new behavior.

Picked: db28221a4a ("Add support for dpkg-style sorting of tilde in version/release")
Authored-by: Michael Schroeder <mls@suse.de>
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
Picked: 8002b3f985 ("Spelling fixes.")
Authored-by: Ville Skyttä <ville.skytta@iki.fi>
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
Link: https://bugzilla.altlinux.org/46585
[ vt: Change to parseRCPOT is not applied because no rpmCharCheck call.
  Unsupported RPM tags (ORDERVERSION, SUGGESTSVERSION, ENHANCESVERSION)
  are removed. haveTildeDep is reworked because we don't have headerGet
  API. ]
Signed-off-by: Vitaly Chikunov <vt@altlinux.org>
This commit is contained in:
Виталий Чикунов 2023-06-25 05:54:19 +03:00
parent 2d55bbb3bf
commit 785ae7a9a2
4 changed files with 55 additions and 5 deletions

View File

@ -479,6 +479,40 @@ static void downgradeLzmaLevel(char *mode, uint64_t archiveSize)
#undef T
}
static int haveTildeDep(Header h)
{
HeaderIterator hi;
int_32 tag, type, count;
const void *ptr;
int ret = 0;
for (hi = headerInitIterator(h);
headerNextIterator(hi, &tag, &type, &ptr, &count);
ptr = headerFreeData(ptr, type))
{
switch (tag) {
case RPMTAG_PROVIDEVERSION:
case RPMTAG_REQUIREVERSION:
case RPMTAG_OBSOLETEVERSION:
case RPMTAG_CONFLICTVERSION:
case RPMTAG_TRIGGERVERSION:
break;
default:
continue;
}
if (type != RPM_STRING_ARRAY_TYPE)
continue;
while (count--) {
const char *p = ((const char **)ptr)[count];
if (strchr(p, '~'))
ret = 1;
}
}
hi = headerFreeIterator(hi);
return ret;
}
int writeRPM(Header *hdrp, const char *fileName, int type,
CSA_t csa, char *passPhrase, const char **cookie)
{
@ -569,6 +603,10 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
(void) headerAddEntry(h, RPMTAG_PAYLOADFLAGS, RPM_STRING_TYPE, buf+1, 1);
}
/* check if the package has a dependency with a '~' */
if (haveTildeDep(h))
(void) rpmlibNeedsFeature(h, "TildeInVersions", "4.10.0-1");
/* Create and add the cookie */
if (cookie) {
if (!headerGetEntry(h, RPMTAG_BUILDHOST, NULL, (void **)&s, NULL))

View File

@ -581,14 +581,14 @@ static int handlePreambleTag(Spec spec, Package pkg, int tag, const char *macro,
break;
case RPMTAG_VERSION:
SINGLE_TOKEN_ONLY;
if (rpmCharCheck(spec, field, "._+", ".."))
if (rpmCharCheck(spec, field, "._+~", ".."))
return RPMERR_BADSPEC;
/* This macro is for backward compatibility */
addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
(void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
break;
case RPMTAG_RELEASE:
if (rpmCharCheck(spec, field, "._+", ".."))
if (rpmCharCheck(spec, field, "._+~", ".."))
return RPMERR_BADSPEC;
/* This macro is for backward compatibility */
addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);

View File

@ -51,6 +51,9 @@ static struct rpmlibProvides_s {
{ "rpmlib(SetVersions)", "4.0.4-alt98",
( RPMSENSE_EQUAL),
N_("dependencies support set/subset versions.") },
{ "rpmlib(TildeInVersions)", "4.10.0-1",
( RPMSENSE_EQUAL),
N_("dependency comparison supports versions with tilde.") },
{ NULL, NULL, 0, NULL }
};

View File

@ -33,9 +33,18 @@ int rpmvercmp(const char * a, const char * b)
two = str2;
/* loop through each version segment of str1 and str2 and compare them */
while (*one && *two) {
while (*one && !xisalnum(*one)) one++;
while (*two && !xisalnum(*two)) two++;
while (*one || *two) {
while (*one && !xisalnum(*one) && *one != '~') one++;
while (*two && !xisalnum(*two) && *two != '~') two++;
/* handle the tilde separator, it sorts before everything else */
if (*one == '~' || *two == '~') {
if (*one != '~') return 1;
if (*two != '~') return -1;
one++;
two++;
continue;
}
if ( !*one && !*two )
return 0;