#! /bin/sh -e

export LC_ALL=C
export LC_ALL=C
verbose=
OPTIONS=
LONGOPTIONS=
REPOSITORY_BRANCH="sisyphus"
# alt system gits
git_default_url=git://git.altlinux.org
# alt system web shared tasks
web_default_tasks_url=http://git.altlinux.org
WEBERY_HOST=
WEB_TASKS_URL=
# alt personal gits
gitery_default_url=git://gitery.altlinux.org
gitery_default_host=
GITERY_HOST=
GIRAR_HOST=
DRY_RUN=
TASK_SHARE=
task_deps=
TASK_RUN_HURRY=
TASK_RUN_UNHURRY=
TASK_RUN_TEST_ONLY=
TASK_RUN_FAIL_LATE=
girar_message=
FROM_REPO=
#TARGET_REPO -> REPOSITORY_BRANCH
TASKS_MOUNT_POINT=

for config_file in /etc/girar-nmu/default ${XDG_CONFIG_HOME:-$HOME/.config}/girar-nmu/default; do
    ! [ -e "$config_file" ] || . "$config_file"
done
# --- autodetection in absence of config file ---
if [ -z "$gitery_default_host" ]; then
    if grep -E '^Host[[:space:]]+gitery[[:space:]]*$' ~/.ssh/config >/dev/null; then
	gitery_default_host=gitery
    elif grep -E '^Host[[:space:]]+git.alt[[:space:]]*$' ~/.ssh/config >/dev/null; then
	gitery_default_host=git.alt
    else
	gitery_default_host=gitery
    fi
fi
if [ -z "$GIRAR_HOST" ]; then
    if grep -E '^Host[[:space:]]+girar[[:space:]]*$' ~/.ssh/config >/dev/null; then
	GIRAR_HOST=girar
    elif grep -E '^Host[[:space:]]+gyle[[:space:]]*$' ~/.ssh/config >/dev/null; then
	GIRAR_HOST=gyle
    elif grep -E '^Host[[:space:]]+gyle.alt[[:space:]]*$' ~/.ssh/config >/dev/null; then
	GIRAR_HOST=gyle.alt
    elif grep -E '^Host[[:space:]]+sborochnitsa[[:space:]]*$' ~/.ssh/config >/dev/null; then
	GIRAR_HOST=sborochnitsa
    else
	GIRAR_HOST=girar
    fi
fi
# --- end autodetection ---------------------------

OPTIONS=SD:m:O
LONGOPTIONS=,deps:,share,no-share,fail-early,fail-late,hurry,no-hurry,unhurry,no-test-only,test-only,message:,gm:,gyle-message:,girar-message:,from-repo:
# not compatible with set -e
#getopt --test > /dev/null; #if [ "$?" -ne 4 ]; then
if getopt --test > /dev/null; then
    echo "Oops! `getopt --test` not failed. Bad getopt!." >&2
    exit 1
fi
__OPTS=hqVvb:H:P:R:
__LONGOPTS=dry-run,help,quiet,verbose,version,branch:,girar:,gyle:,gitery:,git.alt:,profile:,webery:,web_tasks_url:
PARSED=$(getopt --options=$__OPTS$OPTIONS --longoptions=$__LONGOPTS$LONGOPTIONS --name "$0" -- "$@")
if [ "$?" -ne 0 ]; then
    exit 2
fi
eval set -- "$PARSED"

