#!/usr/bin/env perl

# Script to handle building KDE from source code.
#
# Configuration is found in $XDG_CONFIG_HOME/kdesrc-buildrc,
# with fallback at ~/.kdesrc-buildrc. $XDG_CONFIG_HOME normally ".config"
#
# Please also see the documentation that should be included with this program,
# in the doc/ directory.
#
# Home page: https://apps.kde.org/kdesrc_build/
#
# Copyright © 2003 - 2022 Michael Pyne. <mpyne@kde.org>
# Copyright © 2018 - 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
# Copyright © 2005, 2006, 2008 - 2011 David Faure <faure@kde.org>
# Copyright © 2005 Thiago Macieira <thiago@kde.org>
# Copyright © 2006 Stephan Kulow <coolo@kde.org>
# Copyright © 2006, 2008 Dirk Mueller <mueller@kde.org>
# ... and possibly others. Check the git source repository for specifics.
#
# This program 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.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

# Adding an option? Grep for 'defaultGlobalOptions' in ksb::BuildContext --mpyne

####  Script start.  Step 1: Tell Perl where to find our 'ksb' modules in relation
####  to where we are at.

use v5.26;
use strict;
use warnings;

# On many container-based distros, even FindBin is missing to conserve space.
# But we can use File::Spec to do nearly the same.
my $RealBin;
my $modPath;

# The File::Spec calls have to run when parsing (i.e. in BEGIN) to make the
# 'use lib' below work (which itself implicitly uses BEGIN { })
BEGIN {
    use File::Spec;

    # resolve symlinks
    my $scriptPath = $0;
    for (1..16) {
        last unless -l $scriptPath;
        $scriptPath = readlink $scriptPath;
    }
    die "Too many symlinks followed looking for script" if -l $scriptPath;

    my ($volume, $directories, $script) = File::Spec->splitpath($scriptPath);

    $RealBin = File::Spec->catpath($volume, $directories, '');
    die "Couldn't find base directory!" unless $RealBin;

    # Use modules in git repo if running from git dir, otherwise assume
    # system install
    $modPath = File::Spec->rel2abs('modules', $RealBin);
    $modPath = ($RealBin =~ s,/bin/?$,/share/kdesrc-build/modules,r)
        unless -d $modPath;

    die "Couldn't find modules for kdesrc-build!" unless $modPath;
}

# We use third party embedded modules but we should prefer system versions if
# available so add to the end of @INC rather than the beginning, this is why
# we don't do "use lib '$modPath'"
BEGIN {
    push @INC, "$modPath";
}

####  Now that Perl can find our modules, load them and start processing command line arguments

use ksb; # Enable boilerplate

# When running in a limited environment, we might not be able to load
# our modules although we can find them. In this case we should help user
# by setting up system dependencies.
eval {
    if (grep { $_ eq '--initial-setup' } @ARGV) {
        require ksb::FirstRun;
        require ksb::Debug;
        ksb::Debug::setColorfulOutput(1);
        exit ksb::FirstRun::setupUserSystem(File::Spec->rel2abs($RealBin));
    }
};

if ($@) {
    say STDERR <<DONE;
* Unable to even load the simplistic initial setup support for some reason??

$@

You could:
 File a bug https://bugs.kde.org/enter_bug.cgi?product=kdesrc-build
 Ask for help on irc.libera.chat in the #kde channel
DONE
    exit 1;
}

# Even though the flow of execution should not make it here unless the modules
# we need are installed, we still cannot "use" the modules that might be
# missing on first use since just trying to parse/compile the code is then
# enough to cause errors.
eval {
    require Carp;
    require ksb::Debug;
    require ksb::Util;
    require ksb::Version;
    require ksb::Application;
    require ksb::BuildException;
};

if ($@) {
    say STDERR <<DONE;
Couldn't load the base platform for kdesrc-build!

$@
DONE

    # According to XDG spec, if $XDG_CONFIG_HOME is not set, then we should default
    # to ~/.config
    my $xdgConfigHome = $ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config";
    my @possibleConfigPaths = ("./kdesrc-buildrc",
                               "$xdgConfigHome/kdesrc-buildrc",
                               "$ENV{HOME}/.kdesrc-buildrc");

    if (!grep { -e $_ } (@possibleConfigPaths)) {
        say STDERR <<~DONE;
        It appears you've not run kdesrc-build before.

        Please run "kdesrc-build --initial-setup" and kdesrc-build will guide you
        through setting up required dependencies and environment setup.
        DONE
    } else {
        say STDERR <<~DONE;
        You could:
         File a bug https://bugs.kde.org/enter_bug.cgi?product=kdesrc-build
         Ask for help on irc.libera.chat in the #kde channel
        DONE
    }
    exit 1;
}

ksb::Debug->import();
ksb::Util->import();
ksb::BuildException->import();
ksb::Version->import(qw(scriptVersion));
ksb::Application->import();

# Make Perl 'plain die' exceptions use Carp::confess instead of their core
# support. This is not supported by the Perl 5 authors but assuming it works
# will be better than the alternative backtrace we get (which is to say, none)
$SIG{__DIE__} = \&Carp::confess;

ksb::Version::setBasePath($RealBin);

# Script starts.

# Adding in a way to load all the functions without running the program to
# enable some kind of automated QA testing.
if (defined caller && caller eq 'test')
{
    my $scriptVersion = scriptVersion();
    say "kdesrc-build being run from testing framework, BRING IT.";
    say "kdesrc-build is version $scriptVersion";
    return 1;
}

my $app;

eval
{
    $app = ksb::Application->new(@ARGV);

    my $result = $app->runAllModulePhases();

    $app->finish($result); # noreturn
};

if (my $err = $@)
{
    if (had_an_exception()) {
        say <<~DONE;
        kdesrc-build encountered an exceptional error condition:
         ========
            $err
         ========
        Can't continue, so stopping now.

        DONE

        if ($err->{'exception_type'} eq 'Internal') {
            say "Please submit a bug against kdesrc-build on https://bugs.kde.org/";
        }
    } else {
        # We encountered some other kind of error that didn't raise a ksb::BuildException
        say <<~DONE;
        Encountered an error in the execution of the script.
        --> $err
        Please submit a bug against kdesrc-build on https://bugs.kde.org/
        DONE
    }

    $app->finish(99) if $app; # noreturn
    exit 99; # if $app couldn't be created
}

# vim: set et sw=4 ts=4 fdm=marker:
