VPP/ArtifactVersioning
From fd.io
< VPP
DEB artifact versions, in DEB sort order applied, before change Ib69a59ee98aa296c5cb24b183bba807b6cb3c05c: 19.08.2-release <--- in fdio/release 19.08.2-2~g220e40541~b2500 | 19.08.2-1~g99fa5f722~b2499 | <--- fdio/1908 19.08.1-release <--- in fdio/release 19.08.1-402~g0830008b3~b2497 | 19.08.1-401~g8e4ed521a~b2496 | ... 19.08.1-3~g1ffabcb3d~b2098 | 19.08.1-2~g6b9847e80~b2097 | 19.08.1-1~gda900b25c~b2096 | 19.08-rc2~11-g01685bead~b2067 | 19.08-rc2~10-g2ecbf6dc5~b2066 | ... 19.08-rc2~2-ga5766fe13~b2058 | 19.08-rc2~1-g4c945dacb~b2057 | <--- in fdio/1908 19.08-rc1~19-gbb83b16a3~b2055 | 19.08-rc1~18-g8ef151c90~b2054 | ... 19.08-rc1~2-gc7f0fe030~b2038 | 19.08-rc1~1-g7119c22f8~b2037 --/ 19.08-rc0~840-gc0bc26eaf~b2035 ====\ 19.08-rc0~839-g08f2a5dae~b2035 | 19.08-rc0~838-g388f418a8~b2033 | <=== in fdio/master ... 19.08-rc0~2-g7c91007e1~b1197 | 19.08-rc0~1-g10dc2eabd~b1196 =====/ 19.08-release <--- in fdio/release 19.08-rc2~b2056 <--- in fdio/1908 overshadowed by post-rc1 but pre-rc2 builds, overshadows post-19.08 builds 19.08-rc1~b2036 <--- in fdio/1908 (the first build to go into fdio/1908) overshadows post-19.08 builds 19.08-rc0~b1195 <======== === in fdio/master 19.08-26~g7c33c343e~b2094 ---\ 19.08-25~g50f883106~b2093 | 19.08-24~ge6a571262~b2092 | <--- in fdio/1908 (overshadowed by rc1/2 builds) ... 19.08-2~g9e25c7723~b2070 | 19.08-1~g46441cb9c~b2069 --/ 19.04-rc0~674-g3f86ca3ee~b1194 ====\ 19.04-rc0~673-ge36f44ad9~b1193 | <=== in fdio/master (before stable/1904 branch) =====/ DEB artifact versions, in DEB sort order applied, after change: 19.08.2-release <---------- in fdio/release 19.08.2-2~g220e40541~b2500 ----\ 19.08.2-1~g99fa5f722~b2499 ---/ <-- in fdio/1908 19.08.1-release <---------- in fdio/release 19.08.1-402~g0830008b3~b2497 ---\ 19.08.1-401~g8e4ed521a~b2496 | ... 19.08.1-3~g1ffabcb3d~b2098 | 19.08.1-2~g6b9847e80~b2097 | 19.08.1-1~gda900b25c~b2096 | 19.08.0-26~g7c33c343e~b2094 | 19.08.0-25~g50f883106~b2093 | 19.08.0-24~ge6a571262~b2092 | <---- in fdio/1908, all in correct order ... 19.08.0-2~g9e25c7723~b2070 | 19.08.0-1~g46441cb9c~b2069 | 19.08-rc2~11-g01685bead~b2067 | 19.08-rc2~10-g2ecbf6dc5~b2066 | 19.08-rc2~9-g14c7756ad~b2065 | ... 19.08-rc2~1-g4c945dacb~b2057 | 19.08-rc2~0-g2f51729bb~b2056 <------- in fdio/1908 previously was called "19.08-rc2", now in the correct place 19.08-rc1~19-gbb83b16a3~b2055 | 19.08-rc1~18-g8ef151c90~b2054 | ... 19.08-rc1~2-gc7f0fe030~b2038 | 19.08-rc1~1-g7119c22f8~b2037 | 19.08-rc1~0-g23526f78a~b2036 <--/---- in fdio/1908, previously was called "19.08-rc1", now in the correct place 19.08-rc0~840-gc0bc26eaf~b2035 ====\ 19.08-rc0~839-g08f2a5dae~b2034 | <=== in fdio/master ... 19.08-rc0~1-g10dc2eabd~b1196 | 19.08-rc0~0-g40fd1f3df~b1195 ======/ 19.08-release <---- in fdio/release 19.04-rc0~674-g3f86ca3ee~b1194 <======== in fdio/master (before stable/1904 branch) 19.04-rc0~673-ge36f44ad9~b1193 <=======/ The code used to test was as follows: #define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> static int order(char c) { if (isdigit(c)) return 0; else if (isalpha(c)) return c; else if (c == '~') return -1; else if (c) return c + 256; else return 0; } int CmpFragment(const char *A,const char *AEnd, const char *B,const char *BEnd) { /* Iterate over the whole string What this does is to split the whole string into groups of numeric and non numeric portions. For instance: a67bhgs89 Has 4 portions 'a', '67', 'bhgs', '89'. A more normal: 2.7.2-linux-1 Has '2', '.', '7', '.' ,'-linux-','1' */ const char *lhs = A; const char *rhs = B; while (lhs != AEnd && rhs != BEnd) { int first_diff = 0; while (lhs != AEnd && rhs != BEnd && (!isdigit(*lhs) || !isdigit(*rhs))) { int vc = order(*lhs); int rc = order(*rhs); if (vc != rc) return vc - rc; ++lhs; ++rhs; } while (*lhs == '0') ++lhs; while (*rhs == '0') ++rhs; while (isdigit(*lhs) && isdigit(*rhs)) { if (!first_diff) first_diff = *lhs - *rhs; ++lhs; ++rhs; } if (isdigit(*lhs)) return 1; if (isdigit(*rhs)) return -1; if (first_diff) return first_diff; } // The strings must be equal if (lhs == AEnd && rhs == BEnd) return 0; // lhs is shorter if (lhs == AEnd) { if (*rhs == '~') return 1; return -1; } // rhs is shorter if (rhs == BEnd) { if (*lhs == '~') return -1; return 1; } // Shouldn't happen return 1; } /* This fragments the version into E:V-R triples and compares each portion separately. */ int DoCmpVersion(char *A,char *AEnd, char *B, char *BEnd) { // Strip off the epoch and compare it char *lhs = ( char*) memchr(A, ':', AEnd - A); char *rhs = ( char*) memchr(B, ':', BEnd - B); if (lhs == NULL) lhs = A; if (rhs == NULL) rhs = B; // Special case: a zero epoch is the same as no epoch, // so remove it. if (lhs != A) { for (; *A == '0'; ++A); if (A == lhs) { ++A; ++lhs; } } if (rhs != B) { for (; *B == '0'; ++B); if (B == rhs) { ++B; ++rhs; } } // Compare the epoch int Res = CmpFragment(A,lhs,B,rhs); if (Res != 0) return Res; // Skip the : if (lhs != A) lhs++; if (rhs != B) rhs++; // Find the last - char *dlhs = ( char*) memrchr(lhs, '-', AEnd - lhs); char *drhs = ( char*) memrchr(rhs, '-', BEnd - rhs); if (dlhs == NULL) dlhs = AEnd; if (drhs == NULL) drhs = BEnd; // Compare the main version Res = CmpFragment(lhs,dlhs,rhs,drhs); if (Res != 0) return Res; // Skip the - if (dlhs != lhs) dlhs++; if (drhs != rhs) drhs++; // no debian revision need to be treated like -0 if (*(dlhs-1) == '-' && *(drhs-1) == '-') return CmpFragment(dlhs,AEnd,drhs,BEnd); else if (*(dlhs-1) == '-') { char* null = "0"; return CmpFragment(dlhs,AEnd,null, null+1); } else if (*(drhs-1) == '-') { char* null = "0"; return CmpFragment(null, null+1, drhs, BEnd); } else return 0; } char cmp_a[1024]; char cmp_b[1024]; int deb_compare(char **a, char **b) { int len_a = strlen(*a); memcpy(cmp_a, *a, len_a+1); char *end_a = cmp_a + len_a; int len_b = strlen(*b); memcpy(cmp_b, *b, len_b+1); char *end_b = cmp_b + len_b; int res = -DoCmpVersion(cmp_a, end_a, cmp_b, end_b); // printf("A: '%s' B: '%s' res:%d\n", cmp_a, cmp_b, res); return res; } #include <stdlib.h> #include <string.h> #include <ctype.h> /* This was lifted pretty much verbatim from * https://fastapi.metacpan.org/source/HAG/RPM-VersionSort-1.00/VersionSort.xs */ /* This is lifted pretty much verbatim from the RPM 4.0.2 sources. See lib/misc.c */ /* Note that the semantics as documented by redhat are incorrect: some return value semantics are inherited from strcmp, which only promises to use integers greater, less, or equal to zero, which is not the same as (-1,0,1). So we fix this up in the xsub. */ /* compare alpha and numeric segments of two versions */ /* return 1: a is newer than b */ /* 0: a and b are the same version */ /* -1: b is newer than a */ int rpmvercmp(const char * a, const char * b) { char oldch1, oldch2; char * str1, * str2; char * one, * two; int rc; int isnum; /* easy comparison to see if versions are identical */ if (!strcmp(a, b)) return 0; str1 = alloca(strlen(a) + 1); str2 = alloca(strlen(b) + 1); strcpy(str1, a); strcpy(str2, b); one = str1; two = str2; /* loop through each version segment of str1 and str2 and compare them */ while (*one && *two) { while (*one && !isalnum(*one)) one++; while (*two && !isalnum(*two)) two++; str1 = one; str2 = two; /* grab first completely alpha or completely numeric segment */ /* leave one and two pointing to the start of the alpha or numeric */ /* segment and walk str1 and str2 to end of segment */ if (isdigit(*str1)) { while (*str1 && isdigit(*str1)) str1++; while (*str2 && isdigit(*str2)) str2++; isnum = 1; } else { while (*str1 && isalpha(*str1)) str1++; while (*str2 && isalpha(*str2)) str2++; isnum = 0; } /* save character at the end of the alpha or numeric segment */ /* so that they can be restored after the comparison */ oldch1 = *str1; *str1 = '\0'; oldch2 = *str2; *str2 = '\0'; /* take care of the case where the two version segments are */ /* different types: one numeric and one alpha */ if (one == str1) return -1; /* arbitrary */ if (two == str2) return -1; if (isnum) { /* this used to be done by converting the digit segments */ /* to ints using atoi() - it's changed because long */ /* digit segments can overflow an int - this should fix that. */ /* throw away any leading zeros - it's a number, right? */ while (*one == '0') one++; while (*two == '0') two++; /* whichever number has more digits wins */ if (strlen(one) > strlen(two)) return 1; if (strlen(two) > strlen(one)) return -1; } /* strcmp will return which one is greater - even if the two */ /* segments are alpha or if they are numeric. don't return */ /* if they are equal because there might be more segments to */ /* compare */ rc = strcmp(one, two); if (rc) return rc; /* restore character that was replaced by null above */ *str1 = oldch1; one = str1; *str2 = oldch2; two = str2; } /* this catches the case where all numeric and alpha segments have */ /* compared identically but the segment sepparating characters were */ /* different */ if ((!*one) && (!*two)) return 0; /* whichever version still has characters left over wins */ if (!*one) return -1; else return 1; } int rpm_compare(const char **a, const char **b) { int vercmp = rpmvercmp(*a, *b); int result = 0; if(vercmp < 0) result = 1; if(vercmp > 0) result = -1; // printf("RPM comp '%s' vs '%s': %d\n", *a, *b, result); return result; } int main(int argc, char **argv) { FILE * fp; char * line = NULL; size_t len = 0; ssize_t read; char **versions = malloc(1024000); int n_versions = 0; if (argc < 2) { fp = fopen("versions.txt", "r"); } else { fp = fopen(argv[1], "r"); } if (fp == NULL) exit(EXIT_FAILURE); int i; while ((read = getline(&versions[n_versions], &len, fp)) != -1) { line = versions[n_versions]; if (strlen(line) > 0) { line[strlen(line)-1] = 0; } if (strlen(line) == 0) { break; } n_versions++; } /* printf("Original list:\n"); for (i=0; i<n_versions; i++) { printf("%s\n", versions[i]); } */ qsort(versions, n_versions, sizeof(char *), deb_compare); printf("\nDEB sorting:\n"); for (i=0; i<n_versions; i++) { printf("%s\n", versions[i]); } qsort(versions, n_versions, sizeof(char *), rpm_compare); printf("\nRPM sorting:\n"); for (i=0; i<n_versions; i++) { printf("%s\n", versions[i]); } fclose(fp); exit(EXIT_SUCCESS); }