sbotools2

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

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 }