#!/bin/bash # This program will take two EPOCH-VERSION-RELEASE strings and compare # them. The purpose is to be able to figure out if one package is newer # then another without using the command line version of RPM. # # Based on the algorithm described in rpm version 4.1 lib/psm.c and # lib/rpmvercmp.c # # rpmvercmp (version 1) # # Written by # Mark Hatle (fray@mvista.com) # # Copyright 2004 MontaVista Software, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # This is a shell implementation of the logic from the lib/rpmvercmp.c # rpmvercmp(const char * a, const char * b) from rpm # # input: $1 = a # $2 = b # # output: # 0 - a newer then b # 1 - b is newer then a # 2 - a and b are the same version rpmvercmp() { local versionA="$1" local versionB="$2" local local_verA="" local local_verB="" # The idea is to compare chunks.. # We first split at the first non-alphanumeric (partVer / Remainder) # Take the partVer and then figure out what the first character type is # split the result based on the character type # place the stuff after the split back in front of the Remainder # compare (numerically, or alphabetically) the "result" # repeat until there is nothing left to verify.. # First check to make sure they're not equal! if [ "$versionA" = "$versionB" ]; then return 2 fi while [ -n "$versionA" -a -n "$versionB" ]; do local_verA="`echo $versionA | sed -e 's/^[^a-zA-Z0-9]//' -e 's/\([^a-zA-Z0-9]\)/ \1/'`" local_verB="`echo $versionB | sed -e 's/^[^a-zA-Z0-9]//' -e 's/\([^a-zA-Z0-9]\)/ \1/'`" versionA="`echo "$local_verA " | cut -d ' ' -f 2`" local_verA="`echo "$local_verA" | cut -d ' ' -f 1`" versionB="`echo "$local_verB " | cut -d ' ' -f 2`" local_verB="`echo "$local_verB" | cut -d ' ' -f 1`" # isNum = 0 if it's a number # isNum != 0 if it's not echo $local_verA | cut -c 1 | grep -q [0-9] isNum=$? if [ $isNum -eq 0 ]; then local_verA="`echo $local_verA | sed 's/\([^0-9]\)/ \1/'`" local_verB="`echo $local_verB | sed 's/\([^0-9]\)/ \1/'`" else local_verA="`echo $local_verA | sed 's/\([^A-Za-z]\)/ \1/'`" local_verB="`echo $local_verB | sed 's/\([^A-Za-z]\)/ \1/'`" fi versionA="`echo "$local_verA " | cut -d ' ' -f 2`"${versionA} local_verA="`echo "$local_verA" | cut -d ' ' -f 1`" versionB="`echo "$local_verB " | cut -d ' ' -f 2`"${versionB} local_verB="`echo "$local_verB" | cut -d ' ' -f 1`" # echo "compare '$local_verA' to '$local_verB'" # Different types action is specified in the lib/rpmvercmp.c if [ -z "$local_verA" -o -z "$local_verB" ]; then # echo "Different Types!" return 1 fi if [ $isNum -eq 0 ]; then if [ "$local_verA" -gt "$local_verB" ]; then return 0 ; fi if [ "$local_verA" -lt "$local_verB" ]; then return 1 ; fi else if [ "$local_verA" \> "$local_verB" ]; then return 0 ; fi if [ "$local_verA" \< "$local_verB" ]; then return 1 ; fi fi done # Check if anything is left over, they win if [ -n "$versionA" ]; then return 0 fi if [ -n "$versionB" ]; then return 1 fi # They were equal.. we only get here if the seperators were different! return 2 } # Input # $1 = "EPOCH-VERSION-RELEASE" # $2 = "EPOCH-VERSION-RELEASE" # # Input is expected to have been validated! # # EPOCH may be blank or set to "(none)" # # Result # 0 $1 is newer then or same version as $2 # 1 $2 is a newer version then $1 rpmVersionCompare() { local A="$1" local B="$2" # Get this out of the way... if [ "$A" = "$B" ]; then return 0 fi # First compare the epoch local epochA="$( echo $A | cut -f 1 -d - )" local epochB="$( echo $B | cut -f 1 -d - )" if [ "$epochA" = "(none)" ]; then epochA="" ; fi if [ "$epochB" = "(none)" ]; then epochB="" ; fi if [ -n "$epochA" -a -z "$epochB" ]; then return 0 ; fi if [ -z "$epochA" -a -n "$epochB" ]; then return 1 ; fi if [ -n "$epochA" -a -n "$epochB" ]; then if [ "$epochA" -gt "$epochB" ]; then return 0 fi if [ "$epochA" -lt "$epochB" ]; then return 1 fi fi local versionA="$( echo $A | cut -f 2 -d - )" local versionB="$( echo $B | cut -f 2 -d - )" rpmvercmp "$versionA" "$versionB" ret=$? if [ $ret -ne 2 ]; then return $ret fi local releaseA="$( echo $A | cut -f 3 -d - )" local releaseB="$( echo $B | cut -f 3 -d - )" rpmvercmp "$releaseA" "$releaseB" ret=$? if [ $ret -ne 2 ]; then return $ret fi return 0 } rpmVersionCompare "$1" "$2" if [ $? -eq 0 ] ; then echo "res: (A) $1 is newer then or equal to (B) $2" else echo "res: (B) $2 is newer then (A) $1" fi