Created
January 16, 2014 10:47
-
-
Save gregorg/8452941 to your computer and use it in GitHub Desktop.
Find Perl dependencies for Debian packages.
find_perldeps.pl -d script.pl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -w | |
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' | |
if 0; # not running under some shell | |
$VERSION = '0.06'; | |
use strict; | |
use Config; | |
use Getopt::Std; | |
use Module::ScanDeps; | |
use ExtUtils::MakeMaker; | |
use subs qw( _name _modtree ); | |
my %opts; | |
getopts('dBVxce:', \%opts); | |
my (%map, %skip); | |
my $core = $opts{B}; | |
my $verbose = $opts{V}; | |
my $eval = $opts{e}; | |
my $debian = $opts{d}; | |
if ($eval) { | |
require File::Temp; | |
my ($fh, $filename) = File::Temp::tempfile( UNLINK => 1 ); | |
print $fh $eval, "\n" or die $!; | |
close $fh; | |
push @ARGV, $filename; | |
} | |
die "Usage: $0 [ -B ] [ -V ] [ -x | -c ] [ -d ] [ -e STRING | FILE ... ]\n" unless @ARGV; | |
my @files = @ARGV; | |
while (<>) { | |
next unless /^package\s+([\w:]+)/; | |
$skip{$1}++; | |
} | |
my $map = scan_deps( | |
files => \@files, | |
recurse => 1, | |
$opts{x} ? ( execute => 1 ) : | |
$opts{c} ? ( compile => 1 ) : (), | |
); | |
my $len = 0; | |
my @todo; | |
my (%seen, %dist, %core, %bin); | |
foreach my $key (sort keys %$map) { | |
my $mod = $map->{$key}; | |
my $name = $mod->{name} = _name($key); | |
print "# $key [$mod->{type}]\n" if $verbose; | |
if ($mod->{type} eq 'shared') { | |
$key =~ s!auto/!!; | |
$key =~ s!/[^/]+$!!; | |
$key =~ s!/!::!; | |
$bin{$key}++; | |
} | |
next unless $mod->{type} eq 'module'; | |
next if $skip{$name}; | |
if ($mod->{file} eq "$Config::Config{privlib}/$key" | |
or $mod->{file} eq "$Config::Config{archlib}/$key") { | |
next unless $core; | |
$core{$name}++; | |
} | |
elsif (my $dist = _modtree->{$name}) { | |
$seen{$name} = $dist{$dist->package}++; | |
} | |
$len = length($name) if $len < length($name); | |
$mod->{used_by} ||= []; | |
push @todo, $mod; | |
} | |
$len += 2; | |
warn "# Legend: [C]ore [X]ternal [S]ubmodule [?]NotOnCPAN\n" if $verbose; | |
sub in_array | |
{ | |
my $val = shift; | |
my $ref = shift; | |
for ( @$ref ) { return 1 if $_ eq $val } | |
return 0; | |
} | |
my @packages; | |
my $deb_all_found = 1; | |
foreach my $mod (sort { | |
"@{$a->{used_by}}" cmp "@{$b->{used_by}}" or | |
$a->{key} cmp $b->{key} | |
} @todo) { | |
my $version = MM->parse_version($mod->{file}); | |
if ($debian) | |
{ | |
my $dpkg = `dpkg -S $mod->{file} &&>&1`; | |
chomp($dpkg); | |
if ($dpkg !~ /not found/ and $dpkg !~ /^dpkg:/) | |
{ | |
$dpkg =~ /(.+?): .*/; | |
if ($1 and !in_array($1, \@packages)) | |
{ | |
push @packages, $1; | |
} | |
} | |
else | |
{ | |
$deb_all_found = 0; | |
warn "Not found: $mod->{name}\n"; | |
} | |
} | |
elsif (!$verbose) { | |
printf "%-${len}s => '$version',", "'$mod->{name}'" if $version; | |
print "\n"; | |
} else { | |
printf "%-${len}s => '0', # ", "'$mod->{name}'"; | |
my @base = map(_name($_), @{$mod->{used_by}}); | |
print $seen{$mod->{name}} ? 'S' : ' '; | |
print $bin{$mod->{name}} ? 'X' : ' '; | |
print $core{$mod->{name}} ? 'C' : ' '; | |
print _modtree && !_modtree->{$mod->{name}} ? '?' : ' '; | |
print " # "; | |
print "@base" if @base; | |
print "\n"; | |
} | |
} | |
if ($debian) | |
{ | |
print "perllibs:Depends="; | |
print join(", ", @packages); | |
print "\n"; | |
unless ($deb_all_found) | |
{ | |
warn "WARNING: Not all packages were found.\n"; | |
#warn "Not all packages were found, continue ? [yY] "; | |
#$_ = <>; | |
#chomp; | |
#exit 1 if (/n/i); | |
} | |
} | |
warn "No modules found!\n" unless @todo; | |
sub _name { | |
my $str = shift; | |
$str =~ s!/!::!g; | |
$str =~ s!.pm$!!i; | |
$str =~ s!^auto::(.+)::.*!$1!; | |
return $str; | |
} | |
my $modtree; | |
sub _modtree { | |
$modtree ||= eval { | |
require CPANPLUS::Backend; | |
CPANPLUS::Backend->new->module_tree; | |
} || {}; | |
} | |
1; | |
__END__ | |
=head1 NAME | |
find_perldeps.pl - Scan file prerequisites | |
=head1 SYNOPSIS | |
% find_perldeps.pl *.pm # Print PREREQ_PM section for *.pm | |
% find_perldeps.pl -e 'STRING' # Scan an one-liner | |
% find_perldeps.pl -B *.pm # Include core modules | |
% find_perldeps.pl -V *.pm # Show autoload/shared/data files | |
=head1 DESCRIPTION | |
F<find_perldeps.pl> is a simple-minded utility that prints out the | |
C<PREREQ_PM> section needed by modules. | |
If you have B<CPANPLUS> installed, modules that are part of an | |
earlier module's distribution with be denoted with C<S>; modules | |
without a distribution name on CPAN are marked with C<?>. | |
Also, if the C<-B> option is specified, module belongs to a perl | |
distribution on CPAN (and thus uninstallable by C<CPAN.pm> or | |
C<CPANPLUS.pm>) are marked with C<C>. | |
Finally, modules that has loadable shared object files (usually | |
needing a compiler to install) are marked with C<X>; with the | |
C<-V> flag, those files (and all other files found) will be listed | |
before the main output. | |
=head1 OPTIONS | |
=over 4 | |
=item -e STRING | |
Scan I<STRING> as a string containing perl code. | |
=item -c | |
Compiles the code and inspects its C<%INC>, in addition to static scanning. | |
=item -x | |
Executes the code and inspects its C<%INC>, in addition to static scanning. | |
=item -B | |
Include core modules in the output and the recursive search list. | |
=item -V | |
Verbose mode: Output all files found during the process; | |
show dependencies between modules and availability. | |
=back | |
=head1 SEE ALSO | |
L<Module::ScanDeps>, L<CPANPLUS::Backend>, L<PAR> | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment