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

# $1 - needed VERSION of etersoft-build-utils. f.i. 162

# add realpath if missed
if ! which realpath 2>/dev/null >/dev/null ; then
realpath()
{
        [ -n "$*" ] || return
        readlink -f "$@"
}
fi

if which csed 2>/dev/null >/dev/null ; then
colorify()
{
	csed '/(warning|WARNING|Warning|предупреждение):/ p magenta,bold' '/(error|ERROR|Error|ошибка):/ p red,bold' '/(Command not found):/ p red,bold'
}
else
colorify()
{
	cat
}
fi

print_message()
{
	local DESC="$1"
	shift
	if [ -z "$TEXTDOMAIN" ] ; then
		echo "$DESC in $(basename $0): $@" >&2
	else
		echog "$DESC in $(basename $0): $@" >&2
	fi
}

# Print error message and stop the program
fatal()
{
	SETCOLOR_FAILURE 2>/dev/null
	print_message Error "$@"
	SETCOLOR_NORMAL 2>/dev/null
	if [ -n "$ETERSOFT_FATAL_REMOVE_FILES" ] && [ -z "$DEBUG" ]; then
		rm -rvf $ETERSOFT_FATAL_REMOVE_FILES
	fi
	exit 1
}

# TODO: add onexit function

isatty()
{
	# check stdout
	test -t 1
}

isatty2()
{
	# check stderr
	test -t 2
}


# Just print warning message
warning()
{
	SETCOLOR_WARNING
	print_message Warning "$@"
	SETCOLOR_NORMAL
}

info()
{
	[ -n "$quiet" ] && return

	# print message to stderr if stderr forwarded to (a file)
	if isatty2 ; then
		isatty || return 0
		SETCOLOR_WARNING
		echo "$@"
		SETCOLOR_NORMAL
	else
		echo "$@" >&2
	fi
}


mark_file_to_remove()
{
	ETERSOFT_FATAL_REMOVE_FILES=$(estrlist union "$ETERSOFT_FATAL_REMOVE_FILES $@") || fatal
}

remove_file_from_remove()
{
	ETERSOFT_FATAL_REMOVE_FILES=$(estrlist exclude "$*" "$ETERSOFT_FATAL_REMOVE_FILES") || fatal
}

# copied from eepm (and modified)
store_output()
{
    # use make_temp_file from etersoft-build-utils
    RC_STDOUT=$(mktemp)
    mark_file_to_remove $RC_STDOUT
    #RC_STDERR=$(mktemp)
    "$@" 2>&1 | tee $RC_STDOUT
    # http://tldp.org/LDP/abs/html/bashver3.html#PIPEFAILREF
    return $PIPESTATUS
}

# TODO: realize onexit handler (see before) and drop out this clean from use
clean_store_output()
{
    rm -f $RC_STDOUT
}
# end of copied from eepm


set_eterbuilddir()
{
	[ -z "$ETERBUILDDIR" ] || return 0

	if dirname $0 | grep "^/usr" >/dev/null ; then
		ETERBUILDETC=/etc/eterbuild
		ETERBUILDDIR=/usr/share/eterbuild
	else
		# if run from no system installation
		# TODO: use real root dir not script dirname
		[ -n "$TOPDIR" ] || TOPDIR=../
		ATOPDIR=`dirname $0`/$TOPDIR
		ETERBUILDDIR=$(realpath $ATOPDIR/share/eterbuild)
		ETERBUILDETC=$(realpath $ATOPDIR/etc)
		if [ -r "$ETERBUILDETC/../AUTHORS" ] ; then
			if [ -n "$VERBOSE" ] ; then
				echo "Note: run from source tree, datadir=$ETERBUILDDIR, sysconfdir=$ETERBUILDETC"
			fi
		else
			warning "Cannot find source tree root in source tree mode"
			ETERBUILDETC=/etc/eterbuild
			ETERBUILDDIR=/usr/share/eterbuild
		fi
	fi
	ETERBUILDBIN=$(realpath $ETERBUILDDIR/../../bin)
	[ -d "$ETERBUILDDIR" ] && [ -d "$ETERBUILDBIN" ] && PATH=$ETERBUILDDIR/functions/commands:$PATH
	# returns test result
}

# check for needed commands
#for i in distr_vendor realpath ; do
#	which $i >/dev/null || fatal
#done

# set if empty and check it
if ! set_eterbuilddir ; then
	echo "Can't detect package files location" >&2
	exit 1
fi

# lines before do the same as
# assert_var ETERBUILDBIN

#DISTRVENDOR=$(realpath $ETERBUILDBIN/../../rpm-build-altlinux-compat/bin/distr_vendor 2>/dev/null)
DISTRVENDOR=$(realpath $ETERBUILDBIN/../../distro_info/bin/distro_info 2>/dev/null)
[ -x "$DISTRVENDOR" ] || DISTRVENDOR=distro_info
which $DISTRVENDOR >/dev/null 2>/dev/null || DISTRVENDOR=distr_info

EPMCMD=$(realpath $ETERBUILDBIN/../../eepm/bin/epm 2>/dev/null)
[ -x "$EPMCMD" ] || EPMCMD=epm

ERCCMD=$(realpath $ETERBUILDBIN/../../erc/bin/erc 2>/dev/null)
[ -x "$ERCCMD" ] || ERCCMD=erc

print_list()
{
	local i
	for i in $@ ; do
		echo "    $i"
	done
}


# Function debug_print_var()
# show at point of call name of function that called her
# and show list values of variables, defined in parameters.
#
# Difference between function assert_var() -
# assert_var() call fatal() if variable not defined.

debug_print_var()
{
	local i re

	echo
	echo "==================================================="
	echo "Into function : ${FUNCNAME[1]}"
	echo
	echo "Watch of variables :"
	echo "------------------------------------------"
	
	for i in $@
	do
		re=$(eval echo \$$i)
		if [ -n "$re" ]
		then
			echo "    ${i} = ${re}"
		else
			echo "Variable ${i} NOT DEFINED !!!"
		fi
	done

	echo "------------------------------------------"
	echo "==================================================="
}


# Function debug_print_backtrace() show all functions
# (call stack of functions),
# that called before this funcions (callback list)

debug_print_backtrace()
{
	echo
	echo "==================================================="
	echo "Into function : ${FUNCNAME[1]}"
    
	local i=1
	while [ -n "${FUNCNAME[i]}" ]
	do
		echo "        Callback N${i} : ${FUNCNAME[i]} : ${BASH_SOURCE[i]}"
		let "i+=1"
	done   
    
	echo "==================================================="
}


# Function assert_var() also show callstack, if assert variable is empty.

assert_var()
{
	local i re
	
	for i in $@ ; do
		re=$(eval echo \$$i)
		if [ -z "$re" ]
		then
			debug_print_backtrace
			fatal "assert: $i nonexist"
# FIXME :
# Strange behavior with echo
# (may be erase etersoft-build-utils/bin catalog)
# (also may be error in korinf, stage "convert src.rpm to target gentoo ..."
#  or "assure build requires ...")
#
#		else
#			echo "   ${i} = ${re}"

		fi
	done
}


prepare_rpmdir()
{
	assert_var RPMTOPDIR LOGDIR
	mkdir -p $(realpath $RPMDIR)
	mkdir -p $(realpath $RPMTOPDIR)
	mkdir -p "$LOGDIR"
	mkdir -p "$RPMTOPDIR/RPMS"
	test -L "$RPMTOPDIR/tmp" || ln -s $RPMTMPDIR $RPMTOPDIR/tmp
}

get_root_git_dir()
{
        local DIR=
        local LOCDIR="$1"

        if [ -n "$LOCDIR" ] ; then
            cd "$LOCDIR" || fatal "Only dir arg allowed for get_root_git_dir"
        fi

        DIR=$(git rev-parse --git-dir 2>/dev/null)/../ || DIR=
        realpath "$DIR" 2>/dev/null

        if [ -n "$LOCDIR" ] ; then
            cd - >/dev/null
        fi

        # FIXME: 1) can return / with good status 2) no one check status later
}

# Usage: is_gear [path_to_spec|dir_inside_git]
is_gear()
{
	get_gear_rules $@ >/dev/null
}

