#!/usr/bin/perl
#
# vim: ts=4:noet
#
# sboconfig
# script to handle sbotools configuration
#
# authors: Jacob Pipkin <j@dawnrazor.net>
#          Luke Williams <xocel@iquidus.org>
#          Andreas Guldstrand <andreas.guldstrand@gmail.com>
# license: WTFPL <http://sam.zoy.org/wtfpl/COPYING>

use 5.16.0;
use strict;
use warnings FATAL => 'all';
use SBO::Lib qw/ slurp usage_error script_error $tempdir open_fh %config $conf_dir $conf_file show_version /;
use File::Basename;
use Getopt::Long qw(:config no_ignore_case_always);
use File::Copy;
use File::Path qw(make_path);
use File::Temp qw(tempfile);;

my $self = basename($0);

sub show_usage {
	print <<"EOF";
Usage: $self [options] [arguments]

Options:
  -h|--help:
    this screen.
  -v|--version:
    version information.
  -l|--list:
    show current options.

Config options (defaults shown):
  -c|--clean FALSE:
      NOCLEAN: if TRUE, do NOT clean up after building by default.
  -d|--distclean FALSE:
      DISTCLEAN: if TRUE, DO clean distfiles by default after building.
  -j|--jobs FALSE:
      JOBS: numeric -j setting to feed to make for multicore systems.
  -p|--pkg-dir FALSE:
      PKG_DIR: set a directory to store packages in.
  -s|--sbo-home /usr/sbo:
      SBO_HOME: set the SBo directory.
  -o|--local-overrides FALSE:
      LOCAL_OVERRIDES: a directory containing local overrides.
  -V|--slackware-version FALSE:
      SLACKWARE_VERSION: use the SBo repository for this version.
  -r|--repo FALSE:
      REPO: use a repository other than SBo.

EOF
	return 1;
}

my %options;

GetOptions(\%options, 'help|h', 'version|v', 'list|l', 'noclean|c=s',
	'distclean|d=s', 'jobs|j=s', 'pkg-dir|p=s', 'sbo-home|s=s',
	'local-overrides|o=s', 'slackware-version|V=s', 'repo|r=s');

if ($options{help}) { show_usage(); exit 0 }
if ($options{version}) { show_version(); exit 0 }

my %valid_confs = (
	noclean             => 'NOCLEAN',
	distclean           => 'DISTCLEAN',
	jobs                => 'JOBS',
	'pkg-dir'           => 'PKG_DIR',
	'sbo-home'          => 'SBO_HOME',
	'local-overrides'   => 'LOCAL_OVERRIDES',
	'slackware-version' => 'SLACKWARE_VERSION',
	'repo'              => 'REPO',
);

my %params = (
	NOCLEAN           => 'c|--noclean',
	DISTCLEAN         => 'd|--distclean',
	JOBS              => 'j|--jobs',
	PKG_DIR           => 'p|--pkg-dir',
	SBO_HOME          => 's|--sbo-home',
	LOCAL_OVERRIDES   => 'o|--local-overrides',
	SLACKWARE_VERSION => 'V|--slackware-version',
	REPO              => 'r|--repo',
);

if (exists $options{list}) {
	my @keys = sort {$a cmp $b} keys %config;
	say "sboconfig -$params{$_}:\n    $_=$config{$_}" for @keys;
	exit 0;
}

if (not %options) {
	show_usage();
	exit 0;
}

# setup what's being changed, sanity check.
my %changes;
for my $key (keys %valid_confs) {
	my $value = $valid_confs{$key};
	$changes{$value} = $options{$key} if exists $options{$key};
}

my $warn = 'You have provided an invalid parameter for';

if (exists $changes{NOCLEAN}) {
	usage_error("$warn -c") unless $changes{NOCLEAN} =~ /^(TRUE|FALSE)$/;
}
if (exists $changes{DISTCLEAN}) {
	usage_error("$warn -d") unless $changes{DISTCLEAN} =~ /^(TRUE|FALSE)$/;
}
if (exists $changes{JOBS}) {
	usage_error("$warn -j") unless $changes{JOBS} =~ /^(\d+|FALSE)$/;
}
if (exists $changes{PKG_DIR}) {
	usage_error("$warn -p") unless $changes{PKG_DIR} =~ qr#^(/|FALSE$)#;
}
if (exists $changes{SBO_HOME}) {
	usage_error("$warn -s") unless $changes{SBO_HOME} =~ qr#^(/|FALSE$)#;
}
if (exists $changes{LOCAL_OVERRIDES}) {
	usage_error("$warn -o") unless $changes{LOCAL_OVERRIDES} =~ qr#^(/|FALSE$)#;
}
if (exists $changes{SLACKWARE_VERSION}) {
	usage_error("$warn -V") unless $changes{SLACKWARE_VERSION} =~ m/^(\d+\.\d+|FALSE)$/;
}

sub config_write {
	script_error('config_write requires at least two arguments.') unless @_ >= 2;

	if (! -d $conf_dir) {
		mkdir $conf_dir or usage_error("Unable to create $conf_dir. Exiting.");
	}

	my $conf = slurp($conf_file) || '';
	_fixup_conf($conf);

	while (@_ >= 2) {
		my $key = shift;
		my $val = shift;
		say "Setting $key to $val...";

		if ($conf =~ /^\Q$key\E=/m) {
			$conf =~ s/^\Q$key\E=.*$/$key=$val/m;
		} else {
			$conf .= "$key=$val\n";
		}
	}

	_fixup_conf($conf);

	my ($conffh, $exit) = open_fh($conf_file, '>');
	if ($exit) {
		warn $conffh;
		exit $exit;
	}
	print {$conffh} $conf;
}

# make sure there are no duplicate keys in the config
sub _fixup_conf {
	my @lines = split /\n/, $_[0];
	my @fixed;
	my %keys;
	foreach my $line (@lines) {
		# if it's a comment or blank line, just pass it through
		if ($line =~ /^(#|\s*$)/) { push @fixed, $line; next; }

		my ($key, $val) = split /=/, $line;
		next if exists $keys{$key};
		$keys{$key}++;
		push @fixed, $line;
	}

	$_[0] = join "\n", @fixed, ''; # make sure we end with a newline if there are any lines
}

config_write(%changes) if %changes;

exit 0;
