sbotools2

Maintenance fork of the original sbotools version 2
git clone git://git.server.ky/slackcoder/sbotools2
Log | Files | Refs | README

Remove.pm (5671B)


      1 package SBO::App::Remove;
      2 
      3 # vim: ts=2:et
      4 #
      5 # authors: Luke Williams <xocel@iquidus.org>
      6 #          Jacob Pipkin <j@dawnrazor.net>
      7 #          Andreas Guldstrand <andreas.guldstrand@gmail.com>
      8 # maintainer: Slack Coder <slackcoder@server.ky>
      9 
     10 use 5.16.0;
     11 use strict;
     12 use warnings FATAL => 'all';
     13 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 /;
     14 use Getopt::Long qw(GetOptionsFromArray :config bundling);
     15 
     16 use parent 'SBO::App';
     17 
     18 our $VERSION = '2.9.0';
     19 
     20 sub _parse_opts {
     21   my $class = shift;
     22   my @ARGS = @_;
     23 
     24   my ($help, $vers, $non_int, $alwaysask);
     25 
     26   my $res = GetOptionsFromArray(
     27     \@ARGS,
     28     'help|h'        => \$help,
     29     'version|v'     => \$vers,
     30     'nointeractive' => \$non_int,
     31     'alwaysask|a'   => \$alwaysask,
     32   );
     33 
     34   return ({ help => $help, vers => $vers, non_int => $non_int, alwaysask => $alwaysask, args => \@ARGS, }, $res);
     35 }
     36 
     37 sub run {
     38   my $self = shift;
     39 
     40   if ($self->{help}) { $self->show_usage(); return 0; }
     41   if ($self->{vers}) { $self->show_version(); return 0; }
     42   if (!@{ $self->{args} }) { $self->show_usage(); return 1; }
     43 
     44   unless ($< == 0) {
     45   	warn "This script requires root privileges.\n";
     46   	exit _ERR_USAGE;
     47   }
     48 
     49   # current workflow:
     50   # * get names of all installed SBo packages
     51   # * compare commandline args to SBo packages as well as installed SBo packages
     52   # * add reverse deps to list if they're not a dep of something else (which is not also already on the list)
     53   # * confirm removal of each package on the list
     54   #   - while taking into account the options passed in such as $non_int, and $alwaysask
     55   #   - also offering to display README if %README% is passed
     56   # * remove the confirmed packages
     57 
     58   my @args = @{ $self->{args} };
     59 
     60   my @installed = @{ get_installed_packages('SBO') };
     61   my $installed = +{ map {; $_->{name}, $_->{pkg} } @installed };
     62 
     63   @args = grep { check_sbo($_, $installed) } @args;
     64   exit 1 unless @args;
     65   my %sbos = map { $_ => 1 } @args;
     66 
     67   my @remove = get_full_queue($installed, @args);
     68 
     69   my @confirmed;
     70 
     71   if ($self->{non_int}) {
     72     @confirmed = @remove;
     73   } else {
     74     my $required_by = get_reverse_reqs($installed);
     75     for my $remove (@remove) {
     76       # if $remove was on the commandline, mark it as not needed,
     77       # otherwise check if it is needed by something else.
     78       my @required_by = get_required_by($remove->{name}, [map { $_->{name} } @confirmed], $required_by);
     79       my $needed = $sbos{$remove->{name}} ? 0 : @required_by;
     80 
     81       next if $needed and not $self->{alwaysask};
     82 
     83       push @confirmed, $remove if confirm($remove, $needed ? @required_by : ());
     84     }
     85   }
     86 
     87   if (@confirmed) {
     88     $self->remove(@confirmed);
     89   } else {
     90     say "Nothing to remove.";
     91   }
     92 
     93   return 0;
     94 }
     95 
     96 sub show_usage {
     97   my $self = shift;
     98   my $fname = $self->{fname};
     99 
    100 	print <<"EOF";
    101 Usage: $fname [options] sbo
    102 
    103 Options (defaults shown first where applicable):
    104   -h|--help:
    105     this screen.
    106   -v|--version:
    107     version information.
    108   -a|--alwaysask:
    109     always ask to remove, even if required by other packages on system.
    110 
    111 Note: optional dependencies need to be removed separately.
    112 
    113 EOF
    114 	return 1;
    115 }
    116 
    117 sub check_sbo {
    118   my ($sbo, $installed) = @_;
    119 
    120   if (not get_sbo_location($sbo)) {
    121     say "Unable to locate $sbo in the SlackBuilds.org tree.";
    122     return 0;
    123   }
    124 
    125   if (not exists $installed->{$sbo}) {
    126     say "$sbo is not installed from SlackBuilds.org.";
    127     return 0;
    128   }
    129 
    130   return 1;
    131 }
    132 
    133 sub get_full_queue {
    134   my ($installed, @sbos) = @_;
    135 
    136   my $remove_queue = [];
    137   my %warnings;
    138   for my $sbo (@sbos) {
    139     my $queue = get_build_queue([$sbo], \%warnings);
    140     @$queue = reverse @$queue;
    141     $remove_queue = merge_queues($remove_queue, $queue);
    142   }
    143 
    144   return map {; +{
    145       name => $_,
    146       pkg => $installed->{$_},
    147       defined $warnings{$_} ? (warning => $warnings{$_}) : ()
    148     } }
    149     grep { exists $installed->{$_} }
    150     @$remove_queue;
    151 }
    152 
    153 sub get_reverse_reqs {
    154   my $installed = shift;
    155   my %required_by;
    156 
    157   for my $inst (keys %$installed) {
    158     for my $req (@{ get_requires($inst) }) {
    159       $required_by{$req}{$inst} = 1 if exists $installed->{$req};
    160     }
    161   }
    162 
    163   return \%required_by;
    164 }
    165 
    166 sub get_required_by {
    167   my ($sbo, $confirmed, $required_by) = @_;
    168   my @dep_of;
    169 
    170   if ( $required_by->{$sbo} ) {
    171     for my $req_by (keys %{$required_by->{$sbo}}) {
    172       push @dep_of, $req_by unless in($req_by => @$confirmed);
    173     }
    174   }
    175   return @dep_of;
    176 }
    177 
    178 sub confirm {
    179   my ($remove, @required_by) = @_;
    180 
    181   if (@required_by) {
    182     say sprintf "%s : required by %s", $remove->{name}, join ' ', @required_by;
    183   } else {
    184     say $remove->{name};
    185   }
    186 
    187   if ($remove->{warning}) {
    188     say "It is recommended that you view the README before continuing.";
    189     if (prompt("Display README now?", default => 'yes')) {
    190       my $readme = get_readme_contents(get_sbo_location($remove->{name}));
    191       if (not defined $readme) {
    192         warn "Unable to open README for $remove->{name}.\n";
    193       } else {
    194         print "\n" . $readme;
    195       }
    196     }
    197   }
    198 
    199   if (prompt("Remove $remove->{name}?", default => @required_by ? 'no' : 'yes')) {
    200     say " * Added to remove queue\n";
    201     return 1;
    202   }
    203   say " * Ignoring\n";
    204   return 0;
    205 }
    206 
    207 sub remove {
    208   my $self = shift;
    209   my $non_int = $self->{non_int};
    210   my @confirmed = @_;
    211 
    212   say sprintf "Removing %d package(s)", scalar @confirmed;
    213   say join " ", map { $_->{name} } @confirmed;
    214 
    215   if (!$non_int and !prompt("\nAre you sure you want to continue?", default => 'no')) {
    216     return say 'Exiting.';
    217   }
    218 
    219   system("/sbin/removepkg", $_->{pkg}) for @confirmed;
    220 
    221   say "All operations have completed successfully.";
    222 }
    223 
    224 1;