diff options
Diffstat (limited to 'SBO-Lib')
| -rw-r--r-- | SBO-Lib/MANIFEST | 18 | ||||
| -rw-r--r-- | SBO-Lib/Makefile.PL | 11 | ||||
| -rw-r--r-- | SBO-Lib/README | 45 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/App.pm | 26 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/App/Remove.pm | 224 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/App/Snap.pm | 95 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib.pm | 99 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Build.pm | 772 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Cryptography.pm | 213 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Download.pm | 299 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Info.pm | 234 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Pkgs.pm | 198 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Readme.pm | 220 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Repo.pm | 485 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Tree.pm | 161 | ||||
| -rw-r--r-- | SBO-Lib/lib/SBO/Lib/Util.pm | 566 | ||||
| -rw-r--r-- | SBO-Lib/lib/Sort/Versions.pm | 162 | ||||
| -rw-r--r-- | SBO-Lib/t/SBO-Lib.t | 18 | ||||
| -rwxr-xr-x | SBO-Lib/t/versions.t | 116 | 
19 files changed, 0 insertions, 3962 deletions
| diff --git a/SBO-Lib/MANIFEST b/SBO-Lib/MANIFEST deleted file mode 100644 index 8f05699..0000000 --- a/SBO-Lib/MANIFEST +++ /dev/null @@ -1,18 +0,0 @@ -Makefile.PL -MANIFEST -README -t/SBO-Lib.t -t/versions.t -lib/SBO/App.pm -lib/SBO/App/Remove.pm -lib/SBO/App/Snap.pm -lib/SBO/Lib.pm -lib/SBO/Lib/Build.pm -lib/SBO/Lib/Download.pm -lib/SBO/Lib/Info.pm -lib/SBO/Lib/Pkgs.pm -lib/SBO/Lib/Readme.pm -lib/SBO/Lib/Repo.pm -lib/SBO/Lib/Tree.pm -lib/SBO/Lib/Util.pm -lib/Sort/Versions.pm diff --git a/SBO-Lib/Makefile.PL b/SBO-Lib/Makefile.PL deleted file mode 100644 index 310724d..0000000 --- a/SBO-Lib/Makefile.PL +++ /dev/null @@ -1,11 +0,0 @@ -use 5.012003; -use ExtUtils::MakeMaker; -# See lib/ExtUtils/MakeMaker.pm for details of how to influence -# the contents of the Makefile that is written. -WriteMakefile( -    NAME              => 'SBO::Lib', -    VERSION_FROM      => 'lib/SBO/Lib.pm', -    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005 -      (ABSTRACT       => 'methods, variables, etc for the sbotools package', -       AUTHOR         => 'Slack Coder <slackcoder@server.ky>') : ()), -); diff --git a/SBO-Lib/README b/SBO-Lib/README deleted file mode 100644 index 63fd993..0000000 --- a/SBO-Lib/README +++ /dev/null @@ -1,45 +0,0 @@ -SBO-Lib version 2.8.0 -===================== - -SBO::Lib is a library for the sbotools scripts. - -INSTALLATION - -To install this module type the following: - -   perl Makefile.PL -   make -   make test -   make install - -DEPENDENCIES - -This module bundles Sort::Versions 1.62 which has its own license: - -   The files in this package are copyright Kenneth J. Albanowski, Ed -   Avis, and Matt Johnson.  This package is free software; you can -   redistribute it and/or modify it under the same terms as Perl itself. - -MIT License - -Copyright (c) 2012-2024 Luke Williams <xocel@iquidus.org>, Jacob Pipkin <j@dawnrazor.net>, Andreas Guldstrand <andreas.guldstrand@gmail.com> -Copyright (c) 2024 Slack Coder <slackcoder@server.ky> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/SBO-Lib/lib/SBO/App.pm b/SBO-Lib/lib/SBO/App.pm deleted file mode 100644 index d8de5c6..0000000 --- a/SBO-Lib/lib/SBO/App.pm +++ /dev/null @@ -1,26 +0,0 @@ -package SBO::App; - -# vim: ts=2:et -# -# authors: Luke Williams <xocel@iquidus.org> -#          Jacob Pipkin <j@dawnrazor.net> -#          Andreas Guldstrand <andreas.guldstrand@gmail.com> -# maintainer: Slack Coder <slackcoder@server.ky> - -use 5.16.0; -use strict; -use warnings FATAL => 'all'; -use File::Basename; - -our $VERSION = '2.8.0'; - -sub new { -  my $class = shift; - -  my $self = $class->_parse_opts(@_); -  $self->{fname} = basename( (caller(0))[1] ); - -  return bless $self, $class; -} - -1; diff --git a/SBO-Lib/lib/SBO/App/Remove.pm b/SBO-Lib/lib/SBO/App/Remove.pm deleted file mode 100644 index 7b0d27f..0000000 --- a/SBO-Lib/lib/SBO/App/Remove.pm +++ /dev/null @@ -1,224 +0,0 @@ -package SBO::App::Remove; - -# vim: ts=2:et -# -# authors: Luke Williams <xocel@iquidus.org> -#          Jacob Pipkin <j@dawnrazor.net> -#          Andreas Guldstrand <andreas.guldstrand@gmail.com> -# maintainer: Slack Coder <slackcoder@server.ky> - -use 5.16.0; -use strict; -use warnings FATAL => 'all'; -use SBO::Lib qw/ _ERR_USAGE get_inst_names get_installed_packages get_sbo_location get_build_queue merge_queues get_requires get_readme_contents prompt show_version in /; -use Getopt::Long qw(GetOptionsFromArray :config bundling); - -use parent 'SBO::App'; - -our $VERSION = '2.8.0'; - -sub _parse_opts { -  my $class = shift; -  my @ARGS = @_; - -  my ($help, $vers, $non_int, $alwaysask); - -  GetOptionsFromArray( -    \@ARGS, -    'help|h'        => \$help, -    'version|v'     => \$vers, -    'nointeractive' => \$non_int, -    'alwaysask|a'   => \$alwaysask, -  ); - -  return { help => $help, vers => $vers, non_int => $non_int, alwaysask => $alwaysask, args => \@ARGS, }; -} - -sub run { -  my $self = shift; - -  if ($self->{help}) { $self->show_usage(); return 0; } -  if ($self->{vers}) { $self->show_version(); return 0; } -  if (!@{ $self->{args} }) { $self->show_usage(); return 1; } - -  unless ($< == 0) { -  	warn "This script requires root privileges.\n"; -  	exit _ERR_USAGE; -  } - -  # current workflow: -  # * get names of all installed SBo packages -  # * compare commandline args to SBo packages as well as installed SBo packages -  # * add reverse deps to list if they're not a dep of something else (which is not also already on the list) -  # * confirm removal of each package on the list -  #   - while taking into account the options passed in such as $non_int, and $alwaysask -  #   - also offering to display README if %README% is passed -  # * remove the confirmed packages - -  my @args = @{ $self->{args} }; - -  my @installed = @{ get_installed_packages('SBO') }; -  my $installed = +{ map {; $_->{name}, $_->{pkg} } @installed }; - -  @args = grep { check_sbo($_, $installed) } @args; -  exit 1 unless @args; -  my %sbos = map { $_ => 1 } @args; - -  my @remove = get_full_queue($installed, @args); - -  my @confirmed; - -  if ($self->{non_int}) { -    @confirmed = @remove; -  } else { -    my $required_by = get_reverse_reqs($installed); -    for my $remove (@remove) { -      # if $remove was on the commandline, mark it as not needed, -      # otherwise check if it is needed by something else. -      my @required_by = get_required_by($remove->{name}, [map { $_->{name} } @confirmed], $required_by); -      my $needed = $sbos{$remove->{name}} ? 0 : @required_by; - -      next if $needed and not $self->{alwaysask}; - -      push @confirmed, $remove if confirm($remove, $needed ? @required_by : ()); -    } -  } - -  if (@confirmed) { -    $self->remove(@confirmed); -  } else { -    say "Nothing to remove."; -  } - -  return 0; -} - -sub show_usage { -  my $self = shift; -  my $fname = $self->{fname}; - -	print <<"EOF"; -Usage: $fname [options] sbo - -Options (defaults shown first where applicable): -  -h|--help: -    this screen. -  -v|--version: -    version information. -  -a|--alwaysask: -    always ask to remove, even if required by other packages on system. - -Note: optional dependencies need to be removed separately. - -EOF -	return 1; -} - -sub check_sbo { -  my ($sbo, $installed) = @_; - -  if (not get_sbo_location($sbo)) { -    say "Unable to locate $sbo in the SlackBuilds.org tree."; -    return 0; -  } - -  if (not exists $installed->{$sbo}) { -    say "$sbo is not installed from SlackBuilds.org."; -    return 0; -  } - -  return 1; -} - -sub get_full_queue { -  my ($installed, @sbos) = @_; - -  my $remove_queue = []; -  my %warnings; -  for my $sbo (@sbos) { -    my $queue = get_build_queue([$sbo], \%warnings); -    @$queue = reverse @$queue; -    $remove_queue = merge_queues($remove_queue, $queue); -  } - -  return map {; +{ -      name => $_, -      pkg => $installed->{$_}, -      defined $warnings{$_} ? (warning => $warnings{$_}) : () -    } } -    grep { exists $installed->{$_} } -    @$remove_queue; -} - -sub get_reverse_reqs { -  my $installed = shift; -  my %required_by; - -  for my $inst (keys %$installed) { -    for my $req (@{ get_requires($inst) }) { -      $required_by{$req}{$inst} = 1 if exists $installed->{$req}; -    } -  } - -  return \%required_by; -} - -sub get_required_by { -  my ($sbo, $confirmed, $required_by) = @_; -  my @dep_of; - -  if ( $required_by->{$sbo} ) { -    for my $req_by (keys %{$required_by->{$sbo}}) { -      push @dep_of, $req_by unless in($req_by => @$confirmed); -    } -  } -  return @dep_of; -} - -sub confirm { -  my ($remove, @required_by) = @_; - -  if (@required_by) { -    say sprintf "%s : required by %s", $remove->{name}, join ' ', @required_by; -  } else { -    say $remove->{name}; -  } - -  if ($remove->{warning}) { -    say "It is recommended that you view the README before continuing."; -    if (prompt("Display README now?", default => 'yes')) { -      my $readme = get_readme_contents(get_sbo_location($remove->{name})); -      if (not defined $readme) { -        warn "Unable to open README for $remove->{name}.\n"; -      } else { -        print "\n" . $readme; -      } -    } -  } - -  if (prompt("Remove $remove->{name}?", default => @required_by ? 'no' : 'yes')) { -    say " * Added to remove queue\n"; -    return 1; -  } -  say " * Ignoring\n"; -  return 0; -} - -sub remove { -  my $self = shift; -  my $non_int = $self->{non_int}; -  my @confirmed = @_; - -  say sprintf "Removing %d package(s)", scalar @confirmed; -  say join " ", map { $_->{name} } @confirmed; - -  if (!$non_int and !prompt("\nAre you sure you want to continue?", default => 'no')) { -    return say 'Exiting.'; -  } - -  system("/sbin/removepkg", $_->{pkg}) for @confirmed; - -  say "All operations have completed successfully."; -} - -1; diff --git a/SBO-Lib/lib/SBO/App/Snap.pm b/SBO-Lib/lib/SBO/App/Snap.pm deleted file mode 100644 index 64487d7..0000000 --- a/SBO-Lib/lib/SBO/App/Snap.pm +++ /dev/null @@ -1,95 +0,0 @@ -package SBO::App::Snap; - -# vim: ts=2:et -# -# sbosnap -# script to pull down / update a local copy of the slackbuilds.org tree. -# -# authors: Jacob Pipkin <j@dawnrazor.net> -#          Luke Williams <xocel@iquidus.org> -#          Andreas Guldstrand <andreas.guldstrand@gmail.com> -# maintainer: Slack Coder <slackcoder@server.ky> - -use 5.16.0; -use strict; -use warnings FATAL => 'all'; -use SBO::Lib qw/ _ERR_USAGE fetch_tree import_gpg_key update_tree %config show_version /; -use Getopt::Long qw/ GetOptionsFromArray /; - -use parent 'SBO::App'; - -our $VERSION = '2.8.0'; - -sub _parse_opts { -  my $class = shift; -  my @ARGS = @_; - -  my ($help, $vers); - -  GetOptionsFromArray( -    \@ARGS, -    'help|h' => \$help, -    'version|v' => \$vers, -  ); - -  return { help => $help, vers => $vers, args => \@ARGS, }; -} - -sub show_usage { -  my $self = shift; -  my $fname = $self->{fname}; -  print <<"EOF"; -Usage: $fname [options|command] - -Options: -  -h|--help: -    this screen. -  -v|--version: -    version information. - -Commands: -  fetch: initialize a local copy of the slackbuilds.org tree. -  import-key [path or url]: import GPG for verifying the slackbuilds.org tree. Defaults to the key shipped with sbotools2. -  update: update an existing local copy of the slackbuilds.org tree. -          (generally, you may prefer "sbocheck" over "$fname update") - -EOF -	return 1; -} - -sub run { -  my $self = shift; -  my @args = @{ $self->{args} }; - -  if ($self->{help}) { $self->show_usage(); return 0 } -  if ($self->{vers}) { $self->show_version(); return 0 } - -  unless ($< == 0) { -  	warn "This script requires root privileges.\n"; -  	exit _ERR_USAGE; -  } - -  # check for a command and, if found, execute it -  $args[0] //= ''; - -  if ($args[0] eq 'fetch') { -    fetch_tree(); -  } elsif ($args[0] eq 'import-key') { -    my $key_path_or_url = "/usr/doc/sbotools2-$VERSION/slackbuilds-devel\@slackbuilds.org.asc"; -    if ($args[1]) { -      $key_path_or_url = $args[1]; -    } -    my $key_id = $config{'GPG_KEY'}; - -    import_gpg_key($key_path_or_url, $key_id); -  } elsif ($args[0] eq 'update') { -    update_tree(); -  } else { -    $self->show_usage(); -    return 1; -  } - -  return 0; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib.pm b/SBO-Lib/lib/SBO/Lib.pm deleted file mode 100644 index b249dc6..0000000 --- a/SBO-Lib/lib/SBO/Lib.pm +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env perl -# -# vim: set ts=4:noet -# -# Lib.pm -# shared functions for the sbo_ scripts. -# -use 5.16.0; -use strict; -use warnings FATAL => 'all'; - -package SBO::Lib; -our $VERSION = '2.8.0'; - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib - Library for working with SlackBuilds.org. - -=head1 SYNOPSIS - -  use SBO::Lib qw/ :all /; - -=head1 DESCRIPTION - -SBO::Lib is the entry point for all the related modules, and is simply re- -exporting all of their exports. - -=head1 SEE ALSO - -=over - -=item L<SBO::Lib::Cryptography> - -=item L<SBO::Lib::Util> - -=item L<SBO::Lib::Info> - -=item L<SBO::Lib::Repo> - -=item L<SBO::Lib::Tree> - -=item L<SBO::Lib::Pkgs> - -=item L<SBO::Lib::Build> - -=item L<SBO::Lib::Readme> - -=item L<SBO::Lib::Download> - -=back - -=cut - -use SBO::Lib::Cryptography qw/ :all /; -use SBO::Lib::Util qw/ :all /; -use SBO::Lib::Info qw/ :all /; -use SBO::Lib::Repo qw/ :all /; -use SBO::Lib::Tree qw/ :all /; -use SBO::Lib::Pkgs qw/ :all /; -use SBO::Lib::Build qw/:all /; -use SBO::Lib::Readme qw/ :all /; -use SBO::Lib::Download qw/ :all /; - -use Exporter 'import'; - -our @EXPORT_OK = ( -	@SBO::Lib::Cryptography::EXPORT_OK, -	@SBO::Lib::Util::EXPORT_OK, -	@SBO::Lib::Info::EXPORT_OK, -	@SBO::Lib::Repo::EXPORT_OK, -	@SBO::Lib::Tree::EXPORT_OK, -	@SBO::Lib::Pkgs::EXPORT_OK, -	@SBO::Lib::Build::EXPORT_OK, -	@SBO::Lib::Readme::EXPORT_OK, -	@SBO::Lib::Download::EXPORT_OK, -); - -our %EXPORT_TAGS = ( -	all => \@EXPORT_OK, -	cryptography => \@SBO::Lib::Cryptography::EXPORT_OK, -	util => \@SBO::Lib::Util::EXPORT_OK, -	info => \@SBO::Lib::Info::EXPORT_OK, -	repo => \@SBO::Lib::Repo::EXPORT_OK, -	tree => \@SBO::Lib::Tree::EXPORT_OK, -	pkgs => \@SBO::Lib::Pkgs::EXPORT_OK, -	build => \@SBO::Lib::Build::EXPORT_OK, -	readme => \@SBO::Lib::Readme::EXPORT_OK, -	download => \@SBO::Lib::Download::EXPORT_OK, -	const => $SBO::Lib::Util::EXPORT_TAGS{const}, -	config => $SBO::Lib::Util::EXPORT_TAGS{config}, -); - -'ok'; - -__END__ diff --git a/SBO-Lib/lib/SBO/Lib/Build.pm b/SBO-Lib/lib/SBO/Lib/Build.pm deleted file mode 100644 index 4a86e4d..0000000 --- a/SBO-Lib/lib/SBO/Lib/Build.pm +++ /dev/null @@ -1,772 +0,0 @@ -package SBO::Lib::Build; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ :const prompt script_error get_sbo_from_loc get_arch check_multilib uniq %config in /; -use SBO::Lib::Tree qw/ get_sbo_location /; -use SBO::Lib::Info qw/ get_sbo_version check_x32 get_requires /; -use SBO::Lib::Download qw/ get_sbo_downloads get_dl_fns get_filename_from_link check_distfiles /; - -use Exporter 'import'; -use Fcntl qw(F_SETFD F_GETFD); -use File::Copy; # copy() and move() -use File::Path qw/ make_path remove_tree /; -use File::Temp qw/ tempdir tempfile /; -use Tie::File; -use Cwd; - -our @EXPORT_OK = qw{ -  do_convertpkg -  do_slackbuild -  do_upgradepkg -  get_build_queue -  get_dc_regex -  get_pkg_name -  get_src_dir -  get_tmp_extfn -  make_clean -  make_distclean -  merge_queues -  perform_sbo -  process_sbos -  revert_slackbuild -  rewrite_slackbuild -  run_tee - -  $tmpd -  $env_tmp -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Build - Routines for building slackware packages from SlackBuilds.org. - -=head1 SYNOPSIS - -  use SBO::Lib::Build qw/ perform_sbo /; - -  my ($foo, $bar, $exit) = perform_sbo(LOCATION => $location, ARCH => 'x86_64'); - -=head1 VARIABLES - -=head2 $env_tmp - -This will reflect the C<$TMP> from the environment, being C<undef> if it is not -set. - -=head2 $tmpd - -Will be the same as C<$TMP> if it is set, otherwise it will be C</tmp/SBo>. - -=cut - -# get $TMP from the env, if defined - we use two variables here because there -# are times when we need to know if the environment variable is set, and other -# times where it doesn't matter. -our $env_tmp = $ENV{TMP}; -our $tmpd = $env_tmp ? $env_tmp : '/tmp/SBo'; -make_path($tmpd) unless -d $tmpd; - -=head1 SUBROUTINES - -=cut - -=head2 do_convertpkg - -  my ($name32, $exit) = do_convertpkg($name64); - -C<do_convertpkg()> runs C<convertpkg> on the package in C<$name64>. - -It returns two values. If the second value is true, the first will contain an -error message. Otherwise it will contain the name of the converted package. - -=cut - -# run convertpkg on a package to turn it into a -compat32 thing -sub do_convertpkg { -  script_error('do_convertpkg requires an argument.') unless @_ == 1; -  my $pkg = shift; -  my $c32tmpd = $env_tmp // '/tmp'; - -  my ($out, $ret) = run_tee("/bin/bash -c '/usr/sbin/convertpkg-compat32 -i $pkg -d $c32tmpd'"); - -  if ($ret != 0) { -    return "convertpkg-compt32 returned non-zero exit status\n", -      _ERR_CONVERTPKG; -  } -  unlink $pkg; -  return get_pkg_name($out); -} - -=head2 do_slackbuild - -  my ($ver, $pkg, $src, $exit) = do_slackbuild(LOCATION => $location); - -C<do_slackbuild()> will make some checks and set up the C<perform_sbo()> call, -if needed run C<do_convertpkg()>, and return the results. - -It will return a list of four values. If the fourth one is a true value, the -first one will be an error message. Otherwise the first will be the version, -the second will be the package, and the third will be an array reference to the -source directories created by the build. - -=cut - -# "public interface", sort of thing. -sub do_slackbuild { -  my %args = ( -    OPTS      => 0, -    JOBS      => 0, -    LOCATION  => '', -    COMPAT32  => 0, -    @_ -  ); -  $args{LOCATION} or script_error('do_slackbuild requires LOCATION.'); -  my $location = $args{LOCATION}; -  my $sbo = get_sbo_from_loc($location); -  my $arch = get_arch(); -  my $multilib = check_multilib(); -  my $version = get_sbo_version($location); -  my $x32; -  # ensure x32 stuff is set correctly, or that we're setup for it -  if ($args{COMPAT32}) { -    unless ($multilib) { -      return "compat32 requires multilib.\n", (undef) x 2, -        _ERR_NOMULTILIB; -    } -    unless (-f '/usr/sbin/convertpkg-compat32') { -      return "compat32 requires /usr/sbin/convertpkg-compat32.\n", -        (undef) x 2, _ERR_NOCONVERTPKG; -    } -  } else { -    if ($arch eq 'x86_64') { -      $x32 = check_x32 $args{LOCATION}; -      if ($x32 && ! $multilib) { -        my $warn = -          "$sbo is 32-bit which requires multilib on x86_64.\n"; -        return $warn, (undef) x 2, _ERR_NOMULTILIB; -      } -    } -  } -  # setup and run the .SlackBuild itself -  my ($pkg, $src, $exit) = perform_sbo( -    OPTS => $args{OPTS}, -    JOBS => $args{JOBS}, -    LOCATION => $location, -    ARCH => $arch, -    C32 => $args{COMPAT32}, -    X32 => $x32, -  ); -  return $pkg, (undef) x 2, $exit if $exit; -  if ($args{COMPAT32}) { -    ($pkg, $exit) = do_convertpkg($pkg); -    return $pkg, (undef) x 2, $exit if $exit; -  } -  return $version, $pkg, $src; -} - -=head2 do_upgradepkg - -  do_upgradepkg($pkg); - -C<do_upgradepkg()> runs C<upgradepkg> on C<$pkg>. - -There is no useful return value. - -=cut - -# run upgradepkg for a created package -sub do_upgradepkg { -  script_error('do_upgradepkg requires an argument.') unless @_ == 1; -  system('/sbin/upgradepkg', '--reinstall', '--install-new', shift); -  return 1; -} - -=head2 get_build_queue - -  my @queue = @{ get_build_queue($sbo, my $warnings) }; - -C<get_build_queue()> gets the prerequisites for C<$sbo>, and updates the -C<$warnings> hash reference with any C<%README%> encountered. It returns the -prerequisites and the C<$sbo> in the order in which they need to be built. - -=cut - -sub get_build_queue { -  script_error('get_build_queue requires two arguments.') unless @_ == 2; -  return [ _build_queue(@_) ]; -} - -=head2 get_dc_regex - -  my ($rx, $initial) = get_dc_regex($line); - -C<get_dc_regex()> when given a line that is an untar or similar command, creates -a regular expression which should match the filename. This is returned, together -with the C<$initial> character which will start the filename match. - -=cut - -# given a line that looks like it's decompressing something, try to return a -# valid filename regex -sub get_dc_regex { -  my $line = shift; -  # get rid of initial 'tar x'whatever stuff -  $line =~ s/^.*(?<![a-z])(tar|p7zip|unzip|ar|rpm2cpio|sh)\s+[^\s]+\s+//; -  # need to know preceeding character - should be safe to assume it's either -  # a slash or a space -  my $initial = $line =~ qr|/| ? '/' : ' '; -  # get rid of initial path info -  $line =~ s|^\$[^/]+/||; -  # convert any instances of command substitution to [^-]+ -  $line =~ s/\$\([^)]+\)/[^-]+/g; -  # convert any bash variables to [^-]+ -  $line =~ s/\$(\{|)[A-Za-z0-9_]+(}|)/[^-]+/g; -  # get rid of anything excess at the end -  $line =~ s/\s+.*$//; -  # fix .?z* at the end -  $line =~ s/\.\?z\*/\.[a-z]z.*/; -  # return what's left as a regex -  my $regex = qr/$initial$line/; -  return $regex, $initial; -} - -=head2 get_pkg_name - -  my $name = get_pkg_name($str); - -C<get_pkg_name()> searches C<$str> for text matching the output of C<makepkg> -where it outputs the filename of the package it made, and returns it. - -=cut - -# pull the created package name from the temp file we tee'd to -sub get_pkg_name { -  my $str = shift; - -  my ($out) = $str =~ m/^Slackware\s+package\s+([^\s]+)\s+created\.$/m; - -  return $out; -} - -=head2 get_src_dir - -  my @dirs = @{ get_src_dir(@orig_dirs) }; - -C<get_src_dir()> returns a list of the directories under C</tmp/SBo> or C<$TMP> -that aren't in @orig_dirs. - -=cut - -sub get_src_dir { -  my @ls = @_; -  my @src_dirs; -  # scripts use either $TMP or /tmp/SBo -  if (opendir(my $tsbo_dh, $tmpd)) { -    FIRST: while (my $ls = readdir $tsbo_dh) { -      next FIRST if in($ls => qw/ . .. /, qr/^package-/, @ls); -      next FIRST unless -d "$tmpd/$ls"; - -      push @src_dirs, $ls; -    } -    close $tsbo_dh; -  } -  return \@src_dirs; -} - -=head2 get_tmp_extfn - -  my ($ret, $exit) = get_tmp_extfn($fh); - -C<get_tmp_extfn()> gets the filename in the form of C</dev/fd/X> for the C<$fh> -passed in, setting flags on it that make it usable from other processes without -messing things up. - -It returns the filename if successful, otherwise it returns C<undef>. - -=cut - -# return a filename from a temp fh for use externally -sub get_tmp_extfn { -  script_error('get_tmp_extfn requires an argument.') unless @_ == 1; -  my $fh = shift; -  unless (fcntl($fh, F_SETFD, 0)) { return undef; } -  return '/dev/fd/'. fileno $fh; -} - -=head2 make_clean - -  make_clean(SBO => $sbo, SRC => $src, VERSION => $ver); - -C<make_clean()> removes source directories, package directories, and compat32 -directories that are left over from a slackbuild run. - -It has no useful return value. - -=cut - -# remove work directories (source and packaging dirs under /tmp/SBo or $TMP and /tmp or $OUTPUT) -sub make_clean { -  my %args = ( -    SBO      => '', -    SRC      => '', -    VERSION  => '', -    @_ -  ); -  unless ($args{SBO} && $args{SRC} && $args{VERSION}) { -    script_error('make_clean requires three arguments.'); -  } -  my $src = $args{SRC}; -  say "Cleaning for $args{SBO}-$args{VERSION}..."; -  for my $dir (@$src) { -    remove_tree("$tmpd/$dir") if -d "$tmpd/$dir"; -  } - -  my $output = $ENV{OUTPUT} // '/tmp'; -  remove_tree("$output/package-$args{SBO}") if -    -d "$output/package-$args{SBO}"; - -  if ($args{SBO} =~ /^(.+)-compat32$/) { -    my $pkg_name = $1; -    remove_tree("/tmp/package-$args{SBO}") if -      not defined $env_tmp and -      -d "/tmp/package-$args{SBO}"; -    remove_tree("$tmpd/package-$pkg_name") if -      -d "$tmpd/package-$pkg_name"; -  } -  return 1; -} - -=head2 make_distclean - -  make_distclean(SRC => $src, VERSION => $ver, LOCATION => $loc); - -C<make_distclean()> does everything C<make_clean()> does, but in addition it -also removes distribution files, such as the downloaded source tarballs. - -It has no useful return value. - -=cut - -# remove distfiles -sub make_distclean { -  my %args = ( -    SRC       => '', -    VERSION   => '', -    LOCATION  => '', -    @_ -  ); -  unless ($args{SRC} && $args{VERSION} && $args{LOCATION}) { -    script_error('make_distclean requires four arguments.'); -  } -  my $sbo = get_sbo_from_loc($args{LOCATION}); -  make_clean(SBO => $sbo, SRC => $args{SRC}, VERSION => $args{VERSION}); -  say "Distcleaning for $sbo-$args{VERSION}..."; -  # remove any distfiles for this particular SBo. -  my $downloads = get_sbo_downloads(LOCATION => $args{LOCATION}); -  for my $key (keys %$downloads) { -    my $filename = get_filename_from_link($key); -    unlink $filename if -f $filename; -  } -  return 1; -} - -=head2 merge_queues - -  my @merged = @{ merge_queues([@queue1], [@queue2]) }; - -C<merge_queues> takes two array references and merges them with C<@queue1> in -front, and then anything in C<@queue2> that wasn't already in C<@queue1>. This -is then returned as an array reference. - -=cut - -sub merge_queues { -  # Usage: merge_queues(\@queue_a, \@queue_b); -  # Results in queue_b being merged into queue_a (without duplicates) -  script_error('merge_queues requires two arguments.') unless @_ == 2; - -  return [ uniq @{$_[0]}, @{$_[1]} ]; -} - -=head2 perform_sbo - -  my ($pkg, $src, $exit) = perform_sbo(LOCATION => $location, ARCH => $arch); - -C<perform_sbo()> preps and runs a .SlackBuild. It returns a list of three -values, and if the third one is a true value, the first one will be an error -message. Otherwise the first one will be the package name that was built, and -the second one will be an array reference containing the source directories -that were created. - -=cut - -# prep and run .SlackBuild -sub perform_sbo { -  my %args = ( -    OPTS      => 0, -    JOBS      => 0, -    LOCATION  => '', -    ARCH      => '', -    C32       => 0, -    X32       => 0, -    @_ -  ); -  unless ($args{LOCATION} && $args{ARCH}) { -    script_error('perform_sbo requires LOCATION and ARCH.'); -  } - -  my $location = $args{LOCATION}; -  my $sbo = get_sbo_from_loc($location); - -  # we need to get a listing of /tmp/SBo, or $TMP, if we can, before we run -  # the SlackBuild so that we can compare to a listing taken afterward. -  my @src_ls; -  if (opendir(my $tsbo_dh, $tmpd)) { -    @src_ls = grep { ! in( $_ => qw/ . .. /) } readdir $tsbo_dh; -  } - -  my ($cmd, %changes); -  # set any changes we need to make to the .SlackBuild, setup the command - -  $cmd = ''; - -  if ($args{ARCH} eq 'x86_64' and ($args{C32} || $args{X32})) { -    if ($args{C32}) { -      $changes{libdirsuffix} = ''; -    } elsif ($args{X32}) { -      $changes{arch_out} = 'i486'; -    } -    $cmd .= '. /etc/profile.d/32dev.sh &&'; -  } -  if ($args{JOBS} and $args{JOBS} ne 'FALSE') { -    $changes{jobs} = 1; -  } -  $cmd .= " $args{OPTS}" if $args{OPTS}; -  $cmd .= " MAKEOPTS=\"-j$args{JOBS}\"" if $changes{jobs}; - -  # set TMP/OUTPUT if set in the environment -  $cmd .= " TMP=$env_tmp" if $env_tmp; -  $cmd .= " OUTPUT=$ENV{OUTPUT}" if defined $ENV{OUTPUT}; -  $cmd .= " /bin/bash $location/$sbo.SlackBuild"; - -  # attempt to rewrite the slackbuild, or exit if we can't -  my ($fail, $exit) = rewrite_slackbuild( -    SBO => $sbo, -    SLACKBUILD => "$location/$sbo.SlackBuild", -    CHANGES => \%changes, -    C32 => $args{C32}, -  ); -  return $fail, undef, $exit if $exit; - -  # run the slackbuild, grab its exit status, revert our changes -  my $cwd = getcwd(); -  chdir $location; -  my ($out, $ret) = run_tee($cmd); -  chdir $cwd; - -  revert_slackbuild("$location/$sbo.SlackBuild"); -  # return error now if the slackbuild didn't exit 0 -  return "$sbo.SlackBuild return non-zero\n", undef, _ERR_BUILD if $ret != 0; -  my $pkg = get_pkg_name($out); -  return "$sbo.SlackBuild didn't create a package\n", undef, _ERR_BUILD if not defined $pkg; -  my $src = get_src_dir(@src_ls); -  return $pkg, $src; -} - -=head2 process_sbos - -  my ($failures, $exit) = process_sbos(TODO => [@queue]); - -C<process_sbos()> processes the C<@queue> of slackbuilds and returns a list of -two values containing any failed builds in an array ref in the first value, and -the exit status in the second. - -=cut - -# do the things with the provided sbos - whether upgrades or new installs. -sub process_sbos { -  my %args = ( -    TODO       => '', -    CMDS       => '', -    OPTS       => '', -    JOBS       => 'FALSE', -    LOCATIONS  => '', -    NOINSTALL  => 0, -    NOCLEAN    => 'FALSE', -    DISTCLEAN  => 'FALSE', -    NON_INT    => 0, -    @_ -  ); -  my $todo = $args{TODO}; -  my $cmds = $args{CMDS}; -  my $opts = $args{OPTS}; -  my $locs = $args{LOCATIONS}; -  my $jobs = $args{JOBS} =~ /^\d+$/ ? $args{JOBS} : 0; -  @$todo >= 1 or script_error('process_sbos requires TODO.'); -  my (@failures, @symlinks, $err); -  FIRST: for my $sbo (@$todo) { -    my $compat32 = $sbo =~ /-compat32$/ ? 1 : 0; -    my ($temp_syms, $exit) = check_distfiles( -      LOCATION => $$locs{$sbo}, COMPAT32 => $compat32 -    ); -    # if $exit is defined, prompt to proceed or return with last $exit -    if ($exit) { -      $err = $exit; -      my $fail = $temp_syms; -      push @failures, {$sbo => $fail}; -      # return now if we're not interactive -      return \@failures, $exit if $args{NON_INT}; -      say "Unable to download/verify source file(s) for $sbo:"; -      say "  $fail"; -      if (prompt('Do you want to proceed?' , default => 'no')) { -        next FIRST; -      } else { -        unlink for @symlinks; -        return \@failures, $exit; -      } -    } else { -      push @symlinks, @$temp_syms; -    } -  } -  my $count = 0; -  FIRST: for my $sbo (@$todo) { -    $count++; -    my $options = $$opts{$sbo} // 0; -    my $cmds = $$cmds{$sbo} // []; -    for my $cmd (@$cmds) { -      system($cmd) == 0 or warn "\"$cmd\" exited non-zero\n"; -    } -    # switch compat32 on if upgrading/installing a -compat32 -    # else make sure compat32 is off -    my $compat32 = $sbo =~ /-compat32$/ ? 1 : 0; -    my ($version, $pkg, $src, $exit) = do_slackbuild( -      OPTS      => $options, -      JOBS      => $jobs, -      LOCATION  => $$locs{$sbo}, -      COMPAT32  => $compat32, -    ); -    if ($exit) { -      my $fail = $version; -      push @failures, {$sbo => $fail}; -      # return now if we're not interactive -      return \@failures, $exit if $args{NON_INT}; -      # or if this is the last $sbo -      return \@failures, $exit if $count == @$todo; -      say "Failure encountered while building $sbo:"; -      say "  $fail"; -      if (prompt('Do you want to proceed?', default => 'no')) { -        next FIRST; -      } else { -        unlink for @symlinks; -        return \@failures, $exit; -      } -    } - -    do_upgradepkg($pkg) unless $args{NOINSTALL}; - -    unless ($args{DISTCLEAN}) { -      make_clean(SBO => $sbo, SRC => $src, VERSION => $version) -        unless $args{NOCLEAN}; -    } else { -      make_distclean( -        SBO       => $sbo, -        SRC       => $src, -        VERSION   => $version, -        LOCATION  => $$locs{$sbo}, -      ); -    } -    # move package to $config{PKG_DIR} if defined -    unless ($config{PKG_DIR} eq 'FALSE') { -      my $dir = $config{PKG_DIR}; -      unless (-d $dir) { -        mkdir($dir) or warn "Unable to create $dir\n"; -      } -      if (-d $dir) { -        move($pkg, $dir), say "$pkg stored in $dir"; -      } else { -        warn "$pkg left in $tmpd\n"; -      } -    } elsif ($args{DISTCLEAN}) { -      unlink $pkg; -    } -  } -  unlink for @symlinks; -  return \@failures, $err; -} - -=head2 revert_slackbuild - -  revert_slackbuild($path); - -C<revert_slackbuild()> moves back a slackbuild that was rewritten by -C<rewrite_slackbuild()>. - -There is no useful return value. - -=cut - -# move a backed-up .SlackBuild file back into place -sub revert_slackbuild { -  script_error('revert_slackbuild requires an argument') unless @_ == 1; -  my $slackbuild = shift; -  if (-f "$slackbuild.orig") { -    unlink $slackbuild if -f $slackbuild; -    rename "$slackbuild.orig", $slackbuild; -  } -  return 1; -} - -=head2 rewrite_slackbuild - -  my ($ret, $exit) = rewrite_slackbuild(SLACKBUILD => $path); - -C<rewrite_slackbuild()> when given a path and some changes to make, will move -and copy the C<$path> and rewrite the copy with the needed changes. - -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. - -=cut - -# make a backup of the existent SlackBuild, and rewrite the original as needed -sub rewrite_slackbuild { -  my %args = ( -    SBO         => '', -    SLACKBUILD  => '', -    CHANGES     => {}, -    C32         => 0, -    @_ -  ); -  $args{SLACKBUILD} or script_error('rewrite_slackbuild requires SLACKBUILD.'); -  my $slackbuild = $args{SLACKBUILD}; -  my $changes = $args{CHANGES}; - -  # $status will be undefined if either the rename or the copy fails, otherwise it will be 1 -  my $status = eval { -    rename($slackbuild, "$slackbuild.orig") or die "not ok"; -    copy("$slackbuild.orig", $slackbuild) or die "not ok"; -    1; -  }; -  if (not $status) { -    rename "$slackbuild.orig", $slackbuild if not -f $slackbuild; -    return "Unable to backup $slackbuild to $slackbuild.orig\n", -      _ERR_OPENFH; -  } - -  my $libdir_regex = qr/^\s*LIBDIRSUFFIX="64"\s*$/; -  my $arch_regex = qr/\$VERSION-\$ARCH-\$BUILD/; -  my $dc_regex = qr/(?<![a-z])(tar|p7zip|unzip|ar|rpm2cpio|sh)\s+/; -  my $make_regex = qr/^\s*make\s*$/; -  # tie the slackbuild, because this is the easiest way to handle this. -  tie my @sb_file, 'Tie::File', $slackbuild; -  # if we're dealing with a compat32, we need to change the tar line(s) so -  # that the 32-bit source is untarred -  if ($args{C32}) { -    my $location = get_sbo_location($args{SBO}); -    my $downloads = get_sbo_downloads( -      LOCATION => $location, -      32 => 1, -    ); -    my $fns = get_dl_fns([keys %$downloads]); -    for my $line (@sb_file) { -      if ($line =~ $dc_regex) { -        my ($regex, $initial) = get_dc_regex($line); -        for my $fn (@$fns) { -          $fn = "$initial$fn"; -          $line =~ s/$regex/$fn/ if $fn =~ $regex; -        } -      } -    } -  } -  for my $line (@sb_file) { -    # then check for and apply any other %$changes -    if (exists $$changes{libdirsuffix}) { -      $line =~ s/64/$$changes{libdirsuffix}/ if $line =~ $libdir_regex; -    } -    if (exists $$changes{arch_out}) { -      $line =~ s/\$ARCH/$$changes{arch_out}/ if $line =~ $arch_regex; -    } -    if (exists $changes->{jobs}) { -      $line =~ s/make/make \$MAKEOPTS/ if $line =~ $make_regex; -    } -  } -  untie @sb_file; -  return 1; -} - -=head2 run_tee - -  my ($output, $exit) = run_tee($cmd); - -C<run_tee()> runs the C<$cmd >under C<tee(1)> to allow both displaying its -output and returning it as a string. It returns a list of the output and the -exit status (C<$?> in bash). If it can't even run the bash interpreter, the -output will be C<undef> and the exit status will hold a true value. - -=cut - -sub run_tee { -  my $cmd = shift; - -  my $tempdir = tempdir(CLEANUP => 1, DIR => $tmpd); - -  my $out_fh = tempfile(DIR => $tempdir); -  my $out_fn = get_tmp_extfn($out_fh); -  return undef, _ERR_F_SETFD if not defined $out_fn; - -  my $exit_fh = tempfile(DIR => $tempdir); -  my $exit_fn = get_tmp_extfn($exit_fh); -  return undef, _ERR_F_SETFD if not defined $exit_fn; - -  $cmd = sprintf '( %s; echo $? > %s ) | tee %s', $cmd, $exit_fn, $out_fn; - -  my $ret = system('/bin/bash', '-c', $cmd); - -  return undef, $ret if $ret; - -  seek $exit_fh, 0, 0; -  chomp($ret = readline $exit_fh); - -  seek $out_fh, 0, 0; -  my $out = do { local $/; readline $out_fh; }; - -  return $out, $ret; -} - -sub _build_queue { -  my ($sbos, $warnings) = @_; -  my @queue = @$sbos; -  my @result; - -  while (my $sbo = shift @queue) { -    next if $sbo eq "%README%"; -    my $reqs = get_requires($sbo); -    if (defined $reqs) { -      push @result, _build_queue($reqs, $warnings); -      foreach my $req (@$reqs) { -        $warnings->{$sbo}="%README%" if $req eq "%README%"; -      } -    } -    else { -      $warnings->{$sbo} = "nonexistent"; -    } -    push @result, $sbo; -  } - -  return uniq @result; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Cryptography.pm b/SBO-Lib/lib/SBO/Lib/Cryptography.pm deleted file mode 100644 index 7d77332..0000000 --- a/SBO-Lib/lib/SBO/Lib/Cryptography.pm +++ /dev/null @@ -1,213 +0,0 @@ -package SBO::Lib::Cryptography; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use Cwd; -use File::Temp "tempdir"; -use IPC::Open3; - -use Exporter 'import'; - -# Minimal definitions of some GPG raw output messages. -use constant { -  BADSIG => 'bad signature', -  EXPSIG => 'signature expired', -  EXPKEYSIG => 'signed by expired key', -  ERRSIG => 'signature verification not possible', -  GOODSIG => 'good signature', -  REVKEYSIG => 'good signature by revoked public key', -  NO_PUBKEY => 'public key unavailable', -  VALIDSIG => 'valid signature', -  # An unknown message type. -  UNKNOWN => 'unknown', -}; - -our @EXPORT_OK = qw{ -  import_gpg_key -  parse_gpg_output -  verify_gpg_signed_file - -  BADSIG -  EXPSIG -  EXPKEYSIG -  ERRSIG -  GOODSIG -  REVKEYSIG -  NO_PUBKEY -  VALIDSIG -  UNKNOWN -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=cut - -# Messages on Signature status which should only turn up once. -our %is_signature_status = ( -  &BADSIG => 1, -  &ERRSIG => 1, -  &EXPSIG => 1, -  &EXPKEYSIG => 1, -  &GOODSIG => 1, -  &REVKEYSIG => 1, -); - -=head2 - -  parse_gpg_output(@output, $key_id); - -=cut - -sub parse_gpg_output { -  my $output = shift; -  my $key_id = shift; - - -  my $line; -  my $status = ''; - -  foreach $line (@$output) { -    my $msg = parse_gpg_line($line, $key_id); - -    if (exists($is_signature_status{$msg})) { -      # Only one signature expected. -      if ($status ne '') { -        return UNKNOWN; -      } - -      $status = $msg; -    } - -    if ($msg eq NO_PUBKEY) { -      return NO_PUBKEY; -    } elsif ($msg eq VALIDSIG) { -      # VALIDSIG contains the full hex key ID to be certain it is signed by the -      # right key. information can be found in 'DETAILS' in the gnupg2 -      # documentation folder. -      return $status; -    } -  } - -  return UNKNOWN; -} - -sub parse_gpg_line { -  my $line = shift; -  my $key_id = shift; - -  if ($line =~ /^\[GNUPG\:] BADSIG/) { -    return BADSIG; -  } elsif ($line =~ /^\[GNUPG\:] EXPSIG/) { -    return EXPSIG; -  } elsif ($line =~ /^\[GNUPG\:] EXPKEYSIG/) { -    return EXPKEYSIG; -  } elsif ($line =~ /^\[GNUPG\:] ERRSIG/) { -    return ERRSIG; -  } elsif ($line =~ /^\[GNUPG\:] GOODSIG/) { -    return GOODSIG; -  } elsif ($line =~ /^\[GNUPG\:] REVKEYSIG/) { -    return REVKEYSIG; -  } elsif ($line =~ /^\[GNUPG\:] NO_PUBKEY/) { -    return NO_PUBKEY; -  } elsif ($line =~ /^\[GNUPG\:] VALIDSIG $key_id/) { -    return VALIDSIG; -  } else { -    return UNKNOWN; -  } -} - -=head2 import_gpg_key - -  import_gpg_key($key); - -C<import_gpg_key()> will import the key into the systems keychain.  An error will -be reported if the configured key fingerprint does not match the imported one. - -=cut - -sub import_gpg_key { -  script_error('import_gpg_key requires two arguments.') unless @_ == 2; - -  my $key = shift; -  my $key_id = shift; - -  my $key_source; -  if ($key =~ m!^http://! || $key =~ m!^https://!) { -    open3(undef, $key_source, ">&STDERR", "wget", $key, "-O", "-") || die("could not download key from $key"); -  } else { -    open($key_source, "<", $key) || die("could not read '$key': $!"); -  } - -  my $old = $ENV{'GNUPGHOME'}; - -  $ENV{'GNUPGHOME'} = tempdir(CLEANUP => 1); - -  my $gpg_cmd; -  open3($gpg_cmd, undef, undef, "gpg", "--batch", "--yes", "--import", "-") || die("could not import key: $!\n"); - -  while (my $line = <$key_source>) { -    print($gpg_cmd $line); -  } - -  close($gpg_cmd); -  close($key_source); - -  sleep(1); - -  if (system(">/dev/null gpg --list-keys $key_id")) { -    die("GPG key '$key_id' not found.  Confirm the correct key is configured or is being imported.\n"); -  } - -  my $gpg_export; -  open($gpg_export, "-|", "gpg", "--export", $key_id) || die("could not export key: $!\n"); - -  $ENV{'GNUPGHOME'} = $old; - -  my $gpg_import; -  open3($gpg_import, ">&STDOUT", ">&STDOUT", "gpg", "--batch", "--yes", "--import", "-") || die("could not import key: $!\n"); - -  while (my $line = <$gpg_export>) { -    print($gpg_import $line); -  } - -  close($gpg_export); -  close($gpg_import); - -  sleep(1); - -  print("key imported\n"); -} - -=head2 verify_gpg_signed_file - -  verify_gpg_signed_file($file_path, $key_id); - -C<verify_gpg_signed_file()> verifies the C<file_path> is signed by C<key_id>.  - -=cut - -sub verify_gpg_signed_file { -  script_error('verify_gpg_signed_file requires two arguments.') unless @_ == 2; -   -  my $file_path = shift; -  my $key_id = shift; - -  my @output; -  open3(undef, my $std_out, undef, "gpg", "--status-fd=1", "--verify", $file_path) or die("dead"); -  while (my $line = <$std_out>) { -    push(@output, $line); -  } -  close($std_out); - -  return parse_gpg_output(\@output, $key_id); -} diff --git a/SBO-Lib/lib/SBO/Lib/Download.pm b/SBO-Lib/lib/SBO/Lib/Download.pm deleted file mode 100644 index e574580..0000000 --- a/SBO-Lib/lib/SBO/Lib/Download.pm +++ /dev/null @@ -1,299 +0,0 @@ -package SBO::Lib::Download; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ :const script_error get_sbo_from_loc open_read get_arch /; -use SBO::Lib::Repo qw/ $distfiles /; -use SBO::Lib::Info qw/ get_download_info /; - -use Digest::MD5; -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  check_distfiles -  compute_md5sum -  create_symlinks -  get_distfile -  get_dl_fns -  get_filename_from_link -  get_sbo_downloads -  get_symlink_from_filename -  verify_distfile -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Download - Routines for downloading slackbuild sources. - -=head1 SYNOPSIS - -  use SBO::Lib::Download qw/ check_distfiles /; - -  my ($ret, $exit) = check_distfiles(LOCATION => $loc); - -=head2 SUBROUTINES - -=cut - -=head2 check_distfiles - -  my ($ret, $exit) = check_distfiles(LOCATION => $loc); - -C<check_distfiles()> gets the list of downloads from C<$loc>, and checks to see -if any of them are already downloaded. If so, it verifies that they're correct, -otherwise it downloads them, verifies they're correct, and calls -C<create_symlinks> on them. - -It returns a list of two values. If the second value is true, the first value -will contain an error message. Otherwise it will contain an array reference of -symlinks as returned by C<create_symlinks>. - -=cut - -# for the given location, pull list of downloads and check to see if any exist; -# if so, verify they md5 correctly and if not, download them and check the new -# download's md5sum, then create required symlinks for them. -sub check_distfiles { -  my %args = ( -    LOCATION  => '', -    COMPAT32  => 0, -    @_ -  ); -  $args{LOCATION} or script_error('check_distfiles requires LOCATION.'); - -  my $location = $args{LOCATION}; -  my $sbo = get_sbo_from_loc($location); -  my $downloads = get_sbo_downloads( -    LOCATION => $location, -    32 => $args{COMPAT32} -  ); -  # return an error if we're unable to get download info -  unless (keys %$downloads > 0) { -    return "Unable to get download info from $location/$sbo.info\n", -      _ERR_NOINFO; -  } -  for my $link (keys %$downloads) { -    my $md5 = $downloads->{$link}; -    unless (verify_distfile($link, $md5)) { -      my ($fail, $exit) = get_distfile($link, $md5); -      return $fail, $exit if $exit; -    } -  } -  my $symlinks = create_symlinks($args{LOCATION}, $downloads); -  return $symlinks; -} - -=head2 compute_md5sum - -  my $md5sum = compute_md5sum($file); - -C<compute_md5sum()> computes the md5sum of the file in C<$file>, and returns it. - -=cut - -# for a given file, compute its md5sum -sub compute_md5sum { -  script_error('compute_md5sum requires a file argument.') unless -f $_[0]; -  my ($fh, $exit) = open_read(shift); -  my $md5 = Digest::MD5->new; -  $md5->addfile($fh); -  my $md5sum = $md5->hexdigest; -  close $fh; -  return $md5sum; -} - -=head2 create_symlinks - -  my @symlinks = @{ create_symlinks($location, {%downloads}); - -C<create_symlinks()> creates symlinks for the C<%downloads> in C<$location>, -and returns an array reference of the symlinks created. - -=cut - -# given a location and a list of download links, assemble a list of symlinks, -# and create them. -sub create_symlinks { -  script_error('create_symlinks requires two arguments.') unless @_ == 2; -  my ($location, $downloads) = @_; -  my @symlinks; -  for my $link (keys %$downloads) { -    my $filename = get_filename_from_link($link); -    my $symlink = get_symlink_from_filename($filename, $location); -    push @symlinks, $symlink; -    symlink $filename, $symlink; -  } -  return \@symlinks; -} - -=head2 get_distfile - -  my ($msg, $err) = get_distfile($link, $md5); - -C<get_distfile()> downloads the C<$link>, and compares the downloaded file's -md5sum to the one in C<$md5>. It returns a list of two values, and if the -second value is true, the first one will have an error message. - -=cut - -# for a given distfile, attempt to retrieve it and, if successful, check its -# md5sum against that in the sbo's .info file -sub get_distfile { -  script_error('get_distfile requires two arguments') unless @_ == 2; -  my ($link, $info_md5) = @_; -  my $filename = get_filename_from_link($link); -  mkdir $distfiles unless -d $distfiles; -  chdir $distfiles; -  unlink $filename if -f $filename; -  my $fail = {}; - -  #  if wget $link && verify, return -  #  else wget sbosrcarch && verify -  if (system('wget', '--no-check-certificate', '--tries=5', $link) != 0) { -    $fail->{msg} = "Unable to wget $link.\n"; -    $fail->{err} = _ERR_DOWNLOAD; -  } -  return 1 if not %$fail and verify_distfile(@_); -  if (not %$fail) { -    $fail->{msg} = "md5sum failure for $filename.\n"; -    $fail->{err} = _ERR_MD5SUM; -  } - -  # since the download from the original link either didn't download or -  # didn't verify, try to get it from sbosrcarch instead -  unlink $filename if -f $filename; -  my $sbosrcarch = sprintf( -    "ftp://slackware.uk/sbosrcarch/by-md5/%s/%s/%s/%s", -    substr($info_md5, 0, 1), substr($info_md5, 1, 1), $info_md5, _get_fname($link)); - -  return 1 if -    system('wget', '--no-check-certificate', '--tries=5', $sbosrcarch) == 0 and -    verify_distfile(@_); - -  return $fail->{msg}, $fail->{err}; -} - -=head2 get_dl_fns - -  my @filenames = @{ get_dl_fns([@links]) }; - -C<get_dl_fns()> returns the filename parts of the C<@links> in an array -reference. - -=cut - -# given a list of downloads, return just the filenames -sub get_dl_fns { -  my $fns = shift; -  my $return; -  push @$return, ($_ =~ qr|/([^/]+)$|)[0] for @$fns; -  return $return; -} - -=head2 get_filename_from_link - -  my $path = get_filename_from_link($link); - -C<get_filename_from_link> returns the full path to the file downloaded from -C<$link>. - -=cut - -sub get_filename_from_link { -  script_error('get_filename_from_link requires an argument') unless @_ == 1; -  my $filename = _get_fname(shift); -  return undef unless defined $filename; -  return "$distfiles/$filename"; -} - -=head2 get_sbo_downloads - -  my %downloads = %{ get_sbo_downloads(LOCATION => $loc) }; - -C<get_sbo_downloads()> gets the download links and md5sums for the slackbuild -in $loc, and returns them in a hash reference. - -=cut - -# TODO: should probably combine this with get_download_info -sub get_sbo_downloads { -  my %args = ( -    LOCATION  => '', -    32        => 0, -    @_ -  ); -  $args{LOCATION} or script_error('get_sbo_downloads requires LOCATION.'); -  my $location = $args{LOCATION}; -  -d $location or script_error('get_sbo_downloads given a non-directory.'); -  my $arch = get_arch(); -  my $dl_info; -  if ($arch eq 'x86_64') { -    $dl_info = get_download_info(LOCATION => $location) unless $args{32}; -  } -  unless (keys %$dl_info > 0) { -    $dl_info = get_download_info(LOCATION => $location, X64 => 0); -  } -  return $dl_info; -} - -=head2 get_symlink_from_filename - -  my $symlink = get_symlink_from_filename($path, $loc); - -C<get_symlink_from_filename()> returns the path of the symlink in C<$loc> for -the C<$path>. - -=cut - -# for a given distfile, figure out what the full path to its symlink will be -sub get_symlink_from_filename { -  script_error('get_symlink_from_filename requires two arguments') unless @_ == 2; -  script_error('get_symlink_from_filename first argument is not a file') unless -f $_[0]; -  my ($filename, $location) = @_; -  return "$location/". ($filename =~ qr#/([^/]+)$#)[0]; -} - -=head2 verify_distfile - -  my $bool = verify_distfile($link, $md5); - -C<verify_distfile()> verifies that the file downloaded from C<$link> matches -the C<$md5> md5sum, and returns a true value if it does, and a false value -otherwise. - -=cut - -# for a given distfile, see whether or not it exists, and if so, if its md5sum -# matches the sbo's .info file -sub verify_distfile { -  script_error('verify_distfile requires two arguments.') unless @_ == 2; -  my ($link, $info_md5) = @_; -  my $filename = get_filename_from_link($link); -  return() unless -f $filename; -  my $md5sum = compute_md5sum($filename); -  return $info_md5 eq $md5sum ? 1 : 0; -} - -# given a link, grab the filename from it and prepend $distfiles -sub _get_fname { -  my $fn = shift; -  my $regex = qr#/([^/]+)$#; -  my ($filename) = $fn =~ $regex; -  $filename =~ s/%2B/+/g if $filename; -  return $filename; - -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Info.pm b/SBO-Lib/lib/SBO/Lib/Info.pm deleted file mode 100644 index bf47aec..0000000 --- a/SBO-Lib/lib/SBO/Lib/Info.pm +++ /dev/null @@ -1,234 +0,0 @@ -package SBO::Lib::Info; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ get_arch get_sbo_from_loc open_read script_error slurp usage_error /; -use SBO::Lib::Tree qw/ get_orig_location get_sbo_location is_local /; - -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  check_x32 -  get_download_info -  get_from_info -  get_orig_version -  get_requires -  get_sbo_version -  parse_info -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Info - Utilities to get data from SBo .info files. - -=head1 SYNOPSIS - -  use SBO::Lib::Info qw/ get_reqs /; - -  my @reqs = @{ get_requires($sbo) }; - -=head1 SUBROUTINES - -=cut - -=head2 check_x32 - -  my $bool = check_x32($location); - -C<check_x32()> checks if the SBo in C<$location> considers 64bit builds -C<UNTESTED> or C<UNSUPPORTED>, and if so returns a true value. Otherwise it -returns a false value. - -=cut - -# determine whether or not a given sbo is 32-bit only -sub check_x32 { -  script_error('check_x32 requires an argument.') unless @_ == 1; -  my $dl = get_from_info(LOCATION => shift, GET => 'DOWNLOAD_x86_64'); -  return $$dl[0] =~ /UN(SUPPOR|TES)TED/ ? 1 : undef; -} - -=head2 get_download_info - -  my $downloads = get_download_info(LOCATION => $location, X64 => $x64); -  my $downloads = get_download_info(LOCATION => $location); - -C<get_download_info()> takes a C<$location> to read a .info file in, and -C<$x64> which is a flag to determine if the x64 link should be used or not. - -If the C<$x64> flag is not given, it defaults to a true value. - -It returns a hashref where each key is a download link, and the corresponding -value is the md5sum it should have. - -=cut - -# get downloads and md5sums from an sbo's .info file, first -# checking for x86_64-specific info if we are told to -sub get_download_info { -  my %args = ( -    LOCATION  => 0, -    X64       => 1, -    @_ -  ); -  $args{LOCATION} or script_error('get_download_info requires LOCATION.'); -  my ($get, $downs, $exit, $md5s, %return); -  $get = ($args{X64} ? 'DOWNLOAD_x86_64' : 'DOWNLOAD'); -  $downs = get_from_info(LOCATION => $args{LOCATION}, GET => $get); -  # did we get nothing back, or UNSUPPORTED/UNTESTED? -  if ($args{X64}) { -    if (! $$downs[0] || $$downs[0] =~ qr/^UN(SUPPOR|TES)TED$/) { -      $args{X64} = 0; -      $downs = get_from_info(LOCATION => $args{LOCATION}, -        GET => 'DOWNLOAD'); -    } -  } -  # if we still don't have any links, something is really wrong. -  return() unless $$downs[0]; -  # grab the md5s and build a hash -  $get = $args{X64} ? 'MD5SUM_x86_64' : 'MD5SUM'; -  $md5s = get_from_info(LOCATION => $args{LOCATION}, GET => $get); -  return() unless $$md5s[0]; -  $return{$$downs[$_]} = $$md5s[$_] for (keys @$downs); -  return \%return; -} - -=head2 get_from_info - -  my $data = get_from_info(LOCATION => $location, GET => $key); - -C<get_from_info()> retrieves the information under C<$key> from the .info file -in C<$location>. - -=cut - -# pull piece(s) of data, GET, from the $sbo.info file under LOCATION. -sub get_from_info { -  my %args = ( -    LOCATION  => '', -    GET       => '', -    @_ -  ); -  unless ($args{LOCATION} && $args{GET}) { -    script_error('get_from_info requires LOCATION and GET.'); -  } -  state $store = {LOCATION => ['']}; -  my $sbo = get_sbo_from_loc($args{LOCATION}); -  return $store->{$args{GET}} if $store->{LOCATION}[0] eq $args{LOCATION}; - -  # if we're here, we haven't read in the .info file yet. -  my $contents = slurp("$args{LOCATION}/$sbo.info"); -  usage_error("get_from_info: could not read $args{LOCATION}/$sbo.info.") unless -    defined $contents; - -  my %parse = parse_info($contents); -  script_error("error when parsing $sbo.info file.") unless %parse; - -  $store = {}; -  $store->{LOCATION} = [$args{LOCATION}]; -  foreach my $k (keys %parse) { $store->{$k} = $parse{$k}; } - -  # allow local overrides to get away with not having quite all the fields -  if (is_local($sbo)) { -    for my $key (qw/DOWNLOAD_x86_64 MD5SUM_x86_64 REQUIRES/) { -      $store->{$key} //= ['']; # if they don't exist, treat them as empty -    } -  } -  return $store->{$args{GET}}; -} - -=head2 get_orig_version - -  my $ver = get_orig_version($sbo); - -C<get_orig_version()> returns the version in the SlackBuilds.org tree for the -given C<$sbo>. - -=cut - -sub get_orig_version { -  script_error('get_orig_version requires an argument.') unless @_ == 1; -  my $sbo = shift; - -  my $location = get_orig_location($sbo); - -  return $location if not defined $location; - -  return get_sbo_version($location); -} - -=head2 get_requires - -  my $reqs = get_requires($sbo); - -C<get_requires()> returns the requirements for a given C<$sbo>. - -=cut - -# wrapper to pull the list of requirements for a given sbo -sub get_requires { -  my $location = get_sbo_location(shift); -  return undef unless $location; -  my $info = get_from_info(LOCATION => $location, GET => 'REQUIRES'); -  return $info; -} - -=head2 get_sbo_version - -  my $ver = get_sbo_version($location); - -C<get_sbo_version()> returns the version found in the .info file in -C<$location>. - -=cut - -# find the version in the tree for a given sbo (provided a location) -sub get_sbo_version { -  script_error('get_sbo_version requires an argument.') unless @_ == 1; -  my $version = get_from_info(LOCATION => shift, GET => 'VERSION'); -  return $version->[0]; -} - -=head2 parse_info - -  my %parse = parse_info($str); - -C<parse_info()> parses the contents of an .info file from C<$str> and returns -a key-value list of it. - -=cut - -sub parse_info { -    script_error('parse_info requires an argument.') unless @_ == 1; -    my $info_str = shift; -    my $pos = 0; -    my %ret; - -    while ($info_str =~ /\G([A-Za-z0-9_]+)="([^"]*)"\s*(?:\n|\z)/g) { -        my ($key, $val) = ($1, $2); -        $val =~ s/\\[ \t]*$/ /mg; -        my @val = split " ", $val; -        @val = '' unless @val; -        $ret{$key} = \@val; -        $pos = pos($info_str); -    } - -    return if $pos != length($info_str); - -    return %ret; - -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Pkgs.pm b/SBO-Lib/lib/SBO/Lib/Pkgs.pm deleted file mode 100644 index 9e9e029..0000000 --- a/SBO-Lib/lib/SBO/Lib/Pkgs.pm +++ /dev/null @@ -1,198 +0,0 @@ -package SBO::Lib::Pkgs; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ %config script_error open_read version_cmp /; -use SBO::Lib::Tree qw/ get_sbo_location get_sbo_locations is_local /; -use SBO::Lib::Info qw/ get_orig_version get_sbo_version /; - -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  get_available_updates -  get_inst_names -  get_installed_cpans -  get_installed_packages -  get_local_outdated_versions -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Pkgs - Routines for interacting with the Slackware package database. - -=head1 SYNOPSIS - -  use SBO::Lib::Pkgs qw/ get_installed_packages /; - -  my @installed_sbos = get_installed_packages('SBO'); - -=head1 SUBROUTINES - -=cut - -my $pkg_db = '/var/log/packages'; - -=head2 get_available_updates - -  my @updates = @{ get_available_updates() }; - -C<get_available_updates()> compares the installed versions in -C</var/log/packages> that are tagged as SBo with the version available from -the SlackBuilds.org or C<LOCAL_OVERRIDES> repository, and returns an array -reference to an array of hash references which specify package names, and -installed and available versions. - -=cut - -# for each installed sbo, find out whether or not the version in the tree is -# newer, and compile an array of hashes containing those which are -sub get_available_updates { -    my @updates; -    my $pkg_list = get_installed_packages('SBO'); - -    for my $pkg (@$pkg_list) { -        my $location = get_sbo_location($pkg->{name}); -        next unless $location; - -        my $version = get_sbo_version($location); -        if (version_cmp($version, $pkg->{version}) != 0) { -            push @updates, { name => $pkg->{name}, installed => $pkg->{version}, update => $version }; -        } -    } - -    return \@updates; -} - -=head2 get_inst_names - -  my @names = get_inst_names(get_available_updates()); - -C<get_inst_names()> returns a list of package names from an array reference -such as the one returned by C<get_available_updates()>. - -=cut - -# for a ref to an array of hashes of installed packages, return an array ref -# consisting of just their names -sub get_inst_names { -    script_error('get_inst_names requires an argument.') unless @_ == 1; -    my $inst = shift; -    my @installed; -    push @installed, $$_{name} for @$inst; -    return \@installed; -} - -=head2 get_installed_cpans - -  my @cpans = @{ get_installed_cpans() }; - -C<get_installed_cpans()> returns an array reference to a list of the perl -modules installed from the CPAN rather than from packages on SlackBuilds.org. - -=cut - -# return a list of perl modules installed via the CPAN -sub get_installed_cpans { -  my @contents; -  for my $file (grep { -f $_ } map { "$_/perllocal.pod" } @INC) { -    my ($fh, $exit) = open_read($file); -    next if $exit; -    push @contents, grep {/Module/} <$fh>; -    close $fh; -  } -  my $mod_regex = qr/C<Module>\s+L<([^\|]+)/; -  my (@mods, @vers); -  for my $line (@contents) { -    push @mods, ($line =~ $mod_regex)[0]; -  } -  return \@mods; -} - -=head2 get_installed_packages - -  my @packages = @{ get_installed_packages($type) }; - -C<get_installed_packages()> returns an array reference to a list of packages in -C</var/log/packages> that match the specified C<$type>. The available types are -C<STD> for non-SBo packages, C<SBO> for SBo packages, and C<ALL> for both. - -The returned array reference will hold a list of hash references representing -both names, versions, and full installed package name of the returned packages. - -=cut - -# pull an array of hashes, each hash containing the name and version of a -# package currently installed. Gets filtered using STD, SBO or ALL. -sub get_installed_packages { -  script_error('get_installed_packages requires an argument.') unless @_ == 1; -  my $filter = shift; - -  # Valid types: STD, SBO -  my (@pkgs, %types); -  foreach my $pkg (glob("$pkg_db/*")) { -    $pkg =~ s!^\Q$pkg_db/\E!!; -    my ($name, $version, $build) = $pkg =~ m#^([^/]+)-([^-]+)-[^-]+-([^-]+)$# -      or next; -    push @pkgs, { name => $name, version => $version, build => $build, pkg => $pkg }; -    $types{$name} = 'STD'; -  } - -  # If we want all packages, let's just return them all -  return [ map { +{ name => $_->{name}, version => $_->{version}, pkg => $_->{pkg} } } @pkgs ] -    if $filter eq 'ALL'; - -  # Otherwise, mark the SBO ones and filter -  my @sbos = map { $_->{name} } grep { $_->{build} =~ m/_SBo(|compat32)$/ } -    @pkgs; -  if (@sbos) { -    my %locations = get_sbo_locations(map { s/-compat32//gr } @sbos); -    foreach my $sbo (@sbos) { $types{$sbo} = 'SBO' -      if $locations{ $sbo =~ s/-compat32//gr }; } -  } -  return [ map { +{ name => $_->{name}, version => $_->{version}, pkg => $_->{pkg} } } -    grep { $types{$_->{name}} eq $filter } @pkgs ]; -} - -=head2 get_local_outdated_versions - -  my @outdated = get_local_outdated_versions(); - -C<get_local_outdated_versions()> checks the installed SBo packages and returns -a list of the ones for which the C<LOCAL_OVERRIDES> version is different to the -the version on SlackBuilds.org. - -=cut - -sub get_local_outdated_versions { -  my @outdated; - -  my $local = $config{LOCAL_OVERRIDES}; -  unless ( $local eq 'FALSE' ) { -    my $pkglist = get_installed_packages('SBO'); -    my @local = grep { is_local($_->{name}) } @$pkglist; - -    foreach my $sbo (@local) { -      my $orig = get_orig_version($sbo->{name}); -      next if not defined $orig; -      next if not version_cmp($orig, $sbo->{version}); - -      push @outdated, { %$sbo, orig => $orig }; -    } -  } - -  return @outdated; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Readme.pm b/SBO-Lib/lib/SBO/Lib/Readme.pm deleted file mode 100644 index 1022c4a..0000000 --- a/SBO-Lib/lib/SBO/Lib/Readme.pm +++ /dev/null @@ -1,220 +0,0 @@ -package SBO::Lib::Readme; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ prompt script_error slurp open_read _ERR_OPENFH usage_error /; -use SBO::Lib::Tree qw/ is_local /; - -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  ask_opts -  ask_other_readmes -  ask_user_group -  get_opts -  get_readme_contents -  get_user_group -  user_prompt -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Readme - Routines for interacting with a typical SBo README file. - -=head1 SYNOPSIS - -  use SBO::Lib::Readme qw/ get_readme_contents /; - -  print get_readme_contents($sbo); - -=head1 SUBROUTINES - -=cut - -=head2 ask_opts - -  my $opts = ask_opts($sbo, $readme); - -C<ask_opts()> displays the C<$readme> and asks if we should set any of the -options it defines. If the user indicates that we should, we prompt them for -the options to set and then returns them as a string. If the user didn't supply -any options or indicated that we shouldn't, it returns C<undef>. - -=cut - -# provide an opportunity to set options -sub ask_opts { -  # TODO: check number of args -  script_error('ask_opts requires an argument') unless @_; -  my ($sbo, $readme) = @_; -  say "\n". $readme; -  if (prompt("\nIt looks like $sbo has options; would you like to set any when the slackbuild is run?", default => 'no')) { -    my $ask = sub { -      chomp(my $opts = prompt("\nPlease supply any options here, or enter to skip: ")); -      return $opts; -    }; -    my $kv_regex = qr/[A-Z0-9]+=[^\s]+(|\s([A-Z]+=[^\s]+){0,})/; -    my $opts = $ask->(); -    return() unless $opts; -    while ($opts !~ $kv_regex) { -      warn "Invalid input received.\n"; -      $opts = $ask->(); -      return() unless $opts; -    } -    return $opts; -  } -  return(); -} - -=head2 ask_other_readmes - -  ask_other_readmes($sbo, $location); - -C<ask_other_readmes()> checks if there are other readmes for the C<$sbo> in -C<$location>, and if so, asks the user if they should be displayed, and then -displays them if the user didn't decline. - -=cut - -sub ask_other_readmes { -  my ($sbo, $location) = @_; -  my @readmes = sort grep { ! m!/README$! } glob "$location/README*"; - -  return unless @readmes; - -  return unless prompt("\nIt looks like $sbo has additional README files. Would you like to see those too?", default => 'yes'); - -  for my $fn (@readmes) { -    my ($display_fn) = $fn =~ m!/(README.*)$!; -    say "\n$display_fn:"; -    say slurp $fn; -  } -} - -=head2 ask_user_group - -  my $bool = ask_user_group($cmds, $readme); - -C<ask_user_group()> displays the C<$readme> and commands found in C<$cmds>, and -asks the user if we should automatically run the C<useradd>/C</groupadd> -commands found. If the user indicates that we should, it returns the C<$cmds>, -otherwise it returns C<undef>. - -=cut - -# offer to run any user/group add commands -sub ask_user_group { -  script_error('ask_user_group requires two arguments') unless @_ == 2; -  my ($cmds, $readme) = @_; -  say "\n". $readme; -  print "\nIt looks like this slackbuild requires the following"; -  say ' command(s) to be run first:'; -  say "    # $_" for @$cmds; -  return prompt('Shall I run them prior to building?', default => 'yes') ? $cmds : undef; -} - -=head2 get_opts - -  my $bool = get_opts($readme); - -C<get_opts()> checks if the C<$readme> has any options defined, and if so -returns a true value. Otherwise it returns a false value. - -=cut - -# see if the README mentions any options -sub get_opts { -  script_error('get_opts requires an argument') unless @_ == 1; -  my $readme = shift; -  return $readme =~ /[A-Z0-9]+=[^\s]/ ? 1 : undef; -} - -=head2 get_readme_contents - -  my $contents = get_readme_contents($location); - -C<get_readme_contents()> will open the README file in C<$location> and return -its contents. On error, it will return C<undef>. - -=cut - -sub get_readme_contents { -  script_error('get_readme_contents requires an argument.') unless @_ == 1; -  return undef unless defined $_[0]; -  my $readme = slurp(shift . '/README'); -  return $readme; -} - -=head2 get_user_group - -  my @cmds = @{ get_user_group($readme) }; - -C<get_user_group()> searches through the C<$readme> for C<useradd> and -C<groupadd> commands, and returns them in an array reference. - -=cut - -# look for any (user|group)add commands in the README -sub get_user_group { -  script_error('get_user_group requires an argument') unless @_ == 1; -  my $readme = shift; -  my @cmds = $readme =~ /^\s*#*\s*(useradd.*?|groupadd.*?)(?<!\\)\n/msg; -  return \@cmds; -} - -=head2 user_prompt - -  my ($cmds, $opts, $exit) = user_prompt($sbo, $location); - -C<user_prompt()> checks for options and commands, to see if we should run them, -and asks if we should proceed with the C<$sbo> in question. - -It returns a list of three values, and if the third one is a true value, the -first indicates an error message. Otherwise, the first value will either be an -C<'N'>, C<undef>, or an array reference. If it's C<'N'>, the user indicated -that we should B<not> build this C<$sbo>. Otherwise it indicates if we should -run any C<useradd>/C<groupadd> commands, or if it's C<undef>, that we -shouldn't. The second return value indicates the options we should specify if -we build this C<$sbo>. - -B<Note>: This should really be changed. - -=cut - -# for a given sbo, check for cmds/opts, prompt the user as appropriate -sub user_prompt { -  script_error('user_prompt requires two arguments.') unless @_ == 2; -  my ($sbo, $location) = @_; -  if (not defined $location) { usage_error("Unable to locate $sbo in the SlackBuilds.org tree."); } -  my $readme = get_readme_contents($location); -  return "Could not open README for $sbo.", undef, _ERR_OPENFH if not defined $readme; -  if (is_local($sbo)) { print "\nFound $sbo in local overrides.\n"; } -  # check for user/group add commands, offer to run any found -  my $user_group = get_user_group($readme); -  my $cmds; -  $cmds = ask_user_group($user_group, $readme) if $$user_group[0]; -  # check for options mentioned in the README -  my $opts = 0; -  $opts = ask_opts($sbo, $readme) if get_opts($readme); -  print "\n". $readme unless $opts; -  ask_other_readmes($sbo, $location); -  # we have to return something substantial if the user says no so that we -  # can check the value of $cmds on the calling side. we should be able to -  # assume that 'N' will  never be a valid command to run. -  return 'N' unless prompt("\nProceed with $sbo?", default => 'yes'); -  return $cmds, $opts; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Repo.pm b/SBO-Lib/lib/SBO/Lib/Repo.pm deleted file mode 100644 index 7d770c8..0000000 --- a/SBO-Lib/lib/SBO/Lib/Repo.pm +++ /dev/null @@ -1,485 +0,0 @@ -package SBO::Lib::Repo; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ %config prompt usage_error get_slack_version get_slack_version_key get_slack_version_url script_error open_fh open_read in _ERR_DOWNLOAD /; -use SBO::Lib::Cryptography qw/ GOODSIG NO_PUBKEY parse_gpg_output verify_gpg_signed_file /; - -use Cwd; -use File::Copy; -use File::Find; -use File::Temp "tempdir"; -use File::Path qw/ make_path remove_tree /; -use IPC::Open3; -use Sort::Versions; -use Symbol "gensym"; - -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  check_git_remote -  check_repo -  chk_slackbuilds_txt -  fetch_tree -  generate_slackbuilds_txt -  git_sbo_tree -  migrate_repo -  pull_sbo_tree -  rsync_sbo_tree -  slackbuilds_or_fetch -  update_tree - -  $distfiles -  $repo_path -  $slackbuilds_txt -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Repo - Routines for downloading and updating the SBo repo. - -=head1 SYNOPSIS - -  use SBO::Lib::Repo qw/ fetch_tree /; - -  fetch_tree(); - -=head1 VARIABLES - -=head2 $distfiles - -By default $distfiles is set to C</usr/sbo/distfiles>, and it is where all the -downloaded sources are kept. - -The location depends on the C<SBO_HOME> config setting. - -=head2 $repo_path - -By default $repo_path is set to C</usr/sbo/repo>, and it is where the -SlackBuilds.org tree is kept. - -The location depends on the C<SBO_HOME> config setting. - -=cut - -# some stuff we'll need later -our $distfiles = "$config{SBO_HOME}/distfiles"; -our $repo_path = "$config{SBO_HOME}/repo"; -our $slackbuilds_txt = "$repo_path/SLACKBUILDS.TXT"; - -=head1 SUBROUTINES - -=cut - -=head2 check_git_remote - -  my $bool = check_git_remote($path, $url); - -C<check_git_remote()> will check if the repository at C<$path> is a git -repository and if so, it will check if it defined an C<origin> remote that -matches the C<$url>. If so, it will return a true value. Otherwise it will -return a false value. - -=cut - -sub check_git_remote { -  script_error('check_git_remote requires two arguments.') unless @_ == 2; -  my ($path, $url) = @_; -  return 0 unless -f "$path/.git/config"; -  my ($fh, $exit) = open_read("$path/.git/config"); -  return 0 if $exit; - -  while (my $line = readline($fh)) { -    chomp $line; -    if ($line eq '[remote "origin"]') { -      REMOTE: while (my $remote = readline($fh)) { -        last REMOTE if $remote =~ /^\[/; -        return 1 if $remote =~ /^\s*url\s*=\s*\Q$url\E$/; -        return 0 if $remote =~ /^\s*url\s*=/; -      } -    } -  } -  return 0; -} - -=head2 check_repo - -  my $bool = check_repo(); - -C<check_repo()> checks if the path in C<$repo_path> exists and is an empty -directory, and returns a true value if so. - -If it exists but isn't empty, it will exit with a usage error. - -If it doesn't exist, it will attempt to create it and return a true value. If -it fails to create it, it will exit with a usage error. - -=cut - -sub check_repo { -  if (-d $repo_path) { -    _race::cond '$repo_path could be deleted after -d check'; -    opendir(my $repo_handle, $repo_path); -    FIRST: while (my $dir = readdir $repo_handle) { -      next FIRST if in($dir => qw/ . .. /); -      usage_error("$repo_path exists and is not empty. Exiting.\n"); -    } -  } else { -    eval { make_path($repo_path) } -      or usage_error("Unable to create $repo_path.\n"); -  } -  return 1; -} - -=head2 chk_slackbuilds_txt - -  my $bool = chk_slackbuilds_txt(); - -C<chk_slackbuilds_txt()> checks if the file C<SLACKBUILDS.TXT> exists in the -correct location, and returns a true value if it does, and a false value -otherwise. - -Before the check is made, it attempts to call C<migrate_repo()> so it doesn't -give a false negative if the repository hasn't been migrated to its sbotools -2.0 location yet. - -=cut - -# does the SLACKBUILDS.TXT file exist in the sbo tree? -sub chk_slackbuilds_txt { -  if (-f "$config{SBO_HOME}/SLACKBUILDS.TXT") { migrate_repo(); } -  return -f $slackbuilds_txt ? 1 : undef; -} - -=head2 fetch_tree - -  fetch_tree(); - -C<fetch_tree()> will make sure the C<$repo_path> exists and is empty, and then -fetch the SlackBuilds.org repository tree there. - -If the C<$repo_path> is not empty, it will exit with a usage error. - -=cut - -sub fetch_tree { -  check_repo(); -  say 'Pulling SlackBuilds tree...'; -  pull_sbo_tree(), return 1; -} - -=head2 generate_slackbuilds_txt - -  my $bool = generate_slackbuilds_txt(); - -C<generate_slackbuilds_txt()> will generate a minimal C<SLACKBUILDS.TXT> for a -repository that doesn't come with one. If it fails, it will return a false -value. Otherwise it will return a true value. - -=cut - -sub generate_slackbuilds_txt { -  my ($fh, $exit) = open_fh($slackbuilds_txt, '>'); -  return 0 if $exit; - -  opendir(my $dh, $repo_path) or return 0; -  my @categories = -    grep { -d "$repo_path/$_" } -    grep { $_ !~ /^\./ } -    readdir($dh); -  close $dh; - -  for my $cat (@categories) { -    opendir(my $cat_dh, "$repo_path/$cat") or return 0; -    while (my $package = readdir($cat_dh)) { -      next if in($package => qw/ . .. /); -      next unless -f "$repo_path/$cat/$package/$package.info"; -      print { $fh } "SLACKBUILD NAME: $package\n"; -      print { $fh } "SLACKBUILD LOCATION: ./$cat/$package\n"; -    } -    close $cat_dh; -  } -  close $fh; -  return 1; -} - -sub latest_git_tag { -  my $version = shift; -  my $tag = ''; - -  open(my $std_out, "git tag |") or die("dead"); -  while (my $line = <$std_out>) { -    if ($line =~ /^$version-/) { -      $tag = $line; -    } -  } -  close($std_out); - -  chomp($tag); - -  return $tag; -} - -=head2 git_sbo_tree - -  my $bool = git_sbo_tree($url, $key_id); - -C<git_sbo_tree()> will C<git clone> the repository specified by C<$url> to the -C<$repo_path> if the C<$url> repository isn't already there. If it is, it will -run C<git fetch && git reset --hard origin>. - -If any command fails, it will return a false value. Otherwise it will return a -true value. - -=cut - -sub git_sbo_tree { -  script_error('git_sbo_tree requires two arguments.') unless @_ == 2; -  my $url = shift; -  my $key_id = shift; - -  my $cwd = getcwd(); - -  if ((! -d "$repo_path/.git") || ! check_git_remote($repo_path, $url)) { -    chdir $config{SBO_HOME} or return 0; - -    remove_tree($repo_path) if -d $repo_path; -    if (system(qw/ git clone --no-local /, $url, $repo_path)) { -      return 0; -    } -  } - -  _race::cond '$repo_path can be deleted after -d check'; -  chdir($repo_path) or return 0; - -  return 0 unless system("git fetch") == 0; - -  unlink "$repo_path/SLACKBUILDS.TXT"; - -  my $git_ref = 'origin'; -  my $verify_cmd = 'verify-commit'; - -  my $tag = latest_git_tag(get_slack_version()); -  if ($tag ne '') { -    $git_ref = $tag; -    $verify_cmd = 'verify-tag'; -  } - -  if ($key_id) { -    my @output; - -    print("Verifying $git_ref..."); -    open3(undef, undef, my $std_err = gensym, "git", $verify_cmd, "--raw", "$git_ref"); -    while (my $line = <$std_err>) { -      push(@output, $line); -    } -    close($std_err); - -    my $res = parse_gpg_output(\@output, $key_id); -    if ($res eq GOODSIG) { -      print("OK\n"); -    } else { -      print(STDERR "Repository GPG verification failed: $res."); -      if ($res == NO_PUBKEY) { -        print(STDERR "  Did you import the GPG key?"); -      } -      print(STDERR "\n"); - -      chdir $cwd; -      return 0; -    } -  } - -  _race::cond 'git repo could be changed or deleted here'; -  return 0 unless system('git', 'reset', '--hard', $git_ref) == 0; - -  _race::cond '$cwd could be deleted here'; -  return 0 unless chdir $cwd; - -  return 1; -} - -=head2 migrate_repo - -  migrate_repo(); - -C<migrate_repo()> moves an old sbotools 1.x repository to the location it needs -to be in for sbotools 2.x. This means every directory and file except for the -C<distfiles> directory in (by default) C</usr/sbo/> gets moved to -C</usr/sbo/repo>. - -=cut - -# Move everything in /usr/sbo except distfiles and repo dirs into repo dir -sub migrate_repo { -  make_path($repo_path) unless -d $repo_path; -  _race::cond '$repo_path can be deleted between being made and being used'; -  opendir(my $dh, $config{SBO_HOME}); -  foreach my $entry (readdir($dh)) { -    next if in($entry => qw/ . .. repo distfiles /); -    move("$config{SBO_HOME}/$entry", "$repo_path/$entry"); -  } -  close $dh; -} - -=head2 pull_sbo_tree - -  pull_sbo_tree(); - -C<pull_sbo_tree()> will pull the SlackBuilds.org repository tree from -C<rsync://slackbuilds.org/slackbuilds/$ver/> or whatever the C<REPO> -configuration variable has been set to. - -C<$ver> is the version of Slackware you're running, provided it is supported, -or whatever you've set in the C<SLACKWARE_VERSION> configuration variable. - -=cut - -sub pull_sbo_tree { -  my $url = $config{REPO}; -  if ($url eq 'FALSE') { -    $url = get_slack_version_url(); -  } else { -    unlink($slackbuilds_txt); -  } - -  my $key_id = ''; -  if ($config{GPG_KEY} ne 'FALSE') { -    $key_id = $config{GPG_KEY}; -  }; - -  my $res = 0; -  if ($url =~ m!^rsync://!) { -    $res = rsync_sbo_tree($url, $key_id); -  } else { -    $res = git_sbo_tree($url, $key_id); -  } - -  if ($res == 0) { -    warn "Could not sync from $url.\n"; -    if ($url eq 'https://github.com/Ponce/slackbuilds.git' && $key_id ne '') { -      warn "This URL is known not to use GPG verification.  You likely want to disable with 'sboconfig --gpg-key FALSE'." -    } -    exit _ERR_DOWNLOAD; -  } - -  my $wanted = sub { chown 0, 0, $File::Find::name; }; -  find($wanted, $repo_path) if -d $repo_path; -  if ($res and not chk_slackbuilds_txt()) { -    generate_slackbuilds_txt(); -  } -} - -=head2 rsync_sbo_tree - -  my $bool = rsync_sbo_tree($url, $key_id); - -C<rsync_sbo_tree()> syncs the SlackBuilds.org repository to C<$repo_path> from -the C<$url> provided. - -=cut - -# rsync the sbo tree from slackbuilds.org to $repo_path -sub rsync_sbo_tree { -  script_error('rsync_sbo_tree requires two arguments.') unless @_ == 2; - -  my $url = shift; -  $url .= '/' unless $url =~ m!/$!; # make sure $url ends with / -  my $key_id = shift; - -  my @info; -  # only slackware versions above 14.1 have an rsync that supports --info=progress2 -  if (versioncmp(get_slack_version(), '14.1') == 1) { @info = ('--info=progress2'); } - -  my @args = ('rsync', @info, '-a', '--delete', $url); -  return 0 unless system(@args, $repo_path) == 0; - -  my $cwd = getcwd(); -  chdir($repo_path); - -  if ($key_id) { -    if (versioncmp(get_slack_version(), '14.1') == -1) { -      print("GPG verification is not present for 14.0 and earlier.  You should consider disabling GPG verification.") -    } - -    print("Verifying CHECKSUMS.md5..."); -    my $res = verify_gpg_signed_file('CHECKSUMS.md5.asc', $key_id); -    if ($res eq GOODSIG) { -      print("OK\n"); -    } else { -      print(STDERR "Respository CHECKSUMS.md5 GPG verification failed: $res."); -      if ($res eq NO_PUBKEY) { -        print(STDERR "  Did you import the GPG key?"); -      } -      print(STDERR "\n"); - -      chdir($cwd); -      return 0; -    } -  } - -  if ( -e "CHECKSUMS.md5" ) { -    print("Verifying file integrity using CHECKSUMS.md5..."); -    if (system('tail +13 CHECKSUMS.md5 | md5sum -c --quiet -')) { -      chdir($cwd); -      return 0; -    } -    print("OK\n"); -  } - -  return chdir($cwd); -} - -=head2 slackbuilds_or_fetch - -  slackbuilds_or_fetch(); - -C<slackbuilds_or_fetch()> will check if there is a C<SLACKBUILDS.TXT> in the -C<$repo_path>, and if not, offer to run C<sbosnap fetch> for you. - -=cut - -# if the SLACKBUILDS.TXT is not in $repo_path, we assume the tree has -# not been populated there; prompt the user to automagickally pull the tree. -sub slackbuilds_or_fetch { -  unless (chk_slackbuilds_txt()) { -    say 'It looks like you haven\'t run "sbosnap fetch" yet.'; -    if (($< == 0) && prompt("Would you like me to do this now?", default => 'yes')) { -      fetch_tree(); -    } else { -      say 'Please run "sbosnap fetch" as root'; -      exit 0; -    } -  } -  return 1; -} - -=head2 update_tree - -  update_tree(); - -C<update_tree()> will check if there is a C<SLACKBUILDS.TXT> in the -C<$repo_path>, and if not, will run C<fetch_tree()>. Otherwise it will update -the SlackBuilds.org tree. - -=cut - -sub update_tree { -  fetch_tree(), return() unless chk_slackbuilds_txt(); -  say 'Updating SlackBuilds tree...'; -  pull_sbo_tree(), return 1; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Tree.pm b/SBO-Lib/lib/SBO/Lib/Tree.pm deleted file mode 100644 index 4353cf6..0000000 --- a/SBO-Lib/lib/SBO/Lib/Tree.pm +++ /dev/null @@ -1,161 +0,0 @@ -package SBO::Lib::Tree; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.0'; - -use SBO::Lib::Util qw/ script_error open_read idx %config /; -use SBO::Lib::Repo qw/ $repo_path $slackbuilds_txt /; - -use Exporter 'import'; - -our @EXPORT_OK = qw{ -  get_orig_location -  get_sbo_location -  get_sbo_locations -  is_local -}; - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -); - -=pod - -=encoding UTF-8 - -=head1 NAME - -SBO::Lib::Tree - Routines for interacting with a SlackBuilds.org tree. - -=head1 SYNOPSIS - -  use SBO::Lib::tree qw/ is_local /; - -  my $bool = is_local($sbo); - -=head1 SUBROUTINES - -=cut - -# private variables needed by most subroutines -my $store; -my %local; -my %orig; - -=head2 get_orig_location - -  my $loc = get_orig_location($sbo); - -C<get_orig_location()> returns the location in the SlackBuilds.org tree for the -given C<$sbo>. - -=cut - -sub get_orig_location { -  script_error('get_orig_location requires an argument.') unless @_ == 1; -  my $sbo = shift; -  # Make sure we have checked for the slackbuild in question: -  get_sbo_location($sbo); -  return $orig{$sbo}; -} - -=head2 get_sbo_location - -  my $loc = get_sbo_location($sbo, ...); -  my $loc = get_sbo_location([$sbo, ...]); - -C<get_sbo_location()> returns the location in the C<LOCAL_OVERRIDES> or the -SlackBuilds.org tree for the first C<$sbo> given. - -Specifying more than one C<$sbo> is useful for only needing to access the -filesystem once when searching, and populating the internal cache. - -=cut - -sub get_sbo_location { -  my @sbos = map { s/-compat32$//r } defined $_[0] && ref $_[0] eq 'ARRAY' ? @{ $_[0] } : @_; -  script_error('get_sbo_location requires an argument.') unless @sbos; - -  # if we already have the location, return it now. -  return $$store{$sbos[0]} if exists $$store{$sbos[0]}; -  my %locations = get_sbo_locations(@sbos); -  return $locations{$sbos[0]}; -} - -=head2 get_sbo_locations - -  my %locations = get_sbo_locations(@sbos); - -C<get_sbo_locations> tries to find all C<@sbos> and returns a hash matching the -package name to its location. - -=cut - -sub get_sbo_locations { -  my @sbos = map { s/-compat32$//r } defined $_[0] && ref $_[0] eq 'ARRAY' ? @{ $_[0] } : @_; -  script_error('get_sbo_locations requires an argument.') unless @_; - -  my %locations; - -  # if an sbo is already in the $store, set the %location for it and filter it out -  @sbos = grep { exists $$store{$_} ? ($locations{$_} = $$store{$_}, 0) : 1 } @sbos; -  return %locations unless @sbos; - -  my ($fh, $exit) = open_read($slackbuilds_txt); -  if ($exit) { -    warn $fh; -    exit $exit; -  } - -  while (my $line = <$fh>) { -    my ($loc, $sbo) = $line =~ m!LOCATION:\s+\.(/[^/]+/([^/\n]+))$! -      or next; -    my $found = idx($sbo, @sbos); -    next unless defined $found; - -    $$store{$sbo} = $repo_path . $loc; -    $locations{$sbo} = $$store{$sbo}; - -    splice @sbos, $found, 1; -    last unless @sbos; -  } -  close $fh; - -  # after we've checked the regular sbo locations, we'll see if it needs to -  # be overridden by a local change -  my $local = $config{LOCAL_OVERRIDES}; -  unless ( $local eq 'FALSE' ) { -    for my $sbo (@sbos, keys %locations) { -      my $loc = "$local/$sbo"; -      next unless -d $loc; -      $$store{$sbo} = $loc; -      $orig{$sbo} //= $locations{$sbo}; -      $locations{$sbo} = $loc; -      $local{$sbo} = $local; -    } -  } - -  return %locations; -} - -=head2 is_local - -  my $bool = is_local($sbo); - -C<is_local()> checks whether the given C<$sbo> is in the C<LOCAL_OVERRIDES> or -not, and returns a true value if it is, and a false value if it isn't. - -=cut - -sub is_local { -  script_error('is_local requires an argument.') unless @_ == 1; -  my $sbo = shift; -  # Make sure we have checked for the slackbuild in question: -  get_sbo_location($sbo); -  return !!$local{$sbo}; -} - -1; diff --git a/SBO-Lib/lib/SBO/Lib/Util.pm b/SBO-Lib/lib/SBO/Lib/Util.pm deleted file mode 100644 index 1598cf1..0000000 --- a/SBO-Lib/lib/SBO/Lib/Util.pm +++ /dev/null @@ -1,566 +0,0 @@ -package SBO::Lib::Util; - -use 5.016; -use strict; -use warnings; - -our $VERSION = '2.8.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 -    get_slack_version_key -    get_slack_version_url -    idx -    in -    indent -    open_fh -    open_read -    print_failures -    prompt -    script_error -    show_version -    slurp -    uniq -    usage_error -    version_cmp -  }, -  @EXPORT_CONSTS, -  @EXPORT_CONFIG, -); - -our %EXPORT_TAGS = ( -  all => \@EXPORT_OK, -  const => \@EXPORT_CONSTS, -  config => \@EXPORT_CONFIG, -); - -=pod - -=encoding UTF-8 - -=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>, C<GPG_KEY>. - -=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', -  GPG_KEY => 'D3076BC3E783EE747F09B8B70368EF579C7BA3B6', -); - -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 an rsync or https URL -my %supported = ( -  '14.0' => 'rsync://slackbuilds.org/slackbuilds/14.0/', -  '14.1' => 'rsync://slackbuilds.org/slackbuilds/14.1/', -  '14.2' => 'rsync://slackbuilds.org/slackbuilds/14.2/', -  '15.0' => 'rsync://slackbuilds.org/slackbuilds/15.0/', -  '15.0+' => 'https://github.com/Ponce/slackbuilds.git', -  current => 'https://github.com/Ponce/slackbuilds.git', -); - -sub get_slack_version { -  return $config{SLACKWARE_VERSION} unless $config{SLACKWARE_VERSION} eq 'FALSE'; -  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" . -    "Suggest you set the sbotools REPO setting to $supported{current}\n") -    unless $supported{$version}; -  return $version; -} - -=head2 get_slack_version_url - -  my $url = get_slack_version_url(); - -C<get_slack_version_url()> returns the default URL for the given slackware -version. - -If there is an error in getting the URL, or if it's not a supported version, -an error message will be shown on STDERR, and the program will exit. - -=cut - -sub get_slack_version_url { -  return $supported{get_slack_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 prompt - -  exit unless prompt "Should we continue?", default => "yes"; - -C<prompt()> prompts the user for an answer, optionally specifying a default of -C<yes> or C<no>. If the default has been specified it returns a true value in -case 'yes' was selected, and a false value if 'no' was selected. Otherwise it -returns whatever the user answered. - -=cut - -sub prompt { -  my ($q, %opts) = @_; -  my $def = $opts{default}; -  $q = sprintf '%s [%s] ', $q, $def eq 'yes' ? 'y' : 'n' if defined $def; - -  print $q; - -  my $res = readline STDIN; - -  if (defined $def) { -    return 1 if $res =~ /^y/i; -    return 0 if $res =~ /^n/i; -    return $def eq 'yes' if $res =~ /^\n/; - -    # if none of the above matched, we ask again -    goto &prompt; -  } -  return $res; -} - -=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 $text = slurp($conf_file); -  if (defined $text) { -    my %conf_values = $text =~ /^(\w+)=(.*)$/mg; -    for my $key (keys %config) { -      $config{$key} = $conf_values{$key} if exists $conf_values{$key}; -    } -    $config{JOBS} = 'FALSE' unless $config{JOBS} =~ /^\d+$/; -  } else { -    warn "Unable to open $conf_file.\n" if -f $conf_file; -  } - -  $config{SBO_HOME} = '/usr/sbo' if $config{SBO_HOME} eq 'FALSE'; -  unless ($config{SBO_HOME} =~ qr#^(/|$)#) { -    usage_error( "The configuration parameter SBO_HOME must be an absolute path."); -  } -} - -=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"; -} - -=head2 slurp - -  my $data = slurp($fn); - -C<slurp()> takes a filename in C<$fn>, opens it, and reads in the entire file, -the contents of which is then returned. On error, it returns C<undef>. - -=cut - -sub slurp { -  my $fn = shift; -  return undef unless -f $fn; -  my ($fh, $exit) = open_read($fn); -  return undef if $exit; -  local $/; -  return scalar readline($fh); -} - -=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 as well as any locale information -if it happens to be appended to the version string being compared. - -=cut - -# wrapper around versioncmp for checking if versions have kernel version -# or locale info appended to them -sub version_cmp { -  my ($v1, $v2) = @_; -  my $kv = get_kernel_version(); - -  # strip off kernel version -  if ($v1 =~ /(.+)_\Q$kv\E$/) { $v1 = $1 } -  if ($v2 =~ /(.+)_\Q$kv\E$/) { $v2 = $1 } - -  # if $v2 doesn't end in the same thing, strip off locale info from $v1 -  if ($v1 =~ /(.*)_([a-z]{2})_([A-Z]{2})$/) { -      my $v = $1; -      if ($v2 !~ /_$2_$3$/) { $v1 = $v; } -  } -  # and vice versa... -  if ($v2 =~ /(.*)_([a-z]{2})_([A-Z]{2})$/) { -      my $v = $1; -      if ($v1 !~ /_$2_$3$/) { $v2 = $v; } -  } - -  versioncmp($v1, $v2); -} - -# _race::cond will allow both documenting and testing race conditions -# by overriding its implementation for tests -sub _race::cond { return } - -1; diff --git a/SBO-Lib/lib/Sort/Versions.pm b/SBO-Lib/lib/Sort/Versions.pm deleted file mode 100644 index 1bcde93..0000000 --- a/SBO-Lib/lib/Sort/Versions.pm +++ /dev/null @@ -1,162 +0,0 @@ -package Sort::Versions; -$Sort::Versions::VERSION = '1.62'; -# Copyright (c) 1996, Kenneth J. Albanowski. All rights reserved.  This -# program is free software; you can redistribute it and/or modify it under -# the same terms as Perl itself. - -use 5.006; -use strict; -use warnings; - -require Exporter; -our @ISA        = qw(Exporter); -our @EXPORT     = qw(&versions &versioncmp); -our @EXPORT_OK  = qw(); - -sub versioncmp ($$) { -    my @A = ($_[0] =~ /([-.]|\d+|[^-.\d]+)/g); -    my @B = ($_[1] =~ /([-.]|\d+|[^-.\d]+)/g); - -    my ($A, $B); -    while (@A and @B) { -	$A = shift @A; -	$B = shift @B; -	if ($A eq '-' and $B eq '-') { -	    next; -	} elsif ( $A eq '-' ) { -	    return -1; -	} elsif ( $B eq '-') { -	    return 1; -	} elsif ($A eq '.' and $B eq '.') { -	    next; -	} elsif ( $A eq '.' ) { -	    return -1; -	} elsif ( $B eq '.' ) { -	    return 1; -	} elsif ($A =~ /^\d+$/ and $B =~ /^\d+$/) { -	    if ($A =~ /^0/ || $B =~ /^0/) { -		return $A cmp $B if $A cmp $B; -	    } else { -		return $A <=> $B if $A <=> $B; -	    } -	} else { -	    $A = uc $A; -	    $B = uc $B; -	    return $A cmp $B if $A cmp $B; -	}	 -    } -    @A <=> @B; -} - -sub versions () { -    my $callerpkg = (caller)[0]; -    my $caller_a = "${callerpkg}::a"; -    my $caller_b = "${callerpkg}::b"; -    no strict 'refs'; -    return versioncmp($$caller_a, $$caller_b); -} - -=encoding utf-8 - -=head1 NAME - -Sort::Versions - a perl 5 module for sorting of revision-like numbers - -=head1 SYNOPSIS - -	use Sort::Versions; -	@l = sort { versioncmp($a, $b) } qw( 1.2 1.2.0 1.2a.0 1.2.a 1.a 02.a ); - -	... - -	use Sort::Versions; -	print 'lower' if versioncmp('1.2', '1.2a') == -1; - -	... - -	use Sort::Versions; -	%h = (1 => 'd', 2 => 'c', 3 => 'b', 4 => 'a'); -	@h = sort { versioncmp($h{$a}, $h{$b}) } keys %h; - -=head1 DESCRIPTION	 - -Sort::Versions allows easy sorting of mixed non-numeric and numeric strings, -like the 'version numbers' that many shared library systems and revision -control packages use. This is quite useful if you are trying to deal with -shared libraries. It can also be applied to applications that intersperse -variable-width numeric fields within text. Other applications can -undoubtedly be found. - -For an explanation of the algorithm, it's simplest to look at these examples: - -  1.1   <  1.2 -  1.1a  <  1.2 -  1.1   <  1.1.1 -  1.1   <  1.1a -  1.1.a <  1.1a -  1     <  a -  a     <  b -  1     <  2 -  1.1-3 <  1.1-4 -  1.1-5 <  1.1.6 - -More precisely (but less comprehensibly), the two strings are treated -as subunits delimited by periods or hyphens. Each subunit can contain -any number of groups of digits or non-digits. If digit groups are -being compared on both sides, a numeric comparison is used, otherwise -a ASCII ordering is used. A group or subgroup with more units will win -if all comparisons are equal.  A period binds digit groups together -more tightly than a hyphen. - -Some packages use a different style of version numbering: a simple -real number written as a decimal. Sort::Versions has limited support -for this style: when comparing two subunits which are both digit -groups, if either subunit has a leading zero, then both are treated -like digits after a decimal point. So for example: - -  0002  <  1 -  1.06  <  1.5 - -This wonE<39>t always work, because there wonE<39>t always be a leading zero -in real-number style version numbers. There is no way for -Sort::Versions to know which style was intended. But a lot of the time -it will do the right thing. If you are making up version numbers, the -style with (possibly) more than one dot is the style to use. - -=head1 USAGE - -The function C<versioncmp()> takes two arguments and compares them like C<cmp>. -With perl 5.6 or later, you can also use this function directly in sorting: - -    @l = sort versioncmp qw(1.1 1.2 1.0.3); - -The function C<versions()> can be used directly as a sort function even on -perl 5.005 and earlier, but its use is deprecated. - -=head1 SEE ALSO - -L<version>, L<CPAN::Version> which is part of the L<CPAN> distribution. - - -=head1 REPOSITORY - -L<https://github.com/neilb/Sort-Versions> - -=head1 AUTHOR - -Ed Avis <ed@membled.com> and Matt Johnson <mwj99@doc.ic.ac.uk> for -recent releases; the original author is Kenneth J. Albanowski -<kjahds@kjahds.com>.  Thanks to Hack Kampbjørn and Slaven Rezic for -patches and bug reports. - -=head1 COPYRIGHT AND LICENSE - -This software is copyright (c) 1996 by Kenneth J. Albanowski. - -This is free software; you can redistribute it and/or modify it under -the same terms as the Perl 5 programming language system itself. - -=cut - -1; - diff --git a/SBO-Lib/t/SBO-Lib.t b/SBO-Lib/t/SBO-Lib.t deleted file mode 100644 index 1c5866b..0000000 --- a/SBO-Lib/t/SBO-Lib.t +++ /dev/null @@ -1,18 +0,0 @@ -# Before `make install' is performed this script should be runnable with -# `make test'. After `make install' it should work as `perl SBO-Lib.t' - -######################### - -# change 'tests => 1' to 'tests => last_test_to_print'; - -use strict; -use warnings; - -use Test::More tests => 1; -BEGIN { use_ok('SBO::Lib') }; - -######################### - -# Insert your test code below, the Test::More module is use()ed here so read -# its man page ( perldoc Test::More ) for help writing this test script. - diff --git a/SBO-Lib/t/versions.t b/SBO-Lib/t/versions.t deleted file mode 100755 index 5793bdc..0000000 --- a/SBO-Lib/t/versions.t +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/perl -#$Id: versions.t,v 1.9 2003/08/24 22:33:03 ed Exp $ - -use 5.006; -use strict; -use warnings; - -use Sort::Versions; -use Test::More; - -my @tests; - -while(<DATA>) { -	if(/^\s*(\S+)\s*([<>])\s*(\S+)\s*$/) { -		push @tests, $1,$3 if $2 eq "<"; -		push @tests, $3,$1 if $2 eq ">"; -	} -} - -plan tests => (@tests / 2 * 3) + 3; - -my @l = sort versions qw(1.2 1.2a); -is($l[0], "1.2"); - -@l = sort { versioncmp($a, $b) } qw(1.2 1.2a); -is($l[0], "1.2"); - -SKIP: { -    skip "requires perl 5.6.0", 1 unless ($] >= 5.006); -    @l = sort versioncmp qw(1.2 1.2a); -    is($l[0], "1.2"); -} - -my $i=4; -while (@tests) { -    ($a, $b) = @tests[0, 1]; - -    # Test both the versioncmp() and versions() interfaces, in both -    # the main package and other packages. -    # -    is(versions(), -1, "versions($a, $b)"); -    $i++; - -    is(versioncmp($a, $b), -1, "versioncmp($a, $b)"); -    $i++; -	 -    undef $a; undef $b; # just in case -	 -    eval { -	package Foo; -	use Sort::Versions; -	($a, $b) = @tests[0, 1]; - -        if (versions() != -1) { -	    die "failed versions() in foreign package"; -	} - -        if (versioncmp($a, $b) != -1) { -	    die "failed versioncmp() in foreign package"; -	} -    }; -    if ($@) { -	fail($@); -    } -    else { -	pass("foreign package tests ($tests[0], $tests[1])"); -    } - -    shift @tests; shift @tests; -} - - -__END__ - -# Simple . only tests -1.2   < 1.3 -1.2   < 1.2.1 -1.2.1 < 1.3 -1.2   < 1.2a -1.2a  < 1.3 -1.2   < 1.2.b -1.2.1 < 1.2a -1.2.b < 1.2a - -# Assorted non-numerics -a     < b -a     < a.b -a.b   < a.c -a.1   < a.a -1 < a -1a < a -1a < 2 - -# Null version point -1..1 < 1.1.1 - -# Leading 0 tests -1 > 0002 -1.5 > 1.06 - -# Handling mixed -. versions -1 < 1-1 -1-1 < 1-2 -1-2 < 1.2 -1-2 < 1.0-1 -1-2 < 1.0 -1-2 < 1.3 -1.2-1 < 1.2a-1 -1.3-4.6-7 < 1.3-4.8 -1.3-4.6-7 < 1.3-4.6.7 -1.3-4a-7 < 1.3-4a-7.4 - -# 'Bug' reported by pgw99 -1.2-1 < 1.2.1-1 -1.2.1-1 < 1.2.1-2 -1.2.1-2 < 1.3.0-1 | 
