Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 May 2002 14:50:39 +0200
From:      Jeremy Lea <reg@FreeBSD.ORG>
To:        Mark Murray <mark@grondar.za>, "Bruce A. Mah" <bmah@FreeBSD.ORG>
Cc:        current@FreeBSD.ORG, ports@FreeBSD.ORG
Subject:   pkg_version in C [was: Re: Perl scripts that need rewriting - Progress!]
Message-ID:  <20020514145039.B13083@shale.csir.co.za>
In-Reply-To: <200205091933.g49JXMjV041629@grimreaper.grondar.org>; from mark@grondar.za on Thu, May 09, 2002 at 08:33:22PM %2B0100
References:  <200205091933.g49JXMjV041629@grimreaper.grondar.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--Dxnq1zWXvFF0Q93v
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,

On Thu, May 09, 2002 at 08:33:22PM +0100, Mark Murray wrote:
> /usr/sbin/pkg_version	Jeremy Lea <reg@FreeBSD.ORG> - re

OK, the first revision is attached.  It appears to work for me...  It
needs some spit and polish, and probably a few more people to test.

I've not implemented the -d flag since it sort of became unneeded, and
it's not really the way things are done in the rest of pkg_*.  I've also
not implemented -c.  There were enough warnings that it wasn't really
useful, and portupgrade does a much better job... 

Regards,
  -Jeremy

-- 
FreeBSD - Because the best things in life are free...
                                           http://www.freebsd.org/

--Dxnq1zWXvFF0Q93v
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pkg_version.diff"

Index: lib/lib.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/lib.h,v
retrieving revision 1.43
diff -u -r1.43 lib.h
--- lib/lib.h	5 May 2002 21:03:25 -0000	1.43
+++ lib/lib.h	14 May 2002 12:41:41 -0000
@@ -201,6 +201,8 @@
 
 /* Version */
 int		verscmp(Package *, int, int);
+const char	*version_of(const char *, int *, int *);
+int		version_cmp(const char *, const char *);
 
 /* Externs */
 extern Boolean	Verbose;
Index: lib/version.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/version.c,v
retrieving revision 1.2
diff -u -r1.2 version.c
--- lib/version.c	1 Apr 2002 09:39:07 -0000	1.2
+++ lib/version.c	14 May 2002 12:41:41 -0000
@@ -14,6 +14,15 @@
  * Maxim Sobolev
  * 31 July 2001
  *
+ */
+ 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/pkg_install/lib/version.c,v 1.2 2002/04/01 09:39:07 obrien Exp $");
+
+#include "lib.h"
+#include <err.h>
+
+/*
  * Routines to assist with PLIST_FMT_VER numbers in the packing
  * lists.
  *
@@ -23,13 +32,6 @@
  *	 value insted of the hash of an object this links points to.
  *
  */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.sbin/pkg_install/lib/version.c,v 1.2 2002/04/01 09:39:07 obrien Exp $");
-
-#include "lib.h"
-#include <err.h>
-
 int
 verscmp(Package *pkg, int major, int minor)
 {
@@ -43,4 +45,123 @@
 	rval = 1;
 
     return rval;
+}
+
+/*
+ * version_of(pkgname, epoch, revision) returns a pointer to the version
+ * portion of a package name and the two special components.
+ *
+ * Jeremy D. Lea.
+ */
+const char *
+version_of(const char *pkgname, int *epoch, int *revision)
+{
+    char *ch;
+    
+    if (pkgname == NULL)
+	errx(2, "%s: Passed NULL pkgname.", __func__);
+    if (epoch != NULL) {
+	if ((ch = strrchr(pkgname, ',')) == NULL)
+	    *epoch = 0;
+	else
+	    *epoch = atoi(&ch[1]);
+    }
+    if (revision != NULL) {
+	if ((ch = strrchr(pkgname, '_')) == NULL)
+	    *revision = 0;
+	else
+	    *revision = atoi(&ch[1]);
+    }
+    /* Cheat if we are just passed a version, not a valid package name */
+    if ((ch = strrchr(pkgname, '-')) == NULL)
+	return pkgname;
+    else
+    	return &ch[1];
+}
+
+/*
+ * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version
+ * components of pkg1 is less than, equal to or greater than pkg2. No
+ * comparision of the basenames is done.
+ *
+ * The port verison is defined by:
+ * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
+ * ${PORTEPOCH} supercedes ${PORTVERSION} supercedes ${PORTREVISION}.
+ * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk
+ * for more information.
+ *
+ * The epoch and revision are defined to be a single number, while the rest
+ * of the version should conform to the porting guidelines. It can contain
+ * multiple components, seperated by a period, including letters.
+ *
+ * The tests below allow for significantly more latitude in the version
+ * numbers than is allowed in the guidelines. No point in wasting user's
+ * time enforcing them here. That's what flamewars are for.
+ *
+ * Jeremy D. Lea.
+ */
+int
+version_cmp(const char *pkg1, const char *pkg2)
+{
+    const char *c1, *c2, *v1, *v2;
+    char *t1, *t2;
+    int e1, e2, r1, r2, n1, n2;
+    
+    v1 = version_of(pkg1, &e1, &r1);
+    v2 = version_of(pkg2, &e2, &r2);
+    /* Minor optimisation. */
+    if (strcmp(v1, v2) == 0)
+	return 0;
+    /* First compare epoch. */
+    if (e1 != e2)
+	return (e1 < e2 ? -1 : 1);
+    else {
+	/* We walk down the versions, trying to convert to numbers.
+	 * We terminate when we reach an underscore, a comma or the
+	 * string terminator, thanks to a nasty trick with strchr().
+	 *
+	 * strtol() conveniently gobbles up the chars it converts.
+	 */
+	c1 = strchr("_,", v1[0]);
+	c2 = strchr("_,", v2[0]);
+	while (c1 == NULL && c2 == NULL) {
+	    n1 = strtol(v1, &t1, 10);
+	    n2 = strtol(v2, &t2, 10);
+	    if (n1 != n2)
+		return (n1 < n2 ? -1 : 1);
+	    /* The numbers are equal, check for letters. They're letters
+	       purely because strtol() didn't chomp them. */
+	    c1 = strchr("_,.", t1[0]);
+	    c2 = strchr("_,.", t2[0]);
+	    if (c1 == NULL && c2 == NULL) {
+		/* Both have letters. Compare them. */
+		if (t1[0] != t2[0])
+		    return (t1[0] < t2[0] ? -1 : 1);
+		/* Boring. The letters are equal. Carry on. */
+		v1 = &t1[1], v2 = &t2[1];
+	    } else if (c1 == NULL) {
+		/* Letters are strange. After a number, a letter counts
+		   as greater, but after a period it's less. */
+		return (isdigit(v1[0]) ? 1 : -1);
+	    } else if (c2 == NULL) {
+		return (isdigit(v2[0]) ? -1 : 1);
+	    } else {
+		/* Neither were letters.  Advance over the period. */
+		v1 = (t1[0] == '.' ? &t1[1] : t1);
+		v2 = (t2[0] == '.' ? &t2[1] : t2);
+	    }
+	    c1 = strchr("_,", v1[0]);
+	    c2 = strchr("_,", v2[0]);
+	}
+        /* If we got here, check if one version has something left. */
+	if (c1 == NULL)
+	    return (isdigit(v1[0]) ? 1 : -1);
+	if (c2 == NULL)
+	    return (isdigit(v2[0]) ? -1 : 1);
+	/* We've run out of version. Try the revision... */
+	if (r1 != r2)
+	    return (r1 < r2 ? -1 : 1);
+	else
+	    return 0;
+    }
 }
