#!/bin/sh
#
# Download, with rsync, Ubuntu ISO images for testing them.
# This will use a lot of bandwidth and disk space.
#
# You can put a configuration file (~/.dl-ubuntu-test-iso)
# and set some variables to limit what will be downloaded.
# See sample values below.
#
#   * ARCHS: what architectures to download
#   * FLAVORS: what flavors of Ubuntu? Ubuntu itself, Kubuntu, etc
#   * VARIANTS: for each flavor, what variants? desktop (= live cd)?
#     alternate cd?
#   * OPTS: options for rsync
#
# You can get sample configuration files at /usr/share/doc/ubuntu-qa-tools/examples/
#
# This is based on a script by davmor2 on #ubuntu-testing. Modified and
# rewritten to be more easily extensible by Lars Wirzenius. Further
# abuse was perpetrated by Steve Beattie. This is probably
# too simple to be covered by copyright, but if not:
#
# Copyright 2008, 2009 Canonical Ltd.
# Licensed under the GNU General Public License, version 3.

set -e

ISOROOT="${HOME}/iso"
BASEURL="rsync://cdimage.ubuntu.com/cdimage"
RELEASES="karmic hardy"
ARCHS="i386 amd64"
FLAVORS="ubuntu kubuntu edubuntu xubuntu ubuntu-server"
FLAVORS="$FLAVORS ubuntustudio mythbuntu"
VARIANTS="desktop alternate server addon dvd"
EXCLUDE=""
OPTS="-zthhP"
QUIET="false"
NO_ACT=no
VERIFY="true"
BUILD="current"

RSYNC=rsync
ISOINFO=/usr/bin/isoinfo
WGET=/usr/bin/wget
CURL=/usr/bin/curl
CURRENT_RELEASE="karmic"
VERSIONS="false"
CONFIGFILE="${HOME}/.dl-ubuntu-test-iso"

if [ -e "${CONFIGFILE}" ]
then
    . ${CONFIGFILE}
elif [ -e "${ISOROOT}/iso.cfg" ]
then
    echo "******"
    echo "****** ${ISOROOT}/iso.cfg is deprecated, please use ${CONFIGFILE} instead"
    echo "******"
    . "${ISOROOT}/iso.cfg"
fi

setup_dir()
{
    local dir=$1

    [ -d "$dir" ] || mkdir $dir
    cd $dir
}

setup_dir $ISOROOT

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

no_act()
{
    [ "$NO_ACT" = yes ]
}

debugify_commands()
{
    RSYNC="echo $RSYNC"
    ISOINFO="echo $ISOINFO"
}

wantflavor()
{
    echo " $FLAVORS " | grep " $1 " > /dev/null && 
    echo " $EXCLUDE " | grep -v " $1 " > /dev/null
}

wantvariant()
{
    echo " $VARIANTS " | grep " $1 " > /dev/null
}

wantarch()
{
    local arch="$1"
    shift
    echo " $@ " | grep " $arch " > /dev/null
}

# Dead code, kept around for historical raisins
#isold()
#{
#    if [ ! -e "$1" ]
#    then
#        return 0
#    else
#        local mtime=$(stat --printf='%Y\n' "$1")
#        local old=$(date --date="$MINAGE" +%s)
#        [ "$mtime" -lt "$old" ]
#    fi
#}
# end dead code

isquiet()
{
    [ "$QUIET" = "true" ]
}

doverify()
{
    [ "$VERIFY" = "true" ]
}

doversions()
{
    [ "$VERSIONS" = "true" ]
}

computepath()
{
    local flavor="$1"
    local release="$2"
    local dir="$3"

    local releasepath=""
    local flavorpath=""
    if [ "$CURRENT_RELEASE" != "$release" ]
    then
	releasepath="$release/"
    fi

    if [ "$flavor" != "ubuntu" ]
    then
    	flavorpath="$flavor/"
    fi

    echo "${flavorpath}${releasepath}${dir}"
}

has_joliet()
{
    local iso="$1"
    ! isoinfo -d -i "${iso}" | grep -q "^NO Joliet"
}

report_versions()
{
    local dir=$1

    if [ ! -x ${ISOINFO} ]
    then
    	echo "Please install the isoinfo package in order to report iso versions"
	echo "(On ubuntu, 'sudo apt-get install genisoimage' will get it."
	exit 1
    fi

    find $dir -name "*.iso" -print | while read isoname
    do
	# all ubuntu cds should be joliet, but if non-joliet ones are
	# stored in the tree as well, it's nice to not report errors due
	# to that.
	if has_joliet ${isoname}
	then
            DISKINFO=$(${ISOINFO} -J -x "/.disk/info"  -i ${isoname} || true)
            DISKTYPE=$(${ISOINFO} -J -x "/.disk/cd_type"  -i ${isoname} || true)
	fi
	echo "$isoname ${DISKINFO} ${DISKTYPE}"
    done
}

# returns boolean if file exists remotely
remote_file_exists()
{
    local url=$(echo "$1" | sed -e 's/rsync/http/')
    if [ -x "${WGET}" ]
    then
	${WGET} -q --spider "${url}"
    elif [ -x "${CURL}" ]
    then
	# meh, curl, why are you a pain?
	local code=$(${CURL} -s -I --write-out "%{http_code}\n" "${url}" | tail -1)
	[ "${code}" = "200" ]
    else
	return 0
    fi
}

