Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Private Utilities

by Aristotle (Chancellor)
on Dec 01, 2005 at 05:29 UTC ( [id://513198]=note: print w/replies, xml ) Need Help??


in reply to Private Utilities

This is sm, short for Slackware make. I use it to build Slackware packages out of autoconf-based source tarballs, but half its raison d’être is to provide some defaults to the configure script, so non-Slackers might get some use out of it.

#!/usr/bin/perl =begin plans one class per task: inherit from superclass new(): no getopt module parses args must know how not to consume too much! cmd() builds commandline superclass: new() croaks run(): system( $self->cmd() ) die on error main program is dispatcher: pull mode from args construct object call run() modes: cd -- configure with defaults cf -- configure (no defaults) ch -- configure --help mk -- build pk -- package in configure modes: += => --enable- -= => --disable- -: => --with- +: => --without- =end plans =head1 NAME =head1 SYNOPSIS =head1 DESCRIPTION =head1 ARGUMENTS =over 4 =item B<-h>, B<--help> =item B<--man> =item B<-c>, B<--configure> =item B<-m>, B<--make> =item B<-p>, B<--package> =item B<-i>, B<--install> =back =head1 OPTIONS =over 4 =item B<-n>, B<--dry-run> =item B<-N>, B<--pkg-name> =item B<-E>, B<--ac-enable> =item B<-D>, B<--ac-disable> =item B<-W>, B<--ac-with> =item B<-O>, B<--ac-without> =item B<-V>, B<--ac-var> =item B<--pkg-info> =back =head1 SEE ALSO =head1 AUTHORS Aristotle Pagaltzis =head1 COPYRIGHT This script is free software; you can redistribute it and/or modify it + under the same terms as Perl itself. =cut use strict; use warnings; use Pod::Usage; use Getopt::Long 2.24, qw( :config bundling no_ignore_case no_auto_abb +rev ); use Cwd; use File::Spec::Functions qw( catdir catfile tmpdir ); use File::Basename; use File::Temp qw( mkdtemp ); use File::Path; use POSIX qw( strftime ); use constant PWD => getcwd(); my %pkg_info = ( ver => 1, arch => do { chomp( $_ = qx/arch/ ); $_ }, ( basename( PWD ) =~ /\A(.*)-(.*)\z/ ? ( distname => $1, distver => $2 ) : ( distname => basename( PWD ), distver => "0.nover" ) ), ); GetOptions( 'h|help' => sub { pod2usage( -verbose => 1 ) }, 'man' => sub { pod2usage( -verbose => 2 ) }, 'c|configure:s' => \my $opt_configure, 'm|make:s' => \my $opt_make, 'p|package' => \my $opt_package, 'i|install' => \my $opt_install, 'n|dry-run' => \my $opt_dryrun, 'N|pkg-name=s' => \my $opt_pkgname, 'E|ac-enable=s' => \my @ac_enable, 'D|ac-disable=s' => \my @ac_disable, 'W|ac-with=s' => \my @ac_with, 'O|ac-without=s' => \my @ac_without, 'V|ac-var=s' => \my %autoconf_var, 'pkg-info=s' => \%pkg_info, 'cvs' => sub { $pkg_info{ distver } = strftime( '%Y%m%d +', localtime ) }, ) or pod2usage( -verbose => 1 ); $opt_pkgname = join( '-', @pkg_info{ qw( distname distver arch ver ) } + ) . '.tgz' unless defined $opt_pkgname; if( not defined $autoconf_var{ prefix } ) { $autoconf_var{ prefix } ||= '/usr'; $autoconf_var{ sysconfdir } ||= catdir( '/etc', $pkg_info{ dis +tname } ); $autoconf_var{ sharedstatedir } ||= '/var/com'; $autoconf_var{ localstatedir } ||= '/var'; } delete @autoconf_var{ grep !length $autoconf_var{ $_ }, keys %autoconf +_var }; sub parse_features { map /\G ,? ( .+? (?: =.* \z | (?=,) | \z ) ) /xg, + @_ } sub pull_argv { my @pulled; while ( @ARGV ) { my $curr = shift @ARGV; last if $curr eq '--'; push @pulled, $curr; } return @pulled; } sub run { if ( $opt_dryrun ) { print join( ' ', @_ ), "\n"; return 1; } return system( @_ ) == 0; } ###################################################################### +######### my $success = 1; ###################################################################### +######### if ( defined $opt_configure ) { $success = run( ( -x $opt_configure ? $opt_configure : './configure' ), map ( "--$_=$autoconf_var{$_}", sort { length $a <=> length $b + } keys %autoconf_var ), map ( "--enable-$_", parse_features @ac_enable ), map ( "--disable-$_", parse_features @ac_disable ), map ( "--with-$_", parse_features @ac_with ), map ( "--without-$_", parse_features @ac_without ), pull_argv(), ); } ###################################################################### +######### print( "Configure failed.\n" ), exit 1 unless $success; ###################################################################### +######### if ( defined $opt_make ) { $success = run( ( -x $opt_make ? $opt_make : 'make' ), pull_argv() +, ); } ###################################################################### +######### print( "Make failed.\n" ), exit 1 unless $success; ###################################################################### +######### if ( $opt_package ) { unless ( $opt_dryrun or $< == 0 ) { print STDERR "Creating package as non-root. Continue (y/n)? "; last unless <> =~ /^\s*y/i; } my $tmpdir = $opt_dryrun ? '$tmpdir' : mkdtemp( catdir( tmpdir, 'slakmk.XXXXXXXX' ) ); chmod 0755, $tmpdir unless $opt_dryrun; my @cmd; ( @cmd = pull_argv() ) or ( @cmd = qw( make install DESTDIR=%d/ ) +); s/ \G ( %(.) | . ) / ( !defined $2 ) ? $1 : $2 eq '%' ? '%' : $2 eq 'd' ? $tmpdir : do { warn "Unknown format sequence '$1', ignoring\n"; '' } /xge for @cmd; run( @cmd ); chdir $tmpdir unless $opt_dryrun; $success = run( makepkg => -c => 'n', -l => 'y', catfile( PWD, $opt_pkgna +me ) ); chdir PWD unless $opt_dryrun; rmtree $tmpdir unless $opt_dryrun; } ###################################################################### +######### print( "Package creation failed.\n" ), exit 1 unless $success; ###################################################################### +######### $success = run( installpkg => catfile( PWD, $opt_pkgname ) ) if $opt_install; ###################################################################### +######### print( "Installation failed.\n" ), exit 1 unless $success; ###################################################################### +#########

This is ratbecause “tar” is backwards –, which attempts to make dealing with tarballs (and zipfiles) a little saner:

#!/usr/bin/perl use warnings; use strict; use Getopt::Long; use File::Copy qw(move); use File::Temp qw(tempdir); use File::Basename qw(basename); use File::Spec::Functions qw(catdir no_upwards rootdir); use constant BASEDIR => do { require Cwd; Cwd::cwd() }; sub slurp_dir { my $dir = shift; opendir my ($dh), $dir or die "Couldn't read directory $dir: $!\n"; readdir $dh; } sub run_cmd { print "\t@_\n"; my $exit = system(@_); require POSIX; if (POSIX::WIFEXITED($exit)) { return 1 if POSIX::WEXITSTATUS($exit) == 0; print "\tReturned non-zero exit status\n"; return; } else { print "\tQuitting: Subprocess exited abnormally\n"; exit 1; } } sub mangle_targetdir { my ($exdir) = @_; my $basedir_rx = join '.?', map quotemeta, split /[-_ ]/, $exdir; my ($tarbase, @morefiles) = no_upwards(slurp_dir $exdir); my $exdir_tar = catdir($exdir, $tarbase); if (@morefiles or ! -d $exdir_tar or $tarbase !~ /\A$basedir_rx/i) + { print "\tExtracted in $exdir\n"; return; } print "\tExtracted in $tarbase\n" if $tarbase ne $exdir; my $tempdir = tempdir(DIR => BASEDIR); my $tempdir_tar = catdir($tempdir, $tarbase); my $basedir_tar = catdir(BASEDIR, $tarbase); move $exdir_tar, $tempdir_tar and rmdir $exdir and move $tempdir_tar, $basedir_tar and rmdir $tempdir or print "\tFailed moving $exdir_tar to $basedir_tar: $!\n"; } sub run_in_dir { my $basename = basename shift; mkdir $basename; run_cmd(@_); mangle_targetdir($basename); } GetOptions( 'list|l!' => \(my $list = ''), 'overwrite|o!' => \(my $overwrite = ''), 'remove|r!' => \(my $remove = ''), ) and @ARGV or die "usage: FIXME\n"; # FIXME my %ext = $list ? ( zip => sub { local %_ = @_; unzip => -l => $_{archive} }, tar => sub { local %_ = @_; tar => tv => -f => +$_{archive}, }, tgz => sub { local %_ = @_; tar => tv => '--gzip', -f => +$_{archive}, }, tbz2 => sub { local %_ = @_; tar => tv => '--bzip2', -f => +$_{archive}, }, tarz => sub { local %_ = @_; tar => tv => '--compress', -f => +$_{archive}, }, ) : ( zip => sub { local %_ = @_; unzip => -q => -d => $_{dir}, $_{ +archive} }, tar => sub { local %_ = @_; tar => x => -f => $ +_{archive}, -C => $_{dir}, }, tgz => sub { local %_ = @_; tar => x => '--gzip', -f => $ +_{archive}, -C => $_{dir}, }, tbz2 => sub { local %_ = @_; tar => x => '--bzip2', -f => $ +_{archive}, -C => $_{dir}, }, tarz => sub { local %_ = @_; tar => x => '--compress', -f => $ +_{archive}, }, ); @ext{qw(tar.gz tar.bz2 tar.z tar.Z)} = @ext{qw(tgz tbz2 tarz tarz)}; my $rx = join '|', map quotemeta, keys %ext; $rx = qr/\A (.*) \. ($rx) \z/ix; select(STDERR); for (@ARGV) { print "\n$_:\n"; if (-f and my ($basename, $ext) = m/$rx/) { $list ? run_cmd($ext{$ext}->(archive => $_, dir => $basename)) : run_in_dir($basename, $ext{$ext}->(archive => $_, dir => + $basename)); } elsif (not $list and -d) { my $basename = basename catdir $_; my $rootdir = quotemeta rootdir; $basename =~ s/\A$rootdir\z/rootdir/; $basename .= '.tar.bz2'; -e $basename ? print "$basename already exists\n" : run_cmd(tar => c => '--bzip2', -f => $basename, $_); } else { print "\tNo handler found\n"; } }

I’m rather unhappy with the state of both; rat has at least one annoying bug. But they work sufficiently well for me that I don’t get irritated enough to actually fix them. And that’s why they’ve remained private…

Makeshifts last the longest.

Replies are listed 'Best First'.
Re^2: Private Utilities
by wazoox (Prior) on Dec 01, 2005 at 12:10 UTC
    Do you know checkinstall? It's a neat package building utility, and it can build Slack, Debian and RPM packages, though it's primarily a Slackware utility (it comes on slackware CDs in the /extra directory IIRC).

      Yes. It needs to be run as root, so any files created in the source tree during make install as well as the resultant package tarball are owned by root, which means I can’t move the package, and sometimes cannot blow away the source tree, without root permissions. It also knows nothing of DESTDIR, so you cannot run it with fakeroot, which means make install can wreak havoc at will. (Makefiles that try to register schemata with GConf are always great fun… grr.)

      Makeshifts last the longest.

        Well, I use it a lot and I had no problem with it so far, but I admit your script may be better :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://513198]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (8)
As of 2024-04-23 08:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found