source: MondoRescue/branches/3.2/mindi/mindi-get-perl-modules@ 3388

Last change on this file since 3388 was 3388, checked in by Bruno Cornec, 9 years ago
  • mindi now logs MINDI_CACHE
  • Fix mindi-get-perl-modules by using scan_deps instead of internal code from Mageia which wasn't fully working. This implies en new dep for mindi on Module::ScanDeps
  • Property svn:executable set to *
File size: 9.5 KB
Line 
1#!/usr/bin/perl -w
2#
3# $Id$
4# Copyright B. Cornec 2005-2013
5# Provided under the GPL v2
6#
7# Get perl modules required by mindi and mondo and that should be on the restore media
8#
9use strict;
10
11use MondoRescue::File;
12use Data::Dumper;
13use File::Basename;
14use ProjectBuilder::Base;
15use Getopt::Long qw(:config auto_abbrev no_ignore_case);
16use Module::ScanDeps;
17
18=pod
19
20=head1 NAME
21
22mindi-get-perl-modules keeps track of the perl modules that should be on your restore media
23
24=head1 DESCRIPTION
25
26mindi-get-perl-modules keeps track of the perl modules that should be on your restore media by analyzing the references made to them in the scripts passed as parameters and returning all the modules needed to have them work correctly.
27
28=head1 SYNOPSIS
29
30mindi-get-perl-modules /path/to/perl-script ...
31
32=head1 ARGUMENTS
33
34=over 4
35
36=item B</path/to/perl-script>
37
38This is the path of the perl script to analyze and for which we want its perl modules in dependence to be included
39
40=back
41
42=head1 WEB SITES
43
44The main Web site of the project is available at L<http://www.mondorescue.org>. Bug reports should be filled using the trac instance of the project at L<http://trac.mondorescue.org/>.
45
46=head1 USER MAILING LIST
47
48For community exchanges around MondoRescue please use the list L<http://sourceforge.net/mailarchive/forum.php?forum_name=mondo-devel>
49
50=head1 AUTHORS
51
52The MondoRescue team lead by Bruno Cornec L<mailto:bruno@mondorescue.org>.
53
54=head1 COPYRIGHT
55
56MondoRescue is distributed under the GPL v2.0 license or later,
57described in the file C<COPYING> included with the distribution.
58
59=cut
60
61# Globals
62my %files;
63my %found;
64my %opts;
65my @includes;
66my $req;
67GetOptions(
68 "verbose|v+" => \$opts{'v'},
69);
70
71pb_syntax_init("mindi-get-perl-modules Version PBVER-rPBREV\n");
72
73$pbdebug = $opts{'v'};
74$pbdebug = 0 if (not defined $pbdebug);
75
76# Remove non exiting directories from @INC
77# and thus avoid perl warnings
78#
79pb_log(1,"Searching originally in ");
80pb_log(1,join " - ", @INC);
81pb_log(1,"\n");
82
83foreach my $d (@INC) {
84 $d = mr_file_read_all_link($d) if (-l $d);
85 push @includes,$d if (-d $d);
86}
87
88pb_log(1,"Searching finally in ");
89pb_log(1,join " - ", @INC);
90pb_log(1,"\n");
91
92# deduplicate entry list
93if (not defined $ARGV[0]) {
94 pb_syntax();
95}
96
97pb_temp_init();
98
99my $tmpf = "$ENV{'PBTMP'}/mpgm.$$";
100
101open(TMPF,"> $tmpf") || die "Unable to create $tmpf: !$\n";
102print TMPF "# To include module corresponding to perl -w\n";
103print TMPF "use warnings;\n";
104print TMPF "# To include module used by Data:Dumper in a masked way for this script\n";
105print TMPF "use bytes;\n";
106close(TMPF);
107
108push @ARGV,$tmpf;
109
110my $h = scan_deps(
111 files => \@ARGV,
112 recurse => 1,
113 );
114
115unlink("$tmpf");
116
117pb_log(1,"Returning:");
118pb_log(1,Dumper($h));
119pb_log(1,"-----------------------\n");
120foreach my $f (sort keys %$h) {
121 print "$h->{$f}->{'file'}\n";
122}
123
124exit 0;
125
126sub mr_get_perl_modules {
127
128my $f = shift;
129my %newly_found;
130my $require;
131
132return($require) if (not defined $f);
133$require = mr_process_file($f);
134
135pb_log(1,"Requires on $f found:\n");
136pb_log(1,Dumper($require));
137pb_log(1,"---------------\n");
138
139my $cpt = keys %$require;
140
141# Exit recursion
142return($require) if ($cpt == 0);
143
144foreach my $m (keys %$require) {
145 (my $mod = $m) =~ s|::|/|g;
146 # Already found
147 next if (exists $found{$mod});
148 foreach my $d (@includes) {
149 pb_log(1,"Looking at $m in $d\n");
150 if (-f "$d/$mod.pm") {
151 $files{"$d/$mod.pm"} = $mod;
152 $found{$mod} = "$d/$mod.pm";
153 $newly_found{"$d/$mod.pm"} = $mod;
154 pb_log(1,"Found $mod in $d/$mod.pm\n");
155 last;
156 }
157 }
158 print STDERR "ERROR: Unable to find $mod. Your perl setup may be incorrect\n" if (not exists $found{$mod});
159}
160
161pb_log(1,"Files found:\n");
162pb_log(1,Dumper(\%files));
163pb_log(2,Dumper(\%found));
164pb_log(1,"---------------\n");
165
166pb_log(1,"New Files found:\n");
167pb_log(1,Dumper(\%newly_found));
168pb_log(1,"---------------\n");
169
170my $foundrec;
171
172$cpt = keys %newly_found;
173if ($cpt != 0) {
174 # Recurse on what we just found
175 foreach my $f (keys %newly_found) {
176 $foundrec = mr_get_perl_modules($f);
177 foreach my $k (keys %$foundrec) {
178 $files{$k} = $foundrec->{$k};
179 }
180 }
181
182 # Cleanup
183 foreach my $k (keys %newly_found) {
184 delete $newly_found{$k};
185 }
186}
187
188pb_log(1,"End of mr_get_perl_modules on $f we got:".Dumper(\%files)."\n");
189
190return(\%files);
191}
192
193# Adapted From /usr/lib/rpm/mageia/perl.req
194# by Ken Estes Mail.com kestes@staff.mail.com
195# used under the GPL
196
197sub mr_process_file {
198
199my $file = shift;
200my %line;
201my %list_req;
202my $current_line = undef;
203my $tag = undef;
204
205return(\%list_req) if (not defined $file);
206
207pb_log(2, "START Analyze $file\n");
208# In a recursive configuration we need a var as file handle
209open(my $fh, "$file") || return(\%list_req);
210while (my $line = <$fh>) {
211
212 # skip the "= <<" block
213
214 pb_log(2, "LINE: $line");
215 if ( ( $line =~ m/^\s*\$(.*)\s*=\s*<<\s*["'](.*)['"]/i) ||
216 ($line =~ m/^\s*\$(.*)\s*=\s*<<\s*(.*);/i) ) {
217 $tag = $2;
218 while (my $l = <$fh>) {
219 pb_log(2, "LINE-tag: $l");
220 ( $l =~ /^$tag/) && last;
221 }
222 }
223
224 pb_log(2, "PHASE 2: $line");
225 # skip the documentation
226
227 # we should not need to have item in this if statement (it
228 # properly belongs in the over/back section) but people do not
229 # read the perldoc.
230
231 if ( ($line =~ m/^=(head1|head2|pod|item)/) .. ($line =~ m/^=(cut)/) ) {
232 pb_log(2, "PHASE 2bis:$line");
233 next;
234 }
235 pb_log(2, "PHASE 3:\n");
236
237 if ( ($line =~ m/^=(over)/) .. ($line =~ m/^=(back)/) ) {
238 next;
239 }
240 pb_log(2, "PHASE 4:\n");
241
242 # skip the data section
243 if ($line =~ m/^__(DATA|END)__$/) {
244 last;
245 }
246 pb_log(2, "PHASE 5:\n");
247
248 # Each keyword can appear multiple times. Don't
249 # bother with datastructures to store these strings,
250 # if we need to print it print it now.
251
252 if ($line =~ m/^\s*\$RPM_Requires\s*=\s*["'](.*)['"]/i) {
253 foreach my $l (split(/\s+/, $1)) {
254 print "$l\n";
255 }
256 }
257 pb_log(2, "PHASE 6:\n");
258
259 if (
260
261# ouch could be in a eval, perhaps we do not want these since we catch
262# an exception they must not be required
263
264# eval { require Term::ReadLine } or die $@;
265# eval "require Term::Rendezvous;" or die $@;
266# eval { require Carp } if defined $^S; # If error/warning during compilation,
267
268
269 ($line =~ m/^(\s*) # we hope the inclusion starts the line
270 (require|use)\s+(?!\{) # do not want 'do bracket' loops
271 # quotes around name are always legal
272 [\'\"]?([^\;\ \'\"\t]*)[\'\"]?[\t\;\ ]
273 # the syntax for 'use' allows version requirements
274 \s*([.0-9]*)
275 /x)
276 ) {
277 pb_log(2, "REQUIRE FOUND ***\n");
278 my ($whitespace, $statement, $module, $version) = ($1, $2, $3,$4);
279 my $usebase;
280
281 # we only consider require statements that are flush against
282 # the left edge. any other require statements give too many
283 # false positives, as they are usually inside of an if statement
284 # as a fallback module or a rarely used option
285
286 ($whitespace !~ /^\s*$/ && $statement eq "require") && next;
287
288 pb_log(2, "REQUIRE AV *** $whitespace, $statement, $module, $version ***\n");
289 # if there is some interpolation of variables just skip this
290 # dependency, we do not want
291 # do "$ENV{LOGDIR}/$rcfile";
292
293 ($module =~ m/\$/) && next;
294
295 # skip if the phrase was "use of" -- shows up in gimp-perl, et al
296 next if $module eq 'of';
297
298 # if the module ends in a comma we probaly caught some
299 # documentation of the form 'check stuff,\n do stuff, clean
300 # stuff.' there are several of these in the perl distribution
301
302 ($module =~ m/[,>]$/) && next;
303
304 # if the module name starts in a dot it is not a module name.
305 # Is this necessary? Please give me an example if you turn this
306 # back on.
307
308 # ($module =~ m/^\./) && next;
309
310 # if the module ends with .pm strip it to leave only basename.
311 # starts with /, which means its an absolute path to a file
312 if ($module =~ m(^/)) {
313 print "$module\n";
314 next;
315 }
316
317 # as seen in some perl scripts
318 # use base qw(App::CLI Class::Accessor::Chained::Fast App::CLI::Command);
319 if ($module eq 'base') {
320 $list_req{$module} = $version;
321 $line{$module} = $current_line;
322 ($module = $line) =~ s/use\s*base\s*//;
323 $module =~ s/qw\((.*)\)\s*;/$1/;
324 $module =~ s/qw(.)(.*)\1\s*;/$2/;
325 $module =~ s/\s*;$//;
326 $module =~ s/#.*//;
327 $usebase = 1;
328 }
329 # sometimes people do use POSIX qw(foo), or use POSIX(qw(foo)) etc
330 # we can strip qw.*$, as well as (.*$:
331 $module =~ s/qw.*$//;
332 $module =~ s/\(.*$//;
333
334 $module =~ s/\.pm$//;
335
336 # some perl programmers write 'require URI/URL;' when
337 # they mean 'require URI::URL;'
338
339 $module =~ s/\//::/;
340
341 # trim off trailing parenthesis if any. Sometimes people pass
342 # the module an empty list.
343
344 $module =~ s/\(\s*\)$//;
345
346 # if module is a number then both require and use interpret that
347 # to mean that a particular version of perl is specified. Don't
348 # add a dependency, though, since the rpm will already require
349 # perl-base at the build version (via find-requires)
350 next if $module =~ /^v?\d/;
351
352 # ph files do not use the package name inside the file.
353 # perlmodlib documentation says:
354 # the .ph files made by h2ph will probably end up as
355 # extension modules made by h2xs.
356 # so do not spend much effort on these.
357
358 # there is no easy way to find out if a file named systeminfo.ph
359 # will be included with the name sys/systeminfo.ph so only use the
360 # basename of *.ph files
361
362 ($module =~ m/\.ph$/) && next;
363
364 # if the module was loaded trough base, we need to split the list
365 if ($usebase) {
366 my $current_line = $line;
367 foreach my $l (split(/\s+/, $module)) {
368 next unless $l;
369 $list_req{$l} = $version;
370 $line{$l} = $current_line;
371 }
372 } else {
373 $list_req{$module}=$version;
374 $line{$module}=$current_line;
375 }
376 pb_log(2, "REQUIRE FIN *** ".Dumper(\%list_req)." ***\n");
377 }
378}
379
380close($fh) || die("$0: Could not close file: '$file' : $!\n");
381
382return(\%list_req);
383}
Note: See TracBrowser for help on using the repository browser.