File Coverage

blib/lib/Test/Smoke/Util.pm
Criterion Covered Total %
statement 423 549 77.0
branch 245 378 64.8
condition 59 108 54.6
subroutine 29 33 87.8
pod 24 24 100.0
total 780 1092 71.4


line stmt bran cond sub pod time code
1             package Test::Smoke::Util;
2 39     39   1251135 use strict;
  39         309  
  39         1819  
3              
4             our $VERSION = '0.58';
5              
6 39     39   240 use Exporter 'import';
  39         75  
  39         3237  
7             our @EXPORT = qw(
8             &Configure_win32
9             &get_cfg_filename &get_config
10             &get_patch
11             &skip_config &skip_filter
12             );
13              
14             our @EXPORT_OK = qw(
15             &grepccmsg &grepnonfatal &get_local_patches &set_local_patch
16             &get_ncpu &get_smoked_Config &parse_report_Config
17             &get_regen_headers &run_regen_headers
18             &whereis &clean_filename &read_logfile
19             &calc_timeout &time_in_hhmm
20             &do_pod2usage
21             &set_vms_rooted_logical
22             );
23              
24 39     39   19136 use Text::ParseWords;
  39         55353  
  39         2636  
25 39     39   11094 use File::Spec::Functions;
  39         21898  
  39         3215  
26 39     39   20135 use Encode qw ( decode );
  39         570984  
  39         2966  
27 39     39   300 use File::Find;
  39         73  
  39         2736  
28 39     39   285 use Cwd;
  39         99  
  39         2629  
29 39     39   14209 use Test::Smoke::LogMixin;
  39         123  
  39         394965  
30              
31             our $NOCASE = $^O eq 'VMS';
32              
33             =head1 NAME
34              
35             Test::Smoke::Util - Take out some of the functions of the smoke suite.
36              
37             =head1 FUNCTIONS
38              
39             I've taken out some of the general stuff and put it here.
40             Now I can write some tests!
41              
42             =head2 Configure_win32( $command[, $win32_maker[, @args]] )
43              
44             C alters the settings of the makefile for MSWin32.
45              
46             C<$command> is in the form of './Configure -des -Dusedevel ...'
47              
48             C<$win32_maker> should either be C or C, the default
49             is C.
50              
51             C<@args> is a list of C<< option=value >> pairs that will (eventually)
52             be passed to L.
53              
54             PLEASE read README.win32 and study the comments in the makefile.
55              
56             It supports these options:
57              
58             =over 4
59              
60             =item * B<-Duseperlio>
61              
62             set USE_PERLIO = define (default) [should be depricated]
63              
64             =item * B<-Dusethreads>
65              
66             set USE_ITHREADS = define (also sets USE_MULTI and USE_IMP_SYS)
67              
68             =item * B<-Duseithreads>
69              
70             set USE_ITHREADS = define (also sets USE_MULTI and USE_IMP_SYS)
71              
72             =item * B<-Dusemultiplicity>
73              
74             sets USE_MULTI = define (also sets USE_ITHREADS and USE_IMP_SYS)
75              
76             =item * B<-Duseimpsys>
77              
78             sets USE_IMP_SYS = define (also sets USE_ITHREADS and USE_MULTI)
79              
80             =item * B<-Uusethreads> or B<-Uuseithreads>
81              
82             unset C, C and C
83              
84             =item * B<-Dusemymalloc>
85              
86             set C
87              
88             =item * B<-Duselargefiles>
89              
90             set C
91              
92             =item * B<-Duse64bint>
93              
94             set C (always for win64, needed for -UWIN64)
95              
96             =item * B<-Duselongdouble>
97              
98             set C (GCC only)
99              
100             =item * B<-Dusequadmath>
101              
102             set both C and C (GCC only)
103              
104             =item * B<-Dusesitecustomize>
105              
106             set C
107              
108             =item * B<-Udefault_inc_excludes_dot>
109              
110             unsets C<# DEFAULT_INC_EXCLUDES_DOT := define> (comments out the line)
111              
112             =item * B<-Dbccold>
113              
114             set BCCOLD = define (this is for bcc32 <= 5.4)
115              
116             =item * B<-Dgcc_v3_2>
117              
118             set USE_GCC_V3_2 = define (this is for gcc >= 3.2)
119              
120             =item * B<-DDEBUGGING>
121              
122             sets CFG = Debug
123              
124             =item * B<-DINST_DRV=...>
125              
126             sets INST_DRV to a new value (default is "c:")
127              
128             =item * B<-DINST_TOP=...> or B<-Dprefix=...>
129              
130             sets INST_TOp to a new value (default is "$(INST_DRV)\perl"), this is
131             where perl will be installed when C<< [ng]make install >> is run.
132              
133             =item * B<-DINST_VER=...>
134              
135             sets INST_VER to a new value (default is forced not set), this is also used
136             as part of the installation path to get a more unixy installation.
137             Without C and C you get an ActiveState like
138             installation.
139              
140             =item * B<-DINST_ARCH=...>
141              
142             sets INST_ARCH to a new value (default is forced not set), this is also used
143             as part of the installation path to get a more unixy installation.
144             Without C and C you get an ActiveState like
145             installation.
146              
147             =item * B<-DCCHOME=...>
148              
149             Set the base directory for the C compiler.
150             B<$(CCHOME)\bin> still needs to be in the path!
151              
152             =item * B<-DIS_WIN95>
153              
154             sets IS_WIN95 to 'define' to indicate this is Win9[58]
155              
156             =item * B<-DCRYPT_SRC=...>
157              
158             The file to use as source for des_fcrypt()
159              
160             =item * B<-DCRYPT_LIB=...>
161              
162             The library to use for des_fcrypt()
163              
164             =item * B<-Dcf_email=...>
165              
166             Set the cf_email option (Config.pm)
167              
168             =item * B<-Accflags=...>
169              
170             Sets C
171              
172             =item * B<-Aldflags=...>
173              
174             Adds and sets C
175              
176             =back
177              
178             =cut
179              
180             my %win32_makefile_map = (
181             nmake => "Makefile",
182             gmake => "GNUmakefile",
183             );
184              
185             sub Configure_win32 {
186 28     28 1 97021 my($command, $win32_maker, @args ) = @_;
187 28   50     96 $win32_maker ||= 'nmake'; $win32_maker = lc $win32_maker;
  28         63  
188 28         67 my $is_nmake = $win32_maker eq 'nmake';
189 28         45 my $is_gmake = $win32_maker eq 'gmake';
190              
191 28         47 local $_;
192 28         551 my %opt_map = (
193             "-Dusethreads" => "USE_ITHREADS",
194             "-Duseithreads" => "USE_ITHREADS",
195             "-Duseperlio" => "USE_PERLIO",
196             "-Dusemultiplicity" => "USE_MULTI",
197             "-Duseimpsys" => "USE_IMP_SYS",
198             "-Uuseimpsys" => "USE_IMP_SYS",
199             "-Dusemymalloc" => "PERL_MALLOC",
200             "-Duselargefiles" => "USE_LARGE_FILES",
201             "-Duse64bitint" => "USE_64_BIT_INT",
202             "-Duselongdouble" => "USE_LONG_DOUBLE",
203             "-Dusequadmath" => "USE_QUADMATH",
204             "-Dusesitecustomize" => "USE_SITECUST",
205             "-Uuseshrplib" => "BUILD_STATIC",
206             "-Udefault_inc_excludes_dot" => "DEFAULT_INC_EXCLUDES_DOT",
207             "-UWIN64" => "WIN64",
208             "-Uusethreads" => "USE_ITHREADS",
209             "-Uuseithreads" => "USE_ITHREADS",
210             "-UUSE_MINGW_ANSI_STDIO" => "USE_MINGW_ANSI_STDIO",
211             "-DDEBUGGING" => "USE_DEBUGGING",
212             "-DINST_DRV" => "INST_DRV",
213             "-DINST_TOP" => "INST_TOP",
214             "-Dprefix" => "INST_TOP",
215             "-DINST_VER" => "INST_VER",
216             "-DINST_ARCH" => "INST_ARCH",
217             "-Dcf_email" => "EMAIL",
218             "-DCCTYPE" => "CCTYPE",
219             "-Dgcc_v3_2" => "USE_GCC_V3_2",
220             "-DGCC_4XX" => "GCC_4XX",
221             "-DGCCWRAPV" => "GCCWRAPV",
222             "-DGCCHELPERDLL" => "GCCHELPERDLL",
223             "-Dbccold" => "BCCOLD",
224             "-DCCHOME" => "CCHOME",
225             "-DGCCBIN" => "GCCBIN",
226             "-DIS_WIN95" => "IS_WIN95",
227             "-DCRYPT_SRC" => "CRYPT_SRC",
228             "-DCRYPT_LIB" => "CRYPT_LIB",
229             "-DEXTRALIBDIRS" => "EXTRALIBDIRS",
230             );
231             # %opts hash-values:
232             # undef => leave option as-is when no override (makefile default)
233             # 0 => disable option when no override (forced default)
234             # (true) => enable option when no override (change value, unless
235             # $key =~ /^(?:PERL|USE)_/) (forced default)
236 28         388 my %opts = (
237             USE_MULTI => 1,
238             USE_ITHREADS => 1,
239             USE_IMP_SYS => 1,
240             USE_PERLIO => 1,
241             USE_LARGE_FILES => 0, # default define
242             PERL_MALLOC => 0,
243             BUILD_STATIC => 0,
244             USE_64_BIT_INT => 0,
245             USE_LONG_DOUBLE => 0,
246             USE_QUADMATH => 0,
247             I_QUADMATH => 0,
248             WIN64 => 1,
249             USE_SITECUST => 0,
250             DEFAULT_INC_EXCLUDES_DOT => 1,
251             USE_MINGW_ANSI_STDIO => 1,
252             USE_DEBUGGING => 0,
253             INST_DRV => undef,
254             INST_TOP => undef,
255             INST_VER => '',
256             INST_ARCH => '',
257             EMAIL => undef, # used to be $smoker,
258             CCTYPE => undef, # used to be $win32_cctype,
259             USE_GCC_V3_2 => 0,
260             GCC_4XX => 0,
261             GCCWRAPV => 0,
262             GCCHELPERDLL => undef,
263             BCCOLD => 0,
264             CCHOME => undef,
265             GCCBIN => 'GCC',
266             IS_WIN95 => 0,
267             CRYPT_SRC => undef,
268             CRYPT_LIB => undef,
269             EXTRALIBDIRS => undef,
270             );
271              
272             # $undef_re: regex for options that should be UNcommented for -Uxxx
273 28         132 my $undef_re = qr/WIN64/;
274              
275             # $def_re: regex for options that should be UNcommented for -Dxxx
276 28         76 my $def_re = qr/((?:(?:DEFAULT|PERL|USE|IS|GCC|I)_\w+)|BCCOLD|GCCWRAPV)/;
277              
278 28         1489 my @w32_opts = grep ! /^$def_re/, keys %opts;
279 28         145 my $config_args = join " ",
280             grep /^-[DU][a-z_]+/, quotewords( '\s+', 1, $command );
281 28         3925 push @args, "config_args=$config_args";
282              
283             my @adjust_opts = grep {
284 28         85 /^-A(?:ccflags|ldflags)=/
  100         3306  
285             } quotewords('\s+', 1, $command);
286             my $adjust_ccflags = join(
287             " ",
288             map {
289 6 50       55 s/^-Accflags=(["']?)(.+?)\1// ? $2 : ()
290 28         79 } grep { /^-Accflags=/ } @adjust_opts
  6         20  
291             );
292             my $adjust_ldflags = join(
293             " ",
294             map {
295 0 0       0 s/^-Aldflags=(["']?)(.+?)\1// ? $2 : ()
296 28         59 } grep { /^-Aldflags=/ } @adjust_opts
  6         16  
297             );
298              
299 28 50       150 $command =~ m{^\s*\./Configure\s+(.*)} or die "unable to parse command";
300 28         121 my $cmdln = $1;
301 28         73 foreach ( quotewords( '\s+', 1, $cmdln ) ) {
302 72 100       2643 m/^-[des]{1,3}$/ and next;
303 64 100       135 m/^-Dusedevel$/ and next;
304 56 100       121 m/^-A(ccflags|ldflags)/ and next;
305 50 50       234 if (my( $option, $value ) = /^(-[DU]\w+)(?:=(.+))?$/) {
306 50 50       123 die "invalid option '$_'" unless exists $opt_map{$option};
307 50 100       127 $opts{$opt_map{$option}} = $value ? $value : 1;
308 50 100       145 $option =~ /^-U/ and $opts{$opt_map{$option}} = 0;
309             }
310             }
311              
312             # Handle some switches that impact more make-vars
313 28 100       99 if ( $cmdln =~ /-Uusei?threads\b/ ) {
314 2         14 $opts{USE_MULTI} = $opts{USE_ITHREADS} = $opts{USE_IMP_SYS} = 0;
315              
316             }
317 28 50       85 if ( $cmdln =~ /-Dusequadmath\b/ ) {
318 0         0 $opts{USE_QUADMATH} = $opts{I_QUADMATH} = 1;
319             }
320             # If you set one, we do all, so you can have fork()
321             # unless you set -Uuseimpsys
322 28 100       71 if ( $cmdln !~ /-Uuseimpsys\b/ ) {
323 26 50 66     78 if ( $opts{USE_MULTI} || $opts{USE_ITHREADS} || $opts{USE_IMP_SYS} ) {
      33        
324 24         60 $opts{USE_MULTI} = $opts{USE_ITHREADS} = $opts{USE_IMP_SYS} = 1;
325             }
326             }
327             else {
328 2 50 33     22 if ( $opts{USE_MULTI} || $opts{USE_ITHREADS} ) {
329 2         15 $opts{USE_MULTI} = $opts{USE_ITHREADS} = 1;
330             }
331             }
332              
333             # If you -Dgcc_v3_2 you 'll *want* CCTYPE = GCC
334 28 50       63 $opts{CCTYPE} = "GCC" if $opts{USE_GCC_V3_2};
335              
336             # If you -DGCC_4XX you 'll *want* CCTYPE = GCC
337 28 50       56 $opts{CCTYPE} = "GCC" if $opts{GCC_4XX};
338              
339             # If you -Dbccold you 'll *want* CCTYPE = BORLAND
340 28 50       53 $opts{CCTYPE} = "BORLAND" if $opts{BCCOLD};
341              
342 28         25110 printf "* %-25s = %s\n", $_, $opts{$_} for grep $opts{$_}, sort keys %opts;
343              
344 28         219 local (*ORG, *NEW);
345 28 50       125 my $maker = $win32_makefile_map{ $win32_maker }
346             or die "no make file for $win32_maker";
347 28         67 my $in = "win32/$maker";
348 28         47 my $out = "win32/smoke.mk";
349 28 50       1177 open(ORG, "<:raw", $in) or die "Cannot line-end-check '$in': $!";
350 28         420 my $dummy = ;
351 28         427 close(ORG); undef(*ORG);
  28         119  
352 28 50       112 my $layer = $dummy =~ /\015\012\Z/ ? ':crlf' : '';
353              
354 28 50       803 open ORG, "<$layer", $in or die "unable to open '$in': $!";
355 28 50       2580 open NEW, ">:crlf", $out or die "unable to open '$out': $!";
356 28         99 my $donot_change = 0;
357 28 50       70 my $check_linkflags = $adjust_ldflags ? 1 : 0;
358 28         453 while () {
359 2450 100       4307 if ( $donot_change ) {
360             # need to help the Win95 build
361 532 100       981 if (m/^\s*CFG_VARS\s*=/) {
362 28 50 66     127 my( $extra_char, $quote ) = ($is_nmake || $is_gmake)
363             ? ( "\t", '"' ) : ("~", "" );
364 28         245 $_ .= join "", map "\t\t$quote$_$quote\t${extra_char}\t\\\n",
365             grep /\w+=/, @args;
366             }
367 532         799 print NEW $_;
368 532         1459 next;
369             } else {
370 1918         3409 $donot_change = /^#+ CHANGE THESE ONLY IF YOU MUST #+/;
371             }
372              
373             # Only change config stuff _above_ that line!
374 1918 100       11044 if ( m/^\s*#?\s*$def_re(\s*[\*:]?=\s*define)$/ ) {
    100          
    100          
    100          
    100          
375 266 100       1065 $_ = ($opts{$1} ? "" : "#") . $1 . $2 . "\n";
376             }
377             elsif (m/\s*#?\s*($undef_re)(\s*[*:]?=\s*undef)$/) {
378 28 100       173 $_ = ($opts{$1} ? "#" : "") . "$1$2\n";
379             }
380             elsif (m/^\s*#?\s*(CFG\s*[*:]?=\s*Debug)$/) {
381 28 50       122 $_ = ($opts{USE_DEBUGGING} ? "" : "#") . $1 . "\n";
382             }
383             elsif (m/^\s*#?\s*(BUILD_STATIC)\s*([*:]?=)\s*(.*)$/) {
384 28         131 my( $macro, $op, $mval ) = ( $1, $2, $3);
385 28 100       83 if ( $config_args =~ /-([UD])useshrplib\b/ ) {
386 2 50       31 $_ = ( $1 eq 'D' ? "#" : "" ) . "$macro $op $mval\n";
387             }
388             }
389             elsif (m/^\s*#?\s*(BUILDOPT)\s*([*:]?)=\s*\$\(BUILDOPTEXTRA\)/) {
390 28 100       94 my $prf = $2 ? $2 : '';
391 28 100       60 if ($adjust_ccflags) {
392             # Set BUILDOPTEXTRA to $adjust_ccflags
393 4         21 s/^\s*#\s*//;
394 4         17 $_ = "BUILDOPTEXTRA\t${prf}= $adjust_ccflags\n$_";
395             }
396 28 50       64 if ($adjust_ldflags) {
397 0         0 $_ .= "\n# Additional linker flags\n"
398             . "PRIV_LINK_FLAGS\t${prf}= $adjust_ldflags\n";
399             }
400             }
401             else {
402 1540         6318 foreach my $cfg_var ( grep defined $opts{ $_ }, @w32_opts ) {
403 8033 100       171942 if ( m/^\s*#?\s*($cfg_var\s*(\*|:)?=)\s*(.*)$/ ) {
404 72         291 my ($name, $val) = ($1, $2);
405 72 100 100     339 next if $_ =~ /^#/ and !$opts{ $cfg_var };
406 46 100       167 $_ = $opts{ $cfg_var } ?
407             "$name $opts{ $cfg_var }\n":
408             "#$name $val\n";
409 46         119 last;
410             }
411             }
412             }
413 1918         8446 print NEW $_;
414             }
415 28         297 close ORG;
416 28         1713 close NEW;
417 28         636 return $out;
418             } # Configure_win32
419              
420             =head2 set_vms_rooted_logical( $logical, $dir )
421              
422             This will set a VMS rooted logical like:
423              
424             define/translation=concealed $logical $dir
425              
426             =cut
427              
428             sub set_vms_rooted_logical {
429 0     0 1 0 my( $logical, $dir ) = @_;
430 0 0       0 return unless $^O eq 'VMS';
431              
432 0         0 my $cwd = cwd();
433 0   0     0 $dir ||= $cwd;
434              
435 0 0       0 -d $dir or do {
436 0         0 require File::Path;
437 0         0 File::Path::mkpath( $dir );
438             };
439 0 0       0 chdir $dir or die "Cannot chdir($dir): $!";
440              
441             # On older systems we might exceed the 8-level directory depth limit
442             # imposed by RMS. We get around this with a rooted logical, but we
443             # can't create logical names with attributes in Perl, so we do it
444             # in a DCL subprocess and put it in the job table so the parent sees it.
445              
446 0 0       0 open TSBRL, '> tsbuildrl.com' or die "Error creating DCL-file; $!";
447              
448 0         0 print TSBRL <
449             \$ $logical = F\$PARSE("SYS\$DISK:[]",,,,"NO_CONCEAL")-".][000000"-"]["-"].;"+".]"
450             \$ DEFINE/JOB/NOLOG/TRANSLATION=CONCEALED $logical '$logical'
451             COMMAND
452 0         0 close TSBRL;
453              
454 0         0 my $result = system '@tsbuildrl.com';
455 0         0 1 while unlink 'tsbuildrl.com';
456 0         0 chdir $cwd;
457 0         0 return $result == 0;
458             }
459              
460             =head2 get_cfg_filename( )
461              
462             C tries to find a B and returns it.
463              
464             =cut
465              
466             sub get_cfg_filename {
467 5     5 1 1585 my( $cfg_name ) = @_;
468 5 100 100     106 return $cfg_name if defined $cfg_name && -f $cfg_name;
469              
470 2   33     18 my( $base_dir ) = ( $0 =~ m|^(.*)/| ) || File::Spec->curdir;
471 2         25 $cfg_name = File::Spec->catfile( $base_dir, 'smoke.cfg' );
472 2 50 33     67 return $cfg_name if -f $cfg_name && -s _;
473              
474 2         13 $base_dir = File::Spec->curdir;
475 2         15 $cfg_name = File::Spec->catfile( $base_dir, 'smoke.cfg' );
476 2 50 33     32 return $cfg_name if -f $cfg_name && -s _;
477              
478 2         13 return undef;
479             }
480              
481             =head2 read_logfile( )
482              
483             Read the logfile. If an argument is passed, force to (re)read the log
484             If no argument is passed, return the stored log if available otherwise
485             read the logfile
486              
487             =cut
488              
489             sub read_logfile {
490 16     16 1 71 my ($logfile, $verbose) = @_;
491 16 50       115 return if ! defined $logfile;
492              
493 16 50       878 open my $fh, "<", $logfile or return undef;
494 16         70 my $log = do { local $/; <$fh> };
  16         158  
  16         752  
495 16         202 close $fh;
496              
497 16         70 my $es = eval { decode("utf-8", $log, Encode::FB_CROAK ) };
  16         384  
498 16 50       2948 $@ and eval { $es = decode("cp1252", $log, Encode::FB_CROAK ) };
  0         0  
499 16 50       50 $@ and eval { $es = decode("iso-8859-1", $log, Encode::FB_CROAK ) };
  0         0  
500              
501 16 50       73 warn("Couldn't decode logfile($logfile): $@") if $@;
502 16 50       141 return $@ ? $log : $es;
503             }
504              
505             =head2 grepccmsg( $cc, $logfile, $verbose )
506              
507             This is a port of Jarkko Hietaniemi's grepccerr script.
508              
509             =cut
510              
511             sub grepccmsg {
512 70     70 1 30121 my( $cc, $smokelog, $verbose ) = @_;
513 70 50       187 defined $smokelog or return;
514 70 50 33     635 $cc = 'gcc' if !$cc || $cc eq 'g++' || $cc eq 'clang';
      33        
515 70         1738 my %OS2PAT = (
516             'aix' =>
517             # "foo.c", line n.c: pppp-qqq (W) ...error description...
518             # "foo.c", line n.c: pppp-qqq (S) ...error description...
519             '(^".+?", line \d+\.\d+: \d+-\d+ \([WS]\) .+?$)',
520              
521             'dec_osf' =>
522             # DEC OSF/1, Digital UNIX, Tru64 (notice also VMS)
523             # cc: Warning: foo.c, line nnn: ...error description...(error_tag)
524             # ...error line...
525             # ------^
526             # cc: Error: foo.c, line nnn: ...error description... (error_tag)
527             # ...error line...
528             # ------^
529             '(^cc: (?:Warning|Error): .+?^-*\^$)',
530              
531             'hpux' =>
532             # cc: "foo.c"" line nnn: warning ppp: ...error description...
533             # cc: "foo.c"" line nnn: error ppp: ...error description...
534             '(^cc: ".+?", line \d+: (?:warning|error) \d+: .+?$)',
535              
536             'irix' =>
537             # cc-pppp cc: WARNING File = foo.c, Line = nnnn
538             # ...error description...
539             #
540             # ...error line...
541             # ^
542             # cc-pppp cc: ERROR File = foo.c, Line = nnnn
543             # ...error description...
544             #
545             # ...error line...
546             # ^
547             '^(cc-\d+ cc: (?:WARNING|ERROR) File = .+?, ' .
548             'Line = \d+.+?^\s*\^$)',
549              
550             'solaris' =>
551             # "foo.c", line nnn: warning: ...error description...
552             # "foo.c", line nnn: warning: ...:
553             # ...error description...
554             # "foo.c", line nnn: syntax error ...
555             '(^".+?", line \d+: ' .
556             '(?:warning: (?:(?:.+?:$)?.+?$)|syntax error.+?$))',
557              
558             'vms' => # same compiler as Tru64, different message syntax
559             # ...error line...
560             # ......^
561             # %CC-W-MESSAGEID, ...error description...
562             # at line number nnn in file foo.c
563             '(^\n.+?\n^\.+?\^\n^\%CC-(?:I|W|E|F)-\w+, ' .
564             '.+?\nat line number \d+ in file \S+?$)',
565              
566             'gcc' =>
567             # foo.c: In function `foo':
568             # foo.c:nnn: warning: ...
569             # foo.c: In function `foo':
570             # foo.c:nnn:ppp: warning: ...
571             # Sometimes also the column is mentioned.
572             # foo.c: In function `foo':
573             # foo.c:nnn: error: ...
574             # foo.c(:nn)?: undefined reference to ...
575             '(^(?-s:.+?):(?: In function .+?:$|' .
576             '(?: undefined reference to .+?$)|' .
577             '\d+(?:\:\d+)?: ' . '(?:warning:|error:|note:|invalid) .+?$))',
578              
579             'mswin32' => # MSVC(?:60)*
580             # foo.c : error LNKnnn: error description
581             # full\path\to\fooc.c : fatal error LNKnnn: error description
582             # foo.c(nnn) : warning Cnnn: warning description
583             '(^(?!NMAKE)(?-s:.+?) : (?-s:.+?)\d+: .+?$)',
584              
585             'bcc32' => # BORLAND 5.5 on MSWin32
586             # Warning Wnnn filename line: warning description
587             # Error Ennn:: error description
588             '(^(?:(?:Warning W)|(?:Error E))\d+ .+? \d+: .+?$)',
589              
590             'icc' => # Intel C on Linux
591             # pp_sys.c(4412): warning #num: text
592             # SETi( getpriority(which, who) );
593             # ^
594             '(^.*?\([0-9]+\): (?:warning #[0-9]+|error): .+$)',
595             'icpc' => # Intel C++
596             '(^.*?\([0-9]+\): (?:warning #[0-9]+|error): .+$)',
597             );
598 70 50       255 exists $OS2PAT{ lc $cc } or $cc = 'gcc';
599 70         141 my $pat = $OS2PAT{ lc $cc };
600              
601 70         149 my( $indx, %error ) = ( 1 );
602 70 50       141 if ($smokelog) {
603 70 50       147 $verbose and print "Pattern($cc): /$pat/\n";
604             } else {
605 0         0 $error{ "Couldn't examine logfile for compiler warnings." } = 1;
606             }
607              
608 70         104589 while ($smokelog =~ m/$pat/mg) {
609 1260         2809 (my $msg = $1) =~ s/^\s+//;
610 1260         6766 $msg =~ s/[\s\r\n]+\Z//;
611              
612             # Skip known junk from Configure
613 1260 50       2392 $msg =~ m{^try\.c:[ :0-9]+\bwarning:} and next;
614              
615             # We need to think about this IRIX/$Config{cc} thing
616             # $cc eq "irix" && $Config{cc} =~ m/-n32|-64/ &&
617             # $msg =~ m/cc-(?:1009|1110|1047) / and next;
618              
619 1260   66     10742 $error{ $msg } ||= $indx++;
620             }
621              
622 70         364 my @errors = sort { $error{ $a } <=> $error{ $b } } keys %error;
  265         461  
623              
624 70 100       1002 return wantarray ? @errors : \@errors;
625             }
626              
627             =head2 grepnonfatal( $cc, $logfile, $verbose )
628              
629             This is a way to find known failures that do not cause the tests to
630             fail but are important enough to report, like being unable to install
631             manual pages.
632              
633             =cut
634              
635             sub grepnonfatal {
636 68     68 1 24760 my( $cc, $smokelog, $verbose ) = @_;
637 68 50       197 $smokelog or return;
638              
639 68         133 my( $indx, %error ) = ( 1 );
640              
641 68         370 my $kf = qr{
642             # Pod::Man is not available: Can't load module Encode, dynamic loading not available in this perl.
643             (\b (\S+) (?-x: is not available: Can't load module )
644             (\S+?) , (?-x: dynamic loading not available) )
645             }xi;
646              
647 68     1   40886 while ($smokelog =~ m{$kf}g) {
  1         1117  
  1         30  
  1         34  
648 24         77 my $fail = $1; # $2 = "Pod::Man", $3 = "Encode"
649              
650 24   66     35285 $error{ $fail } ||= $indx++;
651             }
652              
653 68         29651 my @errors = sort { $error{ $a } <=> $error{ $b } } keys %error;
  0         0  
654              
655 68 100       757 return wantarray ? @errors : \@errors;
656             }
657              
658             =head2 get_local_patches( $ddir )
659              
660             C reads F to scan for the locally
661             applied patches array.
662              
663             =cut
664              
665             sub get_local_patches {
666 82     82 1 9125 my( $ddir, $verbose ) = @_;
667 82   33     229 $ddir = shift || cwd();
668 82         506 my $plevel = catfile( $ddir, 'patchlevel.h' );
669              
670 82         1755 my $logger = Test::Smoke::Logger->new(v => $verbose);
671              
672 82         258 my @lpatches = ( );
673 82         296 local *PLEVEL;
674 82         934 $logger->log_info("Locally applied patches from '%s'", $plevel);
675 82 100       2162 unless ( open PLEVEL, "< $plevel" ) {
676 59         552 $logger->log_warn("open(%s) error: %s", $plevel, $!);
677 59         959 return @lpatches;
678             }
679 23         92 my( $seen, $patchnum );
680 23         597 while ( ) {
681 3945 100       6437 $patchnum = $1 if /#define PERL_PATCHNUM\s+(\d+)/;
682 3945 100 100     6931 $seen && /^\s*,"(.+)"/ and push @lpatches, $1;
683 3945 100       8869 /^\s*static.+?local_patches\[\]/ and $seen++;
684             }
685 23         241 close PLEVEL;
686 23 100       77 if ( defined $patchnum ) {
687             @lpatches = map {
688 2         5 s/^(MAINT|DEVEL)$/$1$patchnum/;
  4         23  
689 4         13 $_;
690             } @lpatches;
691             }
692 23         162 $logger->log_info("Patches: '%s'", join(';', @lpatches));
693 23         162 return @lpatches;
694             }
695              
696             =head2 set_local_patch( $ddir, @descr )
697              
698             Copy the code from F. Older (pre 5.8.1) perls do not
699             have it and it doesn't work on MSWin32.
700              
701             =cut
702              
703             sub set_local_patch {
704 17     17 1 11682 my( $ddir, @descr ) = @_;
705              
706 17         272 my $plh = catfile( $ddir, 'patchlevel.h' );
707 17         200 my $pln = catfile( $ddir, 'patchlevel.new' );
708 17         177 my $plb = catfile( $ddir, 'patchlevel.bak' );
709 17         155 local( *PLIN, *PLOUT );
710 17 50       1087 open PLIN, "< $plh" or return 0;
711 17 50       1551 open PLOUT, "> $pln" or return 0;
712 17         111 my $seen=0;
713 17         47 my $done=0;
714 17         668 while ( ) {
715 2588 100 100     6363 if ( /^(\s+),NULL/ and $seen ) {
716 17         44 $done++;
717 17         92 while ( my $c = shift @descr ) {
718 19         291 print PLOUT qq{$1,"$c"\n};
719             }
720             }
721 2588 100       5104 $seen++ if /local_patches\[\]/;
722 2588         6389 print PLOUT;
723             }
724 17         258 close PLIN;
725 17 50       966 close PLOUT or return 0;
726              
727 17 50       125 if ( not $done ) {
728 0         0 require Carp;
729 0         0 Carp::carp("Failed to update patchlevel.h. Content not as expected?");
730 0         0 return 0;
731             }
732              
733 17   33     1155 -e $plb and 1 while unlink $plb;
734 17         272 my $errno = "$!";
735 17 50       224 if ( -e $plb ) {
736 0         0 require Carp;
737 0         0 Carp::carp( "Could not unlink $plb : $errno" );
738 0         0 return 0;
739             }
740              
741 17 50       793 unless ( rename $plh, $plb ) {
742 0         0 require Carp;
743 0         0 Carp::carp( "Could not rename $plh to $plb : $!" );
744 0         0 return 0;
745             }
746 17 50       644 unless ( rename $pln, $plh ) {
747 0         0 require Carp;
748 0         0 Carp::carp( "Could not rename '$pln' to '$plh' : $!" );
749 0         0 return 0;
750             }
751              
752 17         184 return 1;
753             }
754              
755             =head2 get_config( $filename )
756              
757             Read and parse the configuration from file, or return the default
758             config.
759              
760             =cut
761              
762             sub get_config {
763 3     3 1 669 my( $config_file ) = @_;
764              
765             return (
766 3 100       24 [ "",
767             "-Dusethreads -Duseithreads"
768             ],
769             [ "",
770             "-Duse64bitint",
771             "-Duse64bitall",
772             "-Duselongdouble",
773             "-Dusemorebits",
774             "-Duse64bitall -Duselongdouble"
775             ],
776             { policy_target => "-DDEBUGGING",
777             args => [ "", "-DDEBUGGING" ]
778             },
779             ) unless defined $config_file;
780              
781 1 50       35 open CONF, "< $config_file" or do {
782 0         0 warn "Can't open '$config_file': $!\nUsing standard configuration";
783 0         0 return get_config( undef );
784             };
785 1         6 my( @conf, @cnf_stack, @target );
786              
787             # Cheat. Force a break marker as a line after the last line.
788 1         42 foreach (, "=") {
789 14 100       34 m/^#/ and next;
790 12 100       41 s/\s+$// if m/\s/; # Blanks, new-lines and carriage returns. M$
791 12 100       23 if (m:^/:) {
792 1         4 m:^/(.*)/$:;
793 1 50       5 defined $1 or die "Policy target line didn't end with '/': '$_'";
794 1         2 push @target, $1;
795 1         2 next;
796             }
797              
798 11 100       25 if (!m/^=/) {
799             # Not a break marker
800 7         13 push @conf, $_;
801 7         12 next;
802             }
803              
804             # Break marker, so process the lines we have.
805 4 50       10 if (@target > 1) {
806             warn "Multiple policy target lines " .
807 0         0 join (", ", map {"'$_'"} @target) . " - will use first";
  0         0  
808             }
809 4         8 my %conf = map { $_ => 1 } @conf;
  7         19  
810 4 50 66     29 if (keys %conf == 1 and exists $conf{""} and !@target) {
      33        
811             # There are only blank lines - treat it as if there were no lines
812             # (Lets people have blank sections in configuration files without
813             # warnings.)
814             # Unless there is a policy target. (substituting '' in place of
815             # target is a valid thing to do.)
816 1         3 @conf = ();
817             }
818              
819 4 100       9 unless (@conf) {
820             # They have no target lines
821 1 50       5 @target and
822             warn "Policy target '$target[0]' has no configuration lines, ".
823             "so it will not be used";
824 1         2 @target = ();
825 1         4 next;
826             }
827              
828 3         20 while (my ($key, $val) = each %conf) {
829 6 50       20 $val > 1 and
830             warn "Configuration line '$key' duplicated $val times";
831             }
832 3         7 my $args = [@conf];
833 3         5 @conf = ();
834 3 100       8 if (@target) {
835 1         5 push @cnf_stack, { policy_target => $target[0], args => $args };
836 1         2 @target = ();
837 1         3 next;
838             }
839              
840 2         5 push @cnf_stack, $args;
841             }
842 1         14 close CONF;
843 1         7 return @cnf_stack;
844             }
845              
846             =head2 get_patch( [$ddir] )
847              
848             Try to find the patchlevel, look for B<.patch> or try to get it from
849             B as a fallback.
850              
851             =cut
852              
853             sub get_patch {
854 12     12 1 8639 my( $ddir ) = @_;
855 12   66     104 $ddir ||= File::Spec->curdir;
856              
857 12         211 my $dot_patch = File::Spec->catfile( $ddir, '.patch' );
858 12         77 local *DOTPATCH;
859 12         59 my $patch_level = '?????';
860 12 100       455 if ( open DOTPATCH, "< $dot_patch" ) {
861 3   50     136 chomp( $patch_level = || '' );
862 3         54 close DOTPATCH;
863              
864 3 50       20 if ( $patch_level ) {
865 3 100       33 if ($patch_level =~ /\s/) {
866 1         9 my ($branch, $sha, $describe) = (split ' ', $patch_level)[0, -2, -1];
867 1         7 (my $short_describe = $describe) =~ s/^GitLive-//;
868 1         9 return [$sha, $short_describe, $branch];
869             }
870 2         20 return [$patch_level];
871             }
872 0         0 return [ '' ];
873             }
874              
875             # There does not seem to be a '.patch', try 'git_version.h'
876             # We are looking for the line: #define PERL_PATCHNUM "v5.21.6-224-g6324db4"
877 9         105 my $git_version_h = File::Spec->catfile($ddir, 'git_version.h');
878 9 100       218 if (open my $gvh, '<', $git_version_h) {
879 2         38 while (my $line = <$gvh>) {
880 14 100       54 if ($line =~ /^#define PERL_PATCHNUM "(.+)"$/) {
881 1         23 return [$1];
882             }
883             }
884 1         12 close $gvh;
885             }
886             # This only applies to
887             # There does not seem to be a '.patch', and we couldn't find git_version.h
888             # Now try 'patchlevel.h'
889             # We are looking for the line: ,"DEVEL19999" (within local_patches[] = {}
890 8         36 local *PATCHLEVEL_H;
891 8         80 my $patchlevel_h = File::Spec->catfile( $ddir, 'patchlevel.h' );
892 8 100       217 if ( open PATCHLEVEL_H, "< $patchlevel_h" ) {
893 5         16 my( $declaration_seen, $patchnum ) = ( 0, 0 );
894 5         87 while ( ) {
895 299 100       508 $patchnum = $1 if /#define PERL_PATCHNUM\s+(\d+)/;
896 299   100     850 $declaration_seen ||= /local_patches\[\]/;
897 299 100 100     976 $declaration_seen &&
898             /^\s+,"(?:(?:DEVEL|MAINT)(\d+)?)|(RC\d+)"/ or next;
899 5   50     27 $patch_level = $patchnum || $1 || $2 || '?????';
900 5 100       17 if ( $patch_level =~ /^RC/ ) {
901 1         5 $patch_level = version_from_patchlevel_h( $ddir ) .
902             "-$patch_level";
903             } else {
904 4 100       16 $patch_level .= $patchnum ? "" : '(+)';
905             }
906             }
907             }
908 8         505 return [ $patch_level ];
909             }
910              
911             =head2 version_from_patchlevel_h( $ddir )
912              
913             C returns a "dotted" version as derived
914             from the F file in the distribution.
915              
916             =cut
917              
918             sub version_from_patchlevel_h {
919 20     20 1 84 my( $ddir ) = @_;
920 20   33     66 $ddir ||= File::Spec->curdir;
921 20         370 my $file = File::Spec->catfile( $ddir, 'patchlevel.h' );
922              
923 20         189 my( $revision, $version, $subversion ) = qw( 5 ? ? );
924 20         70 local *PATCHLEVEL;
925 20 100       504 if ( open PATCHLEVEL, "< $file" ) {
926 5         26 my $patchlevel = do { local $/; };
  5         31  
  5         162  
927 5         66 close PATCHLEVEL;
928              
929 5 100       73 if ( $patchlevel =~ /^#define PATCHLEVEL\s+(\d+)/m ) {
930             # Also support perl < 5.6
931 1         8 $version = sprintf "%03u", $1;
932 1 50       8 $subversion = $patchlevel =~ /^#define SUBVERSION\s+(\d+)/m
933             ? sprintf "%02u", $1 : '??';
934 1         8 return "$revision.$version$subversion";
935             }
936              
937 4 50       57 $revision = $patchlevel =~ /^#define PERL_REVISION\s+(\d+)/m
938             ? $1 : '?';
939 4 50       46 $version = $patchlevel =~ /^#define PERL_VERSION\s+(\d+)/m
940             ? $1 : '?';
941 4 50       27 $subversion = $patchlevel =~ /^#define PERL_SUBVERSION\s+(\d+)/m
942             ? $1 : '?';
943             }
944 19         174 return "$revision.$version.$subversion";
945             }
946              
947             =head2 get_ncpu( $osname )
948              
949             C returns the number of available (online/active/enabled) CPUs.
950              
951             It does this by using some operating system specific trick (usually
952             by running some external command and parsing the output).
953              
954             If it cannot recognize your operating system an empty string is returned.
955             If it can recognize it but the external command failed, C<"? cpus">
956             is returned.
957              
958             In the first case (where we really have no idea how to proceed),
959             also a warning (C) is sent to STDERR.
960              
961             =over
962              
963             =item B
964              
965             If you get the warning C, you will
966             need to help us-- how does one tell the number of available CPUs in
967             your operating system? Sometimes there are several different ways:
968             please try to find the fastest one, and a one that does not require
969             superuser (administrator) rights.
970              
971             Thanks to Jarkko Hietaniemi for donating this!
972              
973             =back
974              
975             =cut
976              
977             sub get_ncpu {
978             # Only *nixy osses need this, so use ':'
979 1     1 1 1003 local $ENV{PATH} = "$ENV{PATH}:/usr/sbin:/sbin";
980              
981 1         3 my $cpus = "?";
982             OS_CHECK: {
983 1 50       2 local $_ = shift or return "";
  1         15  
984              
985 1 50       7 /aix/i && do {
986 0         0 my @output = `lsdev -C -c processor -S Available`;
987 0         0 $cpus = scalar @output;
988 0         0 last OS_CHECK;
989             };
990              
991 1 50       7 /(?:darwin|.*bsd)/i && do {
992 0         0 chomp( my @output = `sysctl -n hw.ncpu` );
993 0         0 $cpus = $output[0];
994 0         0 last OS_CHECK;
995             };
996              
997 1 50       4 /hp-?ux/i && do {
998 0         0 my @output = grep /^processor/ => `ioscan -fnkC processor`;
999 0         0 $cpus = scalar @output;
1000 0         0 last OS_CHECK;
1001             };
1002              
1003 1 50       4 /irix/i && do {
1004 0         0 my @output = grep /\s+processors?$/i => `hinv -c processor`;
1005 0         0 $cpus = (split " ", $output[0])[0];
1006 0         0 last OS_CHECK;
1007             };
1008              
1009 1 50       5 /linux/i && do {
1010 1         2 my @output; local *PROC;
  1         4  
1011 1 50       49 if ( open PROC, "< /proc/cpuinfo" ) {
1012 1         496 @output = grep /^processor/ => ;
1013 1         33 close PROC;
1014             }
1015 1 50       8 $cpus = @output ? scalar @output : '';
1016 1         7 last OS_CHECK;
1017             };
1018              
1019 0 0       0 /solaris|sunos|osf/i && do {
1020 0         0 my @output = grep /on-line/ => `psrinfo`;
1021 0         0 $cpus = scalar @output;
1022 0         0 last OS_CHECK;
1023             };
1024              
1025 0 0       0 /mswin32|cygwin/i && do {
1026             $cpus = exists $ENV{NUMBER_OF_PROCESSORS}
1027 0 0       0 ? $ENV{NUMBER_OF_PROCESSORS} : '';
1028 0         0 last OS_CHECK;
1029             };
1030              
1031 0 0       0 /vms/i && do {
1032 0         0 my @output = grep /CPU \d+ is in RUN state/ => `show cpu/active`;
1033 0 0       0 $cpus = @output ? scalar @output : '';
1034 0         0 last OS_CHECK;
1035             };
1036              
1037 0 0       0 /haiku/i && do {
1038 0         0 eval { require Haiku::SysInfo };
  0         0  
1039 0 0       0 if (!$@) {
1040 0         0 my $hsi = Haiku::SysInfo->new();
1041 0         0 $cpus = $hsi->cpu_count();
1042 0         0 last OS_CHECK;
1043             }
1044             };
1045              
1046 0         0 $cpus = "";
1047 0         0 require Carp;
1048 0         0 Carp::carp( "get_ncpu: unknown operationg system" );
1049             }
1050              
1051 1 50       14 return $cpus ? sprintf( "%s cpu%s", $cpus, $cpus ne "1" ? 's' : '' ) : "";
    50          
1052             }
1053              
1054             =head2 get_smoked_Config( $dir, @keys )
1055              
1056             C returns a hash (a listified hash) with the
1057             specified keys. It will try to find F to get those
1058             values, if that cannot be found (make error?) we can try F
1059             which is used to build F.
1060             If F is not there (./Configure error?) we try to get some
1061             fallback information from C and F.
1062              
1063             =cut
1064              
1065             sub get_smoked_Config {
1066 172     172 1 22306 my( $dir, @fields ) = @_;
1067 172         447 my %Config = map { ( lc $_ => undef ) } @fields;
  428         2330  
1068              
1069 172         1163 my $perl_Config_heavy = catfile ($dir, "lib", "Config_heavy.pl");
1070 172         699 my $perl_Config_pm = catfile ($dir, "lib", "Config.pm");
1071 172         608 my $perl_config_sh = catfile( $dir, 'config.sh' );
1072 172         903 local *CONF;
1073 172 100       4062 if ( open CONF, "< $perl_Config_heavy" ) {
1074              
1075 1         17 while () {
1076 15 100       57 if ( m/^(?:
1077             (?:our|my)\ \$[cC]onfig_[sS][hH].*
1078             |
1079             \$_
1080             )\ =\ <<'!END!';/x..m/^!END!/){
1081 8 100       22 m/!END!(?:';)?$/ and next;
1082 6 100       21 m/^([^=]+)='([^']*)'/ or next;
1083 5 50       27 exists $Config{lc $1} and $Config{lc $1} = $2;
1084             }
1085             }
1086 1         13 close CONF;
1087             }
1088             my %conf2 = map {
1089 423         1432 ( $_ => undef )
1090 172         1563 } grep !defined $Config{ $_ } => keys %Config;
1091 172 100       2366 if ( open CONF, "< $perl_Config_pm" ) {
1092              
1093 2         32 while () {
1094 31 100       127 if ( m/^(?:
1095             (?:our|my)\ \$[cC]onfig_[sS][hH].*
1096             |
1097             \$_
1098             )\ =\ <<'!END!';/x..m/^!END!/){
1099 16 100       47 m/!END!(?:';)?$/ and next;
1100 12 100       42 m/^([^=]+)='([^']*)'/ or next;
1101 10 50       49 exists $conf2{lc $1} and $Config{lc $1} = $2;
1102             }
1103             }
1104 2         22 close CONF;
1105             }
1106             %conf2 = map {
1107 413         1308 ( $_ => undef )
1108 172         908 } grep !defined $Config{ $_ } => keys %Config;
1109 172 100       4859 if ( open CONF, "< $perl_config_sh" ) {
1110 144         3351 while ( ) {
1111 444 100       2547 m/^([^=]+)='([^']*)'/ or next; # '
1112 148 100       2069 exists $conf2{ $1} and $Config{ lc $1 } = $2;
1113             }
1114 144         1622 close CONF;
1115             }
1116             %conf2 = map {
1117 312         1049 ( $_ => undef )
1118 172         996 } grep !defined $Config{ $_ } => keys %Config;
1119 172 100       485 if ( keys %conf2 ) {
1120             # Fall-back values from POSIX::uname() (not reliable)
1121 119         1253 require POSIX;
1122 119         1513 my( $osname, undef, $osvers, undef, $arch) = POSIX::uname();
1123 119 100       442 $Config{osname} = lc $osname if exists $conf2{osname};
1124 119 100       473 $Config{osvers} = lc $osvers if exists $conf2{osvers};
1125 119 100       320 $Config{archname} = lc $arch if exists $conf2{archname};
1126             $Config{version} = version_from_patchlevel_h( $dir )
1127 119 100       459 if exists $conf2{version};
1128             }
1129              
1130             # There should be no under-bars in perl versions!
1131 172 100       609 exists $Config{version} and $Config{version} =~ s/_/./g;
1132 172         1592 return %Config;
1133             }
1134              
1135             =head2 parse_report_Config( $report )
1136              
1137             C returns a list attributes from a smoke report.
1138              
1139             my( $version, $plevel, $os, $osvers, $archname, $summary, $branch ) =
1140             parse_report_Config( $rpt );
1141              
1142             =cut
1143              
1144             sub parse_report_Config {
1145 10     10 1 7127 my( $report ) = @_;
1146              
1147 10 50       55 my $branch = $report =~ /^Automated.+branch (.+?) / ? $1 : 'blead';
1148 10 50       53 my $version = $report =~ /^Automated.*for(?: branch \S+)? (.+) patch/ ? $1 : '';
1149 10 50       87 my $plevel = $report =~ /^Automated.+?(\S+)$/m
1150             ? $1 : '';
1151 10 50       23 if ( !$plevel ) {
1152 0 0       0 $plevel = $report =~ /^Auto.*patch\s+\S+\s+(\S+)/ ? $1 : '';
1153             }
1154 10 50       54 my $osname = $report =~ /\bon\s+(.*) - / ? $1 : '';
1155 10 50       42 my $osvers = $report =~ /\bon\s+.* - (.*)/? $1 : '';
1156 10         21 $osvers =~ s/\s+\(.*//;
1157 10 50       35 my $archname = $report =~ /:.* \((.*)\)/ ? $1 : '';
1158 10 50       37 my $summary = $report =~ /^Summary: (.*)/m ? $1 : '';
1159              
1160 10         63 return ( $version, $plevel, $osname, $osvers, $archname, $summary, $branch );
1161             }
1162              
1163             =head2 get_regen_headers( $ddir )
1164              
1165             C looks in C<$ddir> to find either
1166             F or F (change 18851).
1167              
1168             Returns undef if not found or a string like C<< $^X "$regen_headers_pl" >>
1169              
1170             =cut
1171              
1172             sub get_regen_headers {
1173 14     14 1 19668 my( $ddir ) = @_;
1174              
1175 14   33     67 $ddir ||= File::Spec->curdir; # Don't smoke in a dir "0"!
1176              
1177 14         601 my $regen_headers_pl = File::Spec->catfile( $ddir, "regen_headers.pl" );
1178              
1179 14 100       448 -f $regen_headers_pl and return qq[$^X "$regen_headers_pl"];
1180              
1181 12         173 $regen_headers_pl = File::Spec->catfile( $ddir, "regen.pl" );
1182 12 100       265 -f $regen_headers_pl and return qq[$^X "$regen_headers_pl"];
1183              
1184 10         72 return; # Should this be "make regen_headers"?
1185             }
1186              
1187             =head2 run_regen_headers( $ddir, $verbose );
1188              
1189             C gets its executable from C
1190             and opens a pipe from it. warn()s on error.
1191              
1192             =cut
1193              
1194             sub run_regen_headers {
1195 0     0 1 0 my( $ddir, $verbose ) = @_;
1196              
1197 0         0 my $regen_headers = get_regen_headers( $ddir );
1198              
1199 0 0       0 defined $regen_headers or do {
1200 0         0 warn "Cannot find a regen_headers script\n";
1201 0         0 return;
1202             };
1203              
1204 0 0       0 $verbose and print "Running [$regen_headers]\n";
1205 0         0 local *REGENH;
1206 0 0       0 if ( open REGENH, "$regen_headers |" ) {
1207 0 0       0 while ( ) { $verbose > 1 and print }
  0         0  
1208 0 0       0 close REGENH or do {
1209 0         0 warn "Error in pipe [$regen_headers]\n";
1210 0         0 return;
1211             }
1212             } else {
1213 0         0 warn "Cannot fork [$regen_headers]\n";
1214 0         0 return;
1215             }
1216 0         0 return 1;
1217             }
1218              
1219             =head2 whereis( $prog )
1220              
1221             Try to find an executable instance of C<$prog> in $ENV{PATH}.
1222              
1223             Rreturns a full file-path (with extension) to it.
1224              
1225             =cut
1226              
1227             sub whereis {
1228 30     30 1 49736 my $prog = shift;
1229 30 50       201 return undef unless $prog; # you shouldn't call it '0'!
1230 30 50       257 $^O eq 'VMS' and return vms_whereis( $prog );
1231 30   50     574 my $logger = Test::Smoke::Logger->new(v => shift || 0);
1232              
1233 30         681 my $p_sep = $Config::Config{path_sep};
1234 30         440 my @path = split /\Q$p_sep\E/, $ENV{PATH};
1235 30   50     346 my @pext = split /\Q$p_sep\E/, $ENV{PATHEXT} || '';
1236 30         121 unshift @pext, '';
1237              
1238 30         126 foreach my $dir ( @path ) {
1239 241         1227 $logger->log_debug("Looking in %s for %s", $dir, $prog);
1240 241         549 foreach my $ext ( @pext ) {
1241 241         2004 my $fname = File::Spec->catfile( $dir, "$prog$ext" );
1242 241         914 $logger->log_debug(" check executable %s", $fname);
1243 241 100       4461 if ( -x $fname ) {
1244 18         159 $logger->log_info("Found %s as %s", $prog, $fname);
1245 18         161 return $fname;
1246             #return $fname =~ /\s/ ? qq/"$fname"/ : $fname;
1247             }
1248             }
1249             }
1250 12         101 $logger->log_info("Could not find %s", $prog);
1251 12         98 return '';
1252             }
1253              
1254             =head2 vms_whereis( $prog )
1255              
1256             First look in the SYMBOLS to see if C<$prog> is there.
1257             Next look in the KFE-table C if it is there.
1258             As a last resort we can scan C like we do on *nix/Win32
1259              
1260             =cut
1261              
1262             sub vms_whereis {
1263 0     0 1 0 my $prog = shift;
1264              
1265             # Check SYMBOLS
1266 0         0 eval { require VMS::DCLsym };
  0         0  
1267 0 0       0 if ( $@ ) {
1268 0         0 require Carp;
1269 0         0 Carp::carp( "Oops, cannot load VMS::DCLsym: $@" );
1270             } else {
1271 0         0 my $syms = VMS::DCLsym->new;
1272 0 0       0 return $prog if scalar $syms->getsym( $prog );
1273             }
1274             # Check Known File Entry table (INSTALL LIST)
1275 0         0 my $img_re = '^\s+([\w\$]+);\d+';
1276             my %kfe = map {
1277 0 0       0 my $img = /$img_re/ ? $1 : '';
  0         0  
1278 0         0 ( uc $img => undef )
1279             } grep /$img_re/ => qx/INSTALL LIST/;
1280 0 0       0 return $prog if exists $kfe{ uc $prog };
1281              
1282 0         0 require Config;
1283 0         0 my $dclp_env = 'DCL$PATH';
1284 0   0     0 my $p_sep = $Config::Config{path_sep} || '|';
1285 0   0     0 my @path = split /\Q$p_sep\E/, $ENV{ $dclp_env }||"";
1286 0   0     0 my @pext = ( $Config::Config{exe_ext} || $Config::Config{_exe}, '.COM' );
1287              
1288 0         0 foreach my $dir ( @path ) {
1289 0         0 foreach my $ext ( @pext ) {
1290 0         0 my $fname = File::Spec->catfile( $dir, "$prog$ext" );
1291 0 0       0 if ( -x $fname ) {
1292 0 0       0 return $ext eq '.COM' ? "\@$fname" : "MCR $fname";
1293             }
1294             }
1295             }
1296 0         0 return '';
1297             }
1298              
1299             =head2 clean_filename( $fname )
1300              
1301             C basically returns a vmsify() type of filename for
1302             VMS, and returns an upcase filename for case-ignorant filesystems.
1303              
1304             =cut
1305              
1306             sub clean_filename {
1307 304     304 1 508 my $fname = shift;
1308              
1309 304 50       743 if ( $^O eq 'VMS' ) {
1310 0         0 my @parts = split /[.@#]/, $fname;
1311 0 0       0 if ( @parts > 1 ) {
1312 0   0     0 my $ext = ( pop @parts ) || '';
1313 0         0 $fname = join( "_", @parts ) . ".$ext";
1314             }
1315             }
1316 304 50       1158 return $NOCASE ? uc $fname : $fname;
1317             }
1318              
1319             =head2 calc_timeout( $killtime[, $from] )
1320              
1321             C calculates the timeout in seconds.
1322             C<$killtime> can be one of two formats:
1323              
1324             =over 8
1325              
1326             =item B<+hh:mm>
1327              
1328             This format represents a duration and is the easy format as we only need
1329             to translate that to seconds.
1330              
1331             =item B
1332              
1333             This format represents a clock time (localtime). Calculate minutes
1334             from midnight for both C<$killtime> and C, and get
1335             the difference. If C<$from> is omitted, C is used.
1336              
1337             If C<$killtime> is the actual time, the timeout will be 24 hours!
1338              
1339             =back
1340              
1341             =cut
1342              
1343             sub calc_timeout {
1344 9     9 1 2729 my( $killtime, $from ) = @_;
1345 9         15 my $timeout = 0;
1346 9 100       65 if ( $killtime =~ /^\+(\d+):([0-5]?[0-9])$/ ) {
    100          
1347 2         10 $timeout = 60 * (60 * $1 + $2 );
1348             } elsif ( $killtime =~ /^((?:[0-1]?[0-9])|(?:2[0-3])):([0-5]?[0-9])$/ ) {
1349 6 100       17 defined $from or $from = time;
1350 6         231 my $time_min = 60 * $1 + $2;
1351 6         19 my( $now_m, $now_h ) = (localtime $from)[1, 2];
1352 6         461 my $now_min = 60 * $now_h + $now_m;
1353 6         12 my $kill_min = $time_min - $now_min;
1354 6 100       15 $kill_min += 60 * 24 if $kill_min <= 0;
1355 6         12 $timeout = 60 * $kill_min;
1356             }
1357 9         45 return $timeout;
1358             }
1359              
1360             =head2 time_in_hhmm( $diff )
1361              
1362             Create a string telling elapsed time in days, hours, minutes, seconds
1363             from the number of seconds.
1364              
1365             =cut
1366              
1367             sub time_in_hhmm {
1368 136     136 1 7705 my $diff = shift;
1369              
1370             # Only show decimal point for diffs < 5 minutes
1371 136 100       1541 my $digits = $diff =~ /\./ ? $diff < 5*60 ? 3 : 0 : 0;
    100          
1372 136         428 my $days = int( $diff / (24*60*60) );
1373 136         419 $diff -= 24*60*60 * $days;
1374 136         312 my $hour = int( $diff / (60*60) );
1375 136         242 $diff -= 60*60 * $hour;
1376 136         243 my $mins = int( $diff / 60 );
1377 136         219 $diff -= 60 * $mins;
1378 136         527 $diff = sprintf "%.${digits}f", $diff;
1379              
1380             # GH#78 that sprintf() can round up to 60 secs
1381             # that can look strange: 18 minutes 60 seconds
1382 136 100       777 $mins++, $diff -= 60 if $diff >= 60;
1383              
1384 136         217 my @parts;
1385 136 100       276 $days and push @parts, sprintf "%d day%s", $days, $days == 1 ? "" : 's';
    100          
1386 136 100       464 $hour and push @parts, sprintf "%d hour%s", $hour, $hour == 1 ? "" : 's';
    100          
1387 136 100       536 $mins and push @parts, sprintf "%d minute%s",$mins, $mins == 1 ? "" : 's';
    100          
1388 136 100 100     1257 $diff && !$days && !$hour and push @parts, "$diff seconds";
      100        
1389              
1390 136         1177 return join " ", @parts;
1391             }
1392              
1393             =head2 do_pod2usage( %pod2usage_options )
1394              
1395             If L is there then call its C.
1396             In the other case, print the general message passed with the C key.
1397              
1398             =cut
1399              
1400             sub do_pod2usage {
1401 0     0 1 0 my %p2u_opt = @_;
1402 0         0 eval { require Pod::Usage };
  0         0  
1403 0 0       0 if ( $@ ) {
1404 0   0     0 my $usage = $p2u_opt{myusage} || <<__EO_USAGE__;
1405             Usage: $0 [options]
1406             __EO_USAGE__
1407 0         0 print <
1408             $usage
1409              
1410             Use 'perldoc $0' for the documentation.
1411             Please install 'Pod::Usage' for easy access to the docs.
1412              
1413             EO_MSG
1414 0 0       0 exit( exists $p2u_opt{exitval} ? $p2u_opt{exitval} : 1 );
1415             } else {
1416 0 0       0 exists $p2u_opt{myusage} and delete $p2u_opt{myusage};
1417 0         0 Pod::Usage::pod2usage( @_ );
1418             }
1419             }
1420              
1421             =head2 skip_config( $config )
1422              
1423             Returns true if this config should be skipped.
1424             C<$config> should be a B object.
1425              
1426             =cut
1427              
1428             sub skip_config {
1429 18     18 1 75 my( $config ) = @_;
1430              
1431 18   100     74 my $skip = $config->has_arg(qw( -Uuseperlio -Dusethreads )) ||
1432             $config->has_arg(qw( -Uuseperlio -Duseithreads )) ||
1433             ( $^O eq 'MSWin32' &&
1434             (( $config->has_arg(qw( -Duseithreads -Dusemymalloc )) &&
1435             !$config->has_arg( '-Uuseimpsys' ) ) ||
1436             ( $config->has_arg(qw( -Dusethreads -Dusemymalloc )) &&
1437             !$config->has_arg( '-Uuseimpsys' ) ))
1438             );
1439 18         93 return $skip;
1440             }
1441              
1442             =head2 skip_filter( $line )
1443              
1444             C returns true if the filter rules apply to C<$line>.
1445              
1446             =cut
1447              
1448             sub skip_filter {
1449 2339     2339 1 20598 local( $_ ) = @_;
1450             # Still to be extended
1451 2339   100     57112 return m,^ *$, ||
1452             m,^\t, ||
1453             m,^PERL=./perl\s+./runtests choose, ||
1454             m,^\s+AutoSplitting, ||
1455             m,^\./miniperl , ||
1456             m,^\s*autosplit_lib, ||
1457             m,^\s*PATH=\S+\s+./miniperl, ||
1458             m,^\s+Making , ||
1459             m,^make\[[12], ||
1460             m,make( TEST_ARGS=)? (_test|TESTFILE=|lib/\w+.pm), ||
1461             m,^make:.*Error\s+\d, ||
1462             m,^\s+make\s+lib/, ||
1463             m,^ *cd t &&, ||
1464             m,^if \(true, ||
1465             m,^else \\, ||
1466             m,^fi$, ||
1467             m,^lib/ftmp-security....File::Temp::_gettemp: Parent directory \((\.|/tmp/)\) is not safe, ||
1468             m,^File::Temp::_gettemp: Parent directory \((\.|/tmp/)\) is not safe, ||
1469             m,^ok$, ||
1470             m,^[-a-zA-Z0-9_/.]+\s*\.*\s*(ok|skipped|skipping test on this platform)$, ||
1471             m,^(xlc|cc_r) -c , ||
1472             # m,^\s+$testdir/, ||
1473             m,^sh mv-if-diff\b, ||
1474             m,File \S+ not changed, ||
1475             m,^(not\s+)?ok\s+\d+\s+[-#]\s+(?i:skip\S*[: ]),i ||
1476             # cygwin
1477             m,^dllwrap: no export definition file provided, ||
1478             m,^dllwrap: creating one. but that may not be what you want, ||
1479             m,^(GNUm|M)akefile:\d+: warning: overriding commands for target `perlmain.o', ||
1480             m,^(GNUm|M)akefile:\d+: warning: ignoring old commands for target `perlmain.o', ||
1481             m,^\s+CCCMD\s+=\s+, ||
1482             # Don't know why BSD's make does this
1483             m,^Extracting .*with variable substitutions, ||
1484             # Or these
1485             m,cc\s+-o\s+perl.*perlmain.o\s+lib/auto/DynaLoader/DynaLoader\.a\s+libperl\.a, ||
1486             m,^\S+ is up to date, ||
1487             m,^( )?### , ||
1488             # Clean up Win32's output
1489             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok$, ||
1490             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok\s+\d+(\.\d+)?\s*m?s$, ||
1491             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok\,\s+\d+/\d+\s+skipped:, ||
1492             m,^(?:\.\.[/\\])?[\w/\\-]+\.*skipped[: ], ||
1493             m,^\t?x?copy , ||
1494             m,\d+\s+[Ff]ile\(s\) copied, ||
1495             m,[/\\](?:mini)?perl\.exe ,||
1496             m,^\t?cd , ||
1497             m,^\b[ng]make\b, ||
1498             m,^\s+\d+/\d+ skipped: , ||
1499             m,^\s+all skipped: , ||
1500             m,^\s*pl2bat\.bat [\w\\]+, ||
1501             m,^Making , ||
1502             m,^Skip , ||
1503             m,^Creating library file: libExtTest\.dll\.a, ||
1504             m,^cc: warning 983: ,
1505             }
1506              
1507             1;
1508              
1509             =head1 COPYRIGHT
1510              
1511             (c) 2001-2014, All rights reserved.
1512              
1513             * H. Merijn Brand
1514             * Nicholas Clark
1515             * Jarkko Hietaniemi
1516             * Abe Timmerman
1517              
1518             This library is free software; you can redistribute it and/or modify
1519             it under the same terms as Perl itself.
1520              
1521             See:
1522              
1523             * ,
1524             *
1525              
1526             This program is distributed in the hope that it will be useful,
1527             but WITHOUT ANY WARRANTY; without even the implied warranty of
1528             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1529              
1530             =cut