#!/usr/bin/bash
set -e

### osg installed versions script ###

usage () {
  if [[ $1 ]]; then
    echo "$1" >&2
    echo
  fi
  echo "Usage: $(basename "$0") [options] [series|--all]"
  echo
  echo "Identifies any installed rpms that were part of an OSG release and"
  echo "displays the latest OSG release that included that rpm, relative to"
  echo "a given series (eg, 3.1, 3.2), or --all to display for each series."
  echo
  echo "The default series is based on the version of osg-release installed,"
  echo "or --all if osg-release is not installed."
  echo
  echo "Options:"
  echo "  -r PATH  specify path to output log of 'rpm -qa'"
  echo "  -p PATH  specify path to output log of 'osg-system-profiler'"
  echo "  -t DIR   specify local dir with release info .txt files"
  echo "  --afs    same as: -t $RELEASE_INFO_AFS_PATH"
  echo
  echo "PATH arguments specified as a URL will be downloaded automatically."
  exit
}

fail () { echo "$@" >&2; exit 1; }

RELEASE_INFO_URL=http://vdt.cs.wisc.edu/release-info/
RELEASE_INFO_AFS_PATH=/p/vdt/public/html/release-info
osg=''

export LC_ALL=C

while [[ $1 ]]; do
case $1 in
  -r ) RPM_LOG=$2; shift 2 ;;
  -p ) PROFILER_LOG=$2; shift 2 ;;
  -t ) RELEASE_INFO_PATH=$2; shift 2 ;;
  --afs ) RELEASE_INFO_PATH=$RELEASE_INFO_AFS_PATH; shift ;;
  --all | [3-9].[0-9] ) osg=$1; shift ;;
  --help ) usage ;;
  * ) usage "Unrecognized option '$1'" ;;
esac
done

if [[ $RPM_LOG && $PROFILER_LOG ]]; then
  fail "options '-r' and '-p' are mutually exclusive..."
fi

# work in temp dir

oldwd=$PWD
tmpd=$(mktemp -d)
trap 'rm -rf "$tmpd"' EXIT
cd "$tmpd"

checkpath () {
  local path=${!1}
  case $path in
       /* ) ;;  # OK, fully qualified
    *://* ) if ! wget -nv -a wget.log -O profile "$path"; then
              echo wget download failed:
              cat wget.log
              exit 1
            fi >&2
            path=profile ;;
        * ) path=$oldwd/$path ;;
  esac
  [[ -e $path ]] || fail "'$path' does not exist"
  eval "$1=\$path"
}
  
# list all installed rpms

if [[ $RPM_LOG ]]; then
  checkpath RPM_LOG
  cat "$RPM_LOG"
elif [[ $PROFILER_LOG ]]; then
  checkpath PROFILER_LOG
  perl -lpe 's/\s*$//' "$PROFILER_LOG" \
  | awk '$0 == "***** All RPMs", $0 == ""' | sed '1d;$d'
else
  rpm -qa
fi > installed.rpms

rpm_query () {
  # fake 'rpm -q pkg [...]' run against log file
  perl -e '
    my %pkgs = map {$_=>1} @ARGV;
    for (<STDIN>) {
      print if /^(.*)(?:-[^-\n]+){2}$/ && $pkgs{$1};
    }
  ' "$@" < installed.rpms
}

download_txt_files () {
  wget -nv -a wget.log -O- "$RELEASE_INFO_URL" \
  | perl -lne 'print $1 if /href="(\d[^"]*\.txt)"/' \
  | grep -e-rpms[-.] \
  | wget --base="$RELEASE_INFO_URL" -i- -nv -a wget.log || wget_fail=Y

  if [[ $wget_fail = Y ]] || ! ls | grep -q '\.txt$'; then
    echo wget download failed:
    cat wget.log
    exit 1
  fi >&2
}

if [[ $RELEASE_INFO_PATH ]]; then
  checkpath RELEASE_INFO_PATH
  cp "$RELEASE_INFO_PATH"/[0-9]*rpms*.txt .
else
  download_txt_files
fi

# strip .rpm extension to make txt files match rpm -q output:

perl -pi -e 's/\.rpm$//' *.txt

# strip .arch from everywhere if it doesn't seem to be used in the rpm list

countarch () {
  egrep "$@" -c '\.(i[3-6]86|x86_64|noarch)$' installed.rpms
}

if [[ $(countarch) -le $(countarch -v) ]]; then
  perl -pi -e 's/\.(i[3-6]86|x86_64|noarch)$//' *.txt installed.rpms
fi

# list series:

ls *.txt | perl -pe 's{^(\d+\.\d+)\..*}{$1}' | sort -u > series.list

# which series is installed? (the version of osg-release)

get_osg_series () {
  rpm_query osg-release | awk -F- 'NF>2 {print $(NF-1)}'
}

case $osg in
  --all ) osg='' ;;
     '' ) osg=$(get_osg_series)
esac

# which series do we want to consider / display ?

case $osg in
  3.0 ) osg=3.1 ;;  # special case 3.0, since it used to mean 3.1
   '' ) osg=$(fgrep -vx 3.0 series.list) ;;  # display each, except 3.0
    * ) fgrep -qxe "$osg" series.list || fail "Series $osg not found" ;;
esac

# show latest osg release vesion of each rpm per series;
# prefer series, then series-upcoming, then other, then other-upcoming

for series in $osg; do
  { ls -vr $series.*[0-9]-rpms-*.txt > series.txts
    ls -vr $series.*[0-9]-upcoming-rpms-*.txt > series-upcoming.txts
    ls -vr *[0-9]-rpms-*.txt | fgrep -vxf series.txts > other.txts
    ls -vr *[0-9]-upcoming-rpms-*.txt | fgrep -vxf series-upcoming.txts \
                                                  > other-upcoming.txts
  } 2>/dev/null || :
  echo --OSG-$series--
  cat series.txts series-upcoming.txts other.txts other-upcoming.txts \
  | xargs fgrep -xHf installed.rpms \
  | sed 's/-rpms-.*\.txt:/:/' \
  | awk -F: '!p[$2]++ {printf "%-7s %s\n", $1, $2}'
done

# lastly, detect any installed osg rpms not from a release (eg, from testing),
# based on released osg package names

unique  () { awk '!u[$0]++' "$@"; }
vrstrip () { perl -lpe 's/(-[^-]+){2}$//' "$@"; }

unique *.txt > osg.rpms
vrstrip osg.rpms | unique > osg.pkgs
fgrep -vxf osg.rpms installed.rpms > unreleased.rpms || :
vrstrip unreleased.rpms | unique > unreleased.pkgs

if fgrep -xf osg.pkgs unreleased.pkgs > osg-pkgs-unreleased.pkgs; then
  echo "--NOT-FROM-A-RELEASE--"
  rpm_query $(< osg-pkgs-unreleased.pkgs) | fgrep -xf unreleased.rpms | sort
fi

