This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
makerel: use Digest::SHA to print sha256sum
[perl5.git] / Porting / makemeta
1 #!./perl -w
2 # this script must be run by the current perl to get perl's version right
3 #
4 # Create META.yml and META.json files in the current directory. Must be run from the
5 # root directory of a perl source tree.
6
7 use strict;
8 use warnings;
9 use Getopt::Std;
10
11 # avoid unnecessary churn in x_serialization_backend in META.*
12 $ENV{PERL_JSON_BACKEND} = $ENV{CPAN_META_JSON_BACKEND} = 'JSON::PP';
13 $ENV{PERL_YAML_BACKEND} = 'CPAN::Meta::YAML';
14
15 my $opts = {
16   'META.yml'  => { version => '1.4' },
17   'META.json' => { version => '2' },
18 };
19
20 my %switches;
21 getopts('nbyj', \%switches);
22
23 =head1 SYNOPSIS
24
25   ./perl -Ilib Porting/makemeta
26
27 =head1 OPTIONS
28
29 =item B<-y>
30
31 Update only META.yml
32
33 The default is to update both, META.yml and META.json
34
35 =item B<-n>
36
37 Don't update any files, exit with 1 if changes would be made
38
39 =item B<-b>
40
41 No-op, kept for historical purposes
42
43 =cut
44
45 my @metafiles;
46 if ( $switches{y} ) {
47   push @metafiles, 'META.yml';
48 }
49 elsif ( $switches{j} ) {
50   push @metafiles, 'META.json';
51 }
52 else {
53   push @metafiles, keys %$opts;
54 }
55
56 my ($vers, $stat ) = _determine_status();
57
58 my $distmeta = {
59   'version' => $vers,
60   'name' => 'perl',
61   'author' => [
62     'perl5-porters@perl.org'
63   ],
64   'license' => [
65     'perl_5'
66   ],
67   'abstract' => 'The Perl 5 language interpreter',
68   'release_status' => $stat,
69   'dynamic_config' => 1,
70   'resources' => {
71     'repository' => {
72       'url' => 'https://github.com/Perl/perl5'
73     },
74     'homepage' => 'https://www.perl.org/',
75     'bugtracker' => {
76       'web' => 'https://github.com/Perl/perl5/issues'
77     },
78     'license' => [
79       'https://dev.perl.org/licenses/'
80     ],
81   },
82 };
83
84 use lib "Porting";
85 use File::Basename qw( dirname );
86 use CPAN::Meta;
87 use File::Spec;
88
89 BEGIN {
90     # Get function prototypes
91     require './regen/regen_lib.pl';
92 }
93
94 use Maintainers qw(%Modules get_module_files get_module_pat);
95
96 my @CPAN  = grep { $Modules{$_}{CPAN} } keys %Modules;
97 my @files = ('autodoc.pl', 'lib/unicore/mktables', 'TestInit.pm',
98              'Porting/Maintainers.pm', 'Porting/perldelta_template.pod',
99              map { get_module_files($_) } @CPAN);
100 my @extt = map { my $t = File::Spec->catdir($_, "t");
101                  -d $t ? ( $_ . "t" ) : () }
102   grep { /^ext\b/ } split ' ', $Modules{_PERLLIB}{FILES};
103 my @dirs  = ('cpan', 'win32', 'lib/perl5db', @extt, grep { -d $_ && $_  !~ /^cpan/ } map { get_module_pat($_) } @CPAN);
104
105 my %dirs;
106 @dirs{@dirs} = ();
107
108 @files =
109   grep {
110     my $d = $_;
111     my $previous_d = '';
112     while(($d = dirname($d)) ne "."){
113       last if $d eq $previous_d; # safety valve
114       last if exists $dirs{$d};
115       $previous_d = $d;
116     }
117
118     # if $d is "." it means we tried every parent dir of the file and none
119     # of them were in the private list
120
121     $d eq "." || $d eq $previous_d;
122   }
123   sort { lc $a cmp lc $b } @files;
124
125 @dirs  = sort { lc $a cmp lc $b } @dirs;
126
127 $distmeta->{no_index}->{file} = \@files;
128 $distmeta->{no_index}->{directory} = \@dirs;
129
130 my $meta = CPAN::Meta->create( $distmeta );
131 foreach my $file ( @metafiles ) {
132   my $new = $meta->as_string( $opts->{$file} );
133   if( $switches{n} ) {
134     open my $fh, '<:raw', $file;
135     local $/;
136     my $old = <$fh>;
137     if( $old ne $new ) {
138       exit 1;
139     }
140   } else {
141     my $fh = open_new($file);
142     print $fh $new;
143     close_and_rename($fh);
144   }
145 }
146 exit 0;
147
148 sub _determine_status {
149   my $patchlevel_h = 'patchlevel.h';
150   return unless -e $patchlevel_h;
151   my $status = '';
152   my $version = '';
153   {
154     my %defines;
155     open my $fh, '<', $patchlevel_h;
156     my @vers;
157     while (<$fh>) {
158       chomp;
159       next unless m!^#define! or m!!;
160       if ( m!^#define! ) {
161         my ($foo,$bar) = ( split /\s+/ )[1,2];
162         $defines{$foo} = $bar;
163       }
164       elsif ( m!\"RC\d+\"! ) {
165         $status = 'testing';
166         last;
167       }
168     }
169     unless ( $status ) {
170       $status = $defines{PERL_VERSION} % 2 ? 'unstable' : 'stable';
171     }
172     if ( my @wotsits = grep { defined $defines{$_} } qw(PERL_REVISION PERL_VERSION PERL_SUBVERSION) ) {
173       $version = sprintf '%d.%03d%03d', map { $defines{$_} } @wotsits;
174     }
175     else {
176       # Well, you never know
177       $version = sprintf '5.%03d_%02d', map { $defines{$_} } qw(PATCHLEVEL SUBVERSION);
178     }
179   }
180   return ( $version, $status );
181 }