PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Porting/cmpVERSION.pl

https://gitlab.com/storedmirrors/perl5
Perl | 228 lines | 180 code | 20 blank | 28 comment | 28 complexity | 3c7b95b4f0e9ea90100fa2ef21d9835e MD5 | raw file
  1. #!/usr/bin/perl -w
  2. #
  3. # cmpVERSION - compare the current Perl source tree and a given tag
  4. # for modules that have identical version numbers but different contents.
  5. #
  6. # with -d option, output the diffs too
  7. # with -x option, exclude files from modules where blead is not upstream
  8. #
  9. # (after all, there are tools like core-cpan-diff that can already deal with
  10. # them)
  11. #
  12. # Original by slaven@rezic.de, modified by jhi and matt.w.johnson@gmail.com.
  13. # Adaptation to produce TAP by Abigail, folded back into this file by Nicholas
  14. use strict;
  15. use 5.006;
  16. use ExtUtils::MakeMaker;
  17. use File::Spec::Functions qw(devnull);
  18. use Getopt::Long;
  19. my ($diffs, $exclude_upstream, $tag_to_compare, $tap);
  20. unless (GetOptions('diffs' => \$diffs,
  21. 'exclude|x' => \$exclude_upstream,
  22. 'tag=s' => \$tag_to_compare,
  23. 'tap' => \$tap,
  24. ) && @ARGV == 0) {
  25. die "usage: $0 [ -d -x --tag TAG --tap]";
  26. }
  27. die "$0: This does not look like a Perl directory\n"
  28. unless -f "perl.h" && -d "Porting";
  29. die "$0: 'This is a Perl directory but does not look like Git working directory\n"
  30. unless (-d ".git" || (exists $ENV{GIT_DIR} && -d $ENV{GIT_DIR}));
  31. my $null = devnull();
  32. unless (defined $tag_to_compare) {
  33. my $check = 'HEAD';
  34. while(1) {
  35. $check = `git describe --abbrev=0 $check 2>$null`;
  36. chomp $check;
  37. last unless $check =~ /-RC/;
  38. $check .= '~1';
  39. }
  40. $tag_to_compare = $check;
  41. # Thanks to David Golden for this suggestion.
  42. }
  43. unless (length $tag_to_compare) {
  44. die "$0: Git found, but no Git tags found\n"
  45. unless $tap;
  46. print "1..0 # SKIP: Git found, but no Git tags found\n";
  47. exit 0;
  48. }
  49. my $tag_exists = `git --no-pager tag -l $tag_to_compare 2>$null`;
  50. chomp $tag_exists;
  51. unless ($tag_exists eq $tag_to_compare) {
  52. die "$0: '$tag_to_compare' is not a known Git tag\n" unless $tap;
  53. print "1..0 # SKIP: '$tag_to_compare' is not a known Git tag\n";
  54. exit 0;
  55. }
  56. my %upstream_files;
  57. if ($exclude_upstream) {
  58. unshift @INC, 'Porting';
  59. require Maintainers;
  60. for my $m (grep {!defined $Maintainers::Modules{$_}{UPSTREAM}
  61. or $Maintainers::Modules{$_}{UPSTREAM} ne 'blead'}
  62. keys %Maintainers::Modules) {
  63. $upstream_files{$_} = 1 for Maintainers::get_module_files($m);
  64. }
  65. }
  66. # Files to skip from the check for one reason or another,
  67. # usually because they pull in their version from some other file.
  68. my %skip;
  69. @skip{
  70. 'cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/BFD.pm', # just a test module
  71. 'cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/XS.pm', # just a test module
  72. 'cpan/IO-Compress/lib/File/GlobMapper.pm', # upstream needs to supply $VERSION
  73. 'cpan/Math-BigInt/t/Math/BigFloat/Subclass.pm', # just a test module
  74. 'cpan/Math-BigInt/t/Math/BigInt/BareCalc.pm', # just a test module
  75. 'cpan/Math-BigInt/t/Math/BigInt/Scalar.pm', # just a test module
  76. 'cpan/Math-BigInt/t/Math/BigInt/Subclass.pm', # just a test module
  77. 'cpan/Math-BigRat/t/Math/BigRat/Test.pm', # just a test module
  78. 'cpan/podlators/t/lib/Test/Podlators.pm', # just a test module
  79. 'cpan/podlators/t/lib/Test/RRA.pm', # just a test module
  80. 'cpan/podlators/t/lib/Test/RRA/Config.pm', # just a test module
  81. 'cpan/version/t/coretests.pm', # just a test module
  82. 'dist/Attribute-Handlers/demo/MyClass.pm', # it's just demonstration code
  83. 'dist/Exporter/lib/Exporter/Heavy.pm',
  84. 'lib/Carp/Heavy.pm',
  85. 'lib/Config.pm', # no version number but contents will vary
  86. 'win32/FindExt.pm',
  87. } = ();
  88. # Files to skip just for particular version(s),
  89. # usually due to some # mix-up
  90. my %skip_versions = (
  91. # 'some/sample/file.pm' => [ '1.23', '1.24' ],
  92. );
  93. my $skip_dirs = qr|^t/lib|;
  94. sub pm_file_from_xs {
  95. my $xs = shift;
  96. foreach my $try (sub {
  97. # First try a .pm at the same level as the .xs file
  98. # with the same basename
  99. return shift =~ s/\.xs\z//r;
  100. },
  101. sub {
  102. # Try for a (different) .pm at the same level, based
  103. # on the directory name:
  104. my ($path) = shift =~ m!^(.*)/!;
  105. my ($last) = $path =~ m!([^-/]+)\z!;
  106. return "$path/$last";
  107. },
  108. sub {
  109. # Try to work out the extension's full package, and
  110. # look for a .pm in lib/ based on that:
  111. my ($path) = shift =~ m!^(.*)/!;
  112. my ($last) = $path =~ m!([^/]+)\z!;
  113. $last = 'List-Util' if $last eq 'Scalar-List-Utils';
  114. $last =~ tr !-!/!;
  115. return "$path/lib/$last";
  116. }) {
  117. # For all cases, first look to see if the .pm file is generated.
  118. my $base = $try->($xs);
  119. return "${base}_pm.PL" if -f "${base}_pm.PL";
  120. return "${base}.pm" if -f "${base}.pm";
  121. }
  122. die "No idea which .pm file corresponds to '$xs', so aborting";
  123. }
  124. # Key is the .pm file from which we check the version.
  125. # Value is a reference to an array of files to check for differences
  126. # The trivial case is a pure perl module, where the array holds one element,
  127. # the perl module's file. The "fun" comes with XS modules, and the real fun
  128. # with XS modules with more than one XS file, and "interesting" layouts.
  129. my %module_diffs;
  130. foreach (`git --no-pager diff --name-only $tag_to_compare --diff-filter=ACMRTUXB`) {
  131. chomp;
  132. next unless m/^(.*)\//;
  133. my $this_dir = $1;
  134. next if $this_dir =~ $skip_dirs || exists $skip{$_};
  135. next if exists $upstream_files{$_};
  136. if (/\.pm\z/ || m|^lib/.*\.pl\z| || /_pm\.PL\z/) {
  137. push @{$module_diffs{$_}}, $_;
  138. } elsif (/\.xs\z/ && !/\bt\b/) {
  139. push @{$module_diffs{pm_file_from_xs($_)}}, $_;
  140. }
  141. }
  142. unless (%module_diffs) {
  143. print "1..1\nok 1 - No difference found\n" if $tap;
  144. exit;
  145. }
  146. printf "1..%d\n" => scalar keys %module_diffs if $tap;
  147. my $count;
  148. my $diff_cmd = "git --no-pager diff $tag_to_compare ";
  149. my $q = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'VMS') ? '"' : "'";
  150. my (@diff);
  151. foreach my $pm_file (sort keys %module_diffs) {
  152. # git has already told us that the files differ, so no need to grab each as
  153. # a blob from git, and do the comparison ourselves.
  154. my $pm_version = eval {MM->parse_version($pm_file)};
  155. my $orig_pm_content = get_file_from_git($pm_file, $tag_to_compare);
  156. my $orig_pm_version = eval {MM->parse_version(\$orig_pm_content)};
  157. ++$count;
  158. if (!defined $orig_pm_version || $orig_pm_version eq 'undef') { # sigh
  159. print "ok $count - SKIP Can't parse \$VERSION in $pm_file\n"
  160. if $tap;
  161. } elsif (!defined $pm_version || $pm_version eq 'undef') {
  162. my $nok = "not ok $count - in $pm_file version was $orig_pm_version, now unparsable\n";
  163. print $nok if $tap;
  164. print STDERR "# $nok\n";
  165. } elsif ($pm_version ne $orig_pm_version) { # good
  166. print "ok $count - $pm_file\n" if $tap;
  167. } else {
  168. if ($tap) {
  169. foreach (sort @{$module_diffs{$pm_file}}) {
  170. print "# $_" for `$diff_cmd $q$_$q`;
  171. }
  172. if (exists $skip_versions{$pm_file}
  173. and grep $pm_version eq $_, @{$skip_versions{$pm_file}}) {
  174. print "ok $count - SKIP $pm_file version $pm_version\n";
  175. } else {
  176. my $nok = "not ok $count - $pm_file version $pm_version\n";
  177. print $nok;
  178. print STDERR "# $nok";
  179. }
  180. } else {
  181. push @diff, @{$module_diffs{$pm_file}};
  182. print "$pm_file version $pm_version\n";
  183. }
  184. }
  185. }
  186. sub get_file_from_git {
  187. my ($file, $tag) = @_;
  188. local $/;
  189. use open IN => ':raw';
  190. return scalar `git --no-pager show $tag:$file 2>$null`;
  191. }
  192. if ($diffs) {
  193. for (sort @diff) {
  194. print "\n";
  195. system "$diff_cmd $q$_$q";
  196. }
  197. }