Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 6 Dec 1999 12:56:00 GMT
From:      m.seaman@inpharmatica.co.uk
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   misc/15304: pkg_version revamp
Message-ID:  <199912061256.MAA96243@st-pancras.inpharmatica.co.uk>

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

>Number:         15304
>Category:       misc
>Synopsis:       proposed modifications to pkg_version
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Dec  6 06:10:01 PST 1999
>Closed-Date:
>Last-Modified:
>Originator:     Matthew Seaman
>Release:        FreeBSD 3.3-STABLE i386
>Organization:
Inpharmatica Ltd.
>Environment:

	FreeBSD st-pancras.inpharmatica.co.uk 3.3-STABLE FreeBSD 3.3-STABLE #0: Sun Nov 28 11:19:25 GMT 1999     root@st-pancras.inpharmatica.co.uk:/export/src/sys/compile/ST-PANCRAS  i386

>Description:

	It's been one of those weekends.  I though I'd just tinker a
bit with pkg_version to make a few improvements and then I found I'd
pretty much completely rewritten it...  Anyhow, here are my changes
for general consideration.  The salient points are:

	- Add a new `-m' flag to filter against package names

	- Exhaustively compare all installed and available versions of
	packages: a possible answer to the `multiple versions' problem

	- Make the code emmited by -c conditional on the success of
	preceeding steps.  (This effectively duplicates the changes of
	PR15288, which I hadn't seen until just now)

	- Change default and verbose output formats to show version numbers
	and (verbose only) the corresponding directory from /usr/ports

	eg:

	> ./pkg_version.pl -m 'emacs' 
	emacs                          20.4 > 19.34b
	emacs                          20.4 = 20.4
	> ./pkg_version.pl -v -m 'emacs'
	emacs                          20.4 > 19.34b
	    succeeds index   for /usr/ports/editors/emacs
	
	emacs                          20.4 = 20.4
	    up-to-date       for /usr/ports/editors/emacs20
	

	- Made code comply better with recommendations of
	perlstyle(1).

>How-To-Repeat:

	N/A

>Fix:

Well, the diff is bigger than the new file, so here's the whole thing:
	
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	pkg_version.pl
#
echo x - pkg_version.pl
sed 's/^X//' >pkg_version.pl << 'END-of-pkg_version.pl'
X#! /usr/bin/perl -w
X#
X# Copyright 1998 Bruce A. Mah
X#
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms, with or without
X# modification, are permitted provided that the following conditions
X# are met:
X# 1. Redistributions of source code must retain the above copyright
X#    notice, this list of conditions and the following disclaimer.
X# 2. Redistributions in binary form must reproduce the above copyright
X#    notice, this list of conditions and the following disclaimer in the
X#    documentation and/or other materials provided with the distribution.
X#
X# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X# IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
X# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X#
X# pkg_version.pl
X#
X# A package version-checking utility for FreeBSD.
X#
X# $FreeBSD: src/usr.sbin/pkg_install/version/pkg_version.pl,v 1.2.2.2 1999/12/03 06:18:04 billf Exp $
X#
X
Xuse strict;
Xuse Getopt::Std;
Xuse vars qw { $opt_v $opt_h };
Xrequire "sysexits.ph";
X
X#
X# Program name for error messages: strip leading path
X#
X$0 =~ s@.*/@@;
X
X#
X# Configuration global variables
X#
X$::Version                = '0.1';
X$::CurrentPackagesCommand = '/usr/sbin/pkg_info -aI |';
X$::CatProgram             = "<"; # Just open a regular file for input
X$::FetchProgram           = "/usr/bin/fetch -o - ";
X
X#$::IndexFile = "ftp://ftp.freebsd.org/pub/FreeBSD/ports-current/INDEX";
X$::IndexFile              = 'file:/usr/ports/INDEX';
X$::ShowCommandsFlag       = 0;
X$::DebugFlag              = 0;
X$::VerboseFlag            = 0;
X$::CommentChar            = "#";
X$::LimitFlag              = "";
X$::PackageRE              = "."; # match anything regexp
X
X#
X# CompareVersions
X#
X# Try to figure out the relationship between two program version numbers.
X# Detecting equality is easy, but determining order is a little difficult.
X#
Xsub CompareVersions {
X    my $v1 = shift;
X    my $v2 = shift;
X    my @p1;
X    my @p2;
X
X    # Short-cut in case of equality
X    if ($v1 eq $v2) {
X	return 0;
X    }
X
X    # Loop over different components (the parts separated by dots).
X    # If any component differs, we have the basis for an inequality.
X    @p1 = split /\./, $v1;
X    @p2 = split /\./, $v2;
X
X    while (@p1 || @p2) {
X
X	# We\'re out of one or both components: if both, they\'re
X	# equal (this probably won\'t happen, since the short-cut case
X	# above should get this).  Otherwise, all else being equal,
X	# the longer version number is greater than the shorter: ie:
X	# 1.5.2 > 1.5
X	if (!(@p1 && @p2)) {
X	    return $#p1 <=> $#p2;
X	}
X	# Check for numeric inequality.  We assume here that (for example)
X	# 3.09 < 3.10. Only if there are no non-digits present.  Of course,
X	# there are always some problem packages: eg netscape-communicator
X	# where 4.08 < 4.7 
X	elsif ($p1[0] =~ /^\d+$/ &&
X	       $p2[0] =~ /^\d+$/ &&
X	       $p1[0] != $p2[0]) {
X	    return $p1[0] <=> $p2[0];
X	}
X	# Check for string inequality, given numeric equality.  This
X	# handles version numbers of the form 3.4j < 3.4k. However,
X	# if only one version has a non-numeric part, it sorts higher
X	# -- ie 1.5.2 < 1.5.2b1 (which is probably not correct), although
X	# 1.5.2 < 1.5.2p3 probably *is* correct.  Ho hum.
X	elsif ($p1[0] ne $p2[0]) {
X	    return $p1[0] cmp $p2[0];
X	}
X	shift @p1;
X	shift @p2;
X    }
X
X}
X
X#
X# GetNameAndVersion
X#
X# Get the name and version number of a package. Returns a two element
X# array, first element is name, second element is version number.
X#
Xsub GetNameAndVersion {
X    my $string = shift;
X
X    # If no hyphens then no version number
X    return ($string, "") if $string !~ /-/;
X
X    # Match (and group) everything in between two hyphens. Because the
X    # regexp is 'greedy', the first .* will try and match everything up
X    # to (but not including) the last hyphen
X    $string =~ /(.*)-(.*)/;
X    return ($1, $2);
X}
X
X#
X# PrintHelp
X#
X# Print usage information
X#
Xsub PrintHelp {
X    print <<"EOF"
X$0 $::Version
XBruce A. Mah <bmah\@ca.sandia.gov>
X
XUsage: $0 [-c] [-d debug] [-h] [-v] [index]
X-c              Show commands to update installed packages
X-d debug	Debugging output (debug controls level of output)
X-h		Help (this message)
X-l limchar	Limit output
X-m pkgregex     Only show packages matching regular expression
X-v		Verbose output
Xindex		URL or filename of index file
X		(Default is $::IndexFile)
XEOF
X}
X
X#
X# Parse command-line arguments, deal with them
X#
Xif (!getopts('cdhl:m:v') || ($opt_h)) {
X    &PrintHelp();
X    exit EX_USAGE();
X}
X$::ShowCommandsFlag = $::opt_c if $::opt_c;
X$::DebugFlag        = $::opt_d if $::opt_d;
X$::LimitFlag        = $::opt_l if $::opt_l;
X$::PackageRE        = $::opt_m if $::opt_m;
X$::VerboseFlag      = 1        if $::opt_v;
X$::IndexFile        = $ARGV[0] if $#ARGV >= 0;
X
X# Gross hack to get around a bug in fetch(1).  When PR bin/7203 gets fixed,
X# we can make a lot of this code go away...basically the problem is that
X# we can't depend on "fetch -o -" to do the right thing with files in the
X# filesystem.
Xif ($::IndexFile =~ s-^file:/-/-) {
X    $::IndexPackagesCommand = $::CatProgram . $::IndexFile;
X}
Xelsif ($::IndexFile =~ m-^(http|ftp)://-) {
X    $::IndexPackagesCommand = $::FetchProgram . $::IndexFile . "|";
X}
Xelse {
X    $::IndexPackagesCommand = $::CatProgram . $::IndexFile;
X}
X
X#
X# Slurp in files
X#
Xprint STDERR "$::CurrentPackagesCommand\n" if $::DebugFlag;
X
Xopen CURRENT, "$::CurrentPackagesCommand"
X    or die ("$0: Can't load current packages \"$::CurrentPackagesCommand\"",
X	    " -- $!\n");
Xwhile (<CURRENT>) {
X    my $packageString;
X    my $packageName;
X    my $packageVersion;
X    my $rest;
X
X    ($packageString, $rest) = split;
X    next unless $packageString =~ m/$::PackageRE/o;
X
X    ($packageName, $packageVersion) = &GetNameAndVersion($packageString);
X    $::currentPackages{$packageName}{'list'} = []
X	unless defined $::currentPackages{$packageName}{'list'};
X    push @{$::currentPackages{$packageName}{'list'}},
X        { ident  => $packageString,
X	  version => $packageVersion };
X    $::currentPackages{$packageName}{'refcount'}++;
X}
Xclose CURRENT;
X
Xprint STDERR "$::IndexPackagesCommand\n" if $::DebugFlag;
X
Xopen INDEX, "$::IndexPackagesCommand"
X    or die "$0: Can't load index \"$::IndexPackagesCommand\" -- $!\n";
Xwhile (<INDEX>) {
X    my $packageString;
X    my $packagePath;
X    my $packageName;
X    my $packageVersion;
X    my $rest;
X
X    ($packageString, $packagePath, $rest) = split(/\|/);
X    ($packageName, $packageVersion) = &GetNameAndVersion($packageString);
X
X    $::indexPackages{$packageName}{'list'} = []
X	unless defined $::indexPackages{$packageName}{'list'};
X    push @{$::indexPackages{$packageName}{'list'}},
X        { ident   => $packageString,
X	  version => $packageVersion,
X	  path    => $packagePath };
X    $::indexPackages{$packageName}{'refcount'}++;
X}
Xclose INDEX;
X
XMAIN:
X{
X    my $packageName;
X    my $packagePath;
X    my $indexVersion;
X    my $currentVersion;
X    my $packageNameVer;
X    my $comment;
X    my $versionCode;
X
X    #
X    # Select report type
X    #
X    $~ = "STDOUT_VERBOSE"  if $::VerboseFlag;
X    $~ = "STDOUT_COMMANDS" if $::ShowCommandsFlag;
X
X    #
X    # Produce reports: there may be multiple versions of the package
X    # listed in the index, or none (eg. the package name has changed as
X    # happened when "egcs" mutated into "gcc").  There can be multiple
X    # versions installed.  Account for all combinations.
X    #
X    foreach $packageName (sort keys %::currentPackages) {
X
X	foreach my $cur (@{$::currentPackages{$packageName}{'list'}}) {
X	    $currentVersion = $cur->{version};
X	    $packageNameVer = "$packageName-$cur->{version}";
X
X	    if (!defined $::indexPackages{$packageName}) {
X		# Nothing matches in the index
X		$versionCode  = "?";
X		$comment      = "unknown in index";
X		$packagePath  = "";
X		$indexVersion = "???";
X
X		next if $::ShowCommandsFlag; # Can't rebuild if doesn't exist
X
X		if ($::LimitFlag) {
X		    write if $versionCode =~ m/[$::LimitFlag]/o; 
X		} else {
X		    write;
X		} 
X	    } else {
X		# Compare each installed version to each index entry
X		foreach my $idx (@{$::indexPackages{$packageName}{'list'}}) {
X		    my $rc;
X
X		    $indexVersion = $idx->{version};
X		    $packagePath = $idx->{path};
X		    $rc = &CompareVersions($cur->{version}, $idx->{version});
X	    
X		    if ($rc == 0) {
X			next if $::ShowCommandsFlag;
X			$versionCode = "=";
X			$comment = "up-to-date";
X		    }
X		    elsif ($rc < 0) {
X			$versionCode = "<";
X			$comment = "update available";
X		    }
X		    elsif ($rc > 0) {
X			next if $::ShowCommandsFlag;
X			$versionCode = ">";
X			$comment = "succeeds index";
X		    }
X		    if ($::LimitFlag) {
X			write if $versionCode =~ m/[$::LimitFlag]/o; 
X		    } else {
X			write;
X		    } 
X		}
X	    }
X	}
X    }
X
X    #
X    # Formats
X    #
X    # $CommentChar is in the formats because you can't put a literal '#' in
X    # a format specification
X    
X    # General report (no output flags)
X    format STDOUT =
X@<<<<<<<<<<<<<<<<<<<< @>>>>>>>>>>>> @ @<<<<<<<<<<<<<
X$packageName,         $currentVersion, $versionCode, $indexVersion
X.
X    ;
X
X    # Verbose report (-v flag)
X    format STDOUT_VERBOSE =
X@<<<<<<<<<<<<<<<<<<<< @>>>>>>>>>>>> @ @<<<<<<<<<<<<<
X$packageName,         $currentVersion, $versionCode, $indexVersion
X    @<<<<<<<<<<<<<<< for @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X    $comment,            $packagePath
X
X.
X    ;
X
X    # Report that includes commands to update program (-c flag)
X    format STDOUT_COMMANDS =
X@
X$::CommentChar  
X@ @<<<<<<<<<<<<<<<<<<<<<<<<
X$::CommentChar, $packageNameVer
X@ Index has @<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X$::CommentChar, $indexVersion, $comment  
X@
X$::CommentChar
Xcd @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X$packagePath
Xmake && \
Xpkg_delete -f @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X              "$packageNameVer && \\"
Xmake install
X
X.
X    ;
X    exit EX_OK();
X}
X#
X# That's all folks!
X#
END-of-pkg_version.pl
exit


> diff -u /usr/src/usr.sbin/pkg_install/version/pkg_version.1 ./pkg_version.1   --- /usr/src/usr.sbin/pkg_install/version/pkg_version.1 Sat Dec  4 03:43:54 1999
+++ ./pkg_version.1     Mon Dec  6 12:31:41 1999
@@ -34,6 +34,7 @@
 .Nm pkg_version
 .Op Fl cdhv
 .Op Fl l Ar limchar
+.Op Fl m Ar pkgmatch
 .Op Ar index
 .Sh DESCRIPTION
 The
@@ -44,7 +45,9 @@
 command.  Version numbers are compared against an
 index file, to see which packages might need updating.
 .Pp
-Each package name is printed, along with a one-character status flag:
+Each package name is printed, along with the installed package version
+number, a one-character status flag and the available package version
+number.  The status flags are:
 .Bl -tag -width indent
 .It Li =
 The installed version of the package matches the index.
@@ -56,10 +59,13 @@
 index.
 .It Li ?
 The relationship between the installed version of a package and the
-index file could not be determined.  A common reason for this message
-is that there are multiple versions of a particular software package
-installed, or that multiple versions are listed in the index file.
-Examples from the
+index file could not be determined.  Usually this means that no
+matching package could be identified in the index.
+.Pp
+Where multiple versions of the same package have been installed, or
+where multiple versions of a package are listed in the index, several
+lines are output per package, one for each combination of installed
+and available package versions.  Examples from the
 .Fx
 ports collection are the Tcl toolkit or the
 .Tn EMACS
@@ -85,11 +91,19 @@
 to the shell, it is best to quote
 .Ar limchar
 with single quotes.
+.It Fl m
+Limit the output to just those installed packages that match the Perl
+regular expression
+.Ar pkgmatch .
+Both package names and version numbers may be matched against.  Single
+quotes may be required to protect characters with special meaning to
+the shell.
 .It Fl v
 Enable verbose output.  Verbose output includes some English-text
-interpretations of the version number comparisons, as well as the
-version numbers compared for each package.  Non-verbose output is
-probably easier for programs or scripts to parse.
+interpretations of the version number comparisons, the directory path
+in the ports system, as well as the version numbers compared for each
+package.  Non-verbose output is probably easier for programs or
+scripts to parse.
 .It Ar index
 Specify the index to be used as a basis of comparison.  This index can
 be specified as a filename (in the local filesystem) or a URL.  Any
@@ -105,7 +119,8 @@
 .Xr fetch 1 ,
 .Xr pkg_add 1 ,
 .Xr pkg_create 1 ,
-.Xr pkg_delete 1 .
+.Xr pkg_delete 1 ,
+.Xr perlre 1 .
 .Sh FILES
 .Bl -tag -width /usr/ports/INDEX -compact
 .It Pa /usr/ports/INDEX
@@ -133,15 +148,21 @@
 suggestions, and then cut-and-paste (or retype) the commands you want to run.
 .Pp
 .Dl % pkg_version -c > do_update
+.Pp
+Generate a report limited to just the EMACS or Xemacs packages:
+.Pp
+.Dl % pkg_version -m '^x?emacs'
+.Pp
+Generate a verbose report on all packages with lower case letters as
+part of their version numbers:
+.Pp
+.Dl % pkg_version -v -m '-[^-]*[a-z]+[^-]*$'
 .Sh AUTHOR
 .An Bruce A. Mah Aq bmah@ca.sandia.gov
 .Sh CONTRIBUTORS
 .An Nik Clayton Aq nik@FreeBSD.org ,
 .An Dominic Mitchell Aq dom@palmerharvey.co.uk
 .Sh BUGS
-There should be a better way of dealing with packages that
-can have more than one installed version.
-.Pp
 Patch levels aren't handled
 very well (i.e. version numbers of the form 1.2p3 or 1.2pl3).
 .Pp
	


>Release-Note:
>Audit-Trail:
>Unformatted:


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




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