123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- #!/usr/bin/perl
- ##
- ## Name:
- ## patchprov
- ##
- ## Description:
- ## Patch the provides list in the perl package PKGBUILD. Scan the appropriate
- ## directories under the perl source tree for directories containing dists
- ## similar to CPAN dists. Search the files in the distributions for VERSION
- ## strings, which are perl expressions. Filters these version strings through
- ## the perl interpreter, then transform the dist. names and versions into
- ## package names and versions. Finally, we cut out the "provides" array from the
- ## PKGBUILD and replace it with the newer version.
- ##
- ## Usage:
- ## patchprov [path to perl source tree] [path to PKGBUILD]
- ##
- ## Caveats:
- ## The path code is not platform independent and will only work in POSIX.
- ##
- ## Changelog:
- ## 06/10/14 JD Rewrite from scratch for perl 5.20.0 and ArchLinux.
- ##
- ## Authors:
- ## Justin "juster" Davis <jrcd83@gmail.com>
- ##
- use warnings;
- use strict;
- sub err
- {
- print STDERR "patchprov: error: @_\n";
- exit 1;
- }
- ## Extract the dist. name from its containing directory.
- sub path_dist
- {
- my($path) = @_;
- $path =~ s{^.*/}{};
- return $path;
- }
- ## Create a path like $path/lib/Foo/Bar.pm for Foo::Bar.
- sub lib_modpath
- {
- my($path, $modname) = @_;
- $modname =~ s{::}{/}g;
- return "$path/lib/$modname.pm";
- }
- ## Create a path to a file in the containing directory, named after
- ## the last segment of the module name, with suffix attached.
- sub dumb_modpath
- {
- my($path, $modname, $suffix) = @_;
- $modname =~ s{^.*::}{};
- return "$path/$modname$suffix";
- }
- ## Find a source file contained in the directory that we can scrape the
- ## perl versions string from.
- my %distmods = (
- 'PathTools' => 'Cwd',
- 'Scalar-List-Utils' => 'List::Util',
- 'IO-Compress' => 'IO::Compress::Gzip',
- );
- sub dist_srcpath
- {
- my($path) = @_;
- my $distname = path_dist($path);
- my $modname;
- if(exists $distmods{$distname}){
- $modname = $distmods{$distname};
- }else{
- $modname = $distname;
- $modname =~ s/-/::/g;
- }
- my @srcpaths = (
- lib_modpath($path, $modname),
- dumb_modpath($path, $modname, '.pm'),
- dumb_modpath($path, $modname, '_pm.PL'),
- dumb_modpath($path, '__'.$modname.'__', '.pm'),
- "$path/VERSION", # for podlators
- );
- for my $src (@srcpaths){
- return $src if(-f $src);
- }
- return undef;
- }
- ## Scrape the version string for the module file or Makefile.PL.
- sub scrape_verln
- {
- my($srcpath) = @_;
- open my $fh, '<', $srcpath or die "open: $!";
- while(my $ln = <$fh>){
- if($ln =~ s/^.*VERSION *=>? *//){
- close $fh;
- return $ln;
- }
- }
- close $fh;
- err("failed to find VERSION in $srcpath");
- }
- ## Scrape the version string from the module source file.
- sub scrape_modver
- {
- my($srcpath) = @_;
- return scrape_verln($srcpath);
- }
- ## Scrape the version string from the Makefile.PL. (for libnet)
- sub scrape_mkplver
- {
- my($srcpath) = @_;
- my $verln = scrape_verln($srcpath);
- $verln =~ s/,/;/;
- return $verln;
- }
- ## Scrape the version string from a file inside the dist dir.
- sub distpath_ver
- {
- my($distpath) = @_;
- my $srcpath = dist_srcpath($distpath);
- my $mkplpath = "$distpath/Makefile.PL";
- if(defined $srcpath){
- return scrape_modver($srcpath);
- }elsif(-f $mkplpath){
- return scrape_mkplver($mkplpath);
- }else{
- err("failed to scrape version from $distpath");
- }
- }
- ## Search the base path for the dist dirs and extract their respective
- ## version strings.
- sub find_distvers
- {
- my($basepath) = @_;
- opendir my $dh, $basepath or die "opendir: $!";
- my @dirs = grep { -d $_ } map { "$basepath/$_" } grep { !/^[.]/ } readdir $dh;
- closedir $dh;
- my @distvers;
- for my $dpath (@dirs){
- push @distvers, [ path_dist($dpath), distpath_ver($dpath) ];
- }
- return @distvers;
- }
- ## Maps an aref of dist name/perl version strings (perl expressions) to
- ## a package name and version string suitable for a PKGBUILD.
- sub pkgspec
- {
- my($dist, $ver) = @$_;
- $dist =~ tr/A-Z/a-z/;
- $ver = eval $ver;
- return "perl-$dist=$ver";
- }
- ## Searches the perl source dir provided for a list of packages which
- ## correspond to the core distributions bundled within in.
- sub perlcorepkgs
- {
- my($perlpath) = @_;
- my @dirs = ("$perlpath/cpan", "$perlpath/dist");
- my @provs;
- for my $d (@dirs){
- if(!-d $d){
- err("$d is not a valid directory");
- }
- push @provs, map pkgspec, find_distvers($d);
- }
- return @provs;
- }
- ## Formats the provided lines into a neatly formatted bash array. The first arg
- ## is the name of the bash variable to assign it to.
- sub basharray
- {
- my $vname = shift;
- ## Sort entries and surround with quotes.
- my @lns = sort map { qq{'$_'} } @_;
- $lns[0] = "$vname=($lns[0]";
- ## Indent lines for OCD geeks.
- if(@lns > 1){
- my $ind = length($vname) + 2;
- splice @lns, 1, @lns-1,
- map { (' ' x $ind) . $_ } @lns[1 .. $#lns];
- }
- $lns[$#lns] .= ')';
- return map { "$_\n" } @lns;
- }
- ## Patch the PKGBUILD at the given path with a new provides array, overwriting
- ## the old one.
- sub patchpb
- {
- my $pbpath = shift;
- open my $fh, '<', $pbpath or die "open: $!";
- my @lines = <$fh>;
- close $fh;
- my($i, $j);
- for($i = 0; $i < @lines; $i++){
- last if($lines[$i] =~ /^provides=/);
- }
- if($i == @lines){
- err("failed to find provides array in PKGBUILD");
- }
- for($j = $i; $j < @lines; $j++){
- last if($lines[$j] =~ /[)]/);
- }
- if($j == @lines){
- err("failed to find end of provides array");
- }
- splice @lines, $i, $j-$i+1,
- basharray('provides', grep { !/win32|next/ } @_);
- ## Avoid corrupting the existing PKGBUILD in case of a crash, etc.
- if(-f "$pbpath.$$"){
- err("pbpath.$$ temporary file already exists, please remove it.");
- }
- open $fh, '>', "$pbpath.$$" or die "open: $!";
- print $fh @lines;
- close $fh or die "close: $!";
- rename "$pbpath.$$", "$pbpath" or die "rename: $!";
- return;
- }
- ## Program entrypoint.
- sub main
- {
- if(@_ < 2){
- print STDERR "usage: $0 [perl source path] [PKGBUILD path]\n";
- exit 2;
- }
- my($perlpath, $pbpath) = @_;
- if(!-f $pbpath){
- err("$pbpath is not a valid file.");
- }elsif(!-d $perlpath){
- err("$perlpath is not a valid directory.");
- }else{
- patchpb($pbpath, perlcorepkgs($perlpath));
- }
- exit 0;
- }
- main(@ARGV);
- # EOF
|