addrpm script

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Tony,

 I was recently very frustrated by the add-rpm.py script
alluded to in your very helpful Customized-installer
mini-HOWTO, so I wrote my own addrpm script.  It is a
bash/shell script, so i expect it is easier to understand
and hack about with.  I have tested it and it does what I
want it to (i.e., you can have
openssh-*{2.9p1,3.0p1,3.3p1,3.4p1} all hanging about in the
updates directory yet it will figure out that only the 3.4p1
version is worth trying to wedge into the real tree.  If it
gets confused it will ask for help.

In case this is of use to you (and others on the kickstart
list) here it is.  As per usual, if it breaks you can keep
the pieces.

Paul Knowles.                   phone: 41 26 300 90 64
email: Paul.Knowles@xxxxxxxx      Fax: 41 26 300 97 47
finger me at pexppc33.unifr.ch for more contact information

##################################################
#!/bin/bash
#
#    addrpm  Adds RPM(s) to a Redhat Tree
#    Copyright (C) 2002 Paul Knowles <Paul.Knowles@xxxxxxxx>
#
#    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.
#
#   NOTE: I'm not a bash shell guru.  Its syntax is weird
#   and often difficult to understand for comparisons
#   (something to do with interpreting > as redirection
#   versus comparison problems I expect).  If there is a
#   real bash wizard with interest in correcting all the
#   weird ways I've made the comparisons work, I would
#   appreciate the comments.
#
#   NOTE2: You are running this at your own risk. If it
#   deletes the contents of your hard disk, drinks all your
#   beer, and tries to shave your cat I will disavow having
#   ever seen it before in my life.
#
#  I use a RedHat layout that looks like the tree pictured below.
# This is very convenient since the updating commands are just 
#    $> cd $UPDATES/redhat-updates
#    $> ncftpget -FRT ftp://really.fast.server/linux/mirror/.../redhat-updates/7.3
# and all is magically updated. In fact, cron does this for me at 3 am.
#
# The Redhat 7.3 tree is set out like:
#redhat
#`-- 7.3
#    `-- en
#        `-- os
#            `-- i386
#                |-- RedHat
#                |   |-- RPMS
#                |   `-- base
#                |-- SRPMS
#                |-- dosutils
#                |   |-- autoboot
#                |   |-- fips15c
#                |   |   |-- restorrb
#                |   |   `-- source
#                |   |-- fips20
#                |   |   |-- restorrb
#                |   |   `-- source
#                |   |-- fipsdocs
#                |   `-- rawritewin
#                |-- images
#                |   |-- de
#                |   |-- es
#                |   |-- fr
#                |   |-- it
#                |   `-- pxeboot
#                `-- megroup      <--- Medium Energy Group specific RPMs
#
# and the updates tree looks like
#
#redhat-updates
#|-- 7.3
#|   `-- en
#|       |-- megroup
#|       |   |-- SRPMS
#|       |   `-- i386
#|       `-- os
#|           |-- SRPMS
#|           |-- athlon
#|           |-- i386
#|           |-- i486
#|           |-- i586
#|           |-- i686
#|           `-- noarch
#|-- attic
#|   |-- SRPMS
#|   |-- athlon
#|   |-- i386
#|   |-- i486
#|   |-- i586
#|   |-- i686
#|   `-- noarch
#`-- tosort
#    `-- movie
#
#  This shell script has been very successful in sorting through all the 
# updates in 7.3/en/os/*/*.rpm,  figuring out the latest in the bunch
# and then replacing the RedHat/RPMS/*.rpm packages
#
# If you call it with an argument, it puts itself into test mode
# and prints out what it would do.
#
# e.g.,  to really update the trees
#   $> addrpm
# too see what it will do
#   $> addrpm poo      #or ``1'' or ``t'' or ``flibber'' or ...
#
# see the lines:
#  export putdir=/home/updates/redhat/7.3/en/os/i386/RedHat/RPMS/
#  export extradir=/home/updates/redhat/7.3/en/os/i386/megroup/
#  export getdir=/home/updates/redhat-updates/7.3/en/os/$u
#  export atticdir=/home/updates/redhat-updates/attic/$u
# and the big for loop over SRPMS i386 etc
# if your directory structure is different.
# 
#                                    cheers,
#                                    P. Knowles, July 11, 2002
######################################################
# the comparison function
# called with two strings of form a.b.c.d.e.f
# first is the champion, second is the challenger
# return 0 if $2 is ``above'' $1, i.e., 1.2.3 is above
# 1.2.2, and 3.0.0 is above 2.99.194
# return 2 if $1 and $2 have differing composition (punt value!)
#     i.e., comparing 3.0.0 and 3.0.0rc8 is a hard problem
#     3.1.0 and 3.0.foo is not so much of a problem though
# return 1 if $1 <= $2
#
valcomp() {
#    echo Comparing champion $1 and challenger $2
    if [ $1 == $2 ]; then
	return 1
    fi
    #
    # bugger, we have to work
    declare -a champ
    declare -a chall
    champ=(`echo $1 | sed s/\\\./\ /g`)
    chall=(`echo $2 | sed s/\\\./\ /g`)
#    echo broke champ into ${champ[@]}
#    echo broke chall into ${chall[@]}
    if [ ${#champ[@]} -ne ${#chall[@]} ]; then
	# the strings don't have the same composition; punt
#	echo Punting due to length comparison
	return 2
    fi
    local -i i=0
    local -i j=${#champ[*]}

    for (( i=0 ;  i < j ; i++ ))
      do 
      # either we have just number to compare
      # or we must use strings
      dostringcomp=0

      if [ ${chall[$i]} != `echo ${chall[$i]} | sed -e s/[[:alpha:]]//g` ]; then
	  dostringcomp=$(( $dostringcomp + 1 ))
      fi
      if [ ${champ[$i]} != `echo ${champ[$i]} | sed -e s/[[:alpha:]]//g` ]; then
	  dostringcomp=$(( $dostringcomp + 1 ))
      fi
      if [ "$dostringcomp" == "1" ]; then
	  # must punt here, someone has letters, other just numbers
#	  echo returning punt
	  return 2
      fi
      #
      # directly comparing ${champ[$i]} and ${chall[$i]} fails
      # some weird shell syntax problem I don't yet understand?
      # use this intermediate step form
      poo=${chall[$i]}
      bar=${champ[$i]}
      if [ $dostringcomp -eq 2 ]; then
	  # compare via strings
	  if [ "$poo" \> "$bar" ]; then
#	      echo strings found that ${chall[$i]} is greater than ${champ[$i]}
	      return 0
	  fi
      fi
      if [ $poo -gt $bar  ]; then
#	  echo numerically found ${chall[$i]} is greater than ${champ[$i]}
	  return 0
      elif [ $(( ${chall[$i]} == ${champ[$i]} )) == "1" ]; then
#	  echo at i=$i, ${chall[$i]} is the same as ${champ[$i]}
	  continue
      fi
      # this occurs when ${chall[$i]} is less than ${champ[$i]}
      # claiming ``equality'' is enough to ignore the rpm
      return 1
    done
    # we should never get here: the initial comparison should catch this case!
    # at end, no seen difference
    return 1
}
#
#
# doreplace() is called with the full pathways of the new file,
# the old file, and the test flag
doreplace() {
    new=$1
    old=$2
    local test=$3
    if [ $test == "n" ]; then
	mv $old $atticdir/  || exit 1
	cp $new `dirname $old`/ || exit 1
    else
	echo	mv $old $atticdir/
	echo	cp $new `dirname $old`/
    fi
}
#
# called when the program gets too confused
# ask for operator intervention directly
punt() {
    echo "Oops: comparing "
    echo "          $2"
    echo " and"
    echo "          $4"
    echo "is too confusing for me: Should I replace $4 with $2"
    echo "(default is no)?"
    ans=""
    read -r -p y/N -n1 ans
    if [ $ans == "y" ]; then
	echo
	echo O.k., upgrading to $1/$2
	doreplace $1/$2 $3/$4 $test
    else
	echo
	echo O.k., skipping $2
    fi
}
#
# Done with function definitions
# The action starts here
# 
if [ ! -z $1 ]; then
    test="y"
    echo Test mode
else
    test="n"
fi
export test
#
for u in SRPMS i386 i486 i586 i686 athlon
  do
  export putdir=/home/updates/redhat/7.3/en/os/i386/RedHat/RPMS/
  export extradir=/home/updates/redhat/7.3/en/os/i386/megroup/
  export getdir=/home/updates/redhat-updates/7.3/en/os/$u
  export atticdir=/home/updates/redhat-updates/attic/$u
  echo $getdir
  tag=$u
  if [ $u == "SRPMS" ]; then
      tag=src
      putdir=/home/updates/redhat/7.3/en/os/i386/SRPMS
  fi
  #
  # these are the possible replacement package names
  # there may be more than one replacement available
  # we need to find the latest one
  for f in `rpm -qp --qf '%{name} \n' $getdir/*.rpm | sort | uniq `
    do
    echo
    echo $u:$f
    # the current version and release
    vcurr=`rpm -qp --qf '%{version}' $putdir/$f-[0123456789]*$tag.rpm`
    rcurr=`rpm -qp --qf '%{release}' $putdir/$f-[0123456789]*$tag.rpm`
    # the candidate replacements
    echo "Current version is:   $vcurr-$rcurr"
    declare -a vlist
    declare -a rlist
    #
    # rpm doesn't separate error messages and regular output
    # so scuttling errors to /dev/null won't work here
    # If one of the .rpm files isn't a real rpm
    # the script will get very confused
    # since weird things will show up in the version and release lists
    vlist=(`rpm -qp --qf '%{version} ' $getdir/$f-[0123456789]*$tag.rpm`)
    rlist=(`rpm -qp --qf '%{release} ' $getdir/$f-[0123456789]*$tag.rpm`)
    echo "Candidate versions:    ${vlist[@]}"
    echo "Candidate releases:    ${rlist[@]}"
    tst=$((${#vlist[*]}+${#rlist[*]}))
    vi=0
    ri=0
    if [ $tst -gt 2 ]; then
	# loop over the versions first
	# need to find the biggest version and release of the bunch
	# set i to the index
        # 
	# use vi as sentinal
	vi=-1  
	declare -i i=1
	declare -i j=${#vlist[*]}
	declare -i verdex=0
	for (( i=1 ; $(( i < j))  ; i++ ))
	  do 
#	  echo testing ${vlist[$i]}
	  valcomp ${vlist[$verdex]} ${vlist[$i]}
	  ret=$?
	  if [ $ret -eq 0 ] ; then
#	      echo found ${vlist[$i]} bigger than ${vlist[$verdex]} 
	      verdex=$i
	      reldex=$i
	      vi=$i
	      continue
	  fi
	  if [ $ret -eq 2 ] ; then
	      echo ERROR: This is too hard a hard case for me 
	      break 2 # give up and get another file
	  fi
	done

	if [ $vi == "-1" ]; then
	    # versions are all the same
	    declare -i i=1
	    declare -i j=${#rlist[*]}
	    declare -i reldex=0
	    for (( i=1 ; $(( i < j))  ; i++ ))
	      do 
#	      echo testing ${rlist[$i]}
	      valcomp ${rlist[$reldex]} ${rlist[$i]}
	      ret=$?
	      if [ $ret -eq 0 ] ; then
#		  echo found ${rlist[$i]} bigger than ${rlist[$reldex]} 
		  reldex=$i
		  verdex=$i
		  continue
	      fi
	      if [ $ret -eq 2 ] ; then
		  echo ERROR: This is too hard a hard case for me 
		  break 2 # give up and get another file
	      fi
	    done
	fi
	echo Found ${vlist[$verdex]}-${rlist[$reldex]} is best candidate
	vi=$verdex
	ri=$reldex	
    fi
    vcandidate=${vlist[$vi]}
    rcandidate=${rlist[$ri]}
    #
    # see if candidate should replace curr
    # three cases
    #    - curr doesn't exists: ask user if we add the rpm
    #                      (and where: $putdir or $extradir)
    #    - curr needs replacing:
    #                      move curr to atticdir then
    #                      cp candidate into place
    #    - curr doesn't need replacing: do nothing
    #
    #
    # deal with the case that curr is missing
    # this is a bit of a hack since it doesn't 
    # handle existing rpm's in $extradir very gracefully
    # you probably want to ``hand craft'' extradir in any case
    #
    if [ ! -f $putdir/$f-$vcurr-$rcurr.$tag.rpm -o -f $extradir/$f-$vcandidate-$rcandidate.$tag.rpm ]; then
	moved=""
	echo "Oops: $f doesn't exist in $tag flavour in $putdir"
	echo "or is already in $extradir"
	echo "Shall I add it to $putdir"
        echo "(default is no)?"
	read -r -p y/N -n1 ans
	if [ $ans == "y" ]; then
	    ans=""
	    moved=1
	    echo
	    echo O.k., Adding $f-$vcandidate-$rcandidate.$tag.rpm
	    if [ $test == "n" ]; then
		cp $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $putdir/ || exit 1
	    else
		echo  cp $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $putdir/
	    fi
	    # 
	else
	    echo
	    echo "Shall I add it to $extradir"
	    echo "(default is no)?"
	    read -r -p y/N -n1 ans
	    if [ $ans == y ]; then
		ans=""
		moved=1
		echo
		echo O.k., Adding $f-$vcandidate-$rcandidate.$tag.rpm
		if [ $test == "n" ]; then
		    cp $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $extradir/ || exit 1
		else
		    echo  cp $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $extradir/
		fi
	    fi
	fi
	if [ -z $moved ]; then
	    echo
	    echo O.k., skipping $f-$vcandidate-$rcandidate.$tag.rpm
	fi
	#
	# finished with name isolated $f, get another name now
	continue
    fi
    #
    # because of the continue above, we know curr and candidate both exist
    valcomp $vcurr $vcandidate
    ret=$?
    if [ $ret -eq 0 ] ; then
     	echo $f-$vcandidate-$rcandidate.$tag.rpm replaces $f-$vcurr-$rcurr.$tag.rpm
	doreplace $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $putdir/$f-$vcurr-$rcurr.$tag.rpm $test
	continue
    fi
    if [ $ret -eq 2 ] ; then
	punt $getdir $f-$vcandidate-$rcandidate.$tag.rpm $putdir $f-$vcurr-$rcurr.$tag.rpm
	continue
    fi
    #
    # if we got here, $ret=1, so versions are the same
    # compare releases
    valcomp $rcurr $rcandidate
    ret=$?
    if [ $ret -eq 0 ] ; then
     	echo $f-$vcandidate-$rcandidate.$tag.rpm replaces $f-$vcurr-$rcurr.$tag.rpm
	doreplace $getdir/$f-$vcandidate-$rcandidate.$tag.rpm $putdir/$f-$vcurr-$rcurr.$tag.rpm  $test
	continue
    fi
    if [ $ret -eq 2 ] ; then
	punt $getdir $f-$vcandidate-$rcandidate.$tag.rpm $putdir $f-$vcurr-$rcurr.$tag.rpm
	continue
    fi
    #
    # if we get here both versions and releases 
    # are the same; this means there is nothing to do.
    echo No reason to change $f-$vcurr-$rcurr.$tag.rpm
    echo
  done
done





[Index of Archives]     [Red Hat General]     [CentOS Users]     [Fedora Users]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux