1898184e3Ssthen#!/usr/bin/env perl
2898184e3Ssthen
391f110e0Safresh1=head1 NAME
491f110e0Safresh1
591f110e0Safresh1Porting/sync-with-cpan - Synchronize with CPAN distributions
691f110e0Safresh1
791f110e0Safresh1=head1 SYNOPSIS
891f110e0Safresh1
9b46d8ef2Safresh1    sh ./Configure
1091f110e0Safresh1    perl Porting/sync-with-cpan <module>
1191f110e0Safresh1
12eac174f2Safresh1where C<module> is the name it appears in the C<%Modules> hash
1391f110e0Safresh1of F<Porting/Maintainers.pl>
1491f110e0Safresh1
1591f110e0Safresh1=head1 DESCRIPTION
1691f110e0Safresh1
1791f110e0Safresh1Script to help out with syncing cpan distros.
1891f110e0Safresh1
1991f110e0Safresh1Does the following:
2091f110e0Safresh1
2191f110e0Safresh1=over 4
2291f110e0Safresh1
2391f110e0Safresh1=item *
2491f110e0Safresh1
2591f110e0Safresh1Fetches the package list from CPAN. Finds the current version of the given
2691f110e0Safresh1package. [1]
2791f110e0Safresh1
2891f110e0Safresh1=item *
2991f110e0Safresh1
3091f110e0Safresh1Downloads the relevant tarball; unpacks the tarball. [1]
3191f110e0Safresh1
3291f110e0Safresh1=item *
3391f110e0Safresh1
3491f110e0Safresh1Clean out the old directory (C<git clean -dfx>)
3591f110e0Safresh1
3691f110e0Safresh1=item *
3791f110e0Safresh1
3891f110e0Safresh1Moves the old directory out of the way, moves the new directory in place.
3991f110e0Safresh1
4091f110e0Safresh1=item *
4191f110e0Safresh1
4291f110e0Safresh1Restores any F<.gitignore> file.
4391f110e0Safresh1
4491f110e0Safresh1=item *
4591f110e0Safresh1
4691f110e0Safresh1Removes files from C<@IGNORE> and C<EXCLUDED>
4791f110e0Safresh1
4891f110e0Safresh1=item *
4991f110e0Safresh1
5091f110e0Safresh1C<git add> any new files.
5191f110e0Safresh1
5291f110e0Safresh1=item *
5391f110e0Safresh1
5491f110e0Safresh1C<git rm> any files that are gone.
5591f110e0Safresh1
5691f110e0Safresh1=item *
5791f110e0Safresh1
5891f110e0Safresh1Remove the +x bit on files in F<t/>
5991f110e0Safresh1
6091f110e0Safresh1=item *
6191f110e0Safresh1
6291f110e0Safresh1Remove the +x bit on files that don't have it enabled in the current dir
6391f110e0Safresh1
6491f110e0Safresh1=item *
6591f110e0Safresh1
6691f110e0Safresh1Restore files mentioned in C<CUSTOMIZED>
6791f110e0Safresh1
6891f110e0Safresh1=item *
6991f110e0Safresh1
709f11ffb7Safresh1Updates the contents of F<MANIFEST>
7191f110e0Safresh1
7291f110e0Safresh1=item *
7391f110e0Safresh1
7491f110e0Safresh1Runs a C<make> (assumes a configure has been run)
7591f110e0Safresh1
7691f110e0Safresh1=item *
7791f110e0Safresh1
7891f110e0Safresh1Cleans up
7991f110e0Safresh1
8091f110e0Safresh1=item *
8191f110e0Safresh1
8291f110e0Safresh1Runs tests for the package
8391f110e0Safresh1
8491f110e0Safresh1=item *
8591f110e0Safresh1
8691f110e0Safresh1Runs the porting tests
8791f110e0Safresh1
8891f110e0Safresh1=back
8991f110e0Safresh1
9091f110e0Safresh1[1]  If the C<--tarball> option is given, then CPAN is not consulted.
9191f110e0Safresh1C<--tarball> should be the path to the tarball; the version is extracted
9291f110e0Safresh1from the filename -- but can be overwritten by the C<--version> option.
9391f110e0Safresh1
949f11ffb7Safresh1=head1 OPTIONS
9591f110e0Safresh1
9691f110e0Safresh1=over 4
9791f110e0Safresh1
989f11ffb7Safresh1=item C<--jobs> I<N>
9991f110e0Safresh1
100e0680481Safresh1When running C<make>, pass a C<< -jI<N> >> option to it to enable
101e0680481Safresh1parallel building.
102e0680481Safresh1
103e0680481Safresh1Note that you can also set C<< TEST_JOBS=I<N> >> in the environment
104e0680481Safresh1to enable parallel *testing* on top of parallel *building*.
105e0680481Safresh1
106e0680481Safresh1=item C<--yes>
107e0680481Safresh1
108e0680481Safresh1Just continue at all places where we would normally ask for the user
109e0680481Safresh1to hit enter or hit CTL-C, with the exception of cases related to
110e0680481Safresh1CUSTOMIZED distributions, where this option will cause the update to
111e0680481Safresh1exit immediately unless the C<--force> option has also been used.
112e0680481Safresh1
113e0680481Safresh1=item C<--force>
114e0680481Safresh1
115e0680481Safresh1Do things we normally would refuse to do.
116e0680481Safresh1
117e0680481Safresh1=item C<--tarball>
118e0680481Safresh1
119*3d61058aSafresh1Use a predownloaded tarball and not one from CPAN.  Example:
120*3d61058aSafresh1
121*3d61058aSafresh1    perl Porting/sync-with-cpan Text-Tabs+Wrap \
122*3d61058aSafresh1        --tarball /tmp/Text-Tabs+Wrap-2024.001.tar.gz \
123*3d61058aSafresh1        --yes
124e0680481Safresh1
125e0680481Safresh1=item C<--version>
126e0680481Safresh1
127e0680481Safresh1Sync with a specific version, not the latest on CPAN.
128e0680481Safresh1
129e0680481Safresh1=item C<--no-test>
130e0680481Safresh1
131e0680481Safresh1=item C<--nt>
132e0680481Safresh1
133e0680481Safresh1Do not run tests. This is helpful for bulk updates.
134e0680481Safresh1
135e0680481Safresh1=item C<--help>
136e0680481Safresh1
137e0680481Safresh1Show help.
1389f11ffb7Safresh1
1399f11ffb7Safresh1=back
1409f11ffb7Safresh1
1419f11ffb7Safresh1=head1 TODO
1429f11ffb7Safresh1
1439f11ffb7Safresh1=over 4
14491f110e0Safresh1
14591f110e0Safresh1=item *
14691f110e0Safresh1
14791f110e0Safresh1Update F<Porting/Maintainers.pl>
14891f110e0Safresh1
14991f110e0Safresh1=item *
15091f110e0Safresh1
15191f110e0Safresh1Optional, run a full test suite
15291f110e0Safresh1
15391f110e0Safresh1=item *
15491f110e0Safresh1
15591f110e0Safresh1Handle complicated C<FILES>
15691f110e0Safresh1
15791f110e0Safresh1=back
15891f110e0Safresh1
15991f110e0Safresh1This is an initial version; no attempt has been made yet to make this
16091f110e0Safresh1portable. It shells out instead of trying to find a Perl solution.
1616fb12b70Safresh1In particular, it assumes git, perl, and make
16291f110e0Safresh1to be available.
16391f110e0Safresh1
16491f110e0Safresh1=cut
16591f110e0Safresh1
166898184e3Ssthen
167898184e3Ssthenpackage Maintainers;
168898184e3Ssthen
169898184e3Ssthenuse 5.010;
170898184e3Ssthen
171898184e3Ssthenuse strict;
172898184e3Ssthenuse warnings;
173898184e3Ssthenuse Getopt::Long;
1746fb12b70Safresh1use Archive::Tar;
1759f11ffb7Safresh1use File::Basename qw( basename );
1766fb12b70Safresh1use File::Path qw( remove_tree );
1776fb12b70Safresh1use File::Find;
1789f11ffb7Safresh1use File::Spec::Functions qw( tmpdir rel2abs );
1796fb12b70Safresh1use Config qw( %Config );
180898184e3Ssthen
181898184e3Ssthen$| = 1;
182898184e3Ssthen
1839f11ffb7Safresh1use constant WIN32 => $^O eq 'MSWin32';
1849f11ffb7Safresh1
18591f110e0Safresh1die "This does not look like a top level directory"
186898184e3Ssthen     unless -d "cpan" && -d "Porting";
187898184e3Ssthen
1889f11ffb7Safresh1# Check that there's a Makefile, if needed; otherwise, we'll do most of our
1899f11ffb7Safresh1# work only to fail when we try to run make, and the user will have to
1909f11ffb7Safresh1# either unpick everything we've done, or do the rest manually.
1919f11ffb7Safresh1die "Please run Configure before using $0\n"
1929f11ffb7Safresh1    if !WIN32 && !-f "Makefile";
1939f11ffb7Safresh1
194e0680481Safresh1#these are populated by Porting/Maintainers.pl
195898184e3Ssthenour @IGNORABLE;
196898184e3Ssthenour %Modules;
197e0680481Safresh1our %DistName;
198898184e3Ssthen
199898184e3Ssthenuse autodie;
200898184e3Ssthen
2019f11ffb7Safresh1require "./Porting/Maintainers.pl";
2029f11ffb7Safresh1
2039f11ffb7Safresh1my $MAKE_LOG = 'make.log';
204e0680481Safresh1unlink $MAKE_LOG if -e $MAKE_LOG;
205898184e3Ssthen
206898184e3Ssthenmy %IGNORABLE    = map {$_ => 1} @IGNORABLE;
207898184e3Ssthen
2089f11ffb7Safresh1my $tmpdir = tmpdir();
2096fb12b70Safresh1
210898184e3Ssthenmy $package      = "02packages.details.txt";
211898184e3Ssthenmy $package_url  = "http://www.cpan.org/modules/$package";
2126fb12b70Safresh1my $package_file = "$tmpdir/$package"; # this is a cache
213e0680481Safresh1my $type_dir     = "cpan";
214898184e3Ssthen
21591f110e0Safresh1my @problematic = (
216*3d61058aSafresh1    # no current entries as of perl-5.40.1 (Jan 2025)
21791f110e0Safresh1);
21891f110e0Safresh1
219898184e3Ssthen
220b8851fccSafresh1sub usage
221b8851fccSafresh1{
222b8851fccSafresh1    my $err = shift and select STDERR;
223eac174f2Safresh1    print "Usage: $0 <module-or-dist> [args]\n";
224b8851fccSafresh1    exit $err;
225b8851fccSafresh1}
226b8851fccSafresh1
227898184e3SsthenGetOptions ('tarball=s'  =>  \my $tarball,
228898184e3Ssthen            'version=s'  =>  \my $version,
2299f11ffb7Safresh1            'jobs=i'     =>  \my $make_jobs,
230e0680481Safresh1            'yes'        =>  \my $yes_to_all,
231e0680481Safresh1            'force'      =>  \my $force,
232e0680481Safresh1            'no-test|nt' =>  \my $no_test,
233e0680481Safresh1            'help'       =>  sub { usage 0; },
234e0680481Safresh1            'type=s'     =>  \$type_dir,
235b8851fccSafresh1        ) or  die "Failed to parse arguments";
236898184e3Ssthen
237e0680481Safresh1usage 1 unless @ARGV == 1;
238898184e3Ssthen
2396fb12b70Safresh1sub find_type_f {
2406fb12b70Safresh1    my @res;
2416fb12b70Safresh1    find( { no_chdir => 1, wanted => sub {
2426fb12b70Safresh1        my $file= $File::Find::name;
2436fb12b70Safresh1        return unless -f $file;
2446fb12b70Safresh1        push @res, $file
2456fb12b70Safresh1    }}, @_ );
2466fb12b70Safresh1    @res
2476fb12b70Safresh1};
2486fb12b70Safresh1
2496fb12b70Safresh1# Equivalent of `chmod a-x`
2506fb12b70Safresh1sub de_exec {
2519f11ffb7Safresh1    my ($filename) = @_;
2526fb12b70Safresh1    my $mode = (stat $filename)[2] & 0777;
2536fb12b70Safresh1    if ($mode & 0111) { # exec-bit set
2546fb12b70Safresh1        chmod $mode & 0666, $filename;
2559f11ffb7Safresh1    }
2569f11ffb7Safresh1}
2579f11ffb7Safresh1
2589f11ffb7Safresh1# Equivalent of `chmod +w`
2599f11ffb7Safresh1sub make_writable {
2609f11ffb7Safresh1    my ($filename) = @_;
2619f11ffb7Safresh1    my $mode = (stat $filename)[2] & 0777;
2629f11ffb7Safresh1    if (!($mode & 0222)) { # not writable
2639f11ffb7Safresh1        chmod $mode | (0222 & ~umask), $filename;
2646fb12b70Safresh1    }
2656fb12b70Safresh1}
2666fb12b70Safresh1
267e0680481Safresh1my $SEP_LINE = ("-" x 79) . "\n";
268e0680481Safresh1
269e0680481Safresh1sub cat_make_log {
270e0680481Safresh1    my ($message) = @_;
271e0680481Safresh1    print $message, $message=~/Starting/
272e0680481Safresh1                    ? " and saving its output to '$MAKE_LOG' ...\n"
273e0680481Safresh1                    : "\n";
274e0680481Safresh1
275e0680481Safresh1    open my $ofh, ">>", $MAKE_LOG
276e0680481Safresh1        or die "Failed to open '$MAKE_LOG' for append\n";
277e0680481Safresh1    print $ofh $SEP_LINE,"$message at ",
278e0680481Safresh1                scalar(localtime),"\n",$SEP_LINE;
279e0680481Safresh1    close $ofh;
280e0680481Safresh1}
281e0680481Safresh1
282e0680481Safresh1sub run_make {
2836fb12b70Safresh1    my @args = @_;
2849f11ffb7Safresh1    unshift @args, "-j$make_jobs" if defined $make_jobs;
285e0680481Safresh1    cat_make_log("Starting `make @args`");
286e0680481Safresh1    my $errored;
2879f11ffb7Safresh1    if (WIN32) {
2886fb12b70Safresh1        chdir "Win32";
289e0680481Safresh1        $errored = system "$Config{make} @args >> ..\\$MAKE_LOG 2>&1";
2906fb12b70Safresh1        chdir '..';
2916fb12b70Safresh1    } else {
292e0680481Safresh1        $errored = system "$Config{make} @args >> $MAKE_LOG 2>&1";
2936fb12b70Safresh1    };
294e0680481Safresh1    cat_make_log("Finished `make @args`");
295e0680481Safresh1    if ($errored) {
296e0680481Safresh1        if ($args[0] ne "test-prep") {
297e0680481Safresh1            # see if we can extract the last Test Summary Report from
298e0680481Safresh1            # the $MAKE_LOG file,
299e0680481Safresh1            if (open my $ifh, "<", $MAKE_LOG) {
300e0680481Safresh1                my @report;
301e0680481Safresh1                my $in_summary;
302e0680481Safresh1                while (<$ifh>) {
303e0680481Safresh1                    if (/^Test Summary Report/) {
304e0680481Safresh1                        @report = ();
305e0680481Safresh1                        $in_summary = 1;
306e0680481Safresh1                    } elsif ($_ eq $SEP_LINE) {
307e0680481Safresh1                        $in_summary = 0;
308e0680481Safresh1                    }
309e0680481Safresh1                    push @report, $_ if $in_summary;
310e0680481Safresh1                }
311e0680481Safresh1                print for @report;
312e0680481Safresh1            } else {
313e0680481Safresh1                warn "Failed to open $MAKE_LOG for reading: $!";
314e0680481Safresh1            }
315e0680481Safresh1        }
316e0680481Safresh1        die "Running `make` failed, see '$MAKE_LOG' for more details\n";
317e0680481Safresh1    }
318e0680481Safresh1}
3196fb12b70Safresh1
320e0680481Safresh1sub pause_for_input {
321e0680481Safresh1    my ($after_message) = @_;
322e0680481Safresh1    print "Hit <return> to continue; ^C to abort ";
323e0680481Safresh1    if ($yes_to_all) {
324e0680481Safresh1        print "\n--yes was used on command line, continuing.\n";
325e0680481Safresh1    } else {
326e0680481Safresh1        my $noop = <STDIN>;
327e0680481Safresh1    }
328e0680481Safresh1    print $after_message if $after_message;
329e0680481Safresh1}
3309f11ffb7Safresh1
331e0680481Safresh1my ($module)  = shift @ARGV;
332e0680481Safresh1if (my $mod_name = $DistName{$module}) {
333e0680481Safresh1    $module = $mod_name;
334e0680481Safresh1}
3359f11ffb7Safresh1my $info = $Modules{$module};
3369f11ffb7Safresh1if (!$info) {
3379f11ffb7Safresh1    # Maybe the user said "Test-Simple" instead of "Test::Simple", or
3389f11ffb7Safresh1    # "IO::Compress" instead of "IO-Compress". See if we can fix it up.
3399f11ffb7Safresh1    my $guess = $module;
3409f11ffb7Safresh1    s/-/::/g or s/::/-/g for $guess;
3419f11ffb7Safresh1    $info = $Modules{$guess} or die <<"EOF";
3429f11ffb7Safresh1Cannot find module $module.
3439f11ffb7Safresh1The available options are listed in the %Modules hash in Porting/Maintainers.pl
3449f11ffb7Safresh1EOF
3459f11ffb7Safresh1    say "Guessing you meant $guess instead of $module";
3469f11ffb7Safresh1    $module = $guess;
3479f11ffb7Safresh1}
3489f11ffb7Safresh1
3499f11ffb7Safresh1if ($info->{CUSTOMIZED}) {
3509f11ffb7Safresh1    print <<"EOF";
3519f11ffb7Safresh1$module has a CUSTOMIZED entry in Porting/Maintainers.pl.
3529f11ffb7Safresh1
3539f11ffb7Safresh1This program's behaviour is to copy every CUSTOMIZED file into the version
3549f11ffb7Safresh1of the module being imported. But that might not be the right thing: in some
3559f11ffb7Safresh1cases, the new CPAN version will supersede whatever changes had previously
3569f11ffb7Safresh1been made in blead, so it would be better to import the new CPAN files.
3579f11ffb7Safresh1
3589f11ffb7Safresh1If you've checked that the CUSTOMIZED versions are still correct, you can
3599f11ffb7Safresh1proceed now. Otherwise, you should abort and investigate the situation. If
3609f11ffb7Safresh1the blead customizations are no longer needed, delete the CUSTOMIZED entry
3619f11ffb7Safresh1for $module in Porting/Maintainers.pl (and you'll also need to regenerate
3629f11ffb7Safresh1t/porting/customized.dat in that case; see t/porting/customized.t).
3639f11ffb7Safresh1
3649f11ffb7Safresh1EOF
365e0680481Safresh1    if ($yes_to_all and !$force) {
366e0680481Safresh1        die "This distribution is marked as CUSTOMIZED\n",
367e0680481Safresh1            "You used --yes on the command line, but without --force.\n",
368e0680481Safresh1            "Bailing out. Use --force to go ahead anyway.\n";
3699f11ffb7Safresh1    }
370e0680481Safresh1    pause_for_input("\n");
371e0680481Safresh1}
372e0680481Safresh1
373e0680481Safresh1if (!$ENV{TEST_JOBS} and !WIN32) {
374e0680481Safresh1    print "*** NOTE *** For speedups you can set TEST_JOBS=N in the env before running this script.\n";
375e0680481Safresh1}
376e0680481Safresh1if (!$make_jobs and !WIN32) {
377e0680481Safresh1    print "*** NOTE *** For speedups you can pass --jobs=N as an arg to this script.\n"
378e0680481Safresh1}
379e0680481Safresh1print "About to clean the $type_dir/ directory, and ensure its contents is up to date.\n";
380e0680481Safresh1print "Will also checkout -f on $type_dir/, MANIFEST and Porting/Maintainers.pl\n";
381e0680481Safresh1print "*** WARNING *** - this may DELETE uncommitted changes. Hit ^C if you have ANY doubts!\n";
382e0680481Safresh1pause_for_input("\n");
383e0680481Safresh1# clean out the cpan directory, this cleans up any temporary files that might be
384e0680481Safresh1# in the way, or other issues that might come up if the user bails out of the sync
385e0680481Safresh1# script and then runs it again.
386e0680481Safresh1my $clean_out= `git clean -dfx $type_dir`; # use backticks to hide the output
387*3d61058aSafresh1system git => 'checkout', '-f',
388e0680481Safresh1              $type_dir,
389e0680481Safresh1              'MANIFEST',
390e0680481Safresh1              'Porting/Maintainers.pl'; # let the user see the output
391e0680481Safresh1print "the $type_dir/ directory is now clean and up to date\n---\n";
3929f11ffb7Safresh1
393898184e3Ssthenmy  $distribution = $$info {DISTRIBUTION};
394898184e3Ssthen
395898184e3Ssthenmy @files         = glob $$info {FILES};
39691f110e0Safresh1if (!-d $files [0] || grep { $_ eq $module } @problematic) {
397898184e3Ssthen    say "This looks like a setup $0 cannot handle (yet)";
398898184e3Ssthen    unless ($force) {
399898184e3Ssthen        say "Will not continue without a --force option";
400898184e3Ssthen        exit 1;
401898184e3Ssthen    }
402898184e3Ssthen    say "--force is in effect, so we'll soldier on. Wish me luck!";
403898184e3Ssthen}
404898184e3Ssthen
4059f11ffb7Safresh1use Cwd 'cwd';
4069f11ffb7Safresh1my $orig_pwd = cwd();
407898184e3Ssthen
408e0680481Safresh1chdir "$type_dir";
409898184e3Ssthen
41091f110e0Safresh1my  $pkg_dir      = $files[0];
411898184e3Ssthen    $pkg_dir      =~ s!.*/!!;
412898184e3Ssthen
413*3d61058aSafresh1my $tail_pat = qr/\.(?:tar\.(?:g?z|bz2|Z)|zip|tgz|tbz)/;
414*3d61058aSafresh1my $version_pat = qr/-v?([0-9._]+(?:-TRIAL[0-9]*)?)$tail_pat\z/;
415e0680481Safresh1
416*3d61058aSafresh1my ($old_version) = $distribution =~ $version_pat;
417e0680481Safresh1
418e0680481Safresh1if (!$old_version) {
419e0680481Safresh1    die "WTF: failed to parse old version from '$distribution'\n";
420e0680481Safresh1}
421898184e3Ssthen
4229f11ffb7Safresh1sub wget {
4239f11ffb7Safresh1    my ($url, $saveas) = @_;
424eac174f2Safresh1    my $ht_res;
4259f11ffb7Safresh1    eval {
426eac174f2Safresh1        require IO::Socket::SSL;
427eac174f2Safresh1        require Net::SSLeay;
4289f11ffb7Safresh1        require HTTP::Tiny;
4299f11ffb7Safresh1        my $http = HTTP::Tiny->new();
430eac174f2Safresh1        $ht_res  = $http->mirror( $url => $saveas );
431eac174f2Safresh1        1;
4329f11ffb7Safresh1    } or
433eac174f2Safresh1       # Try harder to download the file
4349f11ffb7Safresh1       # Some system do not have wget.  Fall back to curl if we do not
4359f11ffb7Safresh1       # have it.  On Windows, `which wget` is not going to work, so
4369f11ffb7Safresh1       # just use wget, as this script has always done.
4379f11ffb7Safresh1       WIN32 || -x substr(`which wget`, 0, -1)
4389f11ffb7Safresh1         ? system wget => $url, '-qO', $saveas
4399f11ffb7Safresh1         : system curl => $url, '-sSo', $saveas;
440eac174f2Safresh1
441eac174f2Safresh1    # We were able to use HTTP::Tiny and it didn't have fatal errors,
442eac174f2Safresh1    # but we failed the request
443eac174f2Safresh1    if ( $ht_res && ! $ht_res->{'success'} ) {
444eac174f2Safresh1        die "Cannot retrieve file: $url\n" .
445eac174f2Safresh1            sprintf "Status: %s\nReason: %s\nContent: %s\n",
446eac174f2Safresh1            map $_ // '(unavailable)', @{$ht_res}{qw< status reason content >};
447eac174f2Safresh1    }
4489f11ffb7Safresh1}
4499f11ffb7Safresh1
450898184e3Ssthen#
451898184e3Ssthen# Find the information from CPAN.
452898184e3Ssthen#
453898184e3Ssthenmy $new_file;
454898184e3Ssthenmy $new_version;
455e0680481Safresh1my $re_update = "";
4569f11ffb7Safresh1if (defined $tarball) {
4579f11ffb7Safresh1    $tarball = rel2abs( $tarball, $orig_pwd ) ;
4589f11ffb7Safresh1    die "Tarball $tarball does not exist\n" if !-e $tarball;
4599f11ffb7Safresh1    die "Tarball $tarball is not a plain file\n" if !-f _;
4609f11ffb7Safresh1    $new_file     = $tarball;
461*3d61058aSafresh1    $new_version  = $version // ($new_file =~ $version_pat) [0];
4629f11ffb7Safresh1    die "Blead and that tarball both have version $new_version of $module\n"
4639f11ffb7Safresh1        if $new_version eq $old_version;
4649f11ffb7Safresh1}
4659f11ffb7Safresh1else {
466898184e3Ssthen    #
467898184e3Ssthen    # Poor man's cache
468898184e3Ssthen    #
469898184e3Ssthen    unless (-f $package_file && -M $package_file < 1) {
4709f11ffb7Safresh1        wget $package_url, $package_file;
471898184e3Ssthen    }
472898184e3Ssthen
473eac174f2Safresh1    my $cpan_mod = $info->{MAIN_MODULE} // $module;
4746fb12b70Safresh1    open my $fh, '<', $package_file;
475eac174f2Safresh1    (my $new_line) = grep {/^\Q$cpan_mod\E /} <$fh> # Yes, this needs a lot of memory
476898184e3Ssthen                     or die "Cannot find $cpan_mod on CPAN\n";
477898184e3Ssthen    (undef, $new_version, my $new_path) = split ' ', $new_line;
47891f110e0Safresh1    if (defined $version) {
47991f110e0Safresh1        $new_path =~ s/-$new_version\./-$version\./;
48091f110e0Safresh1        $new_version = $version;
48191f110e0Safresh1    }
482898184e3Ssthen    $new_file = (split '/', $new_path) [-1];
483898184e3Ssthen
484e0680481Safresh1    if ($old_version eq $new_version) {
485e0680481Safresh1        $re_update = "Re-";
486e0680481Safresh1        print "The latest version of $module is $new_version, but blead already has it.\n";
487e0680481Safresh1        print "Continuing may update MANIFEST or other metadata so it may make sense to continue anyway.\n";
488e0680481Safresh1        print "Are you sure you want to continue?\n";
489e0680481Safresh1        pause_for_input();
490e0680481Safresh1    }
4919f11ffb7Safresh1
4929f11ffb7Safresh1    my $url = "https://cpan.metacpan.org/authors/id/$new_path";
493898184e3Ssthen    say "Fetching $url";
494898184e3Ssthen    #
495898184e3Ssthen    # Fetch the new distro
496898184e3Ssthen    #
4979f11ffb7Safresh1    wget $url, $new_file;
498898184e3Ssthen}
499898184e3Ssthen
500e0680481Safresh1my  $old_dir      = "$pkg_dir-$old_version-OLD";
501898184e3Ssthen
502898184e3Ssthensay "Cleaning out old directory";
503898184e3Ssthensystem git => 'clean', '-dfxq', $pkg_dir;
504898184e3Ssthen
505898184e3Ssthensay "Unpacking $new_file";
5066fb12b70Safresh1Archive::Tar->extract_archive( $new_file );
507898184e3Ssthen
508*3d61058aSafresh1(my $new_dir = basename($new_file)) =~ s/$tail_pat\z//;
50991f110e0Safresh1# ensure 'make' will update all files
5106fb12b70Safresh1my $t= time;
5116fb12b70Safresh1for my $file (find_type_f($new_dir)) {
5129f11ffb7Safresh1    make_writable($file); # for convenience if the user later edits it
5136fb12b70Safresh1    utime($t,$t,$file);
5146fb12b70Safresh1};
515898184e3Ssthen
516898184e3Ssthensay "Renaming directories";
517898184e3Ssthenrename $pkg_dir => $old_dir;
518898184e3Ssthen
51991f110e0Safresh1say "Creating new package directory";
52091f110e0Safresh1mkdir $pkg_dir;
52191f110e0Safresh1
52291f110e0Safresh1say "Populating new package directory";
52391f110e0Safresh1my $map = $$info {MAP};
52491f110e0Safresh1my @EXCLUDED_QR;
52591f110e0Safresh1my %EXCLUDED_QQ;
52691f110e0Safresh1if ($$info {EXCLUDED}) {
52791f110e0Safresh1    foreach my $entry (@{$$info {EXCLUDED}}) {
52891f110e0Safresh1        if (ref $entry) {push @EXCLUDED_QR => $entry}
52991f110e0Safresh1        else            {$EXCLUDED_QQ {$entry} = 1}
53091f110e0Safresh1    }
53191f110e0Safresh1}
53291f110e0Safresh1
5336fb12b70Safresh1FILE: for my $file ( find_type_f( $new_dir )) {
53491f110e0Safresh1    my $old_file = $file;
535eac174f2Safresh1    $file =~ s{^\Q$new_dir\E/}{};
53691f110e0Safresh1
53791f110e0Safresh1    next if $EXCLUDED_QQ{$file};
53891f110e0Safresh1    for my $qr (@EXCLUDED_QR) {
53991f110e0Safresh1        next FILE if $file =~ $qr;
54091f110e0Safresh1    }
54191f110e0Safresh1
54291f110e0Safresh1    if ( $map ) {
54391f110e0Safresh1        for my $key ( sort { length $b <=> length $a } keys %$map ) {
54491f110e0Safresh1            my $val = $map->{$key};
54591f110e0Safresh1            last if $file =~ s/^$key/$val/;
54691f110e0Safresh1        }
54791f110e0Safresh1    }
54891f110e0Safresh1    else {
54991f110e0Safresh1        $file = $files[0] . '/' . $file;
55091f110e0Safresh1    }
55191f110e0Safresh1
552e0680481Safresh1    if ( $file =~ m{^$type_dir/} ) {
553e0680481Safresh1        $file =~ s{^$type_dir/}{};
55491f110e0Safresh1    }
55591f110e0Safresh1    else {
55691f110e0Safresh1        $file = '../' . $file;
55791f110e0Safresh1    }
55891f110e0Safresh1
55991f110e0Safresh1    my $prefix = '';
56091f110e0Safresh1    my @parts = split '/', $file;
56191f110e0Safresh1    pop @parts;
56291f110e0Safresh1    for my $part (@parts) {
56391f110e0Safresh1        $prefix .= '/' if $prefix;
56491f110e0Safresh1        $prefix .= $part;
56591f110e0Safresh1        mkdir $prefix unless -d $prefix;
56691f110e0Safresh1    }
56791f110e0Safresh1
56891f110e0Safresh1    rename $old_file => $file;
56991f110e0Safresh1}
5706fb12b70Safresh1remove_tree( $new_dir );
571898184e3Ssthen
572898184e3Ssthenif (-f "$old_dir/.gitignore") {
573898184e3Ssthen    say "Restoring .gitignore";
574898184e3Ssthen    system git => 'checkout', "$pkg_dir/.gitignore";
575898184e3Ssthen}
576898184e3Ssthen
5776fb12b70Safresh1my @new_files = find_type_f( $pkg_dir );
578898184e3Ssthen@new_files = grep {$_ ne $pkg_dir} @new_files;
579898184e3Ssthens!^[^/]+/!! for @new_files;
580898184e3Ssthenmy %new_files = map {$_ => 1} @new_files;
581898184e3Ssthen
5826fb12b70Safresh1my @old_files = find_type_f( $old_dir );
583898184e3Ssthen@old_files = grep {$_ ne $old_dir} @old_files;
584898184e3Ssthens!^[^/]+/!! for @old_files;
585898184e3Ssthenmy %old_files = map {$_ => 1} @old_files;
586898184e3Ssthen
587898184e3Ssthenmy @delete;
588898184e3Ssthenmy @commit;
589898184e3Ssthenmy @gone;
590e0680481Safresh1my $changes_file;
591898184e3SsthenFILE:
592898184e3Ssthenforeach my $file (@new_files) {
593898184e3Ssthen    next if -d "$pkg_dir/$file";   # Ignore directories.
594898184e3Ssthen    next if $old_files {$file};    # It's already there.
595e0680481Safresh1    if ($file=~/Changes/i or $file=~/Changelog/) {
596e0680481Safresh1        if ($changes_file) {
597e0680481Safresh1            die "More than one changes file? $file and $changes_file both exist?";
598e0680481Safresh1        }
599e0680481Safresh1        $changes_file = "$pkg_dir/$file";
600e0680481Safresh1    }
601898184e3Ssthen    if ($IGNORABLE {$file}) {
602898184e3Ssthen        push @delete => $file;
603898184e3Ssthen        next;
604898184e3Ssthen    }
605898184e3Ssthen    push @commit => $file;
606898184e3Ssthen}
607898184e3Ssthenforeach my $file (@old_files) {
608898184e3Ssthen    next if -d "$old_dir/$file";
609898184e3Ssthen    next if $new_files {$file};
610898184e3Ssthen    push @gone => $file;
611898184e3Ssthen}
612898184e3Ssthen
613e0680481Safresh1my @changes_info;
614e0680481Safresh1if (!$changes_file) {
615e0680481Safresh1    print "Could not find a changes file!\n",
616e0680481Safresh1          "If this is not correct and there is one, please consider updating this script!\n";
617e0680481Safresh1} else {
618e0680481Safresh1    open my $ifh, "<", $changes_file
619e0680481Safresh1        or die "Failed to open '$changes_file':$!";
620e0680481Safresh1    chomp(my @lines = <$ifh>);
621e0680481Safresh1    close $ifh;
622e0680481Safresh1    my $seen_new_version;
623e0680481Safresh1    my $is_update = $new_version ne $old_version;
624e0680481Safresh1
625e0680481Safresh1    for(my $idx = 0; $idx < @lines; $idx++) {
626e0680481Safresh1        if ($lines[$idx] =~ /$new_version/ ||
627e0680481Safresh1            ($pkg_dir eq "CPAN" and $lines[$idx] =~/^\d{4}-\d{2}-\d{2}/
628e0680481Safresh1             && $lines[$idx+2]
629e0680481Safresh1             && $lines[$idx+2] =~ /release $new_version/)
630e0680481Safresh1        ){
631e0680481Safresh1            $seen_new_version = 1;
632e0680481Safresh1            push @changes_info, $lines[$idx];
633e0680481Safresh1        } elsif ($seen_new_version) {
634e0680481Safresh1            if ($is_update && $pkg_dir eq "ExtUtils-MakeMaker") {
635e0680481Safresh1                if ($lines[$idx] =~/$old_version/) {
636e0680481Safresh1                    last;
637e0680481Safresh1                }
638e0680481Safresh1            }
639e0680481Safresh1            elsif (($lines[$idx]=~/\d\.\d/ and $lines[$idx]=~/20\d\d/) ||
640e0680481Safresh1                ($lines[$idx]=~/---------------------------------/) ||
641e0680481Safresh1                ($pkg_dir eq "CPAN" and $lines[$idx] =~/^\d{4}-\d{2}-\d{2}/) ||
642e0680481Safresh1                ($pkg_dir eq "version" and $lines[$idx] =~/^\d\.\d+/) ||
643e0680481Safresh1                ($pkg_dir eq "Getopt-Long" and $lines[$idx] =~/Changes in version/) ||
644e0680481Safresh1                ($pkg_dir eq "ExtUtils-Install" and $lines[$idx] =~/^\d+\.\d+/) ||
645e0680481Safresh1                0 # less commit churn if we have to tweak the heuristics above
646e0680481Safresh1            ){
647e0680481Safresh1                last;
648e0680481Safresh1            }
649e0680481Safresh1            push @changes_info, $lines[$idx];
650e0680481Safresh1
651e0680481Safresh1        }
652e0680481Safresh1    }
653e0680481Safresh1    if (!@changes_info) {
654e0680481Safresh1        die "No changes?";
655e0680481Safresh1    } else {
656e0680481Safresh1        print "Changes from $changes_file\n";
657e0680481Safresh1        print $_,"\n" for @changes_info;
658e0680481Safresh1    }
659e0680481Safresh1}
660e0680481Safresh1
661898184e3Ssthen#
662898184e3Ssthen# Find all files with an exec bit
663898184e3Ssthen#
6646fb12b70Safresh1my @exec = find_type_f( $pkg_dir );
665898184e3Ssthenmy @de_exec;
666898184e3Ssthenforeach my $file (@exec) {
667898184e3Ssthen    # Remove leading dir
668898184e3Ssthen    $file =~ s!^[^/]+/!!;
669898184e3Ssthen    if ($file =~ m!^t/!) {
670898184e3Ssthen        push @de_exec => $file;
671898184e3Ssthen        next;
672898184e3Ssthen    }
673898184e3Ssthen    # Check to see if the file exists; if it doesn't and doesn't have
674898184e3Ssthen    # the exec bit, remove it.
675898184e3Ssthen    if ($old_files {$file}) {
676898184e3Ssthen        unless (-x "$old_dir/$file") {
677898184e3Ssthen            push @de_exec => $file;
678898184e3Ssthen        }
679898184e3Ssthen    }
680898184e3Ssthen}
681898184e3Ssthen
682898184e3Ssthen#
683898184e3Ssthen# No need to change the +x bit on files that will be deleted.
684898184e3Ssthen#
685898184e3Ssthenif (@de_exec && @delete) {
686898184e3Ssthen    my %delete = map {+"$pkg_dir/$_" => 1} @delete;
687898184e3Ssthen    @de_exec = grep {!$delete {$_}} @de_exec;
688898184e3Ssthen}
689898184e3Ssthen
6909f11ffb7Safresh1#
6919f11ffb7Safresh1# Mustn't change the +x bit on files that are whitelisted
6929f11ffb7Safresh1#
6939f11ffb7Safresh1if (@de_exec) {
6949f11ffb7Safresh1    my %permitted = map { (my $x = $_) =~ tr/\n//d; $x => 1 } grep !/^#/,
6959f11ffb7Safresh1        do { local @ARGV = '../Porting/exec-bit.txt'; <> };
696e0680481Safresh1    @de_exec = grep !$permitted{"$type_dir/$pkg_dir/$_"}, @de_exec;
6979f11ffb7Safresh1}
698e0680481Safresh1@$_ = sort @$_ for \@delete, \@commit, \@gone, \@de_exec;
6999f11ffb7Safresh1
700898184e3Ssthensay "unlink $pkg_dir/$_" for @delete;
701898184e3Ssthensay "git add $pkg_dir/$_" for @commit;
702898184e3Ssthensay "git rm -f $pkg_dir/$_" for @gone;
703898184e3Ssthensay "chmod a-x $pkg_dir/$_" for @de_exec;
704898184e3Ssthen
705e0680481Safresh1print "--\nWill perform the above steps and then start testing.\n";
706e0680481Safresh1print "You may want to `tail -F $MAKE_LOG` in another window\n";
707e0680481Safresh1pause_for_input("\n");
708898184e3Ssthen
709898184e3Ssthenunlink "$pkg_dir/$_"                      for @delete;
710898184e3Ssthensystem git   => 'add', "$pkg_dir/$_"      for @commit;
711898184e3Ssthensystem git   => 'rm', '-f', "$pkg_dir/$_" for @gone;
7126fb12b70Safresh1de_exec( "$pkg_dir/$_" )                  for @de_exec;
713898184e3Ssthen
714898184e3Ssthen#
715898184e3Ssthen# Restore anything that is customized.
716898184e3Ssthen# We don't really care whether we've deleted the file - since we
717898184e3Ssthen# do a git restore, it's going to be resurrected if necessary.
718898184e3Ssthen#
719898184e3Ssthenif ($$info {CUSTOMIZED}) {
720898184e3Ssthen    say "Restoring customized files";
721898184e3Ssthen    foreach my $file (@{$$info {CUSTOMIZED}}) {
722898184e3Ssthen        system git => "checkout", "$pkg_dir/$file";
723898184e3Ssthen    }
724898184e3Ssthen}
725898184e3Ssthen
726898184e3Ssthenchdir "..";
727e0680481Safresh1{
728e0680481Safresh1    # we update the MANIFEST file always now, so that we can
729e0680481Safresh1    # ensure each file from this sync is updated to say that we
730e0680481Safresh1    # got it from the latest version.
731e0680481Safresh1    say "Updating the MANIFEST file";
732898184e3Ssthen    my $MANIFEST     = "MANIFEST";
7339f11ffb7Safresh1    my $MANIFEST_NEW = "$MANIFEST.new";
7349f11ffb7Safresh1
7359f11ffb7Safresh1    open my $orig, "<", $MANIFEST
7369f11ffb7Safresh1        or die "Failed to open $MANIFEST for reading: $!\n";
7379f11ffb7Safresh1    open my $new, ">", $MANIFEST_NEW
7389f11ffb7Safresh1        or die "Failed to open $MANIFEST_NEW for writing: $!\n";
739e0680481Safresh1    my %keep = map +("$type_dir/$pkg_dir/$_" => 1), keys %new_files;
740e0680481Safresh1    my %gone = map +("$type_dir/$pkg_dir/$_" => 1), @gone;
7419f11ffb7Safresh1    while (my $line = <$orig>) {
742e0680481Safresh1        chomp $line;
743e0680481Safresh1        my ($file, $descr) = split /\t+/, $line;
744e0680481Safresh1        if (!$file) {
745e0680481Safresh1            die "Can't parse MANIFEST line: '$line' at line $.\n";
746e0680481Safresh1        }
747e0680481Safresh1        if ($keep{$file} and !$descr) {
748e0680481Safresh1            # make sure we have at least one tab, old versions of
749e0680481Safresh1            # this script would add lines to MANIFEST with no tab.
750e0680481Safresh1            $line =~ s/^(\S+)\z/$1\t\t/;
751e0680481Safresh1
752e0680481Safresh1            my $file_descr = "";
753e0680481Safresh1            if ( $file =~ /\.t/ ) {
754e0680481Safresh1                $file_descr = "Test file";
755e0680481Safresh1            }
756e0680481Safresh1            elsif ( $file =~ /\.pm/ ) {
757e0680481Safresh1                $file_descr = "Module";
758e0680481Safresh1            }
759e0680481Safresh1            elsif ( $file =~ /\.pl/ ) {
760e0680481Safresh1                $file_descr = "Script";
761e0680481Safresh1            }
762e0680481Safresh1            $file_descr .= " related to " if $file_descr;
763e0680481Safresh1            # and update the line to show where the file came from.
764e0680481Safresh1            $line =~ s/(\t+).*/$1$file_descr$module/;
765e0680481Safresh1        }
766e0680481Safresh1        say $new $line if !$gone{$file};
7679f11ffb7Safresh1    }
7689f11ffb7Safresh1
769e0680481Safresh1    say $new "$type_dir/$pkg_dir/$_\t\t$pkg_dir" for @commit;
7709f11ffb7Safresh1
7719f11ffb7Safresh1    close $new or die "Can't close $MANIFEST: $!\n";
7729f11ffb7Safresh1
7739f11ffb7Safresh1    system $^X => "Porting/manisort", '--quiet', "--output=$MANIFEST", $MANIFEST_NEW;
7749f11ffb7Safresh1    unlink $MANIFEST_NEW
7759f11ffb7Safresh1        or die "Can't delete temporary $MANIFEST_NEW: $!\n";
776898184e3Ssthen}
777898184e3Ssthen
778898184e3Ssthen
779e0680481Safresh1
780e0680481Safresh1# Prepare for running (selected) tests - strictly speaking this isn't
781e0680481Safresh1# necessary, as we run the tests with "run_make" now, but this allows
782e0680481Safresh1# us to separate build issues from test issues.
783e0680481Safresh1run_make 'test-prep' unless $no_test;
784898184e3Ssthen
7859f11ffb7Safresh1# The build system installs code from CPAN dists into the lib/ directory,
7869f11ffb7Safresh1# creating directories as needed. This means that the cleaning-related rules
7879f11ffb7Safresh1# in the Makefile need to know which directories to clean up. The Makefile
7889f11ffb7Safresh1# is generated by Configure from Makefile.SH, so *that* file needs the list
7899f11ffb7Safresh1# of directories. regen/lib_cleanup.pl is capable of automatically updating
7909f11ffb7Safresh1# the contents of Makefile.SH (and win32/Makefile, which needs similar but
7919f11ffb7Safresh1# not identical lists of directories), so we can just run that (using the
7929f11ffb7Safresh1# newly-built Perl, as is done with the regen programs run by "make regen").
7939f11ffb7Safresh1#
7949f11ffb7Safresh1# We do this if any files at all have been added or deleted, regardless of
7959f11ffb7Safresh1# whether those changes result in any directories being added or deleted,
7969f11ffb7Safresh1# because the alternative would be to replicate the regen/lib_cleanup.pl
7979f11ffb7Safresh1# logic here. That's fine, because regen/lib_cleanup.pl is idempotent if run
7989f11ffb7Safresh1# repeatedly.
7999f11ffb7Safresh1if (@commit || @gone) {
8009f11ffb7Safresh1    say "Running regen/lib_cleanup.pl to handle potential added/deleted dirs";
8019f11ffb7Safresh1    my $exe_dir = WIN32 ? ".\\" : './';
8029f11ffb7Safresh1    system "${exe_dir}perl$Config{_exe}", "-Ilib", "regen/lib_cleanup.pl"
8039f11ffb7Safresh1        and die "regen/lib_cleanup.pl failed\n";
8049f11ffb7Safresh1}
8059f11ffb7Safresh1
806898184e3Ssthen#
807898184e3Ssthen# Must clean up, or else t/porting/FindExt.t will fail.
8086fb12b70Safresh1# Note that we can always retrieve the original directory with a git checkout.
809898184e3Ssthen#
810e0680481Safresh1print "About to clean up the old version, update Maintainers.pl and start tests\n";
811e0680481Safresh1pause_for_input("\n");
812898184e3Ssthen
813e0680481Safresh1remove_tree( "$type_dir/$old_dir" );
814e0680481Safresh1unlink "$type_dir/$new_file" unless $tarball;
815898184e3Ssthen
816898184e3Ssthen
81791f110e0Safresh1open my $Maintainers_pl, '<', 'Porting/Maintainers.pl';
81891f110e0Safresh1open my $new_Maintainers_pl, '>', 'Maintainers.pl';
81991f110e0Safresh1
820e0680481Safresh1my $found = 0;
82191f110e0Safresh1my $in_mod_section;
82291f110e0Safresh1while (<$Maintainers_pl>) {
82391f110e0Safresh1    if ($in_mod_section) {
824e0680481Safresh1        if ($found == 1) {
825e0680481Safresh1            # Keep track of when and who did the sync.
826e0680481Safresh1            # This must be before the DISTRIBUTION check.
827e0680481Safresh1            # This ensures that *something* is updated when we re-update.
828e0680481Safresh1            my $date = localtime;
829e0680481Safresh1            my $user = $ENV{USER} ? "$ENV{USER} on " : "";
830e0680481Safresh1            my $key = "SYNCINFO";
831e0680481Safresh1            if ( /^'([A-Z_]+)'\s+=>/ and $1 eq $key) {
832e0680481Safresh1                s/(=>\s+)'[^']+'/$1'$user$date'/;
833e0680481Safresh1            }
834e0680481Safresh1            else {
835e0680481Safresh1                print $new_Maintainers_pl
836e0680481Safresh1                    "        '$key'     => '$user$date',\n";
837e0680481Safresh1            }
838e0680481Safresh1            $found = 2;
839e0680481Safresh1            $in_mod_section = 0;
840e0680481Safresh1        }
84191f110e0Safresh1        if (/DISTRIBUTION/) {
84291f110e0Safresh1            if (s/\Q$old_version/$new_version/) {
84391f110e0Safresh1                $found = 1;
84491f110e0Safresh1            }
84591f110e0Safresh1        }
846e0680481Safresh1        if (/^\s*\}/) { # sanity
84791f110e0Safresh1            $in_mod_section = 0;
84891f110e0Safresh1        }
84991f110e0Safresh1    }
85091f110e0Safresh1
851e0680481Safresh1    if (/\Q$module\E/ and !$found) {
85291f110e0Safresh1        $in_mod_section = 1;
85391f110e0Safresh1    }
85491f110e0Safresh1
85591f110e0Safresh1    print $new_Maintainers_pl $_;
85691f110e0Safresh1}
85791f110e0Safresh1
85891f110e0Safresh1if ($found) {
8599f11ffb7Safresh1    say "Successfully updated Maintainers.pl";
86091f110e0Safresh1    unlink 'Porting/Maintainers.pl';
86191f110e0Safresh1    rename 'Maintainers.pl' => 'Porting/Maintainers.pl';
8626fb12b70Safresh1    chmod 0755 => 'Porting/Maintainers.pl';
86391f110e0Safresh1}
86491f110e0Safresh1else {
86591f110e0Safresh1    say "Could not update Porting/Maintainers.pl.";
86691f110e0Safresh1    say "Make sure you update this by hand before committing.";
86791f110e0Safresh1}
86891f110e0Safresh1
869e0680481Safresh1# Run the tests. First the test belonging to the module, followed by the
870e0680481Safresh1# tests in t/porting
871e0680481Safresh1
872e0680481Safresh1my $shell_quote = WIN32 ? '"' : "'";
873e0680481Safresh1if ($no_test) {
874e0680481Safresh1    print "*** NOT RUNNING TESTS ***\n";
875e0680481Safresh1} else {
876e0680481Safresh1    run_make "test-harness TEST_ARGS=$shell_quote-re $pkg_dir$shell_quote";
877e0680481Safresh1    run_make "test-porting";
878e0680481Safresh1}
879e0680481Safresh1
880e0680481Safresh1my $committed;
881e0680481Safresh1if (@changes_info) {
882e0680481Safresh1    system git => 'commit',
883e0680481Safresh1           join("\n",
884e0680481Safresh1               "-m$type_dir/$pkg_dir - ${re_update}Update to version $new_version",
885e0680481Safresh1               "",@changes_info),
886e0680481Safresh1           "$type_dir/$pkg_dir", "MANIFEST", "Porting/Maintainers.pl"
887e0680481Safresh1        or $committed = 1; # note system returns true for an error!
888e0680481Safresh1}
889e0680481Safresh1
890e0680481Safresh1
8919f11ffb7Safresh1print <<"EOF";
892898184e3Ssthen
8939f11ffb7Safresh1=======================================================================
8949f11ffb7Safresh1
895eac174f2Safresh1$module is now at version $new_version
896eac174f2Safresh1Next, you should run "make minitest" and then "make test".
8979f11ffb7Safresh1
898eac174f2Safresh1Minitest uses miniperl, which does not support XS modules. The full test
899eac174f2Safresh1suite uses perl, which does. Minitest can fail - e.g. if a cpan module
900eac174f2Safresh1has added an XS dependency - even if the full test suite passes just fine.
901eac174f2Safresh1
902eac174f2Safresh1Hopefully all will complete successfully, but if not, you can make any
9039f11ffb7Safresh1changes you need to get the tests to pass. Don't forget that you'll need
9049f11ffb7Safresh1a "CUSTOMIZED" entry in Porting/Maintainers.pl if you change any of the
905e0680481Safresh1files under $type_dir/$pkg_dir.
9069f11ffb7Safresh1
9079f11ffb7Safresh1EOF
908898184e3Ssthen
909e0680481Safresh1if ($committed) {
910e0680481Safresh1    print <<"EOF";
911e0680481Safresh1The changes have already been committed. If the tests above fail you can
912e0680481Safresh1discard this patch with
913e0680481Safresh1
914e0680481Safresh1    git reset --hard HEAD^.
915e0680481Safresh1
916e0680481Safresh1You may also want to review the commit message and alter it with
917e0680481Safresh1
918e0680481Safresh1    git commit --amend
919e0680481Safresh1
920e0680481Safresh1Regardless you still need to push this commit upstream with something like
921e0680481Safresh1
922e0680481Safresh1    git push origin HEAD:$ENV{USER}/update_${pkg_dir}_v_$new_version
923e0680481Safresh1
924e0680481Safresh1EOF
925e0680481Safresh1} else {
926e0680481Safresh1    print <<"EOF";
927e0680481Safresh1Once all tests pass, you can commit it with a command like:
928e0680481Safresh1
929e0680481Safresh1    git commit -m${shell_quote}$type_dir/$pkg_dir - Update to version $new_version${shell_quote} $type_dir/$pkg_dir
930e0680481Safresh1
931e0680481Safresh1and then push it upstream with a command like
932e0680481Safresh1
933e0680481Safresh1    git push origin HEAD:$ENV{USER}/update_${pkg_dir}_v_$new_version
934e0680481Safresh1
935e0680481Safresh1EOF
936e0680481Safresh1}
937e0680481Safresh1
938898184e3Ssthen__END__
939