#!/bin/bash
# 2006-2008 Etersoft www.etersoft.ru
# Author: Vitaly Lipatov <lav@etersoft.ru>
# Public domain

load_mod gear

get_var()
{
	grep -i "^$1:" | head -n 1 | sed -e "s/^[^:]*[ \t]*:[ \t]*//"

}

# TODO: create temp spec, not just output: it masks specs problem now
# FIXME: only ALT handled rpm -bE
# Раскрывает макросы в спеке и выводит на стандартный вывод
eval_spec()
{
	# TODO: use rpm -showrc instead -bE for get main variables?
	local SPECNAME=$1

	# Drop changelog and make spec copy
	# see http://bugs.etersoft.ru/show_bug.cgi?id=6588
	mark_file_to_remove $SPECNAME.tmp $SPECNAME.changelog
	separate_changelog $SPECNAME $SPECNAME.tmp $SPECNAME.changelog
	SPEC=$SPECNAME.tmp

	USEARCH=
	# FIXME: rpm on 64bit ALT has no macros for ix86 arch
	# use i586 if ExclusiveArch is %{ix86}
	#[ "$SYSARCH" = "x86_64" ] && grep "^ExclusiveArch:" $SPEC | grep -q "ix86" && USEARCH=i586

	# Hack for allow repack on x86_64 packages with ExclusiveArch: %{ix586}
	# See https://bugs.etersoft.ru/show_bug.cgi?id=8394
	[ "$SYSARCH" = "x86_64" ] && subst "s|^ExclusiveArch:.*||g" $SPEC

	# Hack: just print spec if -bE failed
	if is_alt ; then
		# on ALT we have to done without errors
		$USEARCH $RPMBUILD -bE --target $SYSARCH $RPMBUILDARG $SPEC || fatal "Check spec's fields"
	else
		$USEARCH $RPMBUILD -bE --target $SYSARCH $RPMBUILDARG $SPEC 2>/dev/null || cat $SPEC
	fi | iconv -f utf8 -r
	# FIXME: hack for koi8-r in spec (grep will not work with it)
	[ -n "$DEBUG" ] || rm -f $SPECNAME.tmp $SPECNAME.changelog
	remove_file_from_remove $SPECNAME.tmp $SPECNAME.changelog
}

get_release()
{
	eval_spec $1 | get_var "Release"
}

# TODO: fix description
# get 11 from alt11, 12.1 from alt12.1t
get_numpartrelease()
{
	echo "$1" | perl -pe "s|([a-zA-Z]+)([0-9]+)[^0-9].*|\2|" || echo "0"
}

# get 11 from alt11, 12.1 from alt12.1t
get_numrelease()
{
	get_release "$1" | sed -e "s|\([a-zA-Z]*\)\([0-9\.]\)[^0-9\.]*|\2|" || echo "0"
}

get_default_txtrelease()
{
	# assert GITHOST
	# TODO: check for git.alt in ~/.ssh/config?
	echo ${GITHOST/git./}
}

# get alt from alt11
# TODO: support alt1.eter2
# TODO: change to use mask gggNNN gggNNN.NNN gggNNN.NNNggg gggNNN.eeee.MMMM.ffff
get_txtrelease()
{
	# TODO: txtrelease is all exclude num part
	get_release "$1" | sed -e "s|\([a-zA-Z]*\)\([0-9\.]\).*|\1|" || get_default_txtrelease
}

set_var()
{
	subst "0,/^$2:/s/^\($2:\)\([[:space:]]*\).*\$/\1\2$3/" $1
	#subst "s|^\($2:\).*\$|\1 $3|q" $1
}

# Args: spec, new_release
# set release to arg2 or reset numeration if arg2 is empty
set_release()
{
	local RELEASE=$2
	[ -n "$RELEASE" ] || RELEASE="$(get_txtrelease $1)1"
	set_var $1 Release $RELEASE
}

# Args: spec, new_release
# Set release to arg2 or to the default start value if arg2 is empty
reset_release()
{
	local RELEASE=$2
	[ -n "$RELEASE" ] || RELEASE="$(get_default_txtrelease)1"
	set_var $1 Release $RELEASE
}

# inc 2 release to 3
# textMAJOR.middle.MINOR
inc_release()
{
	local BASERELEASE=$(get_numrelease "$1")
	local MAJOR=`echo "$BASERELEASE" | sed -e "s|\..*||"`
	local MINOR=`echo "$BASERELEASE" | sed -e "s|.*\.||"`
	local m=$(echo "$BASERELEASE" | sed -e "s|$MAJOR\.\(.*\)\.$MINOR|\1|")
	[ "$m" = "$BASERELEASE" ] && m=''
	local am=''
	# keep minor part
	[ -z "$m" ] && rhas "$MINOR" "[a-zA-Z]" && am=".$MINOR"
	# keep middle part
	[ -n "$m" ] && am=".$m"
	set_release "$1" "$(get_txtrelease "$1")$(($MAJOR + 1 ))$am"
}

