Add support for dpkg-style sorting of tilde in version/release
authorMichael Schroeder <mls@suse.de>
Mon, 23 Apr 2012 08:04:02 +0000 (11:04 +0300)
committerPanu Matilainen <pmatilai@redhat.com>
Mon, 23 Apr 2012 08:04:02 +0000 (11:04 +0300)
- 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 tild 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.

Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
build/pack.c
build/parsePreamble.c
build/parseReqs.c
lib/rpmds.c
lib/rpmvercmp.c

index 000d476..ebfee57 100644 (file)
@@ -231,6 +231,42 @@ static rpmRC copyPayload(FD_t ifd, const char *ifn, FD_t ofd, const char *ofn)
     return rc;
 }
 
+static int depContainsTilde(Header h, rpmTagVal tagEVR)
+{
+    struct rpmtd_s evrs;
+    const char *evr = NULL;
+
+    if (headerGet(h, tagEVR, &evrs, HEADERGET_MINMEM)) {
+       while ((evr = rpmtdNextString(&evrs)) != NULL)
+           if (strchr(evr, '~'))
+               break;
+       rpmtdFreeData(&evrs);
+    }
+    return evr != NULL;
+}
+
+static rpmTagVal depevrtags[] = {
+    RPMTAG_PROVIDEVERSION,
+    RPMTAG_REQUIREVERSION,
+    RPMTAG_OBSOLETEVERSION,
+    RPMTAG_CONFLICTVERSION,
+    RPMTAG_ORDERVERSION,
+    RPMTAG_TRIGGERVERSION,
+    RPMTAG_SUGGESTSVERSION,
+    RPMTAG_ENHANCESVERSION,
+    0
+};
+
+static int haveTildeDep(Header h)
+{
+    int i;
+
+    for (i = 0; depevrtags[i] != 0; i++)
+       if (depContainsTilde(h, depevrtags[i]))
+           return 1;
+    return 0;
+}
+
 static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
             CSA_t csa, char **cookie)
 {
@@ -305,6 +341,10 @@ static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileNam
        free(buf);
     }
 
+    /* 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) {
        rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
index 9944513..3ba035f 100644 (file)
@@ -699,7 +699,7 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
     case RPMTAG_VERSION:
     case RPMTAG_RELEASE:
        SINGLE_TOKEN_ONLY;
-       if (rpmCharCheck(spec, field, strlen(field), "._+%{}"))
+       if (rpmCharCheck(spec, field, strlen(field), "._+%{}~"))
           goto exit;
        headerPutString(pkg->header, tag, field);
        break;
index de2680c..5ad0501 100644 (file)
@@ -156,7 +156,7 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
            }
            EVR = xmalloc((ve-v) + 1);
            rstrlcpy(EVR, v, (ve-v) + 1);
-           if (rpmCharCheck(spec, EVR, ve-v, ".-_+:%{}")) goto exit;
+           if (rpmCharCheck(spec, EVR, ve-v, ".-_+:%{}~")) goto exit;
            re = ve;    /* ==> next token after EVR string starts here */
        } else
            EVR = NULL;
index af7732e..82aec52 100644 (file)
@@ -895,6 +895,9 @@ static const struct rpmlibProvides_s rpmlibProvides[] = {
     { "rpmlib(ScriptletExpansion)",    "4.9.0-1",
        (               RPMSENSE_EQUAL),
     N_("package scriptlets can be expanded at install time.") },
+    { "rpmlib(TildeInVersions)",    "4.10.0-1",
+       (               RPMSENSE_EQUAL),
+    N_("dependency comparison supports versions with tilde.") },
     { NULL,                            NULL, 0,        NULL }
 };
 
index f5ae092..a6b7075 100644 (file)
@@ -32,9 +32,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 && !risalnum(*one)) one++;
-       while (*two && !risalnum(*two)) two++;
+    while (*one || *two) {
+       while (*one && !risalnum(*one) && *one != '~') one++;
+       while (*two && !risalnum(*two) && *two != '~') two++;
+
+       /* handle the tilde separator, it sorts before everthing else */
+       if (*one == '~' || *two == '~') {
+           if (*one != '~') return 1;
+           if (*two != '~') return -1;
+           one++;
+           two++;
+           continue;
+       }
 
        /* If we ran to the end of either, we are finished with the loop */
        if (!(*one && *two)) break;