while true; do
    case "$1" in
        --from-repo)
	    FROM_REPO="$2"
	    shift 2;
	    ;;
        --tasks-root|--tasks-mount-point)
	    TASKS_MOUNT_POINT="$2"
	    shift 2;
	    ;;
	-D|--deps) task_deps="$2"
            shift 2 ;;
	--no-share) TASK_SHARE=
            shift ;;
	-S|--share) TASK_SHARE=1
            shift ;;

	--gm|--girar-message|gyle-message) girar_message="$2"
	    girar_message=${girar_message// /_}
            shift 2 ;;
	-m|--message) girar_message="$2"
	    echo "WARINING: option -m (--message) is ambiguous. Assuming --girar-message">&2;
	    echo "Please, use --gm (--girar-message), --cm (--commit-message), --tm (--tag-message).">&2
	    girar_message=${girar_message// /_}
	    shift 2 ;;
	--test-only) TASK_RUN_TEST_ONLY=--test-only
            shift ;;
	-O|--no-test-only) TASK_RUN_TEST_ONLY=
            shift ;;
	--fail-late) TASK_RUN_FAIL_LATE=1
            shift ;;
	--fail-early) TASK_RUN_FAIL_LATE=
            shift ;;
	--no-hurry) TASK_RUN_HURRY=
            shift ;;
	--unhurry) TASK_RUN_UNHURRY=1
		TASK_RUN_HURRY=
            shift ;;
	--hurry) TASK_RUN_HURRY=1
		TASK_RUN_UNHURRY=
            shift ;;
	-P|--profile)
	    local profile_file="$2"
	    for config_file in /etc/girar-nmu/"$profile_file" ${XDG_CONFIG_HOME:-$HOME/.config}/girar-nmu/"$profile_file"; do
		! [ -e "$config_file" ] || . "$config_file"
	    done
            shift 2 ;;
        -q|--quiet)
            verbose=
            shift ;;
        -V|--version)
            echo "2.015.2"
	    exit 0
            shift ;;
        -v|--verbose)
            verbose=$(($verbose+1))
            shift ;;
	-h|--help)
	    pod2usage --exit=0 "$0";
	    exit 0 ;;
	-b|--branch)
	    REPOSITORY_BRANCH="$2"
	    readonly REPOSITORY_BRANCH
            shift 2 ;;
	-H|--gitery|--git.alt)
	    GITERY_HOST="$2"
	    readonly GITERY_HOST
            shift 2 ;;
	-R|--girar|--gyle)
	    GIRAR_HOST="$2"
	    readonly GIRAR_HOST
            shift 2 ;;
	-W|--webery)
	    WEBERY_HOST="$2"
	    readonly WEBERY_HOST
            shift 2 ;;
	--web-tasks-url)
	    WEB_TASKS_URL="$2"
	    readonly WEB_TASKS_URL
            shift 2 ;;
        --dry-run)
            DRY_RUN=echo
            shift ;;
        --)
            shift
            break
            ;;
        *)
	    echo "Internal error: Unexpected option: $1 $2" >&2
	    #pod2usage --exit=3 "$0"
            exit 3
            ;;
    esac
done

TASK="$1"
if [ -z "$1" ] || [ "$1" -le 0 ]; then
    echo "Not enough arguments. Provide task number in first argument."
    exit 1
fi

