#!/bin/sh

# Main dependencies: aptly(>=0.9), grep, awk, sed, date
# Debug dependencies: time

VERSION="0.1"

# This shell script was written in order to help you to update your mirrors
# every day via crontab with aptly[1]. All you need is to name your mirrors in
# the appropriate format: '$release/$component';

# For example, do this:
# % aptly mirror create sid/main http://mirror.yandex.ru/debian/ sid main
# % aptly mirror create sid/contrib http://mirror.yandex.ru/debian/ sid contrib

# When you run this script it does:
# 1) update all your mirrors
# 2) *drop* *all* your publications and snapshots
# 3) create new snapshots and publish them

# It's originally written by Dmitrii Kashin <freehck@freehck.ru>, and is
# distributed under GNU GPLv2[2]. Feel free to improve it.

set -e

usage () {
    cat <<EOF
repo-update.sh [-d] [-g <gpg-key-passphrase>] [-l <log-file>] <action>

-d	Activates debug mode.
-g	Set a passphrase for your gpg key (it can be useful if you run script
        with cron.
-l	File to store log. Type '-' for output to screen.
-b	Batch mode (not to use tty)
-v	Show script version

Action could be one of:
create	Update mirrors and create publications
update	Update mirrors and publications
clear	Delete publications and snapshots

EOF
}

## Defaults:
SCRIPT="$0"
LOGFILE="$HOME/.aptly/repo-update.log"
SHELL=/bin/sh
PROMPT="% "
DATE=`date +%F-%T`
SUFFIX="$DATE"
GPG_PASSWD=""
DEBUG=0
BATCH=""

## Configuration:
while getopts vhdbg:l: option
do
    case "$option" in
	v) echo "$VERSION"; exit 0;;
        d) DEBUG=1;;
	b) BATCH='-batch=true';;
        g) GPG_PASSWD="$OPTARG";;
	l) LOGFILE="$OPTARG";;
	h) usage; exit 0;;
	*) usage; exit 1;;
    esac
done
ACTION=$(eval "echo \"\$$OPTIND\"") # bit-hack: Dash doesn't have ${!OPTIND} construction

if [ -z "$ACTION" ]
then
    usage
    exit 0
fi

# debug flag enables time measuring 
if [ $DEBUG -eq 1 ]
then
    WITH_TIMER=time
else
    WITH_TIMER=
fi

## Additional functions:

# control output: delete all passwords from it
logger () {
    echo "$@" | if [ -z "$GPG_PASSWD" ]
    then
	cat
    else
	sed "s/$GPG_PASSWD/\*\*\*/g"
    fi
}

# same as logger but append $PROMPT before each line to show it's a separate command
plogger () {
    STR=$(
	echo "$@" | if [ -z "$PROMPT" ]
	then
	    cat
	else
	    sed "s/^/$PROMPT/"
	fi)
    logger "$STR"
}

# log command and run it
run_command () {
    plogger "$1"
    eval "$WITH_TIMER $1"
    echo
}

## aptly commands:

# update all mirrors
CMD_UPDATE_MIRRORS="aptly mirror list -raw | xargs -n 1 -r aptly mirror update $TO_LOGFILE"
cmd_update_mirrors () {
    logger "RUN: CMD_UPDATE_MIRRORS"
    run_command "$CMD_UPDATE_MIRRORS"
}

# create snapshots named '$mirror-$suffix'
CMD_CREATE_SNAPSHOTS="aptly mirror list -raw | xargs -n 1 -I{} aptly snapshot create {}-\"$SUFFIX\" from mirror {} $TO_LOGFILE"
cmd_create_snapshots () {
    logger "RUN: CMD_CREATE_SNAPSHOTS"
    run_command "$CMD_CREATE_SNAPSHOTS"
}

# drop all your publications
CMD_DROP_PUBLICATIONS="aptly publish list -raw | awk '{print \$2}' | xargs -n 1 -r aptly publish drop $TO_LOGFILE"
cmd_drop_publications () {
    logger "RUN: CMD_DROP_PUBLICATIONS"
    run_command "$CMD_DROP_PUBLICATIONS"
}

# drop all your snapshots
CMD_DROP_SNAPSHOTS="aptly snapshot list -raw | xargs -n 1 -r aptly snapshot drop $TO_LOGFILE"
cmd_drop_snapshots () {
    logger "RUN: CMD_DROP_PUBLICATIONS"
    run_command "$CMD_DROP_SNAPSHOTS"
}

# create new publications using last available snapshots
cmd_create_publications () {
    logger "RUN: CMD_CREATE_PUBLICATIONS"
    # check here for available snapshots maybe?
    CMD_CREATE_PUBLICATIONS=$(aptly mirror list -raw | awk -F/ "{targets[\$1]=targets[\$1]\" \"\$2;} END{for (tar in targets) print tar, targets[tar];}" | awk "{release=\$1; comp=snapshots=\"\"; for(i=2; i<=NF; i++) {(comp!=\"\") ? comp=comp\",\"\$i : comp=\$i; snapshots=snapshots\" \"release\"/\"\$i\"-$SUFFIX\"}; print \"aptly publish snapshot -distribution=\"release\" -component=\"comp\" -passphrase=$GPG_PASSWD \"snapshots\" $TO_LOGFILE;\"; }")
    run_command "$CMD_CREATE_PUBLICATIONS"
}

# update all your publications
cmd_update_publications () {
    logger "RUN: CMD_UPRATE_PUBLICATIONS"
    # check here for available publications maybe?
    CMD_UPRATE_PUBLICATIONS=$(aptly mirror list -raw | awk -F/ "{targets[\$1]=targets[\$1]\" \"\$2;} END{for (tar in targets) print tar, targets[tar];}" | awk "{release=\$1; comp=snapshots=\"\"; for(i=2; i<=NF; i++) {(comp!=\"\") ? comp=comp\",\"\$i : comp=\$i; snapshots=snapshots\" \"release\"/\"\$i\"-$SUFFIX\"}; print \"aptly publish switch $BATCH -component=\"comp\" -passphrase=$GPG_PASSWD \"release\" \"snapshots\" $TO_LOGFILE;\"; }")
    run_command "$CMD_UPRATE_PUBLICATIONS"
}

## Actions:

act_update () {
    cmd_update_mirrors
    cmd_create_snapshots
    cmd_update_publications
    exit 0
}

act_create () {
    cmd_update_mirrors
    cmd_create_snapshots
    cmd_create_publications
    exit 0
}    

act_clear () {
    cmd_drop_publications
    cmd_drop_snapshots
    exit 0
}

act_test () {
    # this function is a sandbox for experiments
    exit 0
}

## Runtime:

# output everything into $LOGFILE
if [ "x$LOGFILE" != "x-" ]
then
    exec 3>>"$LOGFILE" 1>&3 2>&1
fi

logger "Script $SCRIPT's started at $(LANG=C date)"

case "$ACTION" in
    test)
	act_test;;
    create)
	act_create;;
    update)
	act_update;;
    clear)
	act_clear;;
    help)
	usage; exit 0;;
esac

# Default behaviour
logger "And immediately finished! =)"
exit 2

# [1] https://github.com/smira/aptly.git
# [2] http://www.gnu.org/licenses/gpl-2.0.html