Add built local::lib
[catagits/Gitalist.git] / local-lib5 / bin / scandeps.pl
1 #!/usr/bin/perl
2
3 eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
4     if 0; # not running under some shell
5
6 $VERSION = '0.76';
7
8 use strict;
9 use Config;
10 use Getopt::Std;
11 use Module::ScanDeps;
12 use ExtUtils::MakeMaker;
13 use subs qw( _name _modtree );
14
15 my %opts;
16 getopts('BVRxce:C:', \%opts);
17
18 my (%map, %skip);
19 my $core    = $opts{B};
20 my $verbose = $opts{V};
21 my $eval    = $opts{e};
22 my $recurse = $opts{R} ? 0 : 1;
23
24 if ($eval) {
25     require File::Temp;
26     my ($fh, $filename) = File::Temp::tempfile( UNLINK => 1 );
27     print $fh $eval, "\n" or die $!;
28     close $fh;
29     push @ARGV, $filename;
30 }
31
32 die "Usage: $0 [ -B ] [ -V ] [ -x | -c ] [ -R ] [-C FILE ] [ -e STRING | FILE ... ]\n" unless @ARGV;
33
34 my @files = @ARGV;
35 while (<>) {
36     next unless /^package\s+([\w:]+)/;
37     $skip{$1}++;
38 }
39
40 my $map = scan_deps(
41     files   => \@files,
42     recurse => $recurse,
43     $opts{x} ? ( execute => 1 ) :
44     $opts{c} ? ( compile => 1 ) : (),
45     $opts{V} ? ( warn_missing => 1 ) : (),
46     $opts{C} ? ( cache_file   => $opts{C}) : (),
47 );
48
49
50 my $len = 0;
51 my @todo;
52 my (%seen, %dist, %core, %bin);
53
54 foreach my $key (sort keys %$map) {
55     my $mod  = $map->{$key};
56     my $name = $mod->{name} = _name($key);
57
58     print "# $key [$mod->{type}]\n" if $verbose;
59
60     if ($mod->{type} eq 'shared') {
61         $key =~ s!auto/!!;
62         $key =~ s!/[^/]+$!!;
63         $key =~ s!/!::!;
64         $bin{$key}++;
65     }
66
67     next unless $mod->{type} eq 'module';
68
69     next if $skip{$name};
70
71     my $privPath = "$Config::Config{privlibexp}/$key";
72     my $archPath = "$Config::Config{archlibexp}/$key";
73     $privPath =~ s|\\|\/|og;
74     $archPath =~ s|\\|\/|og;
75     if ($mod->{file} eq $privPath
76         or $mod->{file} eq $archPath) {
77         next unless $core;
78
79         $core{$name}++;
80     }
81     elsif (my $dist = _modtree->{$name}) {
82         $seen{$name} = $dist{$dist->package}++;
83     }
84
85     $len = length($name) if $len < length($name);
86     $mod->{used_by} ||= [];
87
88     push @todo, $mod;
89 }
90
91 $len += 2;
92
93 print "# Legend: [C]ore [X]ternal [S]ubmodule [?]NotOnCPAN\n" if $verbose;
94
95 foreach my $mod (sort {
96     "@{$a->{used_by}}" cmp "@{$b->{used_by}}" or
97     $a->{key} cmp $b->{key}
98 } @todo) {
99
100     my $version = MM->parse_version($mod->{file});
101
102     if (!$verbose) {
103         printf "%-${len}s => '$version',", "'$mod->{name}'" if $version;
104     } else {
105         printf "%-${len}s => '0', # ", "'$mod->{name}'";
106         my @base = map(_name($_), @{$mod->{used_by}});
107         print $seen{$mod->{name}} ? 'S' : ' ';
108         print $bin{$mod->{name}}  ? 'X' : ' ';
109         print $core{$mod->{name}} ? 'C' : ' ';
110         print _modtree && !_modtree->{$mod->{name}} ? '?' : ' ';
111         print " # ";
112         print "@base" if @base;
113     }
114     print "\n";
115
116 }
117
118 warn "No modules found!\n" unless @todo;
119
120 sub _name {
121     my $str = shift;
122     $str =~ s!/!::!g;
123     $str =~ s!.pm$!!i;
124     $str =~ s!^auto::(.+)::.*!$1!;
125     return $str;
126 }
127
128 my $modtree;
129 sub _modtree {
130     $modtree ||= eval {
131         require CPANPLUS::Backend;
132         CPANPLUS::Backend->new->module_tree;
133     } || {};
134 }
135
136
137 1;
138
139 __END__
140
141 =head1 NAME
142
143 scandeps.pl - Scan file prerequisites
144
145 =head1 SYNOPSIS
146
147     % scandeps.pl *.pm          # Print PREREQ_PM section for *.pm
148     % scandeps.pl -e 'STRING'   # Scan an one-liner
149     % scandeps.pl -B *.pm       # Include core modules
150     % scandeps.pl -V *.pm       # Show autoload/shared/data files
151     % scandeps.pl -R *.pm       # Don't recurse
152     % scandeps.pl -C CACHEFILE  # use CACHEFILE to cache dependencies
153
154 =head1 DESCRIPTION
155
156 F<scandeps.pl> is a simple-minded utility that prints out the
157 C<PREREQ_PM> section needed by modules.
158
159 If you have B<CPANPLUS> installed, modules that are part of an
160 earlier module's distribution with be denoted with C<S>; modules
161 without a distribution name on CPAN are marked with C<?>.
162
163 Also, if the C<-B> option is specified, module belongs to a perl
164 distribution on CPAN (and thus uninstallable by C<CPAN.pm> or
165 C<CPANPLUS.pm>) are marked with C<C>.
166
167 Finally, modules that has loadable shared object files (usually
168 needing a compiler to install) are marked with C<X>; with the
169 C<-V> flag, those files (and all other files found) will be listed
170 before the main output. Additionally, all module files that the
171 scanned code depends on but were not found (and thus not scanned
172 recursively) are listed. These may include genuinely missing
173 modules or false positives. That means, modules your code does
174 not depend on (on this particular platform) but that were picked
175 up by the heuristic anyway.
176
177 =head1 OPTIONS
178
179 =over 4
180
181 =item -e STRING
182
183 Scan I<STRING> as a string containing perl code.
184
185 =item -c
186
187 Compiles the code and inspects its C<%INC>, in addition to static scanning.
188
189 =item -x
190
191 Executes the code and inspects its C<%INC>, in addition to static scanning.
192
193 =item -B
194
195 Include core modules in the output and the recursive search list.
196
197 =item -R
198
199 Only show dependencies found in the files listed and do not recurse.
200
201 =item -V
202
203 Verbose mode: Output all files found during the process; 
204 show dependencies between modules and availability.
205
206 Additionally, warns of any missing dependencies. If you find missing
207 dependencies that aren't really dependencies, you have probably found
208 false positives.
209
210 =item -C CACHEFILE
211
212 Use CACHEFILE to speed up the scanning process by caching dependencies.
213 Creates CACHEFILE if it does not exist yet.
214
215 =back
216
217 =head1 SEE ALSO
218
219 L<Module::ScanDeps>, L<CPANPLUS::Backend>, L<PAR>
220
221 =head1 ACKNOWLEDGMENTS
222
223 Simon Cozens, for suggesting this script to be written.
224
225 =head1 AUTHORS
226
227 Audrey Tang E<lt>autrijus@autrijus.orgE<gt>
228
229 =head1 COPYRIGHT
230
231 Copyright 2003, 2004, 2005, 2006 by Audrey Tang E<lt>autrijus@autrijus.orgE<gt>.
232
233 This program is free software; you can redistribute it and/or modify it
234 under the same terms as Perl itself.
235
236 See L<http://www.perl.com/perl/misc/Artistic.html>
237
238 =cut