#!/bin/bash
# (c) Etersoft 2003-2012, 2017
# Author: Vitaly Lipatov <lav@etersoft.ru>, 2012, 2017
# Public domain
#
# BS - build source
#
# Создаёт пакет с исходниками по спеку
# Параметры:
# - названия спек-файлов
# - или пакетов
# Если указан ключ -s, подписываем пакет
# Если указан ключ --nodeps, не учитываем сборочные зависимости
# Если указан ключ -u, отправляем пакет в incoming
# Если указан ключ -d, удаляем из incoming
# Если указан -n, не проверяем перед отправкой
# TODO: -r

# load common functions, compatible with local and installed script
. `dirname $0`/../share/eterbuild/functions/common
load_mod rpm tarball alt git web buildsrpm branch

SIGN=
SIGNTAG=
FORCE=
UPLOADNOW=
CHECKONLY=
TESTONLY=
NOSOURCE=
NOCHECK=
UPDATES=
DELETENOW=
POCKET=
PREPARETASK=
TASKNUMBER=

#############################
Usage="Usage: $name [GIRAR] [-b REPONAME] [-p POCKET] [-s|-t|-u|-a|-A|-c|-e] [-o -z -n -p --nodeps] [-k [TARGETDIR]] [spec or src.rpm]..."
function mygetopts()
{
name=${0##*/}
Descr="$name (Build Source) - run git repo build or make src.rpm from spec"

phelp()
{
	echog "$Descr"
	echog "$Usage"
	echo
	echog "Options:"
	echog "   -u           sign and run gear build task"
	echog "   -a TASK      sign package(s)/repo, push/upload it and add to (shared) task TASK"
	echog "                -a TASKbeforeSUBTASK (f.i., 43122before90) for put task before SUBTASK in TASK"
	echog "   -A           sign package(s)/repo, push/upload it and add to the last task"
	echog "   -p POCKET    build package in POCKET (supported on git.etersoft.ru only)"
	echog "   -b REPONAME  binary repository name (p7, t7 and so on)"
	echo
	#echog "Korinf options:"
	#echog " -k [TARGET] - generate src.rpm and publish to TARGET dir (from Source: by default)"
	#echog " -r [RELEASE] - publish to RELEASE target dir version"
	echog "Ext. options:"
	echog "   -e           sign and run gear test only task girar build"
	echog "   -c           only sign package(s) with checking"
	echog "   -f           force operation (overwrite tag)"
	echog "   -s           sign package(s) (and move it to dir ETERDESTSRPM if defined)"
	echog "   -t           set tag with sign"
	echog "   -n           do not check with sisyphus_check before upload"
	echog "   -o           create nosrc.rpm package"
	echog "   -z           create src.rpm with compatible gzip compression (obsoleted)"
#	echog " -d - remove package(s) from SRPMS and Incoming"
}

while getopts :hfstcudenop:a:Ab:z opt; do
    case $opt in
    h) phelp; exit 0;;
    s) SIGN=1 ;;
    t) SIGNTAG=1 ;;
    e) TESTONLY="--test-only" ; UPLOADNOW=1 ; SIGN=1 ;;
    f) FORCE="-f" ;;
# FIXME: handle SIGN separately
    c) CHECKONLY=1 ; SIGN=1 ;;
    u) UPLOADNOW=1 ; SIGN=1 ;;
    a) UPLOADNOW=1 ; SIGN=1 ; PREPARETASK=yes ; TASKNUMBER="$(echo $OPTARG | sed -e 's/before/ /g')" ;;
    A) UPLOADNOW=1 ; SIGN=1 ; PREPARETASK=yes ; TASKNUMBER= ;;
# see functions/alt:set_binaryrepo() for BINARYREPONAME
    b) BINARYREPONAME=$OPTARG ;;
    n) NOCHECK=1; ;;
    o) NOSOURCE=1; ;;
    p) UPLOADNOW=1 ; SIGN=1 ; POCKET=$OPTARG ;;
    z) export USE_LEGACY_COMPRESSION=1;
       ;;
    d) DELETENOW=1 ;;
    +?) echog "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
#    ?)  echog "$name: $OPTARG: bad option.  Use -h for help." 1>&2 ; exit 2;;
	?) OPTIND=$((OPTIND-1)); break;
    esac
done

## remove args that were options
if [ $# -gt 0 ]; then
	[ "$OPTIND" -gt 0 ] && shift $(($OPTIND - 1))
fi

LISTRPMARGS=$@

}

