sboinstall (7650B)
1 #!/usr/bin/perl 2 # 3 # vim: ts=4:noet 4 # 5 # sboinstall 6 # script to install (a) SlackBuild(s) by name 7 # 8 # authors: Jacob Pipkin <j@dawnrazor.net> 9 # Luke Williams <xocel@iquidus.org> 10 # Andreas Guldstrand <andreas.guldstrand@gmail.com> 11 # maintainer: Slack Coder <slackcoder@server.ky> 12 13 use 5.16.0; 14 use strict; 15 use warnings FATAL => 'all'; 16 use SBO::Lib qw/ %config _ERR_USAGE _ERR_OPENFH get_arch get_build_queue get_installed_cpans get_installed_packages get_sbo_location get_sbo_locations in merge_queues open_fh print_failures process_sbos prompt show_version slackbuilds_or_fetch slurp usage_error user_prompt /; 17 use Getopt::Long qw(:config bundling); 18 use File::Basename; 19 use JSON::PP; 20 21 my $self = basename($0); 22 23 sub show_usage { 24 print <<"EOF"; 25 Usage: $self [options] sbo 26 $self --use-template file 27 28 Options (defaults shown first where applicable): 29 -h|--help: 30 this screen. 31 -v|--version: 32 version information. 33 -c|--noclean (FALSE|TRUE): 34 set whether or not to clean working files/directories after the build. 35 -d|--distclean (TRUE|FALSE): 36 set whether or not to clean distfiles afterward. 37 -i|--noinstall: 38 do not run installpkg at the end of the build process. 39 -j|--jobs (FALSE|#): 40 specify "-j" setting to make, for multicore systems; overrides conf file. 41 -p|--compat32: 42 install an SBo as a -compat32 pkg on a multilib x86_64 system. 43 -r|--nointeractive: 44 non-interactive; skips README and all prompts. 45 -R|--norequirements: 46 view the README but do not parse requirements, commands, or options. 47 --reinstall: 48 Ask to reinstall any already-installed packages in the requirement list. 49 --create-template (FILE): 50 create a template with specified requirements, commands, and options. 51 --use-template (FILE): 52 use a template created by --create-template to install requirements with 53 specified commands and options. This also enables the --nointeractive flag. 54 55 EOF 56 return 1; 57 } 58 59 my $noclean = $config{NOCLEAN}; 60 my $distclean = $config{DISTCLEAN}; 61 my $jobs = $config{JOBS}; 62 my ($help, $vers, $no_install, $non_int, $no_reqs, $compat32, $ctemp, $utemp, $reinstall); 63 64 if (! GetOptions( 65 'help|h' => \$help, 66 'version|v' => \$vers, 67 'noclean|c=s' => \$noclean, 68 'distclean|d=s' => \$distclean, 69 'noinstall|i' => \$no_install, 70 'jobs|j=s' => \$jobs, 71 'compat32|p' => \$compat32, 72 'nointeractive|r' => \$non_int, 73 'norequirements|R' => \$no_reqs, 74 'reinstall' => \$reinstall, 75 'create-template=s' => \$ctemp, 76 'use-template=s' => \$utemp, 77 )) { 78 show_usage(); 79 exit 1; 80 } 81 82 if ($help) { show_usage(); exit 0 } 83 if ($vers) { show_version(); exit 0 } 84 85 if (!@ARGV and not length $utemp) { show_usage(); exit 1 } 86 if (defined $utemp and not length $utemp) { show_usage(); exit 1 } 87 if (defined $ctemp and not length $ctemp) { show_usage(); exit 1 } 88 89 $noclean = $noclean eq 'TRUE' ? 1 : 0; 90 $distclean = $distclean eq 'TRUE' ? 1 : 0; 91 92 if ($jobs) { 93 usage_error("You have provided an invalid value for -j|--jobs") 94 unless ($jobs =~ /^\d+$/ || $jobs eq 'FALSE'); 95 } 96 97 if ($compat32) { 98 usage_error("compat32 only works on x86_64.") unless get_arch eq 'x86_64'; 99 } 100 101 unless ($< == 0) { 102 warn "This script requires root privileges.\n"; 103 exit _ERR_USAGE; 104 } 105 106 # if we can't find SLACKBUILDS.TXT in $config{HOME}, prompt to fetch the tree 107 slackbuilds_or_fetch(); 108 109 my (%warnings, $build_queue, $template); 110 111 if (length $utemp) { 112 my $json = JSON::PP->new->latin1; 113 $non_int = 1; 114 115 my $data = slurp($utemp); 116 if (length $data) { 117 eval { $template = $json->decode($data); }; 118 } 119 do { warn "Could not read template from $utemp.\n"; exit _ERR_OPENFH } if not defined $template; 120 121 $build_queue = $template->{build_queue}; 122 } else { 123 if ($no_reqs or $non_int) { 124 $build_queue = \@ARGV; 125 } else { 126 for my $sbo (@ARGV) { 127 my $queue = get_build_queue([$sbo], \%warnings); 128 $build_queue = merge_queues($build_queue, $queue); 129 } 130 } 131 } 132 133 # get lists of installed packages and perl modules from CPAN 134 my $inst_pkgs = get_installed_packages('ALL'); 135 my $pms = get_installed_cpans(); 136 s/::/-/g for @$pms; 137 my %inst_names; 138 $inst_names{$_->{name}} = $_ for @$inst_pkgs; 139 140 # populate %locations and sanity check 141 my %locations = get_sbo_locations($build_queue); 142 for my $sbo (@$build_queue) { 143 next if $inst_names{$sbo}; 144 145 if (not $locations{$sbo} and in($sbo, @ARGV)) { 146 usage_error("Unable to locate $sbo in the SlackBuilds.org tree.") 147 } 148 if ($compat32) { 149 usage_error("-p|--compat32 is not supported with Perl SBos.") 150 if $locations{$sbo} =~ qr|/perl/[^/]+$|; 151 } 152 } 153 154 # check for already-installeds and prompt for the rest 155 my (@temp_queue, %commands, %options); 156 if (defined $template) { 157 %commands = %{ $template->{commands} }; 158 %options = %{ $template->{options} }; 159 } 160 my $added = ' added to install queue.'; 161 FIRST: for my $sbo (@$build_queue) { 162 my $name = $compat32 ? "$sbo-compat32" : $sbo; 163 164 if ($inst_names{$name}) { 165 my $inst_msg = sprintf "%s (%s) is already installed.", $name, $inst_names{$name}{pkg}; 166 if ($reinstall and not $non_int) { 167 next FIRST unless prompt("$inst_msg Do you want to reinstall from SBo?", default => 'no'); 168 } elsif ($reinstall) { 169 say "$inst_msg Reinstalling."; 170 } else { 171 say $inst_msg; 172 next FIRST; 173 } 174 } else { 175 if ($sbo =~ /^perl-/) { 176 my $pm_name = $sbo; 177 $pm_name =~ s/^perl-//; 178 for my $pm (@$pms) { 179 if ($pm =~ /^$pm_name$/i) { 180 say "$sbo installed via the cpan."; 181 next FIRST; 182 } 183 } 184 } 185 } 186 187 # Make sure the slackbuild exists on SBo 188 if (defined $warnings{$sbo} and $warnings{$sbo} eq 'nonexistent') { 189 say "Unable to locate $sbo in the SlackBuilds.org tree."; 190 if (not $non_int) { 191 exit 0 unless prompt "Do you want to ignore it and continue?", default => 'no'; 192 } 193 next FIRST; 194 } 195 196 $locations{$name} = get_sbo_location($sbo) if $compat32; 197 unless ($non_int) { 198 # if compat32 is TRUE, we need to see if the non-compat version exists. 199 if ($compat32) { 200 unless ($inst_names{$sbo}) { 201 say "$name requires $sbo."; 202 my ($cmds, $opts, $exit) = user_prompt($sbo, $locations{$sbo}); 203 if ($exit) { 204 warn "Unable to open README for $sbo.\n"; 205 exit $exit; 206 } 207 if ($cmds) { 208 next FIRST if $cmds eq 'N'; 209 } 210 push(@temp_queue, $sbo); 211 $commands{$sbo} = $cmds; 212 $options{$sbo} = $cmds; 213 say "$sbo$added"; 214 } 215 } 216 my ($cmds, $opts, $exit) = user_prompt($name, $locations{$name}); 217 if ($exit) { 218 warn "Unable to open README for $name.\n"; 219 exit $exit; 220 } 221 if ($cmds) { 222 next FIRST if $cmds eq 'N'; 223 } 224 push(@temp_queue, $name); 225 $commands{$sbo} = $cmds; 226 $options{$sbo} = $opts; 227 say "$name$added"; 228 } else { 229 push(@temp_queue, $sbo); 230 say "\n$name$added"; 231 } 232 } 233 @$build_queue = @temp_queue; 234 235 exit 0 if @{ $build_queue } == 0; 236 say "\nInstall queue: " . join(' ', @$build_queue); 237 unless ($non_int) { 238 exit 0 unless prompt("\nAre you sure you wish to continue?", default => 'yes'); 239 } 240 241 if (defined $ctemp) { 242 my ($temp_fh, $exit) = open_fh($ctemp, '>'); 243 do { warn $temp_fh; exit $exit } if $exit; 244 245 my $json = JSON::PP->new->latin1->pretty->canonical; 246 my $build_settings = { 247 build_queue => $build_queue, 248 commands => \%commands, 249 options => \%options, 250 }; 251 print {$temp_fh} $json->encode( $build_settings ); 252 close $temp_fh; 253 print "\nTemplate $ctemp saved.\n"; 254 } 255 256 my ($failures, $exit) = process_sbos( 257 TODO => $build_queue, 258 CMDS => \%commands, 259 OPTS => \%options, 260 JOBS => $jobs, 261 LOCATIONS => \%locations, 262 NOINSTALL => $no_install, 263 NOCLEAN => $noclean, 264 DISTCLEAN => $distclean, 265 NON_INT => $non_int, 266 ); 267 print_failures($failures); 268 269 if ($exit) { 270 exit $exit; 271 } else { 272 exit 0; 273 }