Index: version/Makefile
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/Makefile,v
retrieving revision 1.10
diff -u -r1.10 Makefile
--- version/Makefile	18 Sep 2001 17:58:10 -0000	1.10
+++ version/Makefile	14 May 2002 12:41:41 -0000
@@ -1,7 +1,14 @@
 # $FreeBSD: src/usr.sbin/pkg_install/version/Makefile,v 1.10 2001/09/18 17:58:10 bmah Exp $
 
-SCRIPTS=	pkg_version.pl
-MAN=		pkg_version.1
+PROG=	pkg_version
+SRCS=	main.c perform.c
+
+CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib
+
+WARNS?=	2
+
+DPADD=	${LIBINSTALL} ${LIBFETCH} ${LIBMD}
+LDADD=	${LIBINSTALL} -lfetch -lmd
 
 test:
 	./test-pkg_version.sh
Index: version/main.c
===================================================================
RCS file: version/main.c
diff -N version/main.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ version/main.c	14 May 2002 12:41:41 -0000
@@ -0,0 +1,90 @@
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Jeremy D. Lea
+ * 11 May 2002
+ *
+ * This is the version module.  Based on pkg_version.pl by Bruce A. Mah.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "lib.h"
+#include "version.h"
+#include <err.h>
+
+static char Options[] = "dhl:L:s:tv";
+
+char 	*LimitChars = NULL;
+char 	*PreventChars = NULL;
+char	*MatchName = NULL;
+
+static void usage __P((void));
+
+int
+main(int argc, char **argv)
+{
+    int ch, cmp = 0;
+
+    if (argc == 4 && !strcmp(argv[1], "-t")) {
+	cmp = version_cmp(argv[2], argv[3]);
+	printf(cmp > 0 ? ">\n" : (cmp < 0 ? "<\n" : "=\n"));
+	exit(0);
+    }
+    else while ((ch = getopt(argc, argv, Options)) != -1) {
+	switch(ch) {
+	case 'v':
+	    Verbose = TRUE;
+	    break;
+
+	case 'l':
+	    LimitChars = optarg;
+	    break;
+
+	case 'L':
+	    PreventChars = optarg;
+	    break;
+
+	case 's':
+	    MatchName = optarg;
+	    break;
+
+	case 't':
+	    errx(2, "Invalid -t usage.");
+	    break;
+	    
+	case 'h':
+	case '?':
+	default:
+	    usage();
+	    break;
+	}
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    return pkg_perform(argv);
+}
+
+static void
+usage()
+{
+    fprintf(stderr, "%s\n%s\n",
+	"usage: pkg_version [-chv] [-l limchar] [-L limchar] [-s string] index",
+	"       pkg_info -t v1 v2");
+    exit(1);
+}
Index: version/perform.c
===================================================================
RCS file: version/perform.c
diff -N version/perform.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ version/perform.c	14 May 2002 12:41:41 -0000
@@ -0,0 +1,298 @@
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Jeremy D. Lea
+ * 11 May 2002
+ *
+ * This is the version module.  Based on pkg_version.pl by Bruce A. Mah.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "lib.h"
+#include "version.h"
+#include <err.h>
+#include <fetch.h>
+#include <fts.h>
+#include <signal.h>
+
+FILE *IndexFile;
+struct index_head Index = SLIST_HEAD_INITIALIZER(Index);
+
+static int pkg_do(char *);
+static void show_version(const char *, const char *, const char *);
+static int fname_cmp(const FTSENT **, const FTSENT **);
+
+/*
+ * This is the traditional pkg_perform, except that the argument is _not_
+ * a list of packages.  It is the index file from the command line.
+ *
+ * We loop over the installed packages, matching them with the -s flag
+ * if needed and calling pkg_do().  Before hand we set up a few things,
+ * and after we tear them down...
+ *
+ * Jeremy D. Lea.
+ */
+int
+pkg_perform(char **indexarg)
+{
+    const char *paths[2] = {LOG_DIR, NULL};
+    char tmp[PATH_MAX];
+    struct index_entry *ie;
+    int err_cnt = 0;
+    FTS *ftsp;
+    FTSENT *f;
+
+    if (!isdir(paths[0]))
+    	errx(2, "Unable to find package database directory");
+
+    if (*indexarg == NULL) {
+    	strlcpy(tmp, PORTS_DIR, PATH_MAX);
+    	strlcat(tmp, "/INDEX", PATH_MAX);
+    } else
+	strlcpy(tmp, *indexarg, PATH_MAX);
+    if (isURL(tmp))
+	IndexFile = fetchGetURL(tmp, "");
+    else
+	IndexFile = fopen(tmp, "r");
+
+    ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
+    if (ftsp != NULL) {
+	while ((f = fts_read(ftsp)) != NULL) {
+	    if (f->fts_info == FTS_D && f->fts_level == 1) {
+		fts_set(ftsp, f, FTS_SKIP);
+		if (MatchName == NULL || strstr(f->fts_name, MatchName))
+			err_cnt += pkg_do(f->fts_name);
+	    }
+	}
+	fts_close(ftsp);
+    }
+
+    while (!SLIST_EMPTY(&Index)) {
+    	ie = SLIST_FIRST(&Index);
+    	SLIST_REMOVE_HEAD(&Index, next);
+	free(ie);
+    }
+    if (IndexFile != NULL)
+	fclose(IndexFile);
+
+    return err_cnt;
+}
+
+/*
+ * Traditional pkg_do().  We take the package name we are passed and 
+ * first slurp in the CONTENTS file, getting name and origin, then
+ * we look for it's corresponding Makefile.  If that fails we pull in
+ * the INDEX, and check there.
+ *
+ * Jeremy D. Lea.
+ */
+static int
+pkg_do(char *pkg)
+{
+    char *ch, tmp[PATH_MAX], *latest = NULL;
+    Package plist;
+    struct index_entry *ie;
+    FILE *fp;
+    size_t len;
+
+    /* Suck in the contents list */
+    plist.head = plist.tail = NULL;
+    plist.name = plist.origin = NULL;
+    strlcpy(tmp, LOG_DIR, PATH_MAX);
+    strlcat(tmp, "/", PATH_MAX);
+    strlcat(tmp, pkg, PATH_MAX);
+    strlcat(tmp, "/", PATH_MAX);
+    strlcat(tmp, CONTENTS_FNAME, PATH_MAX);
+    fp = fopen(tmp, "r");
+    if (!fp) {
+	warnx("unable to open %s file", CONTENTS_FNAME);
+	return 1;
+    }
+    read_plist(&plist, fp);
+    fclose(fp);
+
+    if (plist.origin != NULL) {
+	strlcpy(tmp, PORTS_DIR, PATH_MAX);
+	strlcat(tmp, "/", PATH_MAX);
+	strlcat(tmp, plist.origin, PATH_MAX);
+	if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
+	    if ((latest = vpipe("make -V PKGNAME", tmp)) == NULL) {
+	    	warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
+	    	return 1;
+	    }
+	    show_version(plist.name, latest, "port");
+	}		
+    }
+    if (latest == NULL) {
+	/* We only pull in the INDEX once. */
+	if (SLIST_EMPTY(&Index)) {
+	    if (!IndexFile) {
+		warnx("Unable to open INDEX.");
+		return 1;
+	    }
+	    while ((ch = fgetln(IndexFile, &len)) != NULL) {
+		strlcpy(tmp, ch, MIN(len, PATH_MAX));
+		/* The INDEX has pkgname|portdir|... */
+		if ((ch = strchr(tmp, '|')) == NULL)
+		    goto funny;
+		ch[0] = '\0';
+		if ((ch = strchr(&ch[1], '|')) == NULL)
+		    goto funny;
+		ch[0] = '\0';
+		/* Look backwards for the last two dirs = origin */
+		while (*--ch != '/')
+		    if (ch[0] == '\0')
+			goto funny;
+		while (*--ch != '/')
+		    if (ch[0] == '\0')
+			goto funny;
+		if ((ie = malloc(sizeof(struct index_entry))) == NULL) {
+		    warnx("Unable to allocate memory.");
+		    return 1;
+		}
+		strlcpy(ie->name, tmp, PATH_MAX);
+		strlcpy(ie->origin, &ch[1], PATH_MAX);
+		SLIST_INSERT_HEAD(&Index, ie, next);
+            }
+	}
+	/* Now that we've slurped in the INDEX... */
+	SLIST_FOREACH(ie, &Index, next) {
+	    if (plist.origin != NULL) {
+		if (strcmp(plist.origin, ie->origin) == 0)
+		    latest = strdup(ie->name);
+	    } else {
+		strlcpy(tmp, ie->name, PATH_MAX);
+		if ((ch = strrchr(tmp, '-')) == NULL)
+		    goto funny;
+		ch[0] = '\0';
+		if (strstr(plist.name, tmp)) {
+		    if (latest != NULL) {
+			/* Multiple matches */
+			strlcpy(tmp, latest, PATH_MAX);
+			strlcat(tmp, "|", PATH_MAX);
+			strlcat(tmp, ie->name, PATH_MAX);
+			free(latest);
+			latest = strdup(tmp);
+		    } else
+			latest = strdup(ie->name);
+		}
+	    }
+	}
+	if (latest == NULL)
+	    show_version(plist.name, NULL, plist.origin);
+	else
+	    show_version(plist.name, latest, "index");
+    }
+    if (latest != NULL)
+	free(latest);
+    free_plist(&plist);
+    return 0;
+
+ funny:
+    warnx("This is a very funny looking INDEX!");
+    return 1;
+}
+
+#define LIMIT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
+			(LimitChars != NULL && strchr(LimitChars, (c))) || \
+			(PreventChars == NULL && LimitChars == NULL))
+
+/* 
+ * Do the work of comparing and outputing.  Ugly, but well that's what
+ * You get when you try to match perl output in C ;-).  The limit characters
+ * flags don't make any sense to me.
+ *
+ * Jeremy D. Lea.
+ */
+void
+show_version(const char *installed, const char *latest, const char *source)
+{
+    char *ch, tmp[PATH_MAX];
+    const char *ver;
+    int cmp = 0;
+    
+    if (!installed || strlen(installed) == 0)
+	return;
+    strlcpy(tmp, installed, PATH_MAX);
+    if (!Verbose) {
+	if ((ch = strrchr(tmp, '-')) != NULL)
+	    ch[0] = '\0';
+    }
+    if (latest == NULL) {
+	if (source == NULL && LIMIT('!')) {
+	    printf("%-34s  !", tmp);
+	    if (Verbose)
+		printf("   Comparison failed");
+	    printf("\n");
+	} else if (source != NULL && LIMIT('?')) {
+	    printf("%-34s  ?", tmp);
+	    if (Verbose)
+		printf("   orphaned: %s", source);
+	    printf("\n");
+	}
+	return;
+    }
+    if (strchr(latest,'|') != NULL) {
+    	if (LIMIT('*')) {
+	    printf("%-34s  *", tmp);
+	    if (Verbose) {
+		strlcpy(tmp, latest, PATH_MAX);
+		ch = strchr(tmp, '|');
+		ch[0] = '\0'; 
+		ver = version_of(tmp, NULL, NULL);
+		printf("   multiple versions (index has %s", ver);
+		do {
+		    ver = version_of(&ch[1], NULL, NULL);
+		    printf(", %s", ver);
+		} while ((ch = strchr(&ch[1], '|')) != NULL);
+		printf(")");
+	    }
+	    printf("\n");
+	}
+	return;
+    }
+    cmp = version_cmp(installed, latest);
+    ver = version_of(latest, NULL, NULL);
+    if (cmp < 0 && LIMIT('<')) {
+    	printf("%-34s  <", tmp);
+	if (Verbose)
+	    printf("   needs updating (%s has %s)", source, ver);
+	printf("\n");
+    } else if (cmp == 0 && LIMIT('=')) {
+    	printf("%-34s  =", tmp);
+	if (Verbose)
+	    printf("   up-to-date with %s", source);
+	printf("\n");
+    } else if (cmp > 0 && LIMIT('>')) {
+    	printf("%-34s  >", tmp);
+	if (Verbose)
+	    printf("   succeeds %s (%s has %s)", source, source, ver);
+	printf("\n");
+    }
+}
+
+void
+cleanup(int sig)
+{
+    if (sig)
+	exit(1);
+}
+
+static int
+fname_cmp(const FTSENT **a, const FTSENT **b)
+{
+    return strcmp((*a)->fts_name, (*b)->fts_name);
+}
Index: version/pkg_version.1
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.1,v
retrieving revision 1.21
diff -u -r1.21 pkg_version.1
--- version/pkg_version.1	20 Apr 2002 12:27:02 -0000	1.21
+++ version/pkg_version.1	14 May 2002 12:41:41 -0000
@@ -32,7 +32,7 @@
 .Nd summarize installed versions of packages
 .Sh SYNOPSIS
 .Nm
-.Op Fl cdhv
+.Op Fl hv
 .Op Fl l Ar limchar
 .Op Fl L Ar limchar
 .Op Fl s Ar string
@@ -110,23 +110,6 @@
 .Nm
 utility supports several command-line arguments:
 .Bl -tag -width indent
-.It Fl c
-Enable commands output.  Commands output includes the commands you should
-type to update your installed packages to the latest versions in the ports
-system.
-This feature does
-.Bf Em
-not
-.Ef
-constitute an automated packages updating system.
-The output of this command
-.Bf Em
-must
-.Ef
-be edited, in order to avoid destroying dependencies between installed
-packages.
-.It Fl d
-Enable debugging output.
 .It Fl h
 Print help message.
 .It Fl l
@@ -201,42 +184,15 @@
 .Pp
 .Dl % pkg_version ftp://ftp.FreeBSD.org/pub/FreeBSD/branches/-current/ports/INDEX
 .Pp
-The command below generates a file of commands to run to update the installed
-files.
-These commands must
-.Bf Em
-not
-.Ef
-be run without suitable editing.
-They should be treated as suggestions, and may need to be reordered
-to account for dependencies between installed packages, or may need to
-be disregarded if multiple versions of an installed package can coexist.
-Blindly running the output of this command may leave a system in an
-unusable state.
-.Pp
-.Dl % pkg_version -c > do_update
-.Pp
 The following command compares two package version strings:
 .Pp
 .Dl % pkg_version -t 1.5 1.5.1
 .Sh AUTHORS
