#!/bin/bash

# Note: this is only an example of how you'd call create-filelist.  Edit to fit
# your requirements.  Note that you must supply a valid path for the lockfile,
# and it must be outside of your repository unless you want that lockfile to
# show up in your file lists.

# Takes a list of module names.  Generates file lists for all of them and them
# moves them into place at once.  If you are creating hardlinks between rsync
# modules, it is required that you update the file lists of both mirrors at the
# same time.  Otherwise the clients may make separate copies of the files.

# The directory where all of the modules live
# Or pass it with -t
TOPD=/srv/mirror/pub

# The modules to process.  Or pass them on the command line.
MODS=()

# Path to the create-filelist program.
# Or specify it with -p.
CREATE=/usr/local/bin/create-filelist

# These strings will be eval'ed later with $mod replaced by its value in
# context.
FILELIST=fullfilelist
TIMELIST='fullfiletimelist-$mod'
IMAGELIST='imagelist-$mod'

usage () {
    echo
    echo "Usage: $0 [-l lockfile] [-p creator path] [-t top directory] module [module ...]"
    echo
    echo "    -l: Path to the lock file"
    echo "    -p: Path to the create-filelist program"
    echo "    -t: Path to directory containing modules"
    echo
    echo "At least one module to process must be provided."
    echo "All paths must be absolute."
}

while [[ $# > 0 ]]; do
    opt=$1
    case $opt in
        -l)
            LOCKFILE=$(realpath $2)
            shift
            ;;
        -p)
            CREATE=$(realpath $2)
            shift
            ;;
        -t)
            TOPD=$(realpath $2)
            shift
            ;;
        -*)
            (>&2 echo "Unknown option $opt."; usage)
            exit 1
            ;;
        *)  # Remaining args are modules
            MODS+=($opt)
            ;;
    esac
    shift
done

if [[ -z $LOCKFILE ]]; then
    (>&2 echo "Must specify LOCKFILE, either by editing the source or via the -l option."; usage)
    exit 2
fi
if [[ ! -d $(dirname $LOCKFILE) ]]; then
    (>&2 echo "Given directory $(dirname $LOCKFILE) does not exist."; usage)
    exit 2
fi
if [[ ! -f $CREATE ]]; then
    (>&2 echo "Specified executable $CREATE does not exist."; usage)
    exit 2
fi

if [[ ! -d $TOPD ]]; then
    (>&2 echo "Provided directory $TOPD does not exist."; usage)
    exit 2
fi

if [[ ${#MODS[@]} -eq 0 ]]; then
    (>&2 echo "No modules specified"; usage)
    exit 2
fi

tmpd=$(mktemp -d -t create-filelist.XXXXXXXXXX)
if [[ $? -ne 0 ]]; then
    (>&2 echo "Creating temporary directory failed?")
    exit 1
fi
trap "rm -rf $tmpd" EXIT
cd $tmpd

(
    # We want to wait forever until we can do what we're asked
    flock -x 9

    # If you don't want to wait forever, try one of the following:
    # flock -n 9 || exit 1      - Gives up immediately
    # flock -w 120 9 || exit 1  - Waits 120 seconds and then gives up
    # Don't change the '9', unless you change the last line of this script.

    for mod in ${MODS[@]}; do
        currentfl=$TOPD/$mod/${FILELIST/'$mod'/$mod}
        currenttl=$TOPD/$mod/${TIMELIST/'$mod'/$mod}
        currentil=$TOPD/$mod/${IMAGELIST/'$mod'/$mod}
        flname=$(basename $currentfl)
        tlname=$(basename $currenttl)
        ilname=$(basename $currentil)

        $CREATE -c -s -d $TOPD/$mod -f $flname -t $tlname -i $ilname

        # If a file list exists and doesn't differ from what we just generated,
        # delete the latter.
        if [[ -f $currentfl ]] && diff -q $currentfl $flname > /dev/null; then
            rm -f $flname
        fi
        if [[ -f $currenttl ]] && diff -q $currenttl $tlname > /dev/null; then
            rm -f $tlname
        fi
        if [[ -f $currentil ]] && diff -q $currentil $ilname > /dev/null; then
            rm -f $ilname
        fi
    done

    # Now we have the new file lists but in a temporary directory which
    # probably isn't on the same filesystem.  Copy them to temporary files in
    # the right place.
    for mod in ${MODS[@]}; do
        currentfl=$TOPD/$mod/${FILELIST/'$mod'/$mod}
        currenttl=$TOPD/$mod/${TIMELIST/'$mod'/$mod}
        currentil=$TOPD/$mod/${IMAGELIST/'$mod'/$mod}
        flname=$(basename $currentfl)
        fldir=$(dirname $currentfl)
        tlname=$(basename $currenttl)
        tldir=$(dirname $currenttl)
        ilname=$(basename $currentil)
        ildir=$(dirname $currentil)

        if [[ -f $flname ]]; then
            tmpf=$(mktemp -p $fldir $flname.XXXXXXXXXX)
            cp -p $flname $tmpf
            chmod 644 $tmpf
            mv $tmpf $currentfl
        fi
        if [[ -f $tlname ]]; then
            tmpf=$(mktemp -p $tldir $tlname.XXXXXXXXXX)
            cp -p $tlname $tmpf
            chmod 644 $tmpf
            mv $tmpf $currenttl
        fi
        if [[ -f $ilname ]]; then
            tmpf=$(mktemp -p $ildir $ilname.XXXXXXXXXX)
            cp -p $ilname $tmpf
            chmod 644 $tmpf
            mv $tmpf $currentil
        fi
    done

) 9>$LOCKFILE