get()
{
    local flavor="$1"
    local dir="$2"
    shift 2

    local output=""
    if isquiet
    then
        output="> /dev/null"
    fi

    for variant in "$@"
    do
        if wantflavor "$flavor" && wantvariant "$variant"
        then
            [ -d "$flavor" ] || mkdir "$flavor"
            for arch in $ARCHS
            do
		for release in $RELEASES
		do
                    if wantarch "$arch" "$ARCHS"
                    then
			local iso="$release-$variant-$arch.iso"
			local path="$(computepath $flavor $release $dir)"
			local md5sum="MD5SUMS.$release-$variant"
			local remote_path="$BASEURL/$path/$iso"
			if ! remote_file_exists "${remote_path}"
			then
                            isquiet || echo "Skipping $release $flavor $variant $arch: not on server"
			else
                            isquiet || echo "Synching $release $flavor $variant $arch ($path/$iso)"
                            if no_act
                            then
                            	:
                            	# echo "(Not really running rsync because of NO_ACT)"
                            else
                                $RSYNC $OPTS "${remote_path}" "$flavor/$iso" || true
                                doverify && $RSYNC $OPTS "$BASEURL/$path/MD5SUMS" "$flavor/$md5sum" || true
                            fi
			    if doverify
			    then
			    	if [ -f "$flavor/$md5sum" ]
			    	then
			    	    local FILEMD5SUM="$(grep "$iso" "$flavor/$md5sum" | sed -e "s/\($iso\)/$flavor\/\\1/")"
			    	    isquiet || echo -n "Verifying $iso... "
				    eval "echo \"$FILEMD5SUM\" | md5sum -c - $output" || true
			    	else
			    	    isquiet || echo "No checksum file available for $iso, skipping verification"
			        fi
			    fi
			fi
                    fi
		done
            done
        fi
    done
}

print_help()
{
    echo "
    ./dl-ubuntu-test-iso [options]

You may use the following options:

    -n, --no-act
        Do everything, except don't actually run rsync. You can use this
        to test configuration settings, etc.

    --debug
        Similar to --no-act, but echos the actual rsync commands, as you
        might expect, this is useful for debugging the script or
        configurations

    -P  Run rsync with the -P option, to get progress reporting.

    --only flavor, --flavor flavor
        Only download a specific flavor of Ubuntu. Only the last
        --only option applies. (You can also set FLAVORS in the
        configuration file.) --only should probably be considered
        depricated.

    --exclude flavor
        Do not download a specific flavor of Ubuntu. You can use this
        option multiple times, and none of the specified flavors will be
        downloaded. (You can also set EXCLUDE in the configuration
        file.)

    --release release
        Only download a specific release target of Ubuntu. Only the last
        --release option applies. (You can also set RELEASES in the
        configuration file.) \"hardy\" is the earliest release target

    --bwlimit kbpslimit
	Rate limit rsync download to a limit in KBytes/second.
    "
}

TEMP=`getopt -o nPqh --long no-act,help,force,debug,quiet,no-verify,versions,only:,exclude:,release:,flavor:,bwlimit:,build: -- "$@"`
eval set -- "$TEMP"

while true
do
    case "$1" in
    -n|--no-act) NO_ACT=yes; shift ;;
    --debug) debugify_commands ; shift;;
    -q|--quiet) QUIET=true; shift ;;
    -P) OPTS="$OPTS -P"; shift ;;
    --only|--flavor) FLAVORS="$2"; shift 2;;
    --exclude) EXCLUDE="$EXCLUDE $2"; shift 2;;
    --release) RELEASES="$2"; shift 2;;
    --bwlimit) OPTS="$OPTS --bwlimit=$2"; shift 2;;
    --build) BUILD="$2"; shift 2;;
    --no-verify) VERIFY="FALSE"; shift ;;
    --versions) VERSIONS="true"; shift ;;
    -h|--help) print_help ; die ;; 
    --) shift; break ;;
    *) die "Internal error while parsing command line"
    esac
done

if isquiet
then
    OPTS="$OPTS -q"
fi

isquiet || cat << eof
BASEURL=$BASEURL
RELEASES=$RELEASES
ARCHS=$ARCHS
FLAVORS=$FLAVORS
VARIANTS=$VARIANTS
EXCLUDE=$EXCLUDE
OPTS=$OPTS
NO_ACT=$NO_ACT
VERIFY=$VERIFY
BUILD=$BUILD
ISOROOT=$ISOROOT
QUIET=$QUIET

eof

if doversions
then
    report_versions $ISOROOT
    exit 0
fi

get ubuntu daily-live/${BUILD} desktop
get ubuntu daily/${BUILD} alternate
get ubuntu dvd/${BUILD} dvd

get ubuntu-server daily/${BUILD} server

get kubuntu daily-live/${BUILD} desktop
get kubuntu daily/${BUILD} alternate
get kubuntu dvd/${BUILD} dvd

# deprecated, not enabled by default
get kubuntu-kde4 daily-live/${BUILD} desktop
get kubuntu-kde4 daily/${BUILD} alternate

get edubuntu daily/${BUILD} addon

get xubuntu daily-live/${BUILD} desktop
get xubuntu daily/${BUILD} alternate

get ubuntustudio daily/${BUILD} alternate

__ARCHS=$ARCHS
# deprecated, not enabled by default
ARCHS=i386 get jeos daily/${BUILD} jeos
ARCHS=${__ARCHS}

# deprecated, not enabled by default
get gobuntu daily/${BUILD} alternate

# alternate deprecated, should probably be removed
get mythbuntu daily/${BUILD} alternate
get mythbuntu daily-live/${BUILD} desktop
