#!/usr/bin/perl
#
# This file is part of Alien-Bazel
#
# This software is Copyright (c) 2022 by Auto-Parallel Technologies, Inc.
#
# This is free software, licensed under:
#
#   The GNU General Public License, Version 3, June 2007
#

use alienfile;

use strict;
use warnings;
our $VERSION = 0.013_000;

use Data::Dumper;
use English qw(-no_match_vars);  # for $OSNAME
use Time::HiRes qw(time);  # for performance timing

use constant DEBUG_BAZEL_BOOTSTRAP =>
    exists $ENV{ALIEN_BAZEL_DEBUG_BAZEL_BOOTSTRAP}
    ? $ENV{ALIEN_BAZEL_DEBUG_BAZEL_BOOTSTRAP}
    : 0;

use constant FROM_SOURCE =>
    exists $ENV{ALIEN_BAZEL_FROM_SOURCE}
    ? $ENV{ALIEN_BAZEL_FROM_SOURCE}
    : 0;

use lib 'lib';
use Alien::Bazel::Util;

# check if the operating system already has Bazel installed
plugin 'Probe::CommandLine' => (
    command => 'bazel',
    args    => [ '--version' ],
    match   => qr/bazel/,
    version => qr/bazel ([0-9\.]+)/,
);

# if the operating system does not have Bazel, then compile from source
share {
    requires 'Path::Tiny';
    requires 'File::Which';
    requires 'Alien::Build::Plugin::Download::GitHub', '0.10';

    my $time_start = time();
    print {*STDERR} '<<< DEBUG >>> have $time_start = ', $time_start, ' seconds', "\n";

    # START HERE, NEED ANSWER: how to handle prerequisites???
    # START HERE, NEED ANSWER: how to handle prerequisites???
    # START HERE, NEED ANSWER: how to handle prerequisites???
    my %os_arch_to_binary_release = (
        'darwin:aarch64'  => { suffix => 'darwin-arm64',       },
        'darwin:x86_64'   => { suffix => 'darwin-x86_64',      },
        'linux:aarch64'   => { suffix => 'linux-arm64',        },
        'linux:x86_64'    => { suffix => 'linux-x86_64',       },
        'MSWin32:aarch64' => { suffix => 'windows-arm64.exe',  },
        'MSWin32:x86_64'  => { suffix => 'windows-x86_64.exe', },
    );

    # must have prerequisites to compile from source
    # https://bazel.build/install/compile-source#bootstrap-bazel
    # $ sudo apt-get install build-essential openjdk-11-jdk zip unzip python2
#    requires Alien::Bash;
#    requires Alien::ZipUnzip;
#    requires 'Alien::unzip';
#    requires Alien::C++Toolchain;
#    requires Alien::JDK;  # v11
#    requires Alien::Python;  # v2 or v3

    # https://github.com/bazelbuild/bazel/releases
    # Bazel bootstrap archive is always "zip"; the "tar.gz" archives are NOT
    # bootstrap capable

    my %source_asset_info = (
        asset_name   => qr/^bazel-([0-9\.]+)-dist\.zip$/,
        asset_format => 'zip',
    );

    # from source by default
    my %asset_info = %source_asset_info;
    my $binary_release = 0;

    my $os_arch = join ":", ( $^O, meta->prop->{platform}{cpu}{arch}{name} );
    if( exists $os_arch_to_binary_release{$os_arch} && ! FROM_SOURCE ) {
        $binary_release = 1;
        my ($suffix) = @{ $os_arch_to_binary_release{$os_arch} }{qw(suffix)};
        %asset_info = (
            asset_name   => qr/^bazel-([0-9\.]+)-\Q${suffix}\E$/,
            asset_format => 'f',
        );
    }

    plugin 'Download::GitHub' => (
        github_user  => 'bazelbuild',
        github_repo  => 'bazel',
        asset        => 1,
        %asset_info,
    );

    if( ! $binary_release ) { # from source
        # provides `bash` in crippled operating systems
        plugin 'Build::MSYS';

        # NEED UPGRADE: verify the signature made by Bazel's release key 3D5919B448457EE0
        # https://bazel.build/bazel-release.pub.gpg

        meta->prop->{env}->{JAVA_HOME} = Alien::Bazel::Util->_find_jdk_java_home;
        # https://bazel.build/install/compile-source#bootstrap-bazel
        # $ env EXTRA_BAZEL_ARGS="--tool_java_runtime_version=local_jdk" bash ./compile.sh
        meta->prop->{env}->{EXTRA_BAZEL_ARGS} = '--tool_java_runtime_version=local_jdk';

        if( DEBUG_BAZEL_BOOTSTRAP ) {
            meta->prop->{env}->{VERBOSE} = 'yes';
            meta->prop->{env}->{BAZEL_DEBUG_JAVA_COMPILATION} = 1;
        }
        build [
            sub {
                my ($build) = @_;
                $build->log("JAVA_HOME        = $ENV{JAVA_HOME}");
                $build->log("EXTRA_BAZEL_ARGS = $ENV{EXTRA_BAZEL_ARGS}");
            },
            'bash ./compile.sh',
            '%{make_path} %{.install.stage}/bin',
            '%{cp} output/bazel %{.install.stage}/bin'
        ];
    } else {
        patch sub {
            my ($build) = @_;
            my ($bazel_file) = Path::Tiny->new('.')->children(qr/^bazel-/);
            # remove all but 'bazel' prefix and possibly a '.exe' suffix (on
            # MSWin32) so $exe is either 'bazel' or 'bazel.exe'
            (my $exe = $bazel_file->basename) =~ s/^ (bazel) .*? ( (?:\.exe)? ) $/$1$2/x;
            $bazel_file->move( $bazel_file->parent->child($exe) );
            $build->install_prop->{bazel_exe} = $exe;
        };
        build [
            '%{make_path} %{.install.stage}/bin',
            "%{cp} %{.install.bazel_exe} %{.install.stage}/bin",

            ( $^O ne 'MSWin32'
            ? "chmod +x %{.install.stage}/bin/%{.install.bazel_exe}"
            : ()
            )
        ];
    }

    after 'gather' => sub {
        my $time_total = time() - $time_start;
        print {*STDERR} '<<< DEBUG >>> have $time_total = ', $time_total, ' seconds', "\n";
    };
};

