[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: rpmvercmp (was: dovecot imap available for testing, latest upstream release 0.99.10.6)
- From: John Dennis <jdennis redhat com>
- To: For testers of Fedora Core development releases <fedora-test-list redhat com>
- Subject: Re: rpmvercmp (was: dovecot imap available for testing, latest upstream release 0.99.10.6)
- Date: Thu, 01 Jul 2004 19:16:31 -0400
On Thu, 2004-07-01 at 16:28, Michal Jaegermann wrote:
> How you are using rpmvercmp, say, in a shell script? AFAIK there is
> no interface which would make that available.
This is off-topic for this list, but I'll answer it here, further
discussion should be moved to the fedora list.
You can use the rpm python bindings, see attached script (rpmvercmp.py).
Please note, internally the algorithm is:
name is tested for equality
epoch is numerically compared
version is passed to rpmvercmp
release is passed to rpmvercmp
first definitive answer is returned
rpmvercmp splits the string into alphanumeric substrings, then pairwise
compares them, numerically if the leading char is a digit, lexically
otherwise, pairwise comparison ends on first definitive result.
Credit and thanks go to Jerry Katz who showed me the python bindings and
patiently explained many things to me.
Also attached is a tiny C program I wrote that will operate on strings
rather than reading the rpm header's. It's good for when you just want
to test rpm names as strings and don't have a full rpm, you can give it
a pair of n-v-r, in which case it calls rpmvercmp on version and then
release, or you can give it either just a pair of versions or a pair of
revisions and it will call rpmvercmp on just that component. It links
against rpm so it uses the actual rpmvercmp function.
--
John Dennis <jdennis redhat com>
#!/usr/bin/python
import os,rpm,sys
if len(sys.argv) < 3:
print "bad usage"
sys.exit(3)
rpm1 = sys.argv[1]
rpm2 = sys.argv[2]
ts = rpm.TransactionSet()
ts.setVSFlags(-1)
fd = os.open(rpm1, os.O_RDONLY)
h1 = ts.hdrFromFdno(fd)
os.close(fd)
fd = os.open(rpm2, os.O_RDONLY)
h2 = ts.hdrFromFdno(fd)
os.close(fd)
# -1 less than, 0 equal, 1 greater than
ret = rpm.versionCompare(h1, h2)
# map to non-negative
ret += 1
print "%s %s %s" % (os.path.basename(rpm1),
["<", "=", ">"][ret],
os.path.basename(rpm2))
# return 0 = less than, 1 = equal, 2 = greater than
sys.exit(ret)
/*
* gcc -o rpmvercmp -lrpm rpmvercmp.c
* John Dennis - jdennis redhat com
*/
#include <stdio.h>
#include <string.h>
#include <rpm/rpmlib.h>
#define BUF_SIZE 1024
int verbose = 0;
int quiet = 0;
int stripReleaseDots = 0;
char *basename(char *path)
{
char *p;
for (p = path; *p; p++);
for (p--; p > path && p[-1] != '/'; p--);
return(p);
}
void usage(void)
{
fprintf(stderr, "rpmvercmp [-v -q -s] nvr1 nvr2\n");
fprintf(stderr, "rpmvercmp [-v -q -s] r1 r2\n");
fprintf(stderr, "rpmvercmp [-v -q] v1 v2\n");
fprintf(stderr, "-v = verbose\n");
fprintf(stderr, "-q = quiet\n");
fprintf(stderr, "-s = strip dot from release, e.g. kills \".src.rpm\" or \".i386.rpm\"\n");
fprintf(stderr, "returns 0 if arg1 < arg2, 1 if arg1 == arg2, 2 if arg1 > arg2, 3 if error\n");
}
/*
* Try to find an n-v-r in the string. Starting at the end of the
* string search backwards for two hyphens that delimit the n-v-r.
* Searching backwards allows hyphens in the name part.
* Optionally strip off anything following a dot in the release part on the
* assumption its ".src.rpm" or ".i385.rpm", etc.
*/
int parse_nvr(char *str, char *name, char *version, char *release)
{
char *hyphen1 = NULL, *hyphen2 = NULL, *p, *src, *dst, *str_end;
size_t name_len, version_len, release_len;
/* locate last 2 hyphens in string */
for (p = str; *p; p++);
str_end = p - 1;
for (str_end; p >= str && *p != '-'; p--);
if (p >= str && *p == '-') {
hyphen2 = p;
for (p--; p >= str && *p != '-'; p--);
if (p >= str && *p == '-') {
hyphen1 = p;
}
}
if (hyphen1 && hyphen2) {
name_len = hyphen1 - str;
version_len = hyphen2 - hyphen1 - 1;
release_len = str_end - hyphen2;
strncpy(name, str, name_len);
name[name_len] = 0;
strncpy(version, hyphen1+1, version_len);
version[version_len] = 0;
strncpy(release, hyphen2+1, release_len);
release[release_len] = 0;
if (stripReleaseDots) {
/* assume dot (.) terminates release string */
for (p = release; *p && *p != '.'; p++);
if (*p == '.') *p = 0;
}
return(1);
} else {
return 0;
}
}
int main(int argc, char **argv)
{
int i, cmp, name_cmp, version_cmp, release_cmp;
char *v1, *v2, *p;
int nvr1, nvr2;
char name1[BUF_SIZE], version1[BUF_SIZE], release1[BUF_SIZE];
char name2[BUF_SIZE], version2[BUF_SIZE], release2[BUF_SIZE];
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
if (strcmp("-v", argv[i]) == 0) {
verbose = 1;
} else if (strcmp("-q", argv[i]) == 0) {
quiet = 1;
} else if (strcmp("-s", argv[i]) == 0) {
stripReleaseDots = 1;
} else {
usage();
exit(3);
}
}
if ((argc - i) != 2) {
usage();
exit(3);
}
if (quiet) verbose = 0;
v1 = basename(argv[i]);
v2 = basename(argv[i+1]);
/* strip off path components leaving basename */
nvr1 = parse_nvr(v1, name1, version1, release1);
nvr2 = parse_nvr(v2, name2, version2, release2);
if (verbose) {
if (nvr1 && nvr2) {
printf("found n-v-r format in both strings\n");
printf("v1: name=\"%s\" version=\"%s\" release=\"%s\"\n",
name1, version1, release1);
printf("v2: name=\"%s\" version=\"%s\" release=\"%s\"\n",
name2, version2, release2);
} else {
printf("did not find n-v-r format in both strings\n");
printf("v1=\"%s\" v2=\"%s\"\n", v1, v2);
}
}
if (nvr1 && nvr2) {
if (strcmp(name1, name2) != 0) {
fprintf(stderr, "name mismatch name1=\"%s\" name2=\"%s\"\n", name1, name2);
return (3);
}
version_cmp = rpmvercmp(version1, version2);
release_cmp = rpmvercmp(release1, release2);
if (!quiet) {
printf(" name: %s = %s\n", name1, name2);
printf(" verson: %s %s %s\n",
version1,
version_cmp == 0 ? "=" : version_cmp < 0 ? "<" : ">",
version2);
printf(" release: %s %s %s\n",
release1,
release_cmp == 0 ? "=" : release_cmp < 0 ? "<" : ">",
release2);
}
if (version_cmp != 0)
cmp = version_cmp;
else
cmp = release_cmp;
} else {
if (nvr1 || nvr2) {
fprintf(stderr, "WARNING only one string in n-v-r format, bad comparision\n");
exit(3);
}
cmp = rpmvercmp(v1, v2);
}
if (!quiet)
printf("%s %s %s\n", v1, cmp == 0 ? "=" : cmp < 0 ? "<" : ">", v2);
/*
* Shell doesn't like negative return status so offset by 1
* yielding 0,1,2 instead of -1,0,1
*/
return(cmp+1);
}
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]