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