-.An Bruce A. Mah Aq bmah@FreeBSD.org
+.An Bruce A. Mah Aq bmah@FreeBSD.org . Converted to C by
+.An Jeremy D. Lea Aq reg@FreeBSD.org
 .Sh CONTRIBUTORS
 .An Nik Clayton Aq nik@FreeBSD.org ,
 .An Dominic Mitchell Aq dom@palmerharvey.co.uk ,
 .An Mark Ovens Aq marko@FreeBSD.org ,
 .An Doug Barton Aq DougB@gorean.org ,
 .An Akinori MUSHA Aq knu@FreeBSD.org
-.Sh BUGS
-The commands output feature is
-.Bf Em
-not
-.Ef
-an automated ports/packages updating system.
-It does not even attempt to handle dependencies between installed
-packages correctly, and can produce incorrect results if multiple
-versions of a package can coexist on a system.
-.Pp
-Commands output assumes you install new software using the ports system,
-rather than using
-.Xr pkg_add 1 .
Index: version/pkg_version.pl
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.pl,v
retrieving revision 1.24
diff -u -r1.24 pkg_version.pl
--- version/pkg_version.pl	18 Sep 2001 17:56:44 -0000	1.24
+++ version/pkg_version.pl	14 May 2002 12:41:41 -0000
@@ -1,599 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright 1998 Bruce A. Mah
-#
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# pkg_version.pl
-#
-# A package version-checking utility for FreeBSD.
-#
-# $FreeBSD: src/usr.sbin/pkg_install/version/pkg_version.pl,v 1.24 2001/09/18 17:56:44 bmah Exp $
-#
-
-use Cwd;
-use Getopt::Std;
-
-#
-# Configuration global variables
-#
-$AllCurrentPackagesCommand = '/usr/sbin/pkg_info -aI';
-$SelectedCurrentPackagesCommand = '/usr/sbin/pkg_info -I';
-$CatProgram = "cat ";
-$FetchProgram = "fetch -o - ";
-$OriginCommand = '/usr/sbin/pkg_info -qo';
-$GetPkgNameCommand = 'make -V PKGNAME';
-
-#$IndexFile = "ftp://ftp.freebsd.org/pub/FreeBSD/branches/-current/ports/INDEX";
-$PortsDirectory = $ENV{PORTSDIR} || '/usr/ports';
-$IndexFile = "$PortsDirectory/INDEX";
-$ShowCommandsFlag = 0;
-$DebugFlag = 0;
-$VerboseFlag = 0;
-$CommentChar = "#";
-$LimitFlag = "";
-$PreventFlag = "";
-
-#
-# CompareNumbers
-#
-# Try to figure out the relationship between two program version numbers.
-# Detecting equality is easy, but determining order is a little difficult.
-# This function returns -1, 0, or 1, in the same manner as <=> or cmp.
-#
-sub CompareNumbers {
-    my ($v1, $v2) = @_;
-
-    # Short-cut in case of equality
-    if ($v1 eq $v2) {
-	return 0;
-    }
-
-    # Loop over different components (the parts separated by dots).
-    # If any component differs, we have the basis for an inequality.
-    my @s1 = split(/\./, $v1);
-    my @s2 = split(/\./, $v2);
-    my ($c1, $c2);
-    do {
-	last unless @s1 || @s2;
-	$c1 = shift @s1;
-	$c2 = shift @s2;
-    } while ($c1 eq $c2);
-
-    # Look at the first components of the arrays that are left.
-    # These will determine the result of the comparison.
-    # Note that if either version doesn't have any components left,
-    # it's implicitly treated as a "0".
-
-    # Our next set of checks looks to see if either component has a
-    # leading letter (there should be at most one leading letter per
-    # component, so that "4.0b1" is allowed, but "4.0beta1" is not).
-    if ($c1 =~ /^\D/) {
-	if ($c2 =~ /^\D/) {
-
-	    # Both have a leading letter, so do an alpha comparison
-	    # on the letters.  This isn't ideal, since we're assuming
-	    # that "1.0.b4" > "1.0.a2".  But it's about the best we can do, 
-	    # without encoding some explicit policy.
-	    my ($letter1, $letter2);
-	    $letter1 = substr($c1, 0, 1);
-	    $letter2 = substr($c2, 0, 1);
-
-	    if ($letter1 ne $letter2) {
-		return $letter1 cmp $letter2;
-	    }
-	    else {
-		# The letters matched equally.  Delete the leading
-		# letters and invoke ourselves on the remainining
-		# characters, which according to the Porters Handbook
-		# must be digits, so for example, "1.0.a9" < "1.0.a10".
-		substr($c1, 0, 1) = "";
-		substr($c2, 0, 1) = "";
-		return &CompareNumbers($c1, $c2);		
-	    }
-
-	}
-	else {
-	    # $c1 begins with a letter, but $c2 doesn't.  Let $c2
-	    # win the comparison, so that "1.0.b1" < "1.0.1".
-	    return -1;
-	}
-    }
-    else {
-	if ($c2 =~ /^\D/) {
-	    # $c2 begins with a letter but $c1 doesn't.  Let $c1
-	    # win the comparison, as above.
-	    return 1;
-	}
-	else {
-	    # Neither component begins with a leading letter.
-	    # Check for numeric inequality.  We assume here that (for example)
-	    # "3.09" < "3.10", and that we aren't going to be asked to
-	    # decide between "3.010" and "3.10".
-	    if ($c1 != $c2) {
-		return $c1 <=> $c2;
-	    }
-
-	    # String comparison, given numeric equality.  This
-	    # handles comparisons of the form "3.4j" < "3.4k".  This form
-	    # technically isn't allowed by the Porter's Handbook, but a
-	    # number of ports in the FreeBSD Ports Collection as of this
-	    # writing use it (graphics/jpeg and graphics/xv).  So we need
-	    # to support it.
-	    #
-	    # What we actually do is to strip off the leading digits and
-	    # invoke ourselves on the remainder.  This allows us to handle
-	    # comparisons of the form "1.1p1" < "1.1p2".  Again, not
-	    # technically allowed by the Porters Handbook, but lots of ports
-	    # use it.
-	    else {
-		$c1 =~ s/\d+//;
-		$c2 =~ s/\d+//;
-		if ($c1 eq $c2) {
-		    return 0;
-		}
-		elsif ($c1 eq "") {
-		    return -1;
-		}
-		elsif ($c2 eq "") {
-		    return 1;
-		}
-		else {
-		    return &CompareNumbers($c1, $c2);
-		}
-	    }
-	}
-    }
-}
-
-#
-# CompareVersions
-#
-# Try to figure out the relationship between two program "full
-# versions", which is defined as the 
-# ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
-# part of a package's name.
-#
-# Key points:  ${PORTEPOCH} supercedes ${PORTVERSION}
-# supercedes ${PORTREVISION}.  See the commit log for revision
-# 1.349 of ports/Mk/bsd.port.mk for more information.
-#
-sub CompareVersions {
-    local($fv1, $fv2, $v1, $v2, $r1, $r2, $e1, $e2, $rc);
-
-    $fv1 = $_[0];
-    $fv2 = $_[1];
-
-    # Shortcut check for equality before invoking the parsing
-    # routines.
-    if ($fv1 eq $fv2) {
-	return 0;
-    }
-    else {
-	($v1, $r1, $e1) = &GetVersionComponents($fv1);
-	($v2, $r2, $e2) = &GetVersionComponents($fv2);
-
-	# Check epoch, port version, and port revision, in that
-	# order.
-	$rc = &CompareNumbers($e1, $e2);
-	if ($rc == 0) {
-	    $rc = &CompareNumbers($v1, $v2);
-	    if ($rc == 0) {
-		$rc = &CompareNumbers($r1, $r2);
-	    }
-	}
-
-	return $rc;
-    }
-}
-
-#
-# GetVersionComponents
-#
-# Parse out the version number, revision number, and epoch number
-# of a port's version string and return them as a three-element array.
-#
-# Syntax is:  ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
-#
-sub GetVersionComponents {
-    local ($fullversion, $version, $revision, $epoch);
-
-    $fullversion = $_[0];
-
-    $fullversion =~ /([^_,]+)/;
-    $version = $1;
-    
-    if ($fullversion =~ /_([^_,]+)/) {
-	$revision = $1;
-    }
-    
-    if ($fullversion =~ /,([^_,]+)/) {
-	$epoch = $1;
-    }
-
-    return($version, $revision, $epoch);
-}
-
-#
-# GetNameAndVersion
-#
-# Get the name and version number of a package. Returns a two element
-# array, first element is name, second element is full version string.,
-#
-sub GetNameAndVersion {
-    local($fullname, $name, $fullversion);
-    $fullname = $_[0];
-
-    # If no hyphens then no version numbers
-    return ($fullname, "", "", "", "") if $fullname !~ /-/;
-
-    # Match (and group) everything after hyphen(s). Because the
-    # regexp is 'greedy', the first .* will try and match everything up
-    # to (but not including) the last hyphen
-    $fullname =~ /(.+)-(.+)/;
-    $name = $1;
-    $fullversion = $2;
-
-    return ($name, $fullversion);
-}
-
-#
-# PrintHelp
-#
-# Print usage information
-#
-sub PrintHelp {
-    print <<"EOF"
-Usage:	pkg_version [-c] [-d] [-h] [-l limchar] [-L limchar] [-s string] 
-		    [-v] [index]
-	pkg_version [-d debug] -t v1 v2
--c              Show commands to update installed packages
--d		Enable debugging output
--h		Help (this message)
--l limchar	Limit output to status flags that match
--L limchar	Limit output to status flags that DON\'T match
--s string	Limit output to packages matching a string
--v		Verbose output
-index		URL or filename of index file
-		(Default is $IndexFile)
-
--t v1 v2	Test two version strings
-EOF
-}
-
-#
-# Parse command-line arguments, deal with them
-#
-if (!getopts('cdhl:L:s:tv') || ($opt_h)) {
-    &PrintHelp();
-    exit;
-}
-if ($opt_c) {
-    $ShowCommandsFlag = $opt_c;
-    $LimitFlag = "<?";	# note that if the user specifies -l, we
-			# deal with this *after* setting a default
-			# for $LimitFlag
-}
-if ($opt_d) {
-    $DebugFlag = $opt_d;
-}
-if ($opt_l) {
-    $LimitFlag = $opt_l;
-}
-if ($opt_L) {
-    $PreventFlag = $opt_L;
-}
-if ($opt_t) {
-    $TestFlag = 1;
-}
-if ($opt_s) {
-    $StringFlag = $opt_s;
-}
-if ($opt_v) {
-    $VerboseFlag = 1;
-}
-if ($#ARGV >= 0) {
-    if ($TestFlag) {
-	($test1, $test2) = @ARGV;
-    }
-    else {
-	$IndexFile = $ARGV[0];
-    }
-}
-
-# Handle test flag now
-if ($TestFlag) {
-    my $cmp = CompareVersions($test1, $test2);
-    if ($cmp < 0) {
-	print "<\n";
-    }
-    elsif ($cmp == 0) {
-	print "=\n";
-    }
-    else {
-	print ">\n";
-    }
-    exit(0);
-}
-
-# Determine what command to use to retrieve the index file.
-if ($IndexFile =~ m-^((http|ftp)://|file:/)-) {
-    $IndexPackagesCommand = $FetchProgram . $IndexFile;
-}
-else {
-    $IndexPackagesCommand = $CatProgram . $IndexFile;
-}
-
-#
-# Get the current list of installed packages
-#
-if ($StringFlag) {
-    if ($DebugFlag) {
-       print STDERR "$SelectedCurrentPackagesCommand *$StringFlag*\n";
-    }
-    open CURRENT, "$SelectedCurrentPackagesCommand \\*$StringFlag\\*|";
-} else {
-    if ($DebugFlag) {
-       print STDERR "$AllCurrentPackagesCommand\n";
-    }
-    open CURRENT, "$AllCurrentPackagesCommand|";
-}
-while (<CURRENT>) {
-    ($packageString, $rest) = split;
-
-    ($packageName, $packageFullversion) = &GetNameAndVersion($packageString);
-    $currentPackages{$packageString}{'name'} = $packageName;
-    $currentPackages{$packageString}{'fullversion'} = $packageFullversion;
-}
-close CURRENT;
-
-#
-# Iterate over installed packages, get origin directory (if it
-# exists) and PORTVERSION
-#
-$dir = cwd();
-foreach $packageString (sort keys %currentPackages) {
-
-    open ORIGIN, "$OriginCommand $packageString|";
-    $origin = <ORIGIN>;
-    close ORIGIN;
-
-    # If there is an origin variable for this package, then store it.
-    if ($origin ne "") {
-	chomp $origin;
-
-	# Try to get the version out of the makefile.
-	# The chdir needs to be successful or our make -V invocation
-	# will fail.
-	unless (chdir "$PortsDirectory/$origin" and -r "Makefile") {
-	    $currentPackages{$packageString}->{orphaned} = $origin;
-	    next;
-	}
-
-	open PKGNAME, "$GetPkgNameCommand|";
-	$pkgname = <PKGNAME>;
-	close PKGNAME;
-
-	if ($pkgname ne "") {
-	    chomp $pkgname;
-
-	    $pkgname =~ /(.+)-(.+)/;
-	    $portversion = $2;
-	    
-	    $currentPackages{$packageString}{'origin'} = $origin;
-	    $currentPackages{$packageString}{'portversion'} = $portversion;
-	}
-    }
-}
-chdir "$dir";
-
-#
-# Slurp in the index file
-#
-if ($DebugFlag) {
-    print STDERR "$IndexPackagesCommand\n";
-}
-
-open INDEX, "$IndexPackagesCommand|";
-while (<INDEX>) {
-    ($packageString, $packagePath, $rest) = split(/\|/);
-
-    ($packageName, $packageFullversion) = &GetNameAndVersion($packageString);
-    $indexPackages{$packageName}{'name'} = $packageName;
-    $indexPackages{$packageName}{'path'} = $packagePath;
-    if (defined $indexPackages{$packageName}{'fullversion'}) {
-	$indexPackages{$packageName}{'fullversion'} .= "|" . $packageFullversion;
-    }
-    else {
-	$indexPackages{$packageName}{'fullversion'} = $packageFullversion;
-    }
-    $indexPackages{$packageName}{'refcount'}++;
-}
-close INDEX;
-
-#
-# If we're doing commands output, cripple the output so that users
-# can't just pipe the output to sh(1) and expect this to work.
-#
-if ($ShowCommandsFlag) {
-    print<<EOF
-echo "The commands output of pkg_version cannot be executed without editing."
-echo "You MUST save this output to a file and then edit it, taking into"
-echo "account package dependencies and the fact that some packages cannot"
-echo "or should not be upgraded." 
-exit 1
-EOF
-}
-
-#
-# Produce reports
-#
-# Prior versions of pkg_version used commas (",") as delimiters
-# when there were multiple versions of a package installed.
-# The new package version number syntax uses commas as well,
-# so we've used vertical bars ("|") internally, and convert them
-# to commas before we output anything so the reports look the
-# same as they did before.
-#
-foreach $packageString (sort keys %currentPackages) {
-    $~ = "STDOUT_VERBOSE"  if $VerboseFlag;
-    $~ = "STDOUT_COMMANDS" if $ShowCommandsFlag;
-
-    $packageNameVer = $packageString;
-    $packageName = $currentPackages{$packageString}{'name'};
-
-    $currentVersion = $currentPackages{$packageString}{'fullversion'};
-
-    if ($currentPackages{$packageString}->{orphaned}) {
-
-	next if $ShowCommandsFlag;
-	$versionCode = "?";
-	$Comment = "orphaned: $currentPackages{$packageString}->{orphaned}";
-
-    } elsif (defined $currentPackages{$packageString}{'portversion'}) {
-
-	$portVersion = $currentPackages{$packageString}{'portversion'};
-
-	$portPath = "$PortsDirectory/$currentPackages{$packageString}{'origin'}";
-
-	# Do the comparison
-	$rc = &CompareVersions($currentVersion, $portVersion);
-	    
-	if ($rc == 0) {
-	    $versionCode = "=";
-	    $Comment = "up-to-date with port";
-	}
-	elsif ($rc < 0) {
-	    $versionCode = "<";
-	    $Comment = "needs updating (port has $portVersion)";
-	}
-	elsif ($rc > 0) {
-	    $versionCode = ">";
-	    $Comment = "succeeds port (port has $portVersion)";
-	}
-	else {
-	    $versionCode = "!";
-	    $Comment = "Comparison failed";
-	}
-    }
-
-    elsif (defined $indexPackages{$packageName}{'fullversion'}) {
-
-	$indexVersion = $indexPackages{$packageName}{'fullversion'};
-	$indexRefcount = $indexPackages{$packageName}{'refcount'};
-
-	$portPath = $indexPackages{$packageName}{'path'};
-
-	if ($indexRefcount > 1) {
-	    $versionCode = "*";
-	    $Comment = "multiple versions (index has $indexVersion)";
-	    $Comment =~ s/\|/,/g;
-	}
-	else {
-
-	    # Do the comparison
-	    $rc = 
-		&CompareVersions($currentVersion, $indexVersion);
-	    
-	    if ($rc == 0) {
-		$versionCode = "=";
-		$Comment = "up-to-date with index";
-	    }
-	    elsif ($rc < 0) {
-		$versionCode = "<";
-		$Comment = "needs updating (index has $indexVersion)"
-	    }
-	    elsif ($rc > 0) {
-		$versionCode = ">";
-		$Comment = "succeeds index (index has $indexVersion)";
-	    }
-	    else {
-		$versionCode = "!";
-		$Comment = "Comparison failed";
-	    }
-	}
-    }
-    else {
-	next if $ShowCommandsFlag;
-	$versionCode = "?";
-	$Comment = "unknown in index";
-    }
-
-    # Having figured out what to print, now determine, based on the
-    # $LimitFlag and $PreventFlag variables, if we should print or not.
-    if ((not $LimitFlag) and (not $PreventFlag)) {
-	write;
-    } elsif ($PreventFlag) {
-	if ($versionCode !~ m/[$PreventFlag]/o) {
-	    if (not $LimitFlag) {
-		write;
-	    } else {
-		write if $versionCode =~ m/[$LimitFlag]/o;
-	    }
-	}
-    } else {
-	# Must mean that there is a LimitFlag
-	write if $versionCode =~ m/[$LimitFlag]/o;
-    }
-}
-
-exit 0;
-
-#
-# Formats
-#
-# $CommentChar is in the formats because you can't put a literal '#' in
-# a format specification
-
-# General report (no output flags)
-format STDOUT =
-@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  @<
-$packageName,              $versionCode
-.
-  ;
-
-# Verbose report (-v flag)
-format STDOUT_VERBOSE =
-@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  @<  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$packageNameVer,           $versionCode, $Comment
-.
-  ;
-
-# Report that includes commands to update program (-c flag)
-format STDOUT_COMMANDS =
-@<
-$CommentChar  
-@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$CommentChar, $packageName
-@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$CommentChar, $Comment  
-@<
-$CommentChar
-cd @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$portPath
-make clean && make && pkg_delete -f @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-              $packageNameVer
-make install clean
-
-.
-  ;
Index: version/test-pkg_version.sh
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/test-pkg_version.sh,v
retrieving revision 1.2
diff -u -r1.2 test-pkg_version.sh
--- version/test-pkg_version.sh	19 Apr 2001 22:17:07 -0000	1.2
+++ version/test-pkg_version.sh	14 May 2002 12:41:41 -0000
@@ -33,7 +33,7 @@
 #
 
 ECHO=echo
-PKG_VERSION=./pkg_version.pl
+PKG_VERSION=./pkg_version
 
 test-pv ( ) { \
     setvar v1 $1
Index: version/version.h
===================================================================
RCS file: version/version.h
diff -N version/version.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ version/version.h	14 May 2002 12:41:41 -0000
@@ -0,0 +1,44 @@
+/* $FreeBSD$ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Jeremy D. Lea
+ * 11 May 2002
+ *
+ * This is the version module.  Based on pkg_version.pl by Bruce A. Mah.
+ *
+ */
+
+#ifndef _INST_VERSION_H_INCLUDE
+#define _INST_VERSION_H_INCLUDE
+
+/* Where the ports lives by default */
+#define DEF_PORTS_DIR	"/usr/ports"
+/* just in case we change the environment variable name */
+#define PORTSDIR	"PORTSDIR"
+/* macro to get name of directory where we put logging information */
+#define PORTS_DIR		(getenv(PORTSDIR) ? getenv(PORTSDIR) : DEF_PORTS_DIR)
+
+struct index_entry {
+    SLIST_ENTRY(index_entry) next;
+    char name[PATH_MAX];
+    char origin[PATH_MAX];
+};
+SLIST_HEAD(index_head, index_entry);
+
+extern char	*LimitChars;
+extern char	*PreventChars;
+extern char	*MatchName;
+
+#endif	/* _INST_VERSION_H_INCLUDE */

--Dxnq1zWXvFF0Q93v--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020514145039.B13083>