# inc 2.x to 2.(x+1) or 2 to 2.1
# textMAJOR.middle.MINOR
inc_subrelease()
{
	local BASERELEASE=$(get_numrelease $1)
	local MAJOR=`echo "$BASERELEASE" | sed -e "s|\..*||"`
	local MINOR=`echo "$BASERELEASE" | sed -e "s|.*\.||"`
	[ "$MINOR" = "$BASERELEASE" ] && MINOR="0"
	local m=$(echo "$BASERELEASE" | sed -e "s|$MAJOR\.\(.*\)\.$MINOR|\1|")
	local am=''
	# keep minor part
	rhas "$MINOR" "[a-zA-Z]" && am=".$MINOR" && MINOR="0"
	# keep middle part
	[ -n "$m" ] && [ "$m" != "$BASERELEASE" ] && am=".$m"
	set_release "$1" "$(get_txtrelease $1)${MAJOR}$am.$(($MINOR + 1 ))"
}

reset_subrelease()
{
	local BASERELEASE=$(get_numrelease $1)
	local MAJOR=`echo "$BASERELEASE" | sed -e "s|\..*||"`
	local MINOR=`echo "$BASERELEASE" | sed -e "s|.*\.||"`
	MINOR="0"
	set_release "$1" "$(get_txtrelease $1)${MAJOR}.$(($MINOR + 1 ))"
}

get_name()
{
	eval_spec $1 | get_var "Name"
}

get_version()
{
	eval_spec $1 | get_var "Version"
}

# Args: specname, source_number
get_tarballname()
{
	local SOURCE=$(eval_spec "$1" | get_var "Source$2")
	[ -n "$SOURCE" ] || SOURCE=$(eval_spec "$1" | get_var "Source0")
	[ -n "$SOURCE" ] || fatal "Can't grep Source$2 from spec $1"
	basename $(basename "$SOURCE" | sed -e "s|-$(get_version "$1").*||g") .tar
}


# Set version for spec (args: spec version), f.i. test.spec 1.2.3)
# Supports %major and %ver_major macros in spec
# версия может быть указана как 2.6.1 (полная), 2.6 (major) или .1 (minor)
set_version()
{
	local SPEC=$1
	local VER=$2

	if [ -z "$SPEC" ] ; then
		return 1
	fi

	if [ -z "$VER" ] ; then
		return 2
	fi

	VERMAJOR=`echo $VER | sed -e "s|\([0-9]*\.[0-9]*\)\..*|\1|"`
	VERMINOR=`echo $VER | sed -e "s|^[0-9]*\.[0-9]*||;s|^\.||"`
	if [ -z ${VER/.*/} ] ; then
		VERMAJOR=
	fi

	MAJORMACROS=`grep "\%define[[:space:]]\(\|ver_\)major" $SPEC | sed -e "s|.*[[:space:]]\(.*major\).*|\1|"`
	if [ -n "${MAJORMACROS}" ] ; then
		# Change major define
		test -n "$VERMAJOR" && subst "s|\(\%define[[:space:]]$MAJORMACROS[[:space:]]\).*|\1$VERMAJOR|" $SPEC
		# Change version if VERMINOR is defined
		if [ -n "$VERMINOR" ] ; then
			set_var $SPEC Version %$MAJORMACROS.$VERMINOR || fatal "Error 1 with set version to spec"
		else
			set_var $SPEC Version %$MAJORMACROS || fatal "Error 2 with set version to spec"
		fi
	else
		set_var $SPEC Version $VER || fatal "Error 3 with set version to spec"
	fi
}

inc_version()
{
	local VER=$(get_version "$1")
	# fixme: more general and use in other functions (see increment_release test)
	local MAJOR=`echo "$VER" | sed -e "s|\.[0-9]*$||"`
	local MINOR=`echo "$VER" | sed -e "s|.*\.||"`
	[ "$MINOR" = "$VER" ] && MINOR="0"
	VER="${MAJOR}.$(($MINOR + 1 ))"
	set_version "$1" $VER
}

# decrement release with workaround about non textual release
decrement_release()
{
	local NUMPART=$(echo $1 | sed -e "s|[^0-9].*||g")
	[ -n "$NUMPART" ] || NUMPART=1
	[ "$NUMPART" = "0" ] && NUMPART=1
	echo $(($NUMPART - 1))
}

subst_namever()
{
	sed -e "s|%{name}|$BASENAME|g
			s|%{version}|$VERSION|g
			s|%name|$BASENAME|g
			s|%version|$VERSION|g"
}