# Uses: FORCE, BASENAME, VERSION, RELEASE
# Arg: [pipe] args
__gear_create_tag()
{
	local GEARCTAG=gear-create-tag
	if [ "$1" = "pipe" ] ; then
		shift
		$GEARCTAG $FORCE -n "$VERSION-$RELEASE" -m "$BASENAME $VERSION-$RELEASE" "$@" 2>&1
	else
		docmd $GEARCTAG $FORCE -n "$VERSION-$RELEASE" -m "$BASENAME $VERSION-$RELEASE" "$@"
	fi
}

# check and create tag according to package release
# used: SPECDIR, LISTNAMES, FORCE
check_gear_and_tag()
{
	local RESULT=0

	# set SPECDIR from LISTNAMES if empty
	[ -n "$SPECDIR" ] || set_specdir $LISTNAMES

        # do check only on gear repo
	is_gear $SPECDIR || return 0

        if [ -z "$FORCE" ] && is_last_commit_tag ; then
                echo "Tag $(get_last_tag) already exists for the last commit"
                return 0
        fi

	# FIXME: uncomment use-agent in ~/.gnupg/gpg.conf, but with ssh access to build server I got
	#  gpg: problem with the agent - disabling agent use
	#  gpg: Invalid passphrase; please try again ...
	# needed correct user.name/user.email for get GPG id

	# gpg tries to use the agent but will fallback to the regular mode
	# if there is a problem connecting to the agent.
	# GPG_AGENT_INFO=

	[ -n "$FORCE" ] && echo "Force create tag..." || echo "Create tag..."

	cd $SPECDIR >/dev/null

	__gear_create_tag || RESULT=1
	if [ "$RESULT" = 1 ] ; then
		if __gear_create_tag pipe | grep -q "Too many specfiles found"; then
			__gear_create_tag -r .gear/$(readlink .gear/rules) && RESULT=0
		elif __gear_create_tag pipe | grep -q "already exists"; then
			is_last_commit_tag || fatal "Tag is set NOT on the last commit! Use -f key for override tag"
			RESULT=1
		fi
	fi
	local TAG=$(get_last_tag)
	test -z "$TAG" || is_last_commit_tag || fatal "Tag $TAG is not on the last commit"
	cd - >/dev/null
	echo "Tag $TAG is set"
	return $RESULT
}

