#!/bin/bash

# copyright (c) 2005, 2006, 2007, 2008, 2009
# Erik Jan Tromp <alphageek@slackware.com>

# note: this script requires jigdo-file be patched to allow '--hex' to work
#	with 'make-template'. specifically, 'fast' rebuilds will never occur
#	with an unpatched jigdo-file

usage()
{
  cat << EOF

Usage: $(basename $0) <OPTION> [directory] [directory] [directory]

  -v, --verbose		process data verbosely

  NOTE: verbosity & directories can be specified in
  any order, but all 3 directories MUST be specified.

If you have the following layout,

  - isos in /pub/mirrors/slackware/slackware-\$VERSION-iso/
  - tree is /pub/mirrors/slackware/slackware-\$VERSION/
  - save to /tmp/sligdo/slackware-\$VERSION/

Issue the following commandline:

  $(basename $0) /pub/mirrors/slackware/slackware-\$VERSION-iso/ \\
    /pub/mirrors/slackware/slackware-\$VERSION/ /tmp/sligdo/slackware-\$VERSION/

EOF
  exit 1
}

# autosensing fun!
# ISOSPATH: directory has at least one .iso
# TREEPATH: directory has CHECKSUMS.md5 & ChangeLog.txt
# SAVEPATH: directory has .jigdo &/or .template or is empty