# args: "desc text" <spec(s)>
add_changelog_helper()
{
	# it is permitted to run with "" DESC
	local DESC="$1"
	shift
	local SPECS="$*"
	if ! tty -s && [ -z "$DESC" ] ; then
		echo "skip changelog fixing without tty and without desc"
		return 1
	fi
	[ -z "$SPECS" ] && fatal "run add_changelog without spec(s)"
	LANG=C add_changelog -e "$DESC" $SPECS
	R=$?

	[ -n "$QUIET" ] && return
	[ -z "$EDITOR" ] && { echo "skip changelog editing without EDITOR var"; return 0 ; }

	# If changelog sucessfully added, let us to edit
	if [ "$R" = "0" ]; then
		local SPEC
		for SPEC in $SPECS ; do
			N=`grep --text -n '^%changelog' $SPEC | head -n 1 | sed s!:.*!!g`
			# +1 -- comment with date and packager name
			# +2 -- place for edit comments
			# +N works for mcedit and vi
			${EDITOR} +$(($N + 2)) $SPEC
		done
	fi
	return $R
}


# set specdir by spec (run with full path to spec only or in spec dir)
set_specdir()
{
	# support for use git dir instead spec
	if [ -d "$1" ] ; then
		SPECDIR="$1"
		return 0
	fi

	SPECDIR=.
	# get dir from the first spec
	if [ -r "$1" ] ; then
		SPECDIR=`dirname $1`
	fi
	# if spec has no full path, guess from pwd
	if [ "$SPECDIR" = "." ] ; then
		SPECDIR=`pwd`
	fi
	[ -d "$SPECDIR" ]
}

# internal func
get_gear_rule_spec()
{
	local rules=$(get_gear_rules $@)
	[ -r "$rules" ] || return
	local SPEC="$(grep "^spec:" $rules 2>/dev/null | sed -e "s/spec:[ 	]*//g")"
	test -r "$(get_root_git_dir $@)/$SPEC" && echo $(get_root_git_dir $@)/$SPEC
}

# search for gear spec
get_gear_spec()
{
        local trySpec
        trySpec=$(get_gear_rule_spec $@)
        # check spec in git root dir (by default)
        [ -f "$trySpec" ] || trySpec=`echo $(get_root_git_dir $@)/*.spec` || return
        # check locally only if in gear repo
        #is_gear && trySpec=$(echo *.spec)
        # printout nothing if can't get spec
        [ -f "$trySpec" ] || trySpec=""
        echo $trySpec
        test -f "$trySpec"
}

# transform dir to spec if it is dir
repodirs_to_specs()
{
        local i
        for i in "$@" ; do
            if [ -d "$i" ] ; then
                i=$(get_gear_spec "$i") || continue
            fi
            echo "$i"
        done
}

separate_changelog()
{
	local SPEC="$1"
	[ "$SPEC" != "$2" ] && [ "$SPEC" != "$3" ] || fatal "separate_changelog: cannot write to itself"
	cat $SPEC | awk 'BEGIN{desk=0}{if (desk==0) {print}; if(/^%changelog/&&desk==0){desk++}}' > "$2"
	cat $SPEC | awk 'BEGIN{desk=0}{if (desk==1) {print}; if(/^%changelog/&&desk==0){desk++}}' > "$3"
}

# TODO: do standalone command, see ~/Projects/git-eter/fixbashisms
# for rpm + (d)ash
# http://mywiki.wooledge.org/Bashism
remove_bashism()
{
	local SPECNAME="$1"
	test -w "$SPECNAME" || fatal "File '$SPECNAME' is missed or read only"

	separate_changelog $SPECNAME $SPECNAME.main $SPECNAME.changelog

	subst "s|^pushd \(.*\)|cd \1 >/dev/null|g" $SPECNAME.main
	subst "s|^popd|cd - >/dev/null|g" $SPECNAME.main
	subst "s|^echo -e '\\\n'|echo ''|g" $SPECNAME.main

	# {1,2} translation
	# FIXME: miss first spaces
	while read -r n ; do
		echo "$n" | grep -v "{.*,.*}" && continue
		rs="$(echo "$n" | perl -pe "s|.*\s(.*?{.*?}.*?)\s.*|\1|g" )"
		res=$(eval echo "$rs")
		echo "$n" | perl -pe "s|$rs|$res|g"
	done < $SPECNAME.main >$SPECNAME.tmp
	[ -s "$SPECNAME.tmp" ] && mv -f $SPECNAME.tmp $SPECNAME
	checkbashisms $SPECNAME
	cat $SPECNAME.changelog >>$SPECNAME
	rm -f $SPECNAME.main $SPECNAME.changelog
}

