aboutsummaryrefslogtreecommitdiff
path: root/t/SBO/Lib.pm
diff options
context:
space:
mode:
Diffstat (limited to 't/SBO/Lib.pm')
-rw-r--r--t/SBO/Lib.pm668
1 files changed, 668 insertions, 0 deletions
diff --git a/t/SBO/Lib.pm b/t/SBO/Lib.pm
new file mode 100644
index 0000000..398e6a3
--- /dev/null
+++ b/t/SBO/Lib.pm
@@ -0,0 +1,668 @@
+#!/usr/bin/env perl
+#
+# vim: set ts=4:noet
+#
+# Lib.pm
+# shared functions for the sbo_ scripts.
+#
+# author: Jacob Pipkin <j@dawnrazor.net>
+# date: Setting Orange, the 37th day of Discord in the YOLD 3178
+# license: WTFPL <http://sam.zoy.org/wtfpl/COPYING>
+
+use 5.16.0;
+use warnings FATAL => 'all';
+use strict;
+
+package SBO::Lib 1.0;
+my $version = "1.0";
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(get_slack_version chk_slackbuilds_txt check_home rsync_sbo_tree get_sbo_from_loc get_sbo_version get_download_info get_arch get_sbo_downloads get_filename_from_link compute_md5sum compare_md5s verify_distfile get_distfile get_symlink_from_filename check_x32 check_multilib rewrite_slackbuild revert_slackbuild check_distfiles create_symlinks grok_temp_file get_src_dir get_pkg_name perform_sbo do_convertpkg
+ script_error
+ open_fh
+ open_read
+ show_version
+ slackbuilds_or_fetch
+ fetch_tree
+ update_tree
+ get_installed_sbos
+ get_available_updates
+ do_slackbuild
+ make_clean
+ make_distclean
+ do_upgradepkg
+ get_sbo_location
+ get_from_info
+ get_tmp_fn
+);
+
+#$< == 0 or die "This script requires root privileges.\n";
+
+use Tie::File;
+use Sort::Versions;
+use Digest::MD5;
+use File::Copy;
+use File::Path qw(make_path remove_tree);
+use Fcntl;
+use File::Find;
+use File::Temp qw(tempdir tempfile);
+use Data::Dumper;
+use Fcntl qw(F_SETFD F_GETFD);
+
+our $tempdir = tempdir (CLEANUP => 1);
+
+# subroutine for throwing internal script errors
+sub script_error (;$) {
+ exists $_[0] ? die "A fatal script error has occured:\n$_[0]\nExiting.\n"
+ : die "A fatal script error has occured. Exiting.\n";
+}
+
+# sub for opening files, second arg is like '<','>', etc
+sub open_fh ($$) {
+ exists $_[1] or script_error 'open_fh requires two arguments';
+ -f $_[0] or script_error 'open_fh first argument not a file';
+ my ($file, $op) = @_;
+ open my $fh, $op, $file or die "Unable to open $file.\n";
+ return $fh;
+}
+
+sub open_read ($) {
+ return open_fh shift, '<';
+}
+
+# pull in configuration, set sane defaults, etc.
+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',
+);
+
+# if the conf file exists, pull all the $key=$value pairs into a hash
+my %conf_values;
+if (-f $conf_file) {
+ my $fh = open_read $conf_file;
+ my $text = do {local $/; <$fh>};
+ %conf_values = $text =~ /^(\w+)=(.*)$/mg;
+ close $fh;
+}
+
+for my $key (keys %config) {
+ $config{$key} = $conf_values{$key} if exists $conf_values{$key};
+}
+$config{JOBS} = 'FALSE' unless $config{JOBS} =~ /^\d+$/;
+$config{SBO_HOME} = '/usr/sbo' if $config{SBO_HOME} eq 'FALSE';
+
+# some stuff we'll need later.
+my $distfiles = "$config{SBO_HOME}/distfiles";
+my $slackbuilds_txt = "$config{SBO_HOME}/SLACKBUILDS.TXT";
+my $name_regex = '\ASLACKBUILD\s+NAME:\s+';
+
+sub show_version () {
+ say "sbotools version $version";
+ say 'licensed under the WTFPL';
+ say '<http://sam.zoy.org/wtfpl/COPYING>';
+}
+
+# %supported maps what's in /etc/slackware-version to what's at SBo
+# which is now not needed since this version drops support < 14.0
+# but it's already future-proofed, so leave it.
+sub get_slack_version () {
+ my %supported = ('14.0' => '14.0');
+ my $fh = open_read '/etc/slackware-version';
+ chomp (my $line = <$fh>);
+ close $fh;
+ my $version = ($line =~ /\s+(\d+[^\s]+)$/)[0];
+ die "Unsupported Slackware version: $version\n"
+ unless $version ~~ %supported;
+ return $supported{$version};
+}
+
+# does the SLACKBUILDS.TXT file exist in the sbo tree?
+sub chk_slackbuilds_txt () {
+ return -f $slackbuilds_txt ? 1 : 0;
+}
+
+# check for the validity of new $config{SBO_HOME}
+sub check_home () {
+ my $sbo_home = $config{SBO_HOME};
+ if (-d $sbo_home) {
+ opendir (my $home_handle, $sbo_home);
+ FIRST: while (readdir $home_handle) {
+ next FIRST if /^\.[\.]{0,1}$/;
+ die "$sbo_home exists and is not empty. Exiting.\n";
+ }
+ } else {
+ make_path ($sbo_home) or die "Unable to create $sbo_home.\n";
+ }
+}
+
+# rsync the sbo tree from slackbuilds.org to $config{SBO_HOME}
+sub rsync_sbo_tree () {
+ my $slk_version = get_slack_version;
+ my @arg = ('rsync', '-a', '--exclude=*.tar.gz', '--exclude=*.tar.gz.asc');
+ push @arg, "rsync://slackbuilds.org/slackbuilds/$slk_version/*";
+ my $out = system @arg, $config{SBO_HOME};
+ say 'Finished.' and return $out;
+}
+
+# wrappers for differing checks and output
+sub fetch_tree () {
+ check_home;
+ say 'Pulling SlackBuilds tree...';
+ rsync_sbo_tree, return $?;
+}
+
+sub update_tree () {
+ fetch_tree, return unless chk_slackbuilds_txt;
+ say 'Updating SlackBuilds tree...';
+ rsync_sbo_tree, return $?;
+}
+
+# if the SLACKBUILDS.TXT is not in $config{SBO_HOME}, 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.';
+ print 'Would you like me to do this now? [y] ';
+ <STDIN> =~ /^[Yy\n]/ ? fetch_tree :
+ die "Please run \"sbosnap fetch\"\n";
+ }
+ return 1;
+}
+
+# pull an array of hashes, each hash containing the name and version of an sbo
+# currently installed.
+sub get_installed_sbos () {
+ my @installed;
+ # $1 == name, $2 == version
+ my $regex = qr#/([^/]+)-([^-]+)-[^-]+-[^-]+$#;
+ for my $path (</var/log/packages/*_SBo>) {
+ my ($name, $version) = ($path =~ $regex)[0,1];
+ push @installed, {name => $name, version => $version};
+ }
+ return \@installed;
+}
+
+# search the SLACKBUILDS.TXT for a given sbo's directory
+sub get_sbo_location ($) {
+ exists $_[0] or script_error 'get_sbo_location requires an argument.';
+ my $sbo = shift;
+ my $regex = qr#LOCATION:\s+\.(/[^/]+/$sbo)$#;
+ my $fh = open_read $slackbuilds_txt;
+ while (my $line = <$fh>) {
+ if (my $loc = ($line =~ $regex)[0]) {
+ return "$config{SBO_HOME}$loc";
+ }
+ }
+ return;
+}
+
+# pull the sbo name from a $location: $config{SBO_HOME}/system/wine, etc.
+sub get_sbo_from_loc ($) {
+ exists $_[0] or script_error 'get_sbo_from_loc requires an argument.';
+ return (shift =~ qr#/([^/]+)$#)[0];
+}
+
+# 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 $vars = {PRGNAM => ['']};
+ my $sbo = get_sbo_from_loc $args{LOCATION};
+ return $$vars{$args{GET}} if $$vars{PRGNAM}[0] eq $sbo;
+ # if we're here, we haven't read in the .info file yet.
+ my $fh = open_read "$args{LOCATION}/$sbo.info";
+ # suck it all in, clean it all up, stuff it all in $vars.
+ my $contents = do {local $/; <$fh>};
+ $contents =~ s/("|\\\n)//g;
+ $vars = {$contents =~ /^(\w+)=(.*)$/mg};
+ # fill the hash with array refs - even for single values,
+ # since consistency here is a lot easier than sorting it out later
+ for my $key (keys %$vars) {
+ if ($$vars{$key} =~ /\s/) {
+ my @array = split ' ', $$vars{$key};
+ $$vars{$key} = \@array;
+ } else {
+ $$vars{$key} = [$$vars{$key}];
+ }
+ }
+ return exists $$vars{$args{GET}} ? $$vars{$args{GET}} : 0;
+}
+
+# find the version in the tree for a given sbo (provided a location)
+sub get_sbo_version ($) {
+ exists $_[0] or script_error 'get_sbo_version requires an argument.';
+ my $version = get_from_info (LOCATION => shift, GET => 'VERSION');
+ return $$version[0] ? $$version[0] : 0;
+}
+
+# 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_sbos;
+ FIRST: for my $key (keys @$pkg_list) {
+ my $location = get_sbo_location $$pkg_list[$key]{name};
+ # if we can't find a location, assume invalid and skip
+ next FIRST unless defined $location;
+ my $version = get_sbo_version $location;
+ if (versioncmp ($version, $$pkg_list[$key]{version}) == 1) {
+ push @updates, {
+ name => $$pkg_list[$key]{name},
+ installed => $$pkg_list[$key]{version},
+ update => $version
+ };
+ }
+ }
+ return \@updates;
+}
+
+# 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, $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}) {
+ my $nothing;
+ if (! $$downs[0]) {
+ $nothing = 1;
+ } elsif ($$downs[0] =~ qr/^UN(SUPPOR|TES)TED$/) {
+ $nothing = 1;
+ }
+ if ($nothing) {
+ $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;
+}
+
+sub get_arch () {
+ chomp (my $arch = `uname -m`);
+ return $arch;
+}
+
+# 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;
+}
+
+# given a link, grab the filename from the end of it
+sub get_filename_from_link ($) {
+ exists $_[0] or script_error 'get_filename_from_link requires an argument';
+ return "$distfiles/". (shift =~ qr#/([^/]+)$#)[0];
+}
+
+# for a given file, computer its md5sum
+sub compute_md5sum ($) {
+ -f $_[0] or script_error 'compute_md5sum requires a file argument.';
+ my $fh = open_read shift;
+ my $md5 = Digest::MD5->new;
+ $md5->addfile ($fh);
+ my $md5sum = $md5->hexdigest;
+ close $fh;
+ return $md5sum;
+}
+
+sub compare_md5s ($$) {
+ exists $_[1] or script_error 'compare_md5s requires two arguments.';
+ my ($first, $second) = @_;
+ return $first eq $second ? 1 : 0;
+}
+
+# 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 ($$) {
+ exists $_[1] or script_error 'check_distfile requires two arguments.';
+ my ($link, $info_md5sum) = @_;
+ my $filename = get_filename_from_link $link;
+ return unless -d $distfiles;
+ return unless -f $filename;
+ my $md5sum = compute_md5sum $filename;
+ return compare_md5s $info_md5sum, $md5sum;
+}
+
+# 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 ($$) {
+ exists $_[1] or script_error 'get_distfile requires an argument';
+ my ($link, $exp_md5) = @_;
+ my $filename = get_filename_from_link $link;
+ mkdir $distfiles unless -d $distfiles;
+ chdir $distfiles;
+ system ("wget --no-check-certificate $link") == 0 or
+ die "Unable to wget $link\n";
+ my $md5sum = compute_md5sum $filename;
+ # can't do anything if the link in the .info doesn't lead to a good d/l
+ compare_md5s $md5sum, $exp_md5 or die "md5sum failure for $filename.\n";
+ return 1;
+}
+
+# for a given distfile, figure out what the full path to its symlink will be
+sub get_symlink_from_filename ($$) {
+ exists $_[1] or script_error
+ 'get_symlink_from_filename requires two arguments';
+ -f $_[0] or script_error
+ 'get_symlink_from_filename first argument is not a file';
+ my ($filename, $location) = @_;
+ return "$location/". ($filename =~ qr#/([^/]+)$#)[0];
+}
+
+# determine whether or not a given sbo is 32-bit only
+sub check_x32 ($) {
+ exists $_[0] or script_error 'check_x32 requires an argument.';
+ my $dl = get_from_info (LOCATION => shift, GET => 'DOWNLOAD_x86_64');
+ return $$dl[0] =~ /UN(SUPPOR|TES)TED/ ? 1 : 0;
+}
+
+# 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;
+}
+
+# make a backup of the existent SlackBuild, and rewrite the original as needed
+sub rewrite_slackbuild ($$%) {
+ exists $_[1] or script_error 'rewrite_slackbuild requires two arguments.';
+ my ($slackbuild, $tempfn, %changes) = @_;
+ copy ($slackbuild, "$slackbuild.orig") or
+ die "Unable to backup $slackbuild to $slackbuild.orig\n";
+ my $tar_regex = qr/(un|)tar .*$/;
+ my $makepkg_regex = qr/makepkg/;
+ my $libdir_regex = qr/^\s*LIBDIRSUFFIX="64"\s*$/;
+ my $make_regex = qr/^\s*make(| \Q||\E exit 1)$/;
+ my $arch_regex = qr/\$VERSION-\$ARCH-\$BUILD/;
+ # tie the slackbuild, because this is the easiest way to handle this.
+ tie my @sb_file, 'Tie::File', $slackbuild;
+ for my $line (@sb_file) {
+ # get the output of the tar and makepkg commands. hope like hell that v
+ # is specified among tar's arguments
+ if ($line =~ $tar_regex || $line =~ $makepkg_regex) {
+ $line = "$line | tee -a $tempfn";
+ }
+ # then check for and apply any other %changes
+ if (exists $changes{libdirsuffix}) {
+ $line =~ s/64/$changes{libdirsuffix}/ if $line =~ $libdir_regex;
+ }
+ if (exists $changes{make}) {
+ $line =~ s/make/make $changes{make}/ if $line =~ $make_regex;
+ }
+ if (exists $changes{arch_out}) {
+ $line =~ s/\$ARCH/$changes{arch_out}/ if $line =~ $arch_regex;
+ }
+ }
+ untie @sb_file;
+ return 1;
+}
+
+# move a backed-up .SlackBuild file back into place
+sub revert_slackbuild ($) {
+ exists $_[0] or script_error 'revert_slackbuild requires an argument';
+ my $slackbuild = shift;
+ if (-f "$slackbuild.orig") {
+ unlink $slackbuild if -f $slackbuild;
+ rename ("$slackbuild.orig", $slackbuild);
+ }
+ return 1;
+}
+
+# for each $download, see if we have it, and if the copy we have is good,
+# otherwise download a new copy
+sub check_distfiles (%) {
+ exists $_[0] or script_error 'check_distfiles requires an argument.';
+ my %dists = @_;
+ for my $link (keys %dists) {
+ my $md5sum = $dists{$link};
+ unless (verify_distfile $link, $md5sum) {
+ die unless get_distfile $link, $md5sum;
+ }
+ }
+ return 1;
+}
+
+# given a location and a list of download links, assemble a list of symlinks,
+# and create them.
+sub create_symlinks ($%) {
+ exists $_[1] or script_error 'create_symlinks requires two arguments.';
+ 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;
+}
+
+# pull the untarred source directory or created package name from the temp
+# file (the one we tee'd to)
+sub grok_temp_file (%) {
+ my %args = (
+ FH => '',
+ REGEX => '',
+ CAPTURE => 0,
+ @_
+ );
+ unless ($args{FH} && $args{REGEX}) {
+ script_error 'grok_temp_file requires two arguments';
+ }
+ my $fh = $args{FH};
+ seek $fh, 0, 0;
+ my $out;
+ FIRST: while (my $line = <$fh>) {
+ if ($line =~ $args{REGEX}) {
+ $out = ($line =~ $args{REGEX})[$args{CAPTURE}];
+ last FIRST;
+ }
+ }
+# close $fh;
+ return $out;
+}
+
+# wrappers around grok_temp_file
+sub get_src_dir ($) {
+ exists $_[0] or script_error 'get_src_dir requires an argument';
+ return grok_temp_file (FH => shift, REGEX => qr#^([^/]+)/#);
+}
+
+sub get_pkg_name ($) {
+ exists $_[0] or script_error 'get_pkg_name requires an argument';
+ return grok_temp_file (FH => shift,
+ REGEX => qr/^Slackware\s+package\s+([^\s]+)\s+created\.$/);
+}
+
+sub get_tmp_fn ($) {
+ exists $_[0] or script_error 'get_tmp_fn requires an argument.';
+ my $fh = shift;
+ fcntl ($fh, F_SETFD, 0) or die "no unset exec-close thingy\n";
+ return "/dev/fd/". fileno $fh;
+}
+
+# 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;
+ my ($cmd, %changes);
+ # figure out any changes we need to make to the .SlackBuild
+ $changes{make} = "-j $args{JOBS}" if $args{JOBS};
+ 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 &&";
+ }
+ $cmd .= "/bin/sh $location/$sbo.SlackBuild";
+ $cmd = "$args{OPTS} $cmd" if $args{OPTS};
+ my $tempfh = tempfile (DIR => $tempdir);
+ my $fn = get_tmp_fn $tempfh;
+ rewrite_slackbuild "$location/$sbo.SlackBuild", $fn, %changes;
+ chdir $location, my $out = system $cmd;
+ revert_slackbuild "$location/$sbo.SlackBuild";
+ die unless $out == 0;
+ my $pkg = get_pkg_name $tempfh;
+ my $src = get_src_dir $tempfh;
+ return $pkg, $src;
+}
+
+# run convertpkg on a package to turn it into a -compat32 thing
+sub do_convertpkg ($) {
+ exists $_[0] or script_error 'do_convertpkg requires an argument.';
+ my $pkg = shift;
+ my $tempfh = tempfile (DIR => $tempdir);
+ my $fn = get_tmp_fn $tempfh;
+ my $cmd = "/usr/sbin/convertpkg-compat32 -i $pkg -d /tmp | tee $fn";
+ system ($cmd) == 0 or die;
+ unlink $pkg;
+ return get_pkg_name $tempfh;
+}
+
+# "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 $multi = 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}) {
+ die "compat32 only works on x86_64.\n" unless $arch eq 'x86_64';
+ die "compat32 requires multilib.\n" unless $multi;
+ die "compat32 requires /usr/sbin/convertpkg-compat32.\n"
+ unless -f '/usr/sbin/convertpkg-compat32';
+ } else {
+ if ($arch eq 'x86_64') {
+ $x32 = check_x32 $args{LOCATION};
+ if ($x32 && ! $multi) {
+ die "$sbo is 32-bit which requires multilib on x86_64.\n";
+ }
+ }
+ }
+ # get a hash of downloads and md5sums, ensure we have 'em, symlink 'em
+ my %downloads = get_sbo_downloads (
+ LOCATION => $location,
+ 32 => $args{COMPAT32}
+ );
+ check_distfiles %downloads;
+ my @symlinks = create_symlinks $args{LOCATION}, %downloads;
+ # setup and run the .SlackBuild itself
+ my ($pkg, $src) = perform_sbo (
+ OPTS => $args{OPTS},
+ JOBS => $args{JOBS},
+ LOCATION => $location,
+ ARCH => $arch,
+ C32 => $args{COMPAT32},
+ X32 => $x32,
+ );
+ do_convertpkg $pkg if $args{COMPAT32};
+ unlink $_ for @symlinks;
+ return $version, $pkg, $src;
+}
+
+# remove work directories (source and packaging dirs under /tmp/SBo)
+sub make_clean ($$$) {
+ exists $_[2] or script_error 'make_clean requires three arguments.';
+ my ($sbo, $src, $version) = @_;
+ say "Cleaning for $sbo-$version...";
+ my $tmpsbo = "/tmp/SBo";
+ remove_tree ("$tmpsbo/$src") if -d "$tmpsbo/$src";
+ remove_tree ("$tmpsbo/package-$sbo") if -d "$tmpsbo/package-$sbo";
+ return 1;
+}
+
+# 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, $args{SRC}, $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;
+}
+
+# run upgradepkg for a created package
+sub do_upgradepkg ($) {
+ exists $_[0] or script_error 'do_upgradepkg requires an argument.';
+ system ('/sbin/upgradepkg', '--reinstall', '--install-new', shift);
+ return 1;
+}