15759b3d2Safresh1################################################################################ 25759b3d2Safresh1# 35759b3d2Safresh1# devtools.pl -- various utility functions 45759b3d2Safresh1# 5de8cc8edSafresh1# NOTE: This will only be called by the overarching (modern) perl 6de8cc8edSafresh1# 75759b3d2Safresh1################################################################################ 85759b3d2Safresh1# 95759b3d2Safresh1# Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz. 105759b3d2Safresh1# Version 2.x, Copyright (C) 2001, Paul Marquess. 115759b3d2Safresh1# Version 1.x, Copyright (C) 1999, Kenneth Albanowski. 125759b3d2Safresh1# 135759b3d2Safresh1# This program is free software; you can redistribute it and/or 145759b3d2Safresh1# modify it under the same terms as Perl itself. 155759b3d2Safresh1# 165759b3d2Safresh1################################################################################ 175759b3d2Safresh1 18de8cc8edSafresh1use Data::Dumper; 19de8cc8edSafresh1$Data::Dumper::Sortkeys = 1; 205759b3d2Safresh1use IO::File; 21de8cc8edSafresh1use warnings; # Can't use strict because of %opt passed from caller 22de8cc8edSafresh1require "./parts/inc/inctools"; 235759b3d2Safresh1 245759b3d2Safresh1eval "use Term::ANSIColor"; 255759b3d2Safresh1$@ and eval "sub colored { pop; @_ }"; 265759b3d2Safresh1 275759b3d2Safresh1my @argvcopy = @ARGV; 285759b3d2Safresh1 295759b3d2Safresh1sub verbose 305759b3d2Safresh1{ 315759b3d2Safresh1 if ($opt{verbose}) { 325759b3d2Safresh1 my @out = @_; 335759b3d2Safresh1 s/^(.*)/colored("($0) ", 'bold blue').colored($1, 'blue')/eg for @out; 345759b3d2Safresh1 print STDERR @out; 355759b3d2Safresh1 } 365759b3d2Safresh1} 375759b3d2Safresh1 385759b3d2Safresh1sub ddverbose 395759b3d2Safresh1{ 405759b3d2Safresh1 return $opt{verbose} ? ('--verbose') : (); 415759b3d2Safresh1} 425759b3d2Safresh1 435759b3d2Safresh1sub runtool 445759b3d2Safresh1{ 455759b3d2Safresh1 my $opt = ref $_[0] ? shift @_ : {}; 465759b3d2Safresh1 my($prog, @args) = @_; 475759b3d2Safresh1 my $sysstr = join ' ', map { "'$_'" } $prog, @args; 485759b3d2Safresh1 $sysstr .= " >$opt->{'out'}" if exists $opt->{'out'}; 495759b3d2Safresh1 $sysstr .= " 2>$opt->{'err'}" if exists $opt->{'err'}; 505759b3d2Safresh1 verbose("running $sysstr\n"); 515759b3d2Safresh1 my $rv = system $sysstr; 525759b3d2Safresh1 verbose("$prog => exit code $rv\n"); 535759b3d2Safresh1 return not $rv; 545759b3d2Safresh1} 555759b3d2Safresh1 565759b3d2Safresh1sub runperl 575759b3d2Safresh1{ 585759b3d2Safresh1 my $opt = ref $_[0] ? shift @_ : {}; 595759b3d2Safresh1 runtool($opt, $^X, @_); 605759b3d2Safresh1} 615759b3d2Safresh1 625759b3d2Safresh1sub run 635759b3d2Safresh1{ 645759b3d2Safresh1 my $prog = shift; 655759b3d2Safresh1 my @args = @_; 665759b3d2Safresh1 675759b3d2Safresh1 runtool({ 'out' => 'tmp.out', 'err' => 'tmp.err' }, $prog, @args); 685759b3d2Safresh1 695759b3d2Safresh1 my $out = IO::File->new("tmp.out") or die "tmp.out: $!\n"; 705759b3d2Safresh1 my $err = IO::File->new("tmp.err") or die "tmp.err: $!\n"; 715759b3d2Safresh1 725759b3d2Safresh1 my %rval = ( 735759b3d2Safresh1 status => $? >> 8, 745759b3d2Safresh1 stdout => [<$out>], 755759b3d2Safresh1 stderr => [<$err>], 76de8cc8edSafresh1 didnotrun => 0, # Note that currently this will always be 0 77de8cc8edSafresh1 # This must have been used in earlier versions 785759b3d2Safresh1 ); 795759b3d2Safresh1 805759b3d2Safresh1 unlink "tmp.out", "tmp.err"; 815759b3d2Safresh1 825759b3d2Safresh1 $? & 128 and $rval{core} = 1; 835759b3d2Safresh1 $? & 127 and $rval{signal} = $? & 127; 845759b3d2Safresh1 85de8cc8edSafresh1 # This is expected and isn't an error. 86de8cc8edSafresh1 @{$rval{stderr}} = grep { $_ !~ /make.*No rule .*realclean/ } @{$rval{stderr}}; 87de8cc8edSafresh1 88de8cc8edSafresh1 if ( exists $rval{core} 89de8cc8edSafresh1 || exists $rval{signal} 90de8cc8edSafresh1 || ($opt{debug} > 2 && @{$rval{stderr}} && $rval{status}) 91de8cc8edSafresh1 || ($opt{debug} > 3 && @{$rval{stderr}}) 92de8cc8edSafresh1 || ($opt{debug} > 4 && @{$rval{stdout}})) 93de8cc8edSafresh1 { 94de8cc8edSafresh1 print STDERR "Returning\n", Dumper \%rval; 95de8cc8edSafresh1 96de8cc8edSafresh1 # Under verbose, runtool already output the call string 97de8cc8edSafresh1 unless ($opt{verbose}) { 98de8cc8edSafresh1 print STDERR "from $prog ", join ", ", @args; 99de8cc8edSafresh1 print STDERR "\n"; 100de8cc8edSafresh1 } 101de8cc8edSafresh1 } 102de8cc8edSafresh1 1035759b3d2Safresh1 return \%rval; 1045759b3d2Safresh1} 1055759b3d2Safresh1 1065759b3d2Safresh1sub ident_str 1075759b3d2Safresh1{ 1085759b3d2Safresh1 return "$^X $0 @argvcopy"; 1095759b3d2Safresh1} 1105759b3d2Safresh1 1115759b3d2Safresh1sub identify 1125759b3d2Safresh1{ 1135759b3d2Safresh1 verbose(ident_str() . "\n"); 1145759b3d2Safresh1} 1155759b3d2Safresh1 1165759b3d2Safresh1sub ask($) 1175759b3d2Safresh1{ 1185759b3d2Safresh1 my $q = shift; 1195759b3d2Safresh1 my $a; 1205759b3d2Safresh1 local $| = 1; 121de8cc8edSafresh1 do { 122de8cc8edSafresh1 print "\a\n$q [y/n] "; 1239a4edab6Sbluhm return unless -t; # Fail if no tty input 124de8cc8edSafresh1 $a = <>; } 125de8cc8edSafresh1 while ($a !~ /^\s*([yn])\s*$/i); 1265759b3d2Safresh1 return lc $1 eq 'y'; 1275759b3d2Safresh1} 1285759b3d2Safresh1 1295759b3d2Safresh1sub quit_now 1305759b3d2Safresh1{ 1319a4edab6Sbluhm print "\nSorry, cannot continue.\a\n\n"; 1325759b3d2Safresh1 exit 1; 1335759b3d2Safresh1} 1345759b3d2Safresh1 1355759b3d2Safresh1sub ask_or_quit 1365759b3d2Safresh1{ 1375759b3d2Safresh1 quit_now unless &ask; 1385759b3d2Safresh1} 1395759b3d2Safresh1 1405759b3d2Safresh1sub eta 1415759b3d2Safresh1{ 1425759b3d2Safresh1 my($start, $i, $n) = @_; 1435759b3d2Safresh1 return "--:--:--" if $i < 3; 1445759b3d2Safresh1 my $elapsed = tv_interval($start); 1455759b3d2Safresh1 my $h = int($elapsed*($n-$i)/$i); 1465759b3d2Safresh1 my $s = $h % 60; $h /= 60; 1475759b3d2Safresh1 my $m = $h % 60; $h /= 60; 1485759b3d2Safresh1 return sprintf "%02d:%02d:%02d", $h, $m, $s; 1495759b3d2Safresh1} 1505759b3d2Safresh1 151de8cc8edSafresh1sub get_and_sort_perls($) 152de8cc8edSafresh1{ 153de8cc8edSafresh1 my $opt = shift; 154de8cc8edSafresh1 155de8cc8edSafresh1 my $starting; 156de8cc8edSafresh1 $starting = int_parse_version($opt->{'debug-start'}) 157de8cc8edSafresh1 if $opt->{'debug-start'}; 158*eac174f2Safresh1 my $skip_devels = $opt->{'skip-devels'} // 0; 159de8cc8edSafresh1 160de8cc8edSafresh1 # Uses the opt structure parameter to find the perl versions to use this 161de8cc8edSafresh1 # run, and returns an array with a hash representing blead in the 0th 162de8cc8edSafresh1 # element and the oldest in the final one. Each entry looks like 163de8cc8edSafresh1 # { 164de8cc8edSafresh1 # 'version' => '5.031002', 165de8cc8edSafresh1 # 'file' => '5031002', 166de8cc8edSafresh1 # 'path' => '/home/khw/devel/bin/perl5.31.2' 167de8cc8edSafresh1 # }, 168de8cc8edSafresh1 # 169de8cc8edSafresh1 # Get blead and all other perls 170de8cc8edSafresh1 my @perls = $opt->{blead}; 171de8cc8edSafresh1 for my $dir (split ",", $opt->{install}) { 172de8cc8edSafresh1 push @perls, grep !/-RC\d+/, glob "$dir/bin/perl5.*"; 173de8cc8edSafresh1 } 174de8cc8edSafresh1 175de8cc8edSafresh1 # Normalize version numbers into 5.xxxyyy, and convert each element 176de8cc8edSafresh1 # describing the perl to be a hash with keys 'version' and 'path' 177de8cc8edSafresh1 for (my $i = 0; $i < @perls; $i++) { 178de8cc8edSafresh1 my $version = `$perls[$i] -e 'print \$]'`; 179de8cc8edSafresh1 my $file = int_parse_version($version); 180de8cc8edSafresh1 $version = format_version($version); 181de8cc8edSafresh1 182*eac174f2Safresh1 if ($skip_devels) { 183*eac174f2Safresh1 my ($super, $major, $minor) = parse_version($version); 184*eac174f2Safresh1 185*eac174f2Safresh1 # If skipping development releases, we still use blead (0th entry). 186*eac174f2Safresh1 # Devel releases are odd numbered ones 5.6 and above, but use every 187*eac174f2Safresh1 # release for below 5.6 188*eac174f2Safresh1 if ($i != 0 && $major >= 6 && $major % 2 != 0) { 189*eac174f2Safresh1 splice @perls, $i, 1; 190*eac174f2Safresh1 last if $i >= @perls; 191*eac174f2Safresh1 redo; 192*eac174f2Safresh1 } 193*eac174f2Safresh1 } 194*eac174f2Safresh1 195de8cc8edSafresh1 # Make this entry a hash with its version, file name, and path 196de8cc8edSafresh1 $perls[$i] = { version => $version, 197de8cc8edSafresh1 file => $file, 198de8cc8edSafresh1 path => $perls[$i], 199de8cc8edSafresh1 }; 200de8cc8edSafresh1 } 201de8cc8edSafresh1 202de8cc8edSafresh1 # Sort in descending order. We start processing the most recent perl 203de8cc8edSafresh1 # first. 204de8cc8edSafresh1 @perls = sort { $b->{file} <=> $a->{file} } @perls; 205de8cc8edSafresh1 206de8cc8edSafresh1 # Override blead's version if specified. 207de8cc8edSafresh1 if (exists $opt->{'blead-version'}) { 208de8cc8edSafresh1 $perls[0]{version} = format_version($opt->{'blead-version'}); 209de8cc8edSafresh1 } 210de8cc8edSafresh1 211de8cc8edSafresh1 my %seen; 212de8cc8edSafresh1 213de8cc8edSafresh1 # blead's todo is its version plus 1. Otherwise, each todo is the 214de8cc8edSafresh1 # previous one's. Also get rid of duplicate versions. 215de8cc8edSafresh1 $perls[0]{todo} = $perls[0]{file} + 1; 216de8cc8edSafresh1 $seen{$perls[0]{file}} = 1; 217de8cc8edSafresh1 for my $i (1 .. $#perls) { 218de8cc8edSafresh1 last unless defined $perls[$i]; 219de8cc8edSafresh1 if ( exists $seen{$perls[$i]{file}} 220de8cc8edSafresh1 || ($starting && $perls[$i]{file} gt $starting) 221de8cc8edSafresh1 ) { 222de8cc8edSafresh1 splice @perls, $i, 1; 223de8cc8edSafresh1 redo; 224de8cc8edSafresh1 } 225de8cc8edSafresh1 226de8cc8edSafresh1 $seen{$perls[$i]{file}} = 1; 227de8cc8edSafresh1 $perls[$i]{todo} = $perls[$i-1]{file}; 228de8cc8edSafresh1 } 229de8cc8edSafresh1 230de8cc8edSafresh1 # The earliest perl gets a special marker key, consisting of the proper 231de8cc8edSafresh1 # file name 232de8cc8edSafresh1 $perls[$#perls]{final} = $perls[$#perls]{file}; 233de8cc8edSafresh1 234de8cc8edSafresh1 if ($opt{debug}) { 235de8cc8edSafresh1 print STDERR "The perls returned are: ", Dumper \@perls; 236de8cc8edSafresh1 } 237de8cc8edSafresh1 238de8cc8edSafresh1 return \@perls; 239de8cc8edSafresh1} 240de8cc8edSafresh1 2415759b3d2Safresh11; 242