aboutsummaryrefslogtreecommitdiff
path: root/SBO-Lib/lib
diff options
context:
space:
mode:
Diffstat (limited to 'SBO-Lib/lib')
-rw-r--r--SBO-Lib/lib/SBO/Lib/Util.pm496
1 files changed, 496 insertions, 0 deletions
diff --git a/SBO-Lib/lib/SBO/Lib/Util.pm b/SBO-Lib/lib/SBO/Lib/Util.pm
new file mode 100644
index 0000000..ee5137f
--- /dev/null
+++ b/SBO-Lib/lib/SBO/Lib/Util.pm
@@ -0,0 +1,496 @@
+package SBO::Lib::Util;
+
+use 5.016;
+use strict;
+use warnings;
+
+our $VERSION = '2.0';
+
+use Exporter 'import';
+use Sort::Versions;
+
+my $consts;
+use constant $consts = {
+ _ERR_USAGE => 1, # usage errors
+ _ERR_SCRIPT => 2, # errors with the scripts themselves
+ _ERR_BUILD => 3, # errors during the slackbuild process
+ _ERR_MD5SUM => 4, # md5sum verification
+ _ERR_DOWNLOAD => 5, # errors with downloading things
+ _ERR_OPENFH => 6, # opening file handles
+ _ERR_NOINFO => 7, # missing information
+ _ERR_F_SETFD => 8, # unsetting exec-on-close bit
+ _ERR_NOMULTILIB => 9, # lacking multilib where required
+ _ERR_CONVERTPKG => 10, # errors while running convertpkg-compat32
+ _ERR_NOCONVERTPKG => 11, # lacking convertpkg-compat32 where required
+};
+
+my @EXPORT_CONSTS = keys %$consts;
+my @EXPORT_CONFIG = qw{
+ read_config
+
+ $conf_dir
+ $conf_file
+ %config
+};
+
+our @EXPORT_OK = (
+ qw{
+ check_multilib
+ get_arch
+ get_kernel_version
+ get_sbo_from_loc
+ get_slack_version
+ idx
+ in
+ indent
+ open_fh
+ open_read
+ print_failures
+ script_error
+ show_version
+ uniq
+ usage_error
+ version_cmp
+ },
+ @EXPORT_CONSTS,
+ @EXPORT_CONFIG,
+);
+
+our %EXPORT_TAGS = (
+ all => \@EXPORT_OK,
+ const => \@EXPORT_CONSTS,
+ config => \@EXPORT_CONFIG,
+);
+
+=head1 NAME
+
+SBO::Lib::Util - Utility functions for SBO::Lib and the sbotools
+
+=head1 SYNOPSIS
+
+ use SBO::Lib::Util qw/uniq/;
+
+ # ('duplicate');
+ my @uniq = uniq('duplicate', 'duplicate');
+
+=head1 VARIABLES
+
+=head2 $conf_dir
+
+By default, C<$conf_dir> will be C</etc/sbotools>.
+
+=head2 $conf_file
+
+By default, C<$conf_file> will be C</etc/sbotools/sbotools.conf>.
+
+=head2 %config
+
+By default, all values are set to C<"FALSE">, but when C<read_config()> is run,
+the values will change according to the configuration, and C<SBO_HOME> will by
+default get changed to C</usr/sbo>.
+
+The supported keys are: C<NOCLEAN>, C<DISTCLEAN>, C<JOBS>, C<PKG_DIR>,
+C<SBO_HOME>, C<LOCAL_OVERRIDES>, C<SLACKWARE_VERSION>, C<REPO>.
+
+=cut
+
+# global config variables
+our $conf_dir = '/etc/sbotools';
+our $conf_file = "$conf_dir/sbotools.conf";
+our %config = (
+ NOCLEAN => 'FALSE',
+ DISTCLEAN => 'FALSE',
+ JOBS => 'FALSE',
+ PKG_DIR => 'FALSE',
+ SBO_HOME => 'FALSE',
+ LOCAL_OVERRIDES => 'FALSE',
+ SLACKWARE_VERSION => 'FALSE',
+ REPO => 'FALSE',
+);
+
+read_config();
+
+=head1 SUBROUTINES
+
+=cut
+
+=head2 check_multilib
+
+ my $ml = check_multilib();
+
+C<check_multilib()> checks if the file C</etc/profile.d/32dev.sh> exists,
+because without it, there's no way to build 32bit things on an x64 arch.
+
+Returns a true value if it exists, and a false value otherwise.
+
+=cut
+
+# can't do 32-bit on x86_64 without this file, so we'll use it as the test to
+# to determine whether or not an x86_64 system is setup for multilib
+sub check_multilib {
+ return 1 if -f '/etc/profile.d/32dev.sh';
+ return();
+}
+
+=head2 get_arch
+
+ my $arch = get_arch();
+
+C<get_arch()> returns the current machine architechture as reported by C<uname
+-m>.
+
+=cut
+
+sub get_arch {
+ chomp(my $arch = `uname -m`);
+ return $arch;
+}
+
+=head2 get_kernel_version
+
+ my $kv = get_kernel_version();
+
+C<get_kernel_version()> will check what the version of the currently running
+kernel is and return it in a format suitable for appending to a slackware
+package version.
+
+=cut
+
+sub get_kernel_version {
+ state $kv;
+ return $kv if defined $kv;
+
+ chomp($kv = `uname -r`);
+ $kv =~ s/-/_/g;
+ return $kv;
+}
+
+=head2 get_sbo_from_loc
+
+ my $sbo = get_sbo_from_loc($location);
+
+C<get_sbo_from_loc()> gets the package name from the C<$location> passed in
+and returns it.
+
+=cut
+
+# pull the sbo name from a $location: $repo_path/system/wine, etc.
+sub get_sbo_from_loc {
+ script_error('get_sbo_from_loc requires an argument.') unless @_ == 1;
+ return (shift =~ qr#/([^/]+)$#)[0];
+}
+
+=head2 get_slack_version
+
+ my $version = get_slack_version();
+
+C<get_slack_version()> checks which version of the SBo repository to use and if
+successful, returns it.
+
+If there is an error in getting the slackware version, or if it's not a
+supported version, an error message will be shown on STDERR, and the program
+will exit.
+
+=cut
+
+# %supported maps what's in /etc/slackware-version to what's at SBo
+# which is now not needed since this version drops support < 14.0
+# but it's already future-proofed, so leave it.
+sub get_slack_version {
+ return $config{SLACKWARE_VERSION} unless $config{SLACKWARE_VERSION} eq 'FALSE';
+ my %supported = (
+ '14.0' => '14.0',
+ '14.1' => '14.1',
+ '14.2' => '14.2',
+ );
+ my ($fh, $exit) = open_read('/etc/slackware-version');
+ if ($exit) {
+ warn $fh;
+ exit $exit;
+ }
+ chomp(my $line = <$fh>);
+ close $fh;
+ my $version = ($line =~ /\s+(\d+[^\s]+)$/)[0];
+ usage_error("Unsupported Slackware version: $version\n")
+ unless $supported{$version};
+ return $supported{$version};
+}
+
+=head2 idx
+
+ my $idx = idx($needle, @haystack);
+
+C<idx()> looks for C<$needle> in C<@haystack>, and returns the index of where
+it was found, or C<undef> if it wasn't found.
+
+=cut
+
+sub idx {
+ for my $idx (1 .. $#_) {
+ $_[0] eq $_[$idx] and return $idx - 1;
+ }
+ return undef;
+}
+
+=head2 in
+
+ my $found = in($needle, @haystack);
+
+C<in()> looks for C<$needle> in C<@haystack>, and returns a true value if it
+was found, and a false value otherwise.
+
+=cut
+
+# Checks if the first argument equals any of the subsequent ones
+sub in {
+ my ($first, @rest) = @_;
+ foreach my $arg (@rest) {
+ return 1 if ref $arg eq 'Regexp' and $first =~ $arg;
+ return 1 if $first eq $arg;
+ }
+ return 0;
+}
+
+=head2 indent
+
+ my $str = indent($indent, $text);
+
+C<indent()> indents every non-empty line in C<$text> C<$indent> spaces and
+returns the resulting string.
+
+=cut
+
+sub indent {
+ my ($indent, $text) = @_;
+ return $text unless $indent;
+
+ my @lines = split /\n/, $text;
+ foreach my $line (@lines) {
+ next unless length($line);
+ $line = (" " x $indent) . $line;
+ }
+ return join "\n", @lines;
+}
+
+=head2 open_fh
+
+ my ($ret, $exit) = open_fh($fn, $op);
+
+C<open_fh()> will open C<$fn> for reading and/or writing depending on what
+C<$op> is.
+
+It returns a list of two values. The second value is the exit status, and if it
+is true, the first value will be an error message. Otherwise it will be the
+opened filehandle.
+
+=cut
+
+# sub for opening files, second arg is like '<','>', etc
+sub open_fh {
+ script_error('open_fh requires two arguments') unless @_ == 2;
+ unless ($_[1] eq '>') {
+ -f $_[0] or script_error("open_fh, $_[0] is not a file");
+ }
+ my ($file, $op) = @_;
+ my $fh;
+ _race::cond('$file could be deleted between -f test and open');
+ unless (open $fh, $op, $file) {
+ my $warn = "Unable to open $file.\n";
+ my $exit = _ERR_OPENFH;
+ return ($warn, $exit);
+ }
+ return $fh;
+}
+
+=head2 open_read
+
+ my ($ret, $exit) = open_read($fn);
+
+C<open_read()> will open C<$fn> for reading.
+
+It returns a list of two values. The second value is the exit status, and if it
+is true, the first value will be an error message. Otherwise it will be the
+opened filehandle.
+
+=cut
+
+sub open_read {
+ return open_fh(shift, '<');
+}
+
+=head2 print_failures
+
+ print_failures($failures);
+
+C<print_failures()> prints all the failures in the C<$failures> array reference
+to STDERR if any.
+
+There is no useful return value.
+
+=cut
+
+# subroutine to print out failures
+sub print_failures {
+ my $failures = shift;
+ if (@$failures > 0) {
+ warn "Failures:\n";
+ for my $failure (@$failures) {
+ warn " $_: $$failure{$_}" for keys %$failure;
+ }
+ }
+}
+
+=head2 read_config
+
+ read_config();
+
+C<read_config()> reads in the configuration settings from
+C</etc/sbotools/sbotools.conf> and updates the C<%config> hash with them.
+
+There is no useful return value.
+
+=cut
+
+# subroutine to suck in config in order to facilitate unit testing
+sub read_config {
+ my %conf_values;
+ if (-f $conf_file) {
+ _race::cond('$conf_file might not exist after -f');
+ my ($fh, $exit) = open_read($conf_file);
+ if ($exit) {
+ warn $fh;
+ $config{SBO_HOME} = '/usr/sbo';
+ return;
+ }
+ my $text = do {local $/; <$fh>};
+ %conf_values = $text =~ /^(\w+)=(.*)$/mg;
+ close $fh;
+ }
+ for my $key (keys %config) {
+ $config{$key} = $conf_values{$key} if exists $conf_values{$key};
+ }
+ $config{JOBS} = 'FALSE' unless $config{JOBS} =~ /^\d+$/;
+ $config{SBO_HOME} = '/usr/sbo' if $config{SBO_HOME} eq 'FALSE';
+}
+
+=head2 script_error
+
+ script_error();
+ script_error($msg);
+
+script_error() will warn and exit, saying on STDERR
+
+ A fatal script error has occurred. Exiting.
+
+If there was a $msg supplied, it will instead say
+
+ A fatal script error has occurred:
+ $msg.
+ Exiting.
+
+There is no useful return value.
+
+=cut
+
+# subroutine for throwing internal script errors
+sub script_error {
+ if (@_) {
+ warn "A fatal script error has occurred:\n$_[0]\nExiting.\n";
+ } else {
+ warn "A fatal script error has occurred. Exiting.\n";
+ }
+ exit _ERR_SCRIPT;
+}
+
+=head2 show_version
+
+ show_version();
+
+C<show_version()> will print out the sbotools version and licensing information
+to STDOUT.
+
+There is no useful return value.
+
+=cut
+
+sub show_version {
+ say "sbotools version $SBO::Lib::VERSION";
+ say 'licensed under the WTFPL';
+ say '<http://sam.zoy.org/wtfpl/COPYING>';
+}
+
+=head2 uniq
+
+ my @uniq = uniq(@duplicates);
+
+C<uniq()> removes the duplicates from C<@duplicates> but otherwise returns the
+list in the same order.
+
+=cut
+
+sub uniq {
+ my %seen;
+ return grep { !$seen{$_}++ } @_;
+}
+
+=head2 usage_error
+
+ usage_error($msg);
+
+usage_error will warn and exit, saying on STDERR
+
+ $msg
+
+There is no useful return value.
+
+=cut
+
+# subroutine for usage errors
+sub usage_error {
+ warn shift ."\n";
+ exit _ERR_USAGE;
+}
+
+=head2 version_cmp
+
+ my $cmp = version_cmp($ver1, $ver2);
+
+C<version_cmp()> will compare C<$ver1> with C<$ver2> to try to determine which
+is bigger than the other, and returns 1 if C<$ver1> is bigger, -1 if C<$ver2>
+is bigger, and 0 if they are just as big. Before making the comparison, it will
+strip off the version of your running kernel if it happens to be appended to
+the version string being compared.
+
+=cut
+
+# wrapper around versioncmp for checking if versions have kernel version
+# appended to them
+sub version_cmp {
+ my ($v1, $v2) = @_;
+ my $kv = get_kernel_version();
+
+ if ($v1 =~ /(.+)_\Q$kv\E$/) { $v1 = $1 }
+ if ($v2 =~ /(.+)_\Q$kv\E$/) { $v2 = $1 }
+
+ versioncmp($v1, $v2);
+}
+
+# _race::cond will allow both documenting and testing race conditions
+# by overriding its implementation for tests
+sub _race::cond { return }
+
+=head1 AUTHORS
+
+SBO::Lib was originally written by Jacob Pipkin <j@dawnrazor.net> with
+contributions from Luke Williams <xocel@iquidus.org> and Andreas
+Guldstrand <andreas.guldstrand@gmail.com>.
+
+=head1 LICENSE
+
+The sbotools are licensed under the WTFPL <http://sam.zoy.org/wtfpl/COPYING>.
+
+Copyright (C) 2012-2016, Jacob Pipkin, Luke Williams, Andreas Guldstrand.
+
+=cut
+
+1;