Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Finding the latest available version of a program

by tektsu (Acolyte)
on Feb 02, 2004 at 20:53 UTC ( #325996=perlquestion: print w/ replies, xml ) Need Help??
tektsu has asked for the wisdom of the Perl Monks concerning the following question:

I have a hash with the keys being the names and versions of available applications:
%apps = ( gcc-3.3 => 1, gcc-3.3.1 => 1, gcc-3.3.2 => 1, gzip-1.2.4a => 1, make-3.79.1 => 1, );

Given an application name, I need to find the latest available version. For example, given the hash above, if I have "gcc", I want to return "gcc-3.3.2", "make" should return "make-3.79.1", and "cobol" should return false or undef.

I can do this by sorting the keys in reverse order and looking for the first match for, for example /^gcc-/, but that seems... inefficient.

I know I will need to get get more creative in my sorting (for example, when gcc-10.0 is released), but for now let's assume that cmp gives a correct comparision between versions.

Any ideas?



tektsu
kiku wa ittoki no haji kikanu wa matsudai no haji

Comment on Finding the latest available version of a program
Download Code
Re: Finding the latest available version of a program
by saintmike (Vicar) on Feb 02, 2004 at 21:13 UTC
    There's no other way than a linear search, but if you're making these version-checking calls more than once, it's probably most efficient to create another hash, %latest, to map an application's name to its latest version:
    my %apps = qw( gcc-3.3 1 gcc-3.3.1 1 gcc-3.3.2 1 gzip-1.2.4a 1 make-3.79.1 1 ); my %latest = (); for(keys %apps) { my($program, $version) = split /-/, $_, 2; $latest{$program} = $version if not exists $latest{$program} or ($latest{$program} cmp $version) < 0; } print "make: $latest{make}\n"; print "gcc: $latest{gcc}\n";
Re: Finding the latest available version of a program
by ysth (Canon) on Feb 02, 2004 at 21:15 UTC
    The hash doesn't actually make it easier, an array would do just as well. Something like:
    my $package = "gcc"; my $latest_vers = (sort grep /^\Q$package\E-/, keys %apps)[-1];
Re: Finding the latest available version of a program
by Abigail-II (Bishop) on Feb 02, 2004 at 21:39 UTC
    So, is version 4.2 older or newer than version 4.10? For instance, Perl and CPAN think 4.2 comes after 4.10, because they think version numbers are floats. CVS on the other hand thinks version numbers are dotted integers and hence ranks 4.10 after 4.2.

    And is 1.10a an alpha release of version 1.10, or patch level a of version 1.10?

    Abigail

Re: Finding the latest available version of a program
by elwarren (Curate) on Feb 02, 2004 at 21:50 UTC
    Depending on how you're building that hash, you could increment your true value on a per application basis like this:
    %apps = ( gcc-3.3 => 3, gcc-3.3.1 => 2, gcc-3.3.2 => 1, gzip-1.2.4a => 1, make-3.79.1 => 1, );
    I expect you will be querying your installed apps much more than you will be rebuilding that list. Using this method you could ++ existing keys /^gcc-/ then add your new entry with a value of 1. Then when you want the most recent you just specify => 1 or maybe even the previous version with => 2. Added benefit of not needing to know the actual release number of the previous version and your undef test will continue to work.
Re: Finding the latest available version of a program
by paulbort (Hermit) on Feb 02, 2004 at 23:08 UTC
    I wrote something similar to cull old versions of RPMs from the directory where I download patches. The other posters are right about the problems with version numbers. I solved it by storing the version in the hash, and comparing the version whenever a duplicate was found. The downside is that the resulting hash ONLY has the latest version number for each application. That might or might not be an issue for you. To make the version numbers work right, I split them on /\./, so they could be compared as numbers. If you're not doing this with RPMs, you can just change the way the initial hash is loaded.
    my %rpms; my %files; foreach my $file (<*.rpm>) { # RPM-SPECIFIC STUFF: my @result = `rpm -qp --queryformat "%{NAME}/%{ARCH}/%{VERSION}.%{RE +LEASE}\n" $file`; my ($name, $arch, $version) = split /\//, $result[0]; # END RPM-SPECIFIC STUFF $name .= ":" . $arch; if ( exists $rpms{$name} ) { #decide which one we like better: my @a = split /\./, $version; my @b = split /\./, $rpms{$name}; my $i=0; my $max = $#a > $#b ? $#a : $#b; while ($i <= $max) { if ( $a[$i] eq $b[$i] ) { $i++; next; } if ( $a[$i] lt $b[$i] ) { print "rm -f $file\n"; last; } else { my $rm = "rm -f $files{$name}"; print "$rm\n"; `$rm` if lc($ARGV[0]) eq 'rm'; # or whatever else you want to do with old files. last; } $i++; } } else { $rpms{$name} = $version; $files{$name} = $file; } }
    Hope it helps.

    --
    Spring: Forces, Coiled Again!
Re: Finding the latest available version of a program
by Cody Pendant (Prior) on Feb 03, 2004 at 02:55 UTC
    I can't believe I'm the first to say this, but why not use a module?

    http://search.cpan.org/~edavis/Sort-Versions-1.5/Versions.pm would seem to be the thing.

    You'd just use its versioncmp() function in the sorting.

    I'm not sure what its answer is to Abigail's question "is version 4.2 older or newer than version 4.10?" because I'm not in a position to test right now.

    Update: Not an answer to the actual question, I now realise, but to the "I'm going to have to get creative later" part.



    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss')
    =~y~b-v~a-z~s; print
Re: Finding the latest available version of a program
by tektsu (Acolyte) on Feb 03, 2004 at 16:12 UTC

    Thank you everyone for your responses. Since it turns out I don't greatly care about the non-latest package versions, I'll be weeding these out as I build the hash, resulting in a scan through the full data just one time, rather than for each lookup. I'll be using the application name as the key, and the latest version as the value, so I end up with with this:

    %apps = ( gcc => '3.3.1', gzip => '1.2.4a', make => '3.79.1', );

    Then I can check defined($apps{gcc}) to see if gcc is installed, and $apps{gcc} to get the latest version. Thanks saintmike for guiding me down that path.

    As for determining which version is the latest in any given case, in the 150 applications in my full list, cmp works in almost every case. I handle the remaining 5 or 6 packages by exception, but I'll be looking into the Versions module that Cody Pendant suggested to try to reduce the number of exceptions. Thanks again!



    tektsu
    kiku wa ittoki no haji kikanu wa matsudai no haji

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://325996]
Approved by blue_cowdawg
Front-paged by jweed
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2014-07-10 05:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (199 votes), past polls