#!/bin/bash

#
# The script is executed periodically by cronjob
# as part of ~mirror/bin/publish_factory_leap wrapper on pontifex
#
# Tool publises data from stage (/src/ftp-stage) to public (/srv/ftp - download.opensuse.org) 
#
# Configuration lives in openSUSE-release-tools.git/publish_distro_conf
# Syntax: ./publish_distro config_file
# 

# no --delete built in

# number of hours to delay publishing when new isos arrive
PUBLISH_DELAY=2

# force publish even if isos appear to be synced already
force=

# used for cleanup
date='now'

# set to echo for dry run
dryrun=

# cleanup instead of sync
do_cleanup=

# url with snapshot changes app
diff_url_base="https://openqa.opensuse.org/snapshot-changes/opensuse"
changes_dir_base="/srv/www-local/snapshot-changes"
repos=("oss" "non-oss")
extra_repos=("source" "debug")
isodir="iso"

get_version() {
	exit 1
}
get_iso() {
	exit 1
}
get_iso_link() {
	exit 1
}
get_diff_url() {
	exit 1
}
get_mark_published_url() {
	exit 1
}
get_changes_filename() {
	exit 1
}

# --dry and --cleanup should not be passed to rsync through $@
# config file and possibly other opts including --force need to be
for arg do
  shift
  if [ "$arg" == '--force' ]; then
        force=1
        newargs+=("$arg")
        shift
        continue
  elif [ "$arg" == '--dry' ]; then
        dryrun=echo
        shift
        continue
   elif [ "$arg" == '--cleanup' ]; then
        do_cleanup=1
        date="90 days ago"
        continue
  else
        newargs+=("$arg")
  fi
done

# set newargs as $@
set -- "${newargs[@]}"

. "$1" || { echo "need to specify config file" >&2; exit 1; }
shift

stage="/srv/ftp-stage/pub/opensuse/$path"
dest="/srv/ftp/pub/opensuse/$path"

if [ ! -e "$stage" -o ! -e "$dest" ]; then
	echo "stage ($stage) and/or dest ($dest) doesn't exist" >&2
	exit 1
fi

if [ -n "$do_cleanup" ]; then
	# find newest delete log of that day
	deletelog=$(ls -1tr ${deletelog%/*}/*-deletes.log | tail -1)
	test -n "$deletelog" || exit 1
	(
	df -h /srv
	for i in $(awk '/\*deleting   .*/ { print $2}' $deletelog ); do
		if [ -e "$stage/$i" ]; then
			echo "WARNING: $i still exist in stage, not deleting"
		else
			$dryrun rm -rvf "$dest/$i"
		fi
	done
	df -h /srv
	) > $deletelog-deleted
	exit 0
fi

mkdir -p "${synclog%/*}" "${deletelog%/*}"
if test -f $synclog; then
    old $synclog
fi
if test -f $deletelog; then
    old $deletelog
fi

version=
do_sync_isos=1
for flavor in "${flavors[@]}"; do
	get_version

	get_iso

	get_diff_url
	get_changes_filename
	if [ -z "$force" -a -e "$dest/$isodir/$iso" ]; then
		if [ -t 1 ]; then # only log to tty
			echo "$iso already published, skipping isos"
		fi
		do_sync_isos=0
		break
	fi
        if [ -n "$changes" ]; then
                if [ -d "$stage/$changes" ]; then
                       # new way, use the obs generated changelogs
                       $dryrun rsync -avvhiH $stage/$changes \
                         --link-dest=$stage \
                                     $dest/$changes $dry_delete "$@" \
                           | LC_ALL=C grep -v '^\.[fdL]      ' \
                           | LC_ALL=C grep -v '^\(sending\|delta\)' \
                           | tee -a $log
                else
                       # old way (already broken?)
                       if [ ! -s "$changes" ]; then
                        echo "generating $changes" | tee -a $synclog
                        [ -z "$dryrun" ] || changes=/dev/stdout
                        $dryrun curl -sf "$url" > $changes
                       fi
                       if [ ! -e $stage/$isodir/$changes ]; then
                        $dryrun cp -v $changes $stage/$isodir | tee -a $synclog
                        [ -e $stage/$isodir/Changes ] || $dryrun ln -sf . $stage/$isodir/Changes 2>&1 | tee -a $synclog
                       fi
                fi
        fi
	if [ ! -e "$stage/$isodir/$iso" ]; then
		echo "$flavor with $version doesn't exist, skipping isos" | tee -a $synclog
		do_sync_isos=0
		break
	else
		get_iso_link
		if [ "`readlink $link`" != "$iso" ]; then
			$dryrun ln -sf "$iso" "$link"
			$dryrun ln -sf "$iso.sha256" "$link.sha256"
		fi
		if [ -z "$force" ]; then
			if test `date -d "$PUBLISH_DELAY hours ago" +%s` -lt `stat -c "%Z" "$stage/$isodir/$iso"`; then
				echo "$iso was created less than $PUBLISH_DELAY hours ago, delay publishing" | tee -a $synclog
				do_sync_isos=0
			fi
		fi
	fi
done

# produce directories stamped with build number
for r in "${repos[@]/#//repo/}"; do
	for i in /suse/setup /boot; do
		d="$stage$r$i"
		[ -d "$d" ] || continue
		if [ -e "$stage$r/media.1/build" ]; then
			read build < "$stage$r/media.1/build"
			stamp="${build#*Build}"
			if [ "$build" = "$stamp" ]; then
				echo "ERROR: build id not parsable: $build. not syncing"
				do_sync_isos=0
				break 2
			fi
		elif [ -e "$stage$r/media.1/media" ]; then
			{ read dummy; read build; } < "$stage$r/media.1/media"
			stamp="${build#*Build}"
			if [ "$build" = "$stamp" ]; then
				echo "ERROR: build id not parsable: $build. not syncing"
				do_sync_isos=0
				break 2
			fi
		else
			echo "ERROR: repo $r is missing build id, not syncing"
			do_sync_isos=0
			break 2
		fi
		stamped="$stage$r${i%/*}/$stamp-${i##*/}"
		if [ ! -L "$d" ]; then
			$dryrun mv "$d" "$stamped"
			$dryrun ln -s "${stamped##*/}" "$d"
			echo "current $stamp" | $dryrun tee $stage/$r/.current.txt
		fi
	done
done

if [ "$do_sync_isos" = 0 ]; then
	if [ -t 1 ]; then
		echo "nothing to do"
	fi
	exit 0
fi

# scan mirrors before making the files visible
#mb scan -q -a -d /tumbleweed

TODO=()
#if [ "$do_sync_isos" = 1 ]; then
	TODO+=(iso)
	echo "current $version" | $dryrun tee $stage/$isodir/.current.txt
#fi

if [ -n "$repos" ]; then
	TODO+=(repo)
	TODO+=(DELETE_repo)
fi

# a single grep -v regexp performs awfully bad (needs at least 30x so long)
# although LC_ALL=C might fix this, too
for i in "${TODO[@]}"; do

    case $i in 
    DELETE_*)
        i=${i#DELETE_}
        log=$deletelog
        dry_delete="--delete -n"
        ;;
    iso) # ISOs we sync with delete
       log=$synclog
       dry_delete="--delete-after"
	i="$isodir"
       ;;
    *)
        log=$synclog
        dry_delete=""
        ;;
    esac

    echo ========== $i $dry_delete ===========
    $dryrun rsync -avvhiH $stage/$i \
      --link-dest=$stage \
                  $dest $dry_delete "$@" \
        | LC_ALL=C grep -v '^\.[fdL]      ' \
        | LC_ALL=C grep -v '^\(sending\|delta\)' \
        | tee -a $log
done

# also sync source and debug, not bind mounted for Leap
for r in "${extra_repos[@]}"; do
	stage="/srv/ftp-stage/pub/opensuse/$r/$path"
	dest="/srv/ftp/pub/opensuse/$r/$path"
	$dryrun rsync -avhiH $stage/ --link-dest=$stage \
                  $dest --delete-after "$@" | tee -a log
done

# mark published
get_mark_published_url
if [ -n "$url" ]; then
	$dryrun curl -X POST -F "version=$version" "$url"
fi

#echo creating hashes
#metalink-hasher update -t /srv/metalink-hashes/srv/ftp/pub/opensuse/tumbleweed \
#                       -b /srv/ftp/pub/opensuse/tumbleweed \
#                          /srv/ftp/pub/opensuse/tumbleweed

# mb makehaskes is not needed by mirrorcache (replaced mirrorbrain)
#$dryrun /usr/bin/mb makehashes -b /srv/ftp/pub/opensuse \
#                       -t /srv/metalink-hashes/srv/ftp/pub/opensuse \
#                       $dest
