#!/usr/bin/perl # # vim: set ts=4:noet # # sboconfig # script to handle sbotools configuration # # authors: Jacob Pipkin # Luke Williams # Andreas Guldstrand # license: WTFPL use 5.16.0; use strict; use warnings FATAL => 'all'; use SBO::Lib qw/ usage_error script_error $tempdir open_read 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: this screen. -v: version information. -l: 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#^/#; } 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)$/; } # safely modify our conf file; write its contents to a temp file, modify the # temp file, write the contents of the temp file back to the conf file # TODO: if multiple options are provided to this script, this sub should write # them all at once, instead of only a single one and having to call it once for # each option specified to the script. sub config_write { my ($key, $val) = @_; script_error('config_write requires two arguments.') unless @_ == 2; if (! -d $conf_dir) { mkdir $conf_dir or usage_error("Unable to create $conf_dir. Exiting."); } if (-f $conf_file) { my $tempfh = tempfile(DIR => $tempdir); my ($conffh, $exit) = open_read($conf_file); if ($exit) { warn $conffh; exit $exit; } my $conftents = do {local $/; <$conffh>}; print {$tempfh} $conftents; # tie the temp file so that if $key is already there, we just change # that line and untie it tie my @temp, 'Tie::File', $tempfh; my $has; my $regex = qr/\A\Q$key\E=/; # TODO: fix this monstrosity FIRST: for my $tmpline (@temp) { $has++, $tmpline = "$key=$val", last FIRST if $tmpline =~ $regex; } untie @temp; # otherwise, append our new $key=$value pair print {$tempfh} "$key=$val\n" unless $has; # then overwrite the conf file with the contents of the temp file seek $tempfh, 0, 0; my $contents = do {local $/; <$tempfh>}; close $conffh; ($conffh, $exit) = open_fh($conf_file, '>'); if ($exit) { warn $conffh; exit $exit; } print {$conffh} $contents or return(); } else { # no config file, easiest case of all. my ($fh, $exit) = open_fh($conf_file, '>') or return(); if ($exit) { warn $fh; exit $exit; } print {$fh} "$key=$val\n"; close $fh; } return 1; } for my $key (keys %changes) { my $value = $changes{$key}; say "Setting $key to $value..."; config_write($key, $value); } exit 0;