unset ISOSPATH TREEPATH SAVEPATH
VERBOSE=quiet
while [ $# -gt 0 ] ; do
  ONE=${1/%\//}
  if [ -z "$ISOSPATH" -a \
  ! -z "$(ls $ONE/*.iso 2> /dev/null)" ] ; then
    if [ "$ONE" == "${ONE//\/\//}" ] ; then
      ISOSPATH=$(dirname $ONE)//$(basename $ONE)
    else
      ISOSPATH=$ONE
    fi
    shift
  elif [ -z "$TREEPATH" -a \
  ! -z "$(ls $ONE/CHECKSUMS.md5 2> /dev/null)" -a \
  ! -z "$(ls $ONE/ChangeLog.txt 2> /dev/null)" ] ; then
    if [ "$ONE" == "${ONE//\/\//}" ] ; then
      TREEPATH=$(dirname $ONE)//$(basename $ONE)
    else
      TREEPATH=$ONE
    fi
    CLDATE=$(date -ud "$(head -n1 $TREEPATH/ChangeLog.txt)")
    # set label to 'Bar' from '/foo//bar-version/baz' or '/foo//bar'
    LABEL=${TREEPATH//*\/\//}
    LABEL=$(echo ${LABEL/\/*/} | sed 's,-.*,, ; s,^.,\U&,')
    shift
  elif [ -z "$SAVEPATH" -a \
  \( -d "$ONE" -o ! -z "$(ls $ONE/*.{jigdo,template} 2> /dev/null)" \) ] ; then
    SAVEPATH=$ONE
    shift
  elif [ "$ONE" == "-v" -o "$ONE" == "--verbose" ] ; then
    VERBOSE=default
    shift
  else
    shift
  fi
done

# rudimentary sanity checks
if [ -z "$ISOSPATH" ] ; then
  echo "invalid isos path specified. aborting"
  usage
fi
if [ -z "$TREEPATH" ] ; then
  echo "invalid tree path specified. aborting"
  usage
fi
if [ -z "$SAVEPATH" ] ; then
  echo "invalid save path specified. aborting"
  usage
fi

for ISONAME in $(find $ISOSPATH/ -type f -name '*.iso' \
| sed "s,^$ISOSPATH/,, ; s,\.iso$,," | sort) ; do

  unset REBUILD

  # the complete fileset doesn't exist
  if [ ! -r "$SAVEPATH/$ISONAME.jigdo" -o \
  ! -r "$SAVEPATH/$ISONAME.template" ] ; then
    REBUILD=full

  # jigdo-file version change (anything goes. simplest to do a full rebuild)
  elif [ "$(jigdo-file --version | sed 's, version ,/,')" \
  != "$(sed -n 's,^Generator=,,p' $SAVEPATH/$ISONAME.jigdo)" ] ; then
    REBUILD=full

  # .jigdo/.template mismatch (shouldn't happen, but let's test anyway)
  elif [ "$(jigdo-file md5sum --report quiet $SAVEPATH/$ISONAME.template \
  | sed -n 's, .*,,p')" != "$(sed -n 's,^Template-MD5Sum=,,p' \
  $SAVEPATH/$ISONAME.jigdo)" -a "$(jigdo-file md5sum --hex --report quiet \
  $SAVEPATH/$ISONAME.template | sed -n 's, .*,,p')" != "$(sed -n \
  's,^Template-MD5Sum=,,p' $SAVEPATH/$ISONAME.jigdo)" ] ; then
    REBUILD=full

  # the fileset is potentially out of date. compare md5sums & act accordingly
  elif [ "$(date -ur "$SAVEPATH/$ISONAME.jigdo")" != "$CLDATE" -o \
  "$(date -ur "$SAVEPATH/$ISONAME.template")" != "$CLDATE" ] ; then

    # this whole segment pretty much defies sane description. enjoy
    # (essentially, compare md5sums in the .jigdo to those in the tree's
    # toplevel CHECKSUMS.md5. for some isos [specifically, dvd], there may
    # be subdirectory CHECKSUMS.md5 listed in the .jigdo that do not exist
    # in the tree's toplevel CHECKSUMS.md5. for these, compare md5sums
    # from the .jigdo to the files in the live tree itself. confused yet?)
    MD5SUMS=($(comm -13 <(sort $TREEPATH/CHECKSUMS.md5) \
    <(sed -n "s,=$LABEL:${TREEPATH//*\/\//}/,  ./,p" \
    $SAVEPATH/$ISONAME.jigdo | sort)))
    for SUBSCRIPT in $(seq 0 2 $[${#MD5SUMS[*]}-1]) ; do
      if [ "${MD5SUMS[$SUBSCRIPT]}  $TREEPATH/${MD5SUMS[$SUBSCRIPT+1]}" == \
      "$(md5sum $TREEPATH/${MD5SUMS[$SUBSCRIPT+1]} 2> /dev/null)" ] ; then
        unset MD5SUMS[$SUBSCRIPT] MD5SUMS[$SUBSCRIPT+1]
      fi
    done
    if [ ${#MD5SUMS[*]} -eq 0 ] ; then
      REBUILD=fast
    else
      REBUILD=full
    fi
  fi

  if [ ! -z "$REBUILD" ] ; then
    [ "$VERBOSE" == "default" ] && echo "processing ($REBUILD): $ISONAME.iso"

    if [ "$REBUILD" == "full" ] ; then
      # prevent accidental downloads of mismatched .jigdo/.template data
      rm -f $SAVEPATH/$ISONAME.{jigdo,template}

      # (re)create .jigdo/.template from iso & tree
      find $TREEPATH/ -type f -size +255c \
      | egrep -v "^$TREEPATH/patches/|\.iso$" \
      | sort \
      | jigdo-file make-template --files-from - \
      --hex --md5-block-size 256 --min-length 256 \
      --no-greedy-matching --no-servers-section \
      --report $VERBOSE \
      --jigdo $SAVEPATH/$ISONAME.jigdo \
      --template $SAVEPATH/$ISONAME.template \
      --image $ISOSPATH/$ISONAME.iso \
      --label $LABEL=${TREEPATH//\/\/*/}

      # post-processing

      # tweak .jigdo image path & timestamp
      sed -i "s,^Filename=,Filename=${ISOSPATH//*\/\//}/, ; \
      /^Template=/iFiletime=$(date -ur $ISOSPATH/$ISONAME.iso)" \
      $SAVEPATH/$ISONAME.jigdo

    # fast. be tidy & break any existing hardlinks
    else
      for FILE in $SAVEPATH/$ISONAME.{jigdo,template} ; do
        if [ $(stat -c %h $FILE) -gt 1 ] ; then
          cp -p $FILE{,.$$}
          mv $FILE{.$$,}
        fi
      done
    fi

    # set timestamps of .jigdo/.template to match tree's changelog date
    touch $SAVEPATH/$ISONAME.{jigdo,template} --date "$CLDATE"
  fi
done
