diff options
Diffstat (limited to 'SBO-Lib/lib/SBO/Lib')
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Util.pm | 496 | 
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; | 