get_packager()
{
	local packager="$($RPMBUILD --eval "%packager" "$1" 2>/dev/null)"
	rhas "$packager" "%packager" && fatal "Packager $packager is not defined correctly in spec $1 or in ~/.rpmmacros"
	echo "$packager"
}


if [ "$UID" = "0" ] && [ -z "$ALLOW_ROOT_USER" ] ; then
	fatal "It is strict recommended do not use these scripts as root"
fi

load_mod()
{
	local i
	for i in $@ ; do
		. $ETERBUILDDIR/functions/$i
	done
}

load_mod config gettext alt spec gear strings outformat


# check for needed version
if [ -n "$NEEDETERBUILD" ] ; then
	if [ "$NEEDETERBUILD" -gt "$ETERBUILDVERSION" ] ; then
		echo "Obsoleted version $ETERBUILDVERSION of etersoft-build-utils version is used. Please upgrade it to $NEEDETERBUILD version."
		exit 1
	fi
fi

set_gear_host


# Used DISTRNAME
set_target_pkg_env()
{
	assert_var DISTRNAME
	[ "$($DISTRVENDOR -V)" -ge "20120519" ] || fatal "update rpm-build-altlinux-compat package to get new $DISTRVENDOR command"
	PKGFORMAT=$($DISTRVENDOR -p "$DISTRNAME")
	PKGVENDOR=$($DISTRVENDOR -s "$DISTRNAME")
	RPMVENDOR=$($DISTRVENDOR -n "$DISTRNAME")
	[ -n "$MENV" ] || MENV="$(get_altdistr_mod "$DISTRVERSION")"
	assert_var MENV
}

# We believe that follow vars correctly in any way:
#  DISTRNAME - f.i. ALTLinux
#  DISTRVERSION - f.i. p6
#  BUILDARCH - f.i. x86_64 (set in config)

# Filled with set_target_pkg_env:
#  PKGFORMAT (was TARGET) - f.i. rpm
#  use DISTRNAME if possible instead follow
#   PKGVENDOR (was VENDOR) - like in package name release, f.i. alt
#   RPMVENDOR - like %_vendor in spec, f.i. alt

# Internal
# Detect distro name / vendor according to ROOTDIR system or current system
# You can set DISTRNAME, DISTRVERSION, BUILDARCH externally
detect_target_env()
{
MENVARG=""
[ -n "$DISTRNAME" ] || DISTRNAME=$($DISTRVENDOR -d)
[ -n "$DISTRVERSION" ] || DISTRVERSION=$($DISTRVENDOR -v)
[ -n "$DISTRVERSION" ] || fatal "can't get distro version from $DISTRVENDOR, write lav@etersoft.ru"
set_target_pkg_env

if [ "$PKGVENDOR" = "alt" ] && [ -n "$MENV" ] ; then
	#[ -n "$APTCONF" ] && fatal "Internal error: APTCONF already defined as $APTCONF for $MENV"
	APTCONF=${APTCONFBASE/.SS}.$MENV
	[ "$MENV" = "SS" ] && [ ! -r "$APTCONF" ] && APTCONF=${APTCONFBASE/.SS}
	
	[ -n "$VERBOSE" ] && echog "Target ALT Linux system: `get_altdistr_version $MENV`, use \$APTCONF"
	MENVARG="-$MENV"
else
	# FIXME: echog breaks vars
	echog "Distribution: \$DISTRNAME/\$DISTRVERSION (\$PKGVENDOR) (target package: \$PKGFORMAT)"
fi
}

