#!/usr/bin/perl -w
# Copyright 2009-2013 Bernhard M. Wiedemann
# Copyright 2012-2020 SUSE LLC
# SPDX-License-Identifier: GPL-2.0-or-later
#

=head1 SYNOPSIS

isotovideo [OPTIONS] [TEST PARAMETER]

Parses command line parameters, vars.json and tests the given assets/ISOs.

=head1 OPTIONS

=over 4

=item B<-d, --debug>

Enable direct output to STDERR instead of autoinst-log.txt

=item B<--workdir=>

isotovideo will chdir to that directory on startup

=item B<--color=[yes|no]>

Enable or disable color output explicitly. Defaults to "yes". Alternatively
ANSI_COLORS_DISABLED or NO_COLOR can be set to any value to disable colors.

=item B<-v, --version>

Show the current program version and test API version

=item B<-h, -?, --help>

Show this help.

=head1 TEST PARAMETER

All additional command line arguments specified in the C<key=value> format are
parsed as test parameters which take precedence over the settings in the
vars.json file. Lower case key names are transformed into upper case
automatically for convenience.

=cut

use Mojo::Base -strict, -signatures;
use autodie ':all';
no autodie 'kill';

# Avoid "Subroutine JSON::PP::Boolean::(0+ redefined" warnings
# Details: https://progress.opensuse.org/issues/90371
use JSON::PP;

my $installprefix;    # $bmwqemu::scriptdir

BEGIN {
    # the following line is modified during make install
    $installprefix = undef;

    my ($wd) = $0 =~ m-(.*)/-;
    $wd ||= '.';
    $installprefix ||= $wd;
    unshift @INC, "$installprefix";
}

use log qw(diag);
use Getopt::Long;
use Mojo::File qw(curfile);
use Mojo::IOLoop::ReadWriteProcess::Session 'session';
Getopt::Long::Configure("no_ignore_case");
use OpenQA::Isotovideo::Interface;
use OpenQA::Isotovideo::Runner;
use OpenQA::Isotovideo::Utils qw(git_rev_parse spawn_debuggers handle_generated_assets);

my %options;

# global exit status
my $return_code = 1;

sub usage ($r) {
    $return_code = $r;
    eval { require Pod::Usage; Pod::Usage::pod2usage($r) };
    die "cannot display help, install perl(Pod::Usage)\n" if $@;
}

sub _get_version_string () {
    my $thisversion = git_rev_parse(curfile->dirname);
    return "Current version is $thisversion [interface v$OpenQA::Isotovideo::Interface::version]";
}

sub version () {
    print _get_version_string() . "\n";
    $return_code = 0;
    exit 0;
}

GetOptions(\%options, 'debug|d', 'workdir=s', 'color=s', 'help|h|?', 'version|v') or usage(1);
usage(0) if $options{help};
version() if $options{version};

session->enable;
session->enable_subreaper;

my $color = $options{color} // 'yes';
# User setting has preference, see https://no-color.org/
delete $ENV{NO_COLOR} if $color eq 'yes';
# Term::ANSIColor honors this variable
$ENV{ANSI_COLORS_DISABLED} = 1 if $color eq 'no';

chdir $options{workdir} if $options{workdir};

# abstraction providing many helpers and function to run the select-loop
my $runner;

# make sure all commands coming from the backend will not be in the
# developers's locale - but a defined english one. This is SUSE's
# default locale
$ENV{LC_ALL} = 'en_US.UTF-8';
$ENV{LANG} = 'en_US.UTF-8';

eval {
    diag(_get_version_string());

    # enable debug default when started from a tty
    $log::direct_output = $options{debug};

    $bmwqemu::scriptdir = $installprefix;

    $runner = OpenQA::Isotovideo::Runner->new;
    $runner->_init_bmwqemu(@ARGV);
    $runner->prepare;
    $runner->start_autotest;
    $runner->create_backend;

    spawn_debuggers;

    $runner->handle_commands;

    $return_code = 0;

    # enter the main loop: process messages from autotest, command server and backend
    $runner->run;

    # terminate/kill the command server and let it inform its websocket clients before
    $runner->stop_commands('test execution ended');

    if ($runner->testfd) {
        # unusual shutdown
        $return_code = 1;    # uncoverable statement
        CORE::close $runner->testfd;    # uncoverable statement
        $runner->stop_autotest();    # uncoverable statement
    }

    diag 'isotovideo ' . ($return_code ? 'failed' : 'done');
    my $clean_shutdown = $runner->handle_shutdown(\$return_code);

    # read calculated variables from backend and tests
    bmwqemu::load_vars();

    $return_code = handle_generated_assets($runner->command_handler, $clean_shutdown) unless $return_code;
};
if (my $error = $@) {
    log::fctwarn $error, 'main';
    bmwqemu::serialize_state(component => 'isotovideo', msg => $error);
}

END {
    $runner->backend->stop if $runner and $runner->backend;
    $runner and $runner->stop_commands('test execution ended through exception');
    $runner and $runner->stop_autotest();

    # in case of early exit, e.g. help display
    $return_code //= 0;

    print "$$: EXIT $return_code\n";
    $? = $return_code;
}
