This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade Socket to 2.000
[perl5.git] / Porting / sync-with-cpan
CommitLineData
418f4069
A
1#!/usr/bin/perl
2
3#
4# Script to help out with syncing cpan distros.
5#
6# Does the following:
7# - Fetches the package list from CPAN. Finds the current version of
8# the given package.
9# - Downloads the relevant tarball; unpacks the tarball;.
10# - Clean out the old directory (git clean -dfx)
11# - Moves the old directory out of the way, moves the new directory in place.
12# - Restores any .gitignore file.
13# - Removes files from @IGNORE and EXCLUDED
14# - git add any new files.
15# - git rm any files that are gone.
16# - Remove the +x bit on files in t/
ad9b4e6f 17# - Remove the +x bit on files that don't have in enabled in the current dir
418f4069
A
18# - Adds new files to MANIFEST
19# - Runs a "make" (assumes a configure has been run)
20# - Cleans up
ad9b4e6f 21# - Runs tests for the package
418f4069
A
22# - Runs the porting tests
23#
24# TODO: - Restore files from CUSTOMIZED
25# - Delete files from MANIFEST
26# - Update Porting/Maintainers.pl
418f4069 27# - Optional, run a full test suite
6f865444 28# - Handle complicated FILES
418f4069
A
29#
30# This is an initial version; no attempt has been made yet to make this
31# portable. It shells out instead of trying to find a Perl solution.
32# In particular, it assumes wget, git, tar, chmod, perl, make, and rm
33# to be available.
34#
35# Usage: perl Porting/sync-with-cpan <module>
36# where <module> is the name it appears in the %Modules hash
37# of Porting/Maintainers.pl
38#
39
40use 5.010;
41
42use strict;
43use warnings;
44no warnings 'syntax';
45
46$| = 1;
47
48die "This does not like top level directory"
49 unless -d "cpan" && -d "Porting";
50
51package Maintainers;
52
53our @IGNORABLE;
54our %Modules;
55
56use autodie;
57
58require "Porting/Maintainers.pl";
59
60chdir "cpan";
61
62my %IGNORABLE = map {$_ => 1} @IGNORABLE;
63
64my $package = "02packages.details.txt";
65my $package_url = "http://www.cpan.org/modules/$package";
66my $package_file = "/tmp/$package";
67
68#
69# Poor man's cache
70#
71unless (-f $package_file && -M $package_file < 1) {
72 system wget => $package_url, '-qO', $package_file;
73}
74
75die "Usage: $0 module" unless @ARGV == 1;
76
77my ($module) = @ARGV;
78
79my $info = $Modules {$module} or die "Cannot find module $module";
80my $distribution = $$info {DISTRIBUTION};
81my $pkg_dir = $$info {FILES};
82 $pkg_dir =~ s!.*/!!;
83
84my ($old_version) = $distribution =~ /-([0-9.]+)\.tar\.gz/;
85
86my $o_module = $module;
87if ($module =~ /-/ && $module !~ /::/) {
88 $module =~ s/-/::/g;
89}
90
91#
92# Find the information from CPAN.
93#
94my $new_line = `grep '^$module ' $package_file`
95 or die "Cannot find $module on CPAN\n";
96chomp $new_line;
97my (undef, $new_version, $new_path) = split ' ', $new_line;
98my $new_file = (split '/', $new_path) [-1];
99
100my $old_dir = "$pkg_dir-$old_version";
101my $new_dir = "$pkg_dir-$new_version";
102
103say "Cleaning out old directory";
104system git => 'clean', '-dfxq', $pkg_dir;
105
106
107
108my $url = "http://search.cpan.org/CPAN/authors/id/$new_path";
109
110say "Fetching $url";
111
112#
113# Fetch the new distro
114#
115system wget => $url, '-qO', $new_file;
116
117say "Unpacking $new_file";
118
119system tar => 'xfz', $new_file;
120
121say "Renaming directories";
122rename $pkg_dir => $old_dir;
123rename $new_dir => $pkg_dir;
124
125
126if (-f "$old_dir/.gitignore") {
127 say "Restoring .gitignore";
128 system git => 'checkout', "$pkg_dir/.gitignore";
129}
130
ad9b4e6f 131my @new_files = `find $pkg_dir -type f`;
418f4069
A
132chomp @new_files;
133@new_files = grep {$_ ne $pkg_dir} @new_files;
134s!^[^/]+/!! for @new_files;
135my %new_files = map {$_ => 1} @new_files;
136
ad9b4e6f 137my @old_files = `find $old_dir -type f`;
418f4069
A
138chomp @old_files;
139@old_files = grep {$_ ne $old_dir} @old_files;
140s!^[^/]+/!! for @old_files;
141my %old_files = map {$_ => 1} @old_files;
142
143#
144# Find files that can be deleted.
145#
146my @EXCLUDED_QR;
147my %EXCLUDED_QQ;
148if ($$info {EXCLUDED}) {
149 foreach my $entry (@{$$info {EXCLUDED}}) {
150 if (ref $entry) {push @EXCLUDED_QR => $entry}
151 else {$EXCLUDED_QQ {$entry} = 1}
152 }
153}
154
155my @delete;
156my @commit;
157my @gone;
418f4069
A
158FILE:
159foreach my $file (@new_files) {
160 next if -d "$pkg_dir/$file"; # Ignore directories.
161 next if $old_files {$file}; # It's already there.
162 if ($IGNORABLE {$file}) {
163 push @delete => $file;
164 next;
165 }
166 if ($EXCLUDED_QQ {$file}) {
167 push @delete => $file;
168 next;
169 }
170 foreach my $pattern (@EXCLUDED_QR) {
171 if ($file =~ /$pattern/) {
172 push @delete => $file;
173 next FILE;
174 }
175 }
176 push @commit => $file;
177}
178foreach my $file (@old_files) {
179 next if -d "$old_dir/$file";
180 next if $new_files {$file};
181 push @gone => $file;
182}
ad9b4e6f
A
183
184#
185# Find all files with an exec bit
186#
187my @exec = `find $pkg_dir -type f -perm +111`;
418f4069 188chomp @exec;
ad9b4e6f
A
189my @de_exec;
190foreach my $file (@exec) {
191 # Remove leading dir
192 $file =~ s!^[^/]+/!!;
193 if ($file =~ m!^t/!) {
194 push @de_exec => $file;
195 next;
196 }
197 # Check to see if the file exists; if it doesn't and doesn't have
198 # the exec bit, remove it.
199 if ($old_files {$file}) {
200 unless (-x "$old_dir/$file") {
201 push @de_exec => $file;
202 }
203 }
204}
418f4069
A
205
206#
207# No need to change the +x bit on files that will be deleted.
208#
ad9b4e6f 209if (@de_exec && @delete) {
a9f5d1d4 210 my %delete = map {+"$pkg_dir/$_" => 1} @delete;
ad9b4e6f 211 @de_exec = grep {!$delete {$_}} @de_exec;
418f4069
A
212}
213
214say "unlink $pkg_dir/$_" for @delete;
215say "git add $pkg_dir/$_" for @commit;
216say "git rm -f $pkg_dir/$_" for @gone;
ad9b4e6f 217say "chmod a-x $pkg_dir/$_" for @de_exec;
418f4069
A
218
219print "Hit return to continue; ^C to abort "; <STDIN>;
220
221unlink "$pkg_dir/$_" for @delete;
222system git => 'add', "$pkg_dir/$_" for @commit;
223system git => 'rm', '-f', "$pkg_dir/$_" for @gone;
ad9b4e6f 224system chmod => 'a-x', "$pkg_dir/$_" for @de_exec;
418f4069 225
a8121781 226chdir "..";
418f4069
A
227if (@commit) {
228 say "Fixing MANIFEST";
a8121781 229 my $MANIFEST = "MANIFEST";
418f4069
A
230 my $MANIFEST_SORT = "$MANIFEST.sorted";
231 open my $fh, ">>", $MANIFEST;
a8121781 232 say $fh "cpan/$pkg_dir/$_" for @commit;
418f4069 233 close $fh;
a8121781 234 system perl => "Porting/manisort", '--output', $MANIFEST_SORT;
418f4069
A
235 rename $MANIFEST_SORT => $MANIFEST;
236}
237
238
418f4069
A
239print "Running a make ... ";
240system "make > make.log 2>&1" and die "Running make failed, see make.log";
241print "done\n";
242
243#
244# Must clean up, or else t/porting/FindExt.t will fail.
245# Note that we can always retrieve the orginal directory with a git checkout.
246#
247print "About to clean up; hit return or abort (^C) "; <STDIN>;
248
249chdir "cpan";
250system rm => '-r', $old_dir;
251unlink $new_file;
252
253
ad9b4e6f
A
254#
255# Run the tests. First the test belonging to the module, followed by the
256# the tests in t/porting
257#
418f4069 258chdir "../t";
ad9b4e6f
A
259say "Running module tests";
260my @test_files = `find ../cpan/$pkg_dir -name '*.t' -type f`;
261chomp @test_files;
262my $output = `./perl TEST @test_files`;
263unless ($output =~ /All tests successful/) {
264 say $output;
265 exit 1;
266}
267
418f4069
A
268print "Running tests in t/porting ";
269my @tests = `ls porting/*.t`;
270chomp @tests;
271my @failed;
272foreach my $t (@tests) {
273 my @not = `./perl -I../lib -I.. $t | grep ^not | grep -v "# TODO"`;
274 print @not ? '!' : '.';
275 push @failed => $t if @not;
276}
277print "\n";
278say "Failed tests: @failed" if @failed;
279
280
281print "Now you ought to run a make; make test ...\n";
282
283say "Do not forget to update Porting/Maintainers.pl before committing";
284say "$o_module is now version $new_version";
285
286
287__END__