15759b3d2Safresh1################################################################################
25759b3d2Safresh1#
35759b3d2Safresh1#  devtools.pl -- various utility functions
45759b3d2Safresh1#
5*de8cc8edSafresh1#  NOTE: This will only be called by the overarching (modern) perl
6*de8cc8edSafresh1#
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
18*de8cc8edSafresh1use Data::Dumper;
19*de8cc8edSafresh1$Data::Dumper::Sortkeys = 1;
205759b3d2Safresh1use IO::File;
21*de8cc8edSafresh1use warnings;   # Can't use strict because of %opt passed from caller
22*de8cc8edSafresh1require "./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>],
76*de8cc8edSafresh1    didnotrun => 0,         # Note that currently this will always be 0
77*de8cc8edSafresh1                            # 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
85*de8cc8edSafresh1  # This is expected and isn't an error.
86*de8cc8edSafresh1  @{$rval{stderr}} = grep { $_ !~ /make.*No rule .*realclean/ } @{$rval{stderr}};
87*de8cc8edSafresh1
88*de8cc8edSafresh1  if (    exists $rval{core}
89*de8cc8edSafresh1      ||  exists $rval{signal}
90*de8cc8edSafresh1      || ($opt{debug} > 2 && @{$rval{stderr}} && $rval{status})
91*de8cc8edSafresh1      || ($opt{debug} > 3 && @{$rval{stderr}})
92*de8cc8edSafresh1      || ($opt{debug} > 4 && @{$rval{stdout}}))
93*de8cc8edSafresh1  {
94*de8cc8edSafresh1    print STDERR "Returning\n", Dumper \%rval;
95*de8cc8edSafresh1
96*de8cc8edSafresh1    # Under verbose, runtool already output the call string
97*de8cc8edSafresh1    unless ($opt{verbose}) {
98*de8cc8edSafresh1        print STDERR "from $prog ", join ", ", @args;
99*de8cc8edSafresh1        print STDERR "\n";
100*de8cc8edSafresh1    }
101*de8cc8edSafresh1  }
102*de8cc8edSafresh1
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;
121*de8cc8edSafresh1  do {
122*de8cc8edSafresh1    print "\a\n$q [y/n] ";
123*de8cc8edSafresh1    $a = <>; }
124*de8cc8edSafresh1  while ($a !~ /^\s*([yn])\s*$/i);
1255759b3d2Safresh1  return lc $1 eq 'y';
1265759b3d2Safresh1}
1275759b3d2Safresh1
1285759b3d2Safresh1sub quit_now
1295759b3d2Safresh1{
1305759b3d2Safresh1  print "\nSorry, cannot continue.\n\n";
1315759b3d2Safresh1  exit 1;
1325759b3d2Safresh1}
1335759b3d2Safresh1
1345759b3d2Safresh1sub ask_or_quit
1355759b3d2Safresh1{
1365759b3d2Safresh1  quit_now unless &ask;
1375759b3d2Safresh1}
1385759b3d2Safresh1
1395759b3d2Safresh1sub eta
1405759b3d2Safresh1{
1415759b3d2Safresh1  my($start, $i, $n) = @_;
1425759b3d2Safresh1  return "--:--:--" if $i < 3;
1435759b3d2Safresh1  my $elapsed = tv_interval($start);
1445759b3d2Safresh1  my $h = int($elapsed*($n-$i)/$i);
1455759b3d2Safresh1  my $s = $h % 60; $h /= 60;
1465759b3d2Safresh1  my $m = $h % 60; $h /= 60;
1475759b3d2Safresh1  return sprintf "%02d:%02d:%02d", $h, $m, $s;
1485759b3d2Safresh1}
1495759b3d2Safresh1
150*de8cc8edSafresh1sub get_and_sort_perls($)
151*de8cc8edSafresh1{
152*de8cc8edSafresh1    my $opt = shift;
153*de8cc8edSafresh1
154*de8cc8edSafresh1    my $starting;
155*de8cc8edSafresh1    $starting = int_parse_version($opt->{'debug-start'})
156*de8cc8edSafresh1                                                       if $opt->{'debug-start'};
157*de8cc8edSafresh1
158*de8cc8edSafresh1    # Uses the opt structure parameter to find the perl versions to use this
159*de8cc8edSafresh1    # run, and returns an array with a hash representing blead in the 0th
160*de8cc8edSafresh1    # element and the oldest in the final one.  Each entry looks like
161*de8cc8edSafresh1    #     {
162*de8cc8edSafresh1    #       'version' => '5.031002',
163*de8cc8edSafresh1    #       'file' => '5031002',
164*de8cc8edSafresh1    #       'path' => '/home/khw/devel/bin/perl5.31.2'
165*de8cc8edSafresh1    #     },
166*de8cc8edSafresh1    #
167*de8cc8edSafresh1    # Get blead and all other perls
168*de8cc8edSafresh1    my @perls = $opt->{blead};
169*de8cc8edSafresh1    for my $dir (split ",", $opt->{install}) {
170*de8cc8edSafresh1        push @perls, grep !/-RC\d+/, glob "$dir/bin/perl5.*";
171*de8cc8edSafresh1    }
172*de8cc8edSafresh1
173*de8cc8edSafresh1    # Normalize version numbers into 5.xxxyyy, and convert each element
174*de8cc8edSafresh1    # describing the perl to be a hash with keys 'version' and 'path'
175*de8cc8edSafresh1    for (my $i = 0; $i < @perls; $i++) {
176*de8cc8edSafresh1        my $version = `$perls[$i] -e 'print \$]'`;
177*de8cc8edSafresh1        my $file = int_parse_version($version);
178*de8cc8edSafresh1        $version = format_version($version);
179*de8cc8edSafresh1
180*de8cc8edSafresh1        # Make this entry a hash with its version, file name, and path
181*de8cc8edSafresh1        $perls[$i] = { version =>  $version,
182*de8cc8edSafresh1                       file    =>  $file,
183*de8cc8edSafresh1                       path    =>  $perls[$i],
184*de8cc8edSafresh1                     };
185*de8cc8edSafresh1    }
186*de8cc8edSafresh1
187*de8cc8edSafresh1    # Sort in descending order.  We start processing the most recent perl
188*de8cc8edSafresh1    # first.
189*de8cc8edSafresh1    @perls = sort { $b->{file} <=> $a->{file} } @perls;
190*de8cc8edSafresh1
191*de8cc8edSafresh1    # Override blead's version if specified.
192*de8cc8edSafresh1    if (exists $opt->{'blead-version'}) {
193*de8cc8edSafresh1        $perls[0]{version} = format_version($opt->{'blead-version'});
194*de8cc8edSafresh1    }
195*de8cc8edSafresh1
196*de8cc8edSafresh1    my %seen;
197*de8cc8edSafresh1
198*de8cc8edSafresh1    # blead's todo is its version plus 1.  Otherwise, each todo is the
199*de8cc8edSafresh1    # previous one's.  Also get rid of duplicate versions.
200*de8cc8edSafresh1    $perls[0]{todo} = $perls[0]{file} + 1;
201*de8cc8edSafresh1    $seen{$perls[0]{file}} = 1;
202*de8cc8edSafresh1    for my $i (1 .. $#perls) {
203*de8cc8edSafresh1        last unless defined $perls[$i];
204*de8cc8edSafresh1        if (    exists $seen{$perls[$i]{file}}
205*de8cc8edSafresh1            || ($starting && $perls[$i]{file} gt $starting)
206*de8cc8edSafresh1        ) {
207*de8cc8edSafresh1            splice @perls, $i, 1;
208*de8cc8edSafresh1            redo;
209*de8cc8edSafresh1        }
210*de8cc8edSafresh1
211*de8cc8edSafresh1        $seen{$perls[$i]{file}} = 1;
212*de8cc8edSafresh1        $perls[$i]{todo} = $perls[$i-1]{file};
213*de8cc8edSafresh1    }
214*de8cc8edSafresh1
215*de8cc8edSafresh1    # The earliest perl gets a special marker key, consisting of the proper
216*de8cc8edSafresh1    # file name
217*de8cc8edSafresh1    $perls[$#perls]{final} = $perls[$#perls]{file};
218*de8cc8edSafresh1
219*de8cc8edSafresh1    if ($opt{debug}) {
220*de8cc8edSafresh1        print STDERR "The perls returned are: ", Dumper \@perls;
221*de8cc8edSafresh1    }
222*de8cc8edSafresh1
223*de8cc8edSafresh1    return \@perls;
224*de8cc8edSafresh1}
225*de8cc8edSafresh1
2265759b3d2Safresh11;
227