abort() {
    if [ $# > 0 ]; then
        echo $1 >&2
    fi
    exit ${2-1}
}

shift 2 && abort "Too many parameters" ||:

tmpdir=
atexit()
{
    err="${1:-0}"; shift ||:
    [ -z "$tmpdir" ] || rm -rf -- "$tmpdir"
    if { [ "$err" -ne 0 ] || [ -z "${ANY_ACTION-}" ] ;} && [ -n "${NEW_TASK-}" ]
    then
        # echo ssh "$GIRAR_HOST" task rm "$NEW_TASK"
        ssh "$GIRAR_HOST" task rm "$NEW_TASK"
    fi
    [ "$err" -eq 0 ] || echo ErrorExit "$err" >&2
    exit "$err"
}

tmpdir=$(mktemp -dt "${0##*/}.XXXXXXXX")
trap 'atexit $?' EXIT
trap 'exit 143' HUP INT QUIT PIPE TERM

if ! [ -d "$TASKS_MOUNT_POINT/tasks/index" ]; then
    echo "FATAL: $TASKS_MOUNT_POINT/tasks/index not found."
    echo
    echo "This script requires filesystem access to girar tasks."
    echo "For the filesystem access to the default(sisyphus) girar tasks"
    echo "you should have an account on team.alt."
    echo
    echo "Please, eather run this script on team.alt"
    echo "or mount /tasks from team.alt using sshfs"
    echo "and use --tasks-mount-point=/path/to/tasks option."
    exit 1
fi

[ 0"$verbose" -ge 3 ] && set -x ||:

if [ -z "$FROM_REPO" ]; then
    if stat -t "$TASKS_MOUNT_POINT/tasks/index/"*"/done/$TASK"; then
	task_path=`ls -d "$TASKS_MOUNT_POINT/tasks/index/"*"/done/$TASK" | head -1`
	FROM_REPO=`dirname $task_path`
	FROM_REPO=`dirname $FROM_REPO`
	FROM_REPO=`basename $FROM_REPO`
    else
	echo "The task $TASK is not found at $TASKS_MOUNT_POINT/tasks/index/*/done/$TASK"
	exit 1
    fi
fi

cd "$TASKS_MOUNT_POINT/tasks/index/$FROM_REPO/done/$TASK"

if [ -s plan/add-src ]; then
    # echo rsync -L $(sort -k5,5n plan/add-src | cut -f 4 | paste -s) "$GIRAR_HOST":
    rsync -L $(sort -k5,5n plan/add-src | cut -f 4 | paste -s) "$GIRAR_HOST":
fi

NEW_TASK="$(ssh $GIRAR_HOST task new $REPOSITORY_BRANCH)"
cut -f1 plan/rm-src | sort > "$tmpdir"/removed-package-names
cut -f1 plan/add-src | sort > "$tmpdir"/added-package-names
comm -23 "$tmpdir"/removed-package-names "$tmpdir"/added-package-names > \
    "$tmpdir"/del-packages
sort -k5,5n plan/add-src | cut -f3  > "$tmpdir"/srpm-packages

ANY_ACTION=
for action in del srpm; do
    for name in $(cat "$tmpdir"/$action-packages); do
        err=0
        if  echo $name | grep -Eq 'kernel-(module|image)';  then
            echo "Get kernel module/image $name" >&2
            continue
        else
            # echo ssh "$GIRAR_HOST" task add "$NEW_TASK" $action "$name"
            if ssh "$GIRAR_HOST" task add "$NEW_TASK" $action "$name"  &> "$tmpdir"/output; then
                ANY_ACTION=True
                cat "$tmpdir"/output
            else
                if grep -qF < "$tmpdir"/output \
                    ": too old for "; then
                    echo "Adding too old srpm $name" >&2
                elif grep -qF < "$tmpdir"/output \
                    "task add: Invalid request to delete a nonexistent package "; then
                    echo "Delete absent package \`$name'" >&2
                else
                    err=$?
                    cat "$tmpdir"/output >&2
                    exit $err
                fi
            fi
        fi
    done
done

if [ -n "$ANY_ACTION" ]; then
    $DRY_RUN ssh "$GIRAR_HOST" task run ${TASK_RUN_TEST_ONLY:---commit} ${TASK_RUN_HURRY:+--hurry} ${TASK_RUN_UNHURRY:+--unhurry} ${TASK_RUN_FAIL_LATE:+--fail-late} ${girar_message:+-m "$girar_message"} "$NEW_TASK"
    echo "$TASK->$NEW_TASK"
fi

: <<'__EOF__'

=head1	NAME

girar-task-rerunner - re-runs a task (from sisyphus to e2k...)

=head1	SYNOPSIS

B<girar-task-rerunner>
[B<--from-repo> I<repo>]
[B<--tasks-root|--tasks-mount-point> I</path>]
[B<-D|--deps> I<comma separated list>]
[B<-S|--share>]
[B<--gm|--girar-message|--gyle-message> I<message>]
[B<-O|--no-test-only>]
[B<--test-only>]
[B<--unhurry>]
[B<--hurry>]
[B<--fail-early|--fail-late>]
[B<-H|--gitery> I<ssh gitery alias>]
[B<-R|--girar> I<ssh girar(gule) alias>]
[B<-W|--webery> I<tasks web site>]
[B<--web-tasks-url> I<tasks web site url>]
[B<-b|--branch> I<repository>]
[B<--dry-run>]
[B<-P|--profile> I<profile>]
[B<-h|--help>]
[B<-v|--verbose>]
[B<-q|--quiet>]

I<TASK ID>

=head1	DESCRIPTION

B<girar-task-rerunner> re-runs given task for different repository
and/or with different options. It is often used for re-running
sisyphus tasks in girar.e2k or other secondary architecture.
Another example is re-running a successfull e2k task in gitrar.e2k
for rebuild purposes.

This script requires filesystem access to girar tasks.
For the filesystem access to the default(sisyphus) girar tasks
you should have an account on team.alt.

Please, eather run this script on team.alt
or mount /tasks from team.alt using sshfs
and use --tasks-mount-point=/path/to/tasks option.

An example fstab(5) entry for grenka@:
grenka@team.alt:/tasks /tasks fuse.sshfs allow_other,ro,_netdev,user,idmap=user,identityfile=/home/grenka/.ssh/id_rsa,uid=500,gid=500,follow_symlinks,x-systemd.automount 0 0

=head1	OPTIONS

=over

=item	B<--from-repo> I<repo>

Repository to take task from. Optional. By default it is determined by task.

=item	B<--tasks-root|--tasks-mount-point> I</path>

Path to the /tasks filesystem. Default is I</tasks> .

=item  Run task options.

=over

=item	B<-D|--deps> I<dep1,...,depN>

Comma separated list of task dependencies to add.

=item	B<-S|--share>

Create and run a shared task. Disabled by default.
Also, B<--no-share> disables it.


=item	B<--gm|--girar-message|--gyle-message> I<message>

Specifies a girar task message.

=item	B<--test-only>

Run task --test-only

=item	B<--commit|-O|--no-test-only>

Do not run task --test-only (default).

=item	B<--hurry>

Run task with --hurry (undocumented girar option)

=item	B<--no-hurry>

Remove --hurry from run command line,
B<--no-hurry> option does not set --unhurry.

=item	B<--unhurry>

Run task with --unhurry (undocumented girar option)

=item	B<--fail-early>

Stop building the task after the first error.

=item	B<--fail-late>

Do not stop building the task after the first error.

=back


=item	B<-b|--branch> I<repository branch>

Name of the repository branch. Values: sisyphus|p8|..
Default is sisyphus.

=item	B<-R|--girar> I<girar(gyle) ssh alias>

By default, gyle.altlinux.org account should be configured as girar or gyle in ~/.ssh/config.
If you do not follow that convention, use -R <your girar ssh alias> option.

=item	B<-H|--gitery> I<gitery ssh alias>

Alternative gitery or ssh alias for gitery, for example, git.e2k.
If not specified, by default, gitery is used where ssh account is
required and git.altlinux.org is used where http:// is enough.

=item	B<-W|--webery> I<tasks web site>

Alternative site that hosts girar tasks.
If not specified, by default, git.altlinux.org is used.

=item	[B<--web-tasks-url> I<tasks web site url>]

The default URL for web task site is http://I<tasks web site>.
See --webery for details. B<--web-tasks-url> overrides this URL.

=item	B<--dry-run>

Echo state-changing commands instead of doing them. An extra safety.
Also a bit useful for debugging.

=item	B<-P|--profile> I<profile>

Name of the configuration profile. The profile is loaded as
/etc/girar-nmu/I<profile> and $HOME/.config/girar-nmu/I<profile>.
Note that default configuration is stored in
/etc/girar-nmu/default and $HOME/.config/girar-nmu/default.

=item	B<-V|--version>

Print version and exit.

=item	B<-v|--verbose>

Verbose. Prints extra information. Multiple -v accumulate.
-v -v -v set debug mode (set -x).

=item	B<-q|--quiet>

Quiet. Print no warnings.

=item	B<-h|--help>

Display this help and exit.


=back

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	COPYING

Copyright (c) 2010-2022 Igor Vlasenko, ALT Linux Team.

This is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

=cut

__EOF__