# Отделяет файлы в LISTNAMES (с полными путями)
# Отделяет указание среды в MENV
# Устанавливает LISTARGS в оставшиеся аргументы
# использование:
# - отделяем среду (MENV)
# - отделяем файлы
# - оставшееся обрабатываем как параметры программы
parse_cmd_pre()
{
local i
if [ $# -lt 1 ]; then
    [ -n "$Usage" ] && echog "$Usage"
	fatal "Use -h for help."
fi

[ "$1" = "--help" ] && mygetopts -h

if is_gear ; then
	# Set target according to current branch
	set_target_type $(get_type_by_current_branch)
fi

LISTNAMES=
LISTARGS=
OPTINDEX=1
for i in "$@"
do
	# Если файл или каталог существует, то добавляем, иначе считаем аргумент параметром.
	if [ -e "$i" ]; then
		# echo is workaround for missed readlink
		LISTNAMES="$LISTNAMES $(realpath "$i" 2>/dev/null || echo "$i")"
	else
		# set target type if -M?? in param
		set_target_type ${i/-/} || LISTARGS="$LISTARGS $i"
	fi
done
LISTNAMES=$(estrlist strip_spaces "$LISTNAMES")
LISTARGS=$(estrlist strip_spaces "$LISTARGS")
[ -n "$VERBOSE" ] && echo "LISTNAMES=$LISTNAMES LISTARGS=$LISTARGS" || :
}

parse_cmd_pre_spec()
{
	[ "$1" = "--help" ] && mygetopts -h

	# hack for check spec or src.rpm presence in command line: skip spec detecting
	if rhas "$*" "\.(spec|src\.rpm)" ; then
		parse_cmd_pre "$@"
        else
		local SPEC=$(get_gear_spec)
		[ -f "$SPEC" ] && info "Using autodetected spec $SPEC ..."
		# it is possible in some command we need only possibility for spec
		# || fatal "Run in dir with spec or in gear repo"
		parse_cmd_pre "$SPEC" "$@"
	fi
}

check_ssh_key()
{
	echog "Check access to SSH private key..."
	ssh-add -l || ssh-add $SSH_KEYFILE || return 1
	return 0
}

# for backward compatibility
check_key()
{
	check_ssh_key
}

get_ext()
{
	# first check if it is archive
	$ERCCMD type "$1" && return
	# default code, it broken sequenced extensions (like .tar.gz)
	rhas "$1" "\." && echo "$1" | sed -e "s|.*\.||" | grep -v "/"
}

make_temp_file()
{
	# Workaround about broken mktemp
	if mktemp -V >/dev/null 2>/dev/null ; then
		mktemp || exit 1
	else
		mktemp /tmp/$1.XXXXXX || exit 1
	fi
}

cd_to_realcwd()
{
	cd "$(realpath "$(pwd)" )"
}

# check if path is server:/path
is_ssh_target()
{
	rhas "$1" ":"
}

try_enable_ccache()
{
	if [ -n "$CCACHE_DISABLE" ] ; then
		info "ccache disabled by CCACHE_DISABLE var"
		return
	fi

	if ! which ccache >/dev/null ; then
		info "No ccache (from ccache package)"
		return
	fi

	# TODO: add support for clang
	# TODO: check for work with scan-build (clang-analizer)
	# handled in gcc-common
	export GCC_USE_CCACHE=1

	if [ -n "$CXX$CC" ] ; then
		info "CXX=$CXX CC=$CC already exists, skip setting"
		return
	fi

	if rhas "$*" "C[CX].?=" ; then
		info "ran with CXX= or CC= in args '$*', skip setting"
		return
	fi

	# step to gcc-common
	export CC=gcc CXX=g++
}


# If DISPLAY is broken
check_display()
{
	local XSET=$(which xset 2>/dev/null)
	[ -n "$XSET" ] || return
	$XSET -b
}

# Print command line only
showcmd()
{
	local i
	SETCOLOR_SUCCESS
	echo -n " \$"
	for i in "$@" ; do
		# hack against echo -n -n
		[ "$i" = "-n" ] && echo -n " -n" && continue
		# print with qoutes if args have spaces
		echo -n " "
		echo -n "$i" | sed -e "s|\(.* .*\)|'\1'|g"
	done
	echo
	SETCOLOR_NORMAL

}

# Print command line and run command line
docmd()
{
	showcmd "$@"
	"$@"
}


# Example:
# $ command $(usearg -d "$PARAM")
#  will add -d "$PARAM" if $PARAM is not empty
# $ command $(usearg -d "$PARAM" "empty-word)
# will add -d "$PARAM" if $PARAM is not 'empty-word'
usearg()
{
        local ARG=$1
        shift

        [ "$1" != "$2" ] && echo "$ARG $1"
}

# return 0 if arg1 >= arg2
version_more_version()
{
	[ "$2" = "$(echo -e "$1\n$2" | sort -n | head -n1)" ]
}

HELP_GIRAR="   GIRAR - git.alt (ga, galt) or git.eter (ge, geter)"
