#!/usr/bin/env perl
#
# vim: set ts=4:noet
#
# sboinstall
# script to install (a) SlackBuild(s) by name
#
# authors: Jacob Pipkin <j@dawnrazor.net>
#		   Luke Williams <xocel@iquidus.org>
# license: WTFPL <http://sam.zoy.org/wtfpl/COPYING>

use 5.16.0;
use strict;
use warnings FATAL => 'all';
use SBO::Lib;
use Getopt::Long qw(:config bundling);
use File::Basename;

my $self = basename($0);

sub show_usage {
	print <<EOF
Usage: $self [options] sbo

Options (defaults shown first where applicable):
  -h|--help:
    this screen.
  -v|--version:
    version information.
  -c|--noclean (FALSE|TRUE):
    set whether or not to clean working files/directories after the build.
  -d|--distclean (TRUE|FALSE):
   set whether or not to clean distfiles afterward. 
  -i|--noinstall:
    do not run installpkg at the end of the build process.
  -j|--jobs (FALSE|#):
    specify "-j" setting to make, for multicore systems; overrides conf file.
  -p|--compat32:
    install an SBo as a -compat32 pkg on a multilib x86_64 system.
  -r|--nointeractive:
    non-interactive; skips README and all prompts.
  -R|--norequirements:
    view the README but do not parse requirements, commands, or options.

EOF
}

my $noclean = $config{NOCLEAN};
my $distclean = $config{DISTCLEAN};
my $jobs = $config{JOBS};
my ($help, $vers, $no_install, $non_int, $no_reqs, $compat32);

GetOptions(
	'help|h'			=> \$help,
	'version|v'			=> \$vers,
	'noclean|c=s'		=> \$noclean,
	'distclean|d=s'		=> \$distclean,
	'noinstall|i'		=> \$no_install,
	'jobs|j=s'			=> \$jobs,
	'compat32|p'		=> \$compat32,
	'nointeractive|r'	=> \$non_int,
	'norequirements|R'	=> \$no_reqs,
);

show_usage() and exit 0 if $help;
show_version() and exit 0 if $vers;
show_usage() and exit 1 unless exists $ARGV[0];

$noclean = $noclean eq 'TRUE' ? 1 : 0;
$distclean = $distclean eq 'TRUE' ? 1 : 0;

if ($jobs) {
	usage_error("You have provided an invalid value for -j|--jobs")
		unless ($jobs =~ /^\d+$/ || $jobs eq 'FALSE');
}

if ($compat32) {
	usage_error("compat32 only works on x86_64.") unless get_arch eq 'x86_64';
}

# if we can't find SLACKBUILDS.TXT in $config{HOME}, prompt to fetch the tree
slackbuilds_or_fetch();

my (%warnings, $build_queue, %locations);

if ($no_reqs or $non_int) {
    $build_queue = \@ARGV;
} else {
	for my $sbo (@ARGV) {
        my $queue = get_build_queue([$sbo], \%warnings);
        $build_queue = merge_queues($build_queue, $queue);
	}
}

# populate %locations and sanity check
%locations = get_sbo_locations($build_queue);
for my $sbo (@$build_queue) {
	usage_error("Unable to locate $sbo in the SlackBuilds.org tree.") unless
		$locations{$sbo};
	if ($compat32) {
		usage_error("-p|--compat32 is not supported with Perl SBos.")
			if $locations{$sbo} =~ qr|/perl/[^/]+$|;
	}
}

# get lists of installed packages and perl modules from CPAN
my $inst_names = get_inst_names(get_installed_packages 'ALL');
my $pms = get_installed_cpans();
s/::/-/g for @$pms;

# check for already-installeds and prompt for the rest
my (@temp_queue, %commands, %options);
my $added = ' added to install queue.';
my %inst_names;
$inst_names{$_} = 1 for @$inst_names;

FIRST: for my $sbo (@$build_queue) {
    my $name = $compat32 ? "$sbo-compat32" : $sbo;

	if ($inst_names{$name}) {
		say "$name already installed.";
		next FIRST;
	} else {
		if ($sbo =~ /^perl-/) {
			my $pm_name = $sbo;
			$pm_name =~ s/^perl-//;
			for my $pm (@$pms) {
				if ($pm =~ /^$pm_name$/i) {
					say "$sbo installed via the cpan.";
					next FIRST;
				}
			}
		}
	}

    $locations{$name} = get_sbo_location($sbo) if $compat32;
    unless ($non_int) {
        # if compat32 is TRUE, we need to see if the non-compat version exists.
        if ($compat32) {
			unless ($inst_names{$sbo}) {
				say "$name requires $sbo.";
                my ($cmds, $opts, $exit) = user_prompt($sbo, $locations{$sbo});
				if ($exit) {
					warn "Unable to open README for $sbo.\n";
					exit $exit;
				}
				if ($cmds) {
					next FIRST if $cmds eq 'N';
				}
               	push(@temp_queue, $sbo);
				$commands{$sbo} = $cmds;
				$options{$sbo} = $cmds;
				say "$sbo$added";
            } 
        }
        my ($cmds, $opts, $exit) = user_prompt($name, $locations{$name});
		if ($exit) {
			warn "Unable to open README for $name.\n";
			exit $exit;
		}
		if ($cmds) {
			next FIRST if $cmds eq 'N';
		}
        push(@temp_queue, $name);
		$commands{$sbo} = $cmds;
		$options{$sbo} = $opts;
		say "$name$added";
    } else {
        push(@temp_queue, $sbo);
		say "\n$name$added";
    }
}
@$build_queue = @temp_queue;

exit 0 unless exists $$build_queue[0];
say "\nInstall queue: " . join(' ', @$build_queue);
unless ($non_int) {
    print "\nAre you sure you wish to continue? [y]: ";
    exit 0 unless <STDIN> =~ /^[Yy\n]/;
}

my ($failures, $exit) = process_sbos(
	TODO		=> $build_queue,
	CMDS		=> \%commands,
	OPTS		=> \%options,
	JOBS		=> $jobs,
	LOCATIONS	=> \%locations,
	NOINSTALL	=> $no_install,
	NOCLEAN		=> $noclean,
	DISTCLEAN	=> $distclean,
	NON_INT		=> $non_int,
);
print_failures($failures);

if ($exit) {
	exit $exit;
} else {
	exit 0;
}