# SRC.RPM DIR
extract_tarball_to_dest()
{
	local TDIR=$(mktemp -d || fatal "can't create tmp dir")
	cd $TDIR
		cat "$1" | rpm2cpio | cpio -i "*.tar*"
		local TARNAME=$(querypackage $1 "" "%{NAME}-%{VERSION}")
		# FIXME: hack to replace alt release to eter
		local TARGETTARNAME=$(querypackage $1 "" "%{NAME}-%{VERSION}-%{RELEASE}" | sed -e "s/-alt/-eter/g")
		erc --force conv $TARNAME*.tar* $2/$TARGETTARNAME.tar.bz2
		make_md5sum $2 $TARGETTARNAME.tar.bz2
		# copy other tarballs
		for i in $(ls -1 *.tar* | grep -v "^$TARNAME.*\.tar.*") ; do
			cp -fv $i $2/
			make_md5sum $2 $(basename $i)
		done
	cd -
	rm -f $TDIR/*
	rmdir $TDIR
}

rpmbs_copying_built()
{
	[ -n "$ETERDESTSRPM" ] || return 0
	echog "Moving package(s) in \$ETERDESTSRPM"
	if is_ssh_target "$ETERDESTSRPM" ; then
		docmd scp $LISTBUILT $ETERDESTSRPM && docmd rm -fv $LISTBUILT || echog "Error during copying"
	else
		mkdir -p $ETERDESTSRPM || echog "Error mkdir $ETERDESTSRPM"

		# Lav disable 06.12.2012: use umask instead
		#chmod ug+rw $LISTBUILT

		# Publish tarball if target dir is exist
		if [ -d "$ETERDESTSRPM/tarball" ] ; then
			echog "There is tarball dir exists. Extract tarball for other build system compatibility."
			for i in $LISTBUILT ; do
				extract_tarball_to_dest $i $ETERDESTSRPM/tarball
			done
		fi

		# Note: use cp for apply directory group (forced by sgid on dir)
		cp -fv $LISTBUILT $ETERDESTSRPM || echog "Error during copying"
		rm -f $LISTBUILT
		# FIXME: update only for published file
		#make_md5sum "$ETERDESTSRPM"
	fi
}

set_girar_host $1 && shift

parse_cmd_pre_spec "$@"
# quotes brokes option handling
mygetopts $LISTARGS

prepare_rpmdir

#############################
LISTBUILT=""
CURDIR=`pwd`

# FIXME: need we it later?
# set SPECDIR from LISTNAMES if empty
[ -n "$SPECDIR" ] || set_specdir $LISTNAMES

# see functions/alt:set_binaryrepo() for BINARYREPONAME
set_binaryrepo $MENV

if [ -n "$SIGNTAG" ] ; then
	for ln in $LISTNAMES ; do
		if set_usebranch ; then
			checkout_usebranch || fatal
		fi

		# check release
		build_rpms_name "$ln"
		pkg_release_check $RELEASE

		check_gear_and_tag

		checkout_original_branch
	done
	exit $?
fi

if [ -n "$NOSOURCE" ] ; then
	docmd $RPMBUILD -bs --nosource 0 $LISTNAMES
	exit $?
fi

# If we build from gear repo, run task
if [ -n "$UPLOADNOW" ] && is_gear $SPECDIR ; then

	# assure we have only specs or src.rpm
	LISTNAMES=$(repodirs_to_specs $LISTNAMES)

	if [ -n "$PREPARETASK" ] ; then
		if [ -z "$TASKNUMBER" ] ; then
			showcmd "ssh $GEARHOST task ls"
			TASKNUMBER="$(ssh $GEARHOST task ls | head -n1 | sed -e "s|^#\([0-9]*\) .*|\1|g")" || fatal
		# hack "
		fi
	else
			NUMSPECS=$(estrlist count $LISTNAMES)
		# if more then one spec, use common task
		if [ $NUMSPECS -gt 1 ] ; then
			PREPARETASK=internal
			# FIXME: no pocket support on git.eter task new?
			showcmd ssh $GEARHOST task new $BINARYREPO
			TASKNUMBER=$(ssh $GEARHOST task new $BINARYREPO | head -n1) || fatal
			[ -n "$TASKNUMBER" ] || fatal "Can't get task number from $GEARHOST"
		fi
	fi

	for ln in $LISTNAMES ; do
		# force SPECDIR
		set_specdir $ln

		[ -n "$VERBOSE" ] && echo "Run with gear repo in dir $SPECDIR..."

		echo "Prepare to publish to $GIRARHOST..."
		cd $SPECDIR || fatal

		if set_usebranch ; then
			checkout_usebranch || fatal
		fi

		# check release
		build_rpms_name "$ln"
		pkg_release_check $RELEASE

		PROJECTNAME=$(get_repo_name)

		if ! check_gear_and_tag ; then
			if [ "$PREPARETASK" = "internal" ] ; then
				docmd ssh $GEARHOST task rm $TASKNUMBER
			fi
			fatal "Can't make tag"
		fi

		TAG=$(get_last_tag)

		# TODO: add check for repo (as in rpmgp) and run ginit if needed
		docmd gpush $GIRARHOST $FORCE || fatal "gpush failed. It is possible you need run '\$ ginit $GIRARHOST' to create remote repo."
		echo
		echo "Run build $PROJECTNAME at $GEARHOST"
		# FIXME: tee hangup during first call with ssh ControlMaster
		if [ -n "$PREPARETASK" ] ; then
			showcmd "GIT_ALT=$GEARHOST girar-show $TASKNUMBER@"
			SUBTASK="$(GIT_ALT=$GEARHOST girar-show $TASKNUMBER@ | grep "/$PROJECTNAME.git" | sed -e "s|.*#\([0-9]*\) .*|\1|g")"
			# hack "
			if [ -n "$SUBTASK" ] && ! echo "$TASKNUMBER" | grep -q " " ; then
				info "$PROJECTNAME already in task as subtask $SUBTASK, replacing"
				docmd ssh $GEARHOST task delsub $TASKNUMBER $SUBTASK
				TASKNUMBER="$TASKNUMBER $SUBTASK"
			fi
			docmd ssh $GEARHOST task add $TASKNUMBER repo $PROJECTNAME $TAG 2>&1 | tee $RPMDIR/uploaded.log.tmp
		else
			docmd ssh $GEARHOST build $TESTONLY $(usearg -b $BINARYREPO sisyphus) $(usearg -p $POCKET) $PROJECTNAME $TAG 2>&1 | tee $RPMDIR/uploaded.log.tmp
		fi

		checkout_original_branch

		# FIXME: incorporate
		cat $RPMDIR/uploaded.log.tmp | grep task | head -n2 | tail -n1 >> $RPMDIR/uploaded.log
		echo "     run $TASKNUMBER task $PROJECTNAME with tag $TAG at $GEARHOST (in $BINARYREPO) at `date "+%c"`" >>$RPMDIR/uploaded.log
		rm -f $RPMDIR/uploaded.log.tmp
		cd - >/dev/null
	done

	if [ -n "$TASKNUMBER" ] ; then
		# TODO: separate TASKNUMBER and SUBTASKNUMBER
		RTASKNUMBER=$(echo "$TASKNUMBER" | sed -e "s| .*||g")
		showcmd "GIT_ALT=$GEARHOST girar-show $RTASKNUMBER@"
		GIT_ALT=$GEARHOST girar-show "$RTASKNUMBER@"
	fi

	# if more then one spec, use common task
	if [ "$PREPARETASK" = "internal" ] ; then
		docmd ssh $GEARHOST task run $TESTONLY $TASKNUMBER
	fi

	exit
fi

pack_src_rpm $LISTRPMARGS

if [ -n "${DELETENOW}" ]; then
	fatal "Removing did not realized yet"
fi

# if just packing
if [ -z "$SIGN" ]; then
	rpmbs_copying_built
	RET=$?
	checkout_original_branch
	exit $RET
fi

######## Sign src.rpm and upload it

# check package releases according to ALT
pkg_release_check $LISTBUILT

# if only one file
if [ -r "$LISTBUILT" ] ; then
	check_gear_and_tag
fi


echog "Will try to sign follow packages with GPG: \$LISTBUILT"
# 1. only rpm command has --addsign 2. do 3 retries
docmd rpm --addsign $LISTBUILT || docmd rpm --addsign $LISTBUILT || docmd rpm --addsign $LISTBUILT
RET=$?
if [ ! "$RET" = "0" ] ; then
	echog "Impossible to sign package. Check your password and try again."
	echog "Wait for ten seconds."
	sleep 10
	exit 1
fi


############################################
echog "Changing permissions..."
chmod 644 -- $LISTBUILT || fatal "can't chmod"

# TODO: check for ALT specific
# skip some checking for src.rpm if it is local upload
CHECK_OPTIONS=""
[ -n "${UPLOADNOW}" ] || CHECK_OPTIONS="--no-check=$HASHER_NOCHECK"

if [ -z "$NOCHECK" ] ; then
    docmd sisyphus_check $CHECK_OPTIONS --files $LISTBUILT || fatal "sisyphus check failed"
fi

# due rpm's find-req
RPMLINT=rpmlint
if which $RPMLINT &>/dev/null ; then
	echog -n "Checking with rpmlint..."
	echo
	$RPMLINT $LISTBUILT
#else
#	echog "It is recommended to install rpmlint package for additional checking"
fi

test -n "$CHECKONLY" && exit 0
############################################

# If upload signed package is not needed
if [ -z "${UPLOADNOW}" ] ; then
	rpmbs_copying_built
	exit $?
fi

echog "Uploading to $GIRARHOST"
check_ssh_key

docmd $RSYNC -vay --partial --progress --checksum \
 	-e ssh $LISTBUILT $GEARHOST: && \
echo "---------------------" && \
echog "All files synced" || fatal "Error during rsync"

TASKLIST=""
for i in $LISTBUILT ; do
	TASKLIST="$TASKLIST srpm $(basename $i)"
done
if [ -n "$PREPARETASK" ] ; then
	echo "Add $TASKLIST to task $TASKNUMBER"
	docmd ssh $GEARHOST task add $TASKNUMBER $TASKLIST 2>&1 | tee $RPMDIR/uploaded.log.tmp
else
	echo "Create task for $TASKLIST"
	docmd ssh $GEARHOST build $(usearg -b $BINARYREPO sisyphus) $TASKLIST 2>&1 | tee $RPMDIR/uploaded.log.tmp
fi

# FIXME: parse and incorporate
cat $RPMDIR/uploaded.log.tmp | grep task | head -n2 | tail -n1 >> $RPMDIR/uploaded.log

for i in $LISTBUILT ; do
	LOGFILE="$LOGDIR/`basename $i .src.rpm`$MENVARG.log"
	echo >>$LOGFILE
	date >>$LOGFILE
	echo "uploaded">>$LOGFILE
	TEXTADD="     run $TASKNUMBER build src.rpm"
	[ -z "$PREPARETASK" ] || TEXTADD="     add src.rpm to task $TASKNUMBER"
	echo "$(basename $i) $TEXTADD at $GIRARHOST ($BINARYREPO) at `date "+%c"`" >>$RPMDIR/uploaded.log
done

rm -f $RPMDIR/uploaded.log.tmp

echog "Removing buildroot after upload..."
for i in $LISTNAMES ; do
	if [ -z ${i/*.src.rpm/} ] ; then
		echo "  skipping for $i"
		continue
	fi
	# Hack about paths
	test -f "$i" && NAME=$i || NAME=$CURDIR/$i
	build_rpms_name $NAME
	if [ -d "$BUILDROOT" ] ; then
		docmd rm -rf "$BUILDROOT" && echog "DONE" || echog "failed"
	else
		echog "missed"
	fi
done

