Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / Module / Install / Metadata.pm
1 package Module::Install::Metadata;
2
3 use strict 'vars';
4 use Module::Install::Base ();
5
6 use vars qw{$VERSION @ISA $ISCORE};
7 BEGIN {
8         $VERSION = '0.91';
9         @ISA     = 'Module::Install::Base';
10         $ISCORE  = 1;
11 }
12
13 my @boolean_keys = qw{
14         sign
15 };
16
17 my @scalar_keys = qw{
18         name
19         module_name
20         abstract
21         author
22         version
23         distribution_type
24         tests
25         installdirs
26 };
27
28 my @tuple_keys = qw{
29         configure_requires
30         build_requires
31         requires
32         recommends
33         bundles
34         resources
35 };
36
37 my @resource_keys = qw{
38         homepage
39         bugtracker
40         repository
41 };
42
43 my @array_keys = qw{
44         keywords
45 };
46
47 sub Meta              { shift          }
48 sub Meta_BooleanKeys  { @boolean_keys  }
49 sub Meta_ScalarKeys   { @scalar_keys   }
50 sub Meta_TupleKeys    { @tuple_keys    }
51 sub Meta_ResourceKeys { @resource_keys }
52 sub Meta_ArrayKeys    { @array_keys    }
53
54 foreach my $key ( @boolean_keys ) {
55         *$key = sub {
56                 my $self = shift;
57                 if ( defined wantarray and not @_ ) {
58                         return $self->{values}->{$key};
59                 }
60                 $self->{values}->{$key} = ( @_ ? $_[0] : 1 );
61                 return $self;
62         };
63 }
64
65 foreach my $key ( @scalar_keys ) {
66         *$key = sub {
67                 my $self = shift;
68                 return $self->{values}->{$key} if defined wantarray and !@_;
69                 $self->{values}->{$key} = shift;
70                 return $self;
71         };
72 }
73
74 foreach my $key ( @array_keys ) {
75         *$key = sub {
76                 my $self = shift;
77                 return $self->{values}->{$key} if defined wantarray and !@_;
78                 $self->{values}->{$key} ||= [];
79                 push @{$self->{values}->{$key}}, @_;
80                 return $self;
81         };
82 }
83
84 foreach my $key ( @resource_keys ) {
85         *$key = sub {
86                 my $self = shift;
87                 unless ( @_ ) {
88                         return () unless $self->{values}->{resources};
89                         return map  { $_->[1] }
90                                grep { $_->[0] eq $key }
91                                @{ $self->{values}->{resources} };
92                 }
93                 return $self->{values}->{resources}->{$key} unless @_;
94                 my $uri = shift or die(
95                         "Did not provide a value to $key()"
96                 );
97                 $self->resources( $key => $uri );
98                 return 1;
99         };
100 }
101
102 foreach my $key ( grep { $_ ne "resources" } @tuple_keys) {
103         *$key = sub {
104                 my $self = shift;
105                 return $self->{values}->{$key} unless @_;
106                 my @added;
107                 while ( @_ ) {
108                         my $module  = shift or last;
109                         my $version = shift || 0;
110                         push @added, [ $module, $version ];
111                 }
112                 push @{ $self->{values}->{$key} }, @added;
113                 return map {@$_} @added;
114         };
115 }
116
117 # Resource handling
118 my %lc_resource = map { $_ => 1 } qw{
119         homepage
120         license
121         bugtracker
122         repository
123 };
124
125 sub resources {
126         my $self = shift;
127         while ( @_ ) {
128                 my $name  = shift or last;
129                 my $value = shift or next;
130                 if ( $name eq lc $name and ! $lc_resource{$name} ) {
131                         die("Unsupported reserved lowercase resource '$name'");
132                 }
133                 $self->{values}->{resources} ||= [];
134                 push @{ $self->{values}->{resources} }, [ $name, $value ];
135         }
136         $self->{values}->{resources};
137 }
138
139 # Aliases for build_requires that will have alternative
140 # meanings in some future version of META.yml.
141 sub test_requires     { shift->build_requires(@_) }
142 sub install_requires  { shift->build_requires(@_) }
143
144 # Aliases for installdirs options
145 sub install_as_core   { $_[0]->installdirs('perl')   }
146 sub install_as_cpan   { $_[0]->installdirs('site')   }
147 sub install_as_site   { $_[0]->installdirs('site')   }
148 sub install_as_vendor { $_[0]->installdirs('vendor') }
149
150 sub dynamic_config {
151         my $self = shift;
152         unless ( @_ ) {
153                 warn "You MUST provide an explicit true/false value to dynamic_config\n";
154                 return $self;
155         }
156         $self->{values}->{dynamic_config} = $_[0] ? 1 : 0;
157         return 1;
158 }
159
160 sub perl_version {
161         my $self = shift;
162         return $self->{values}->{perl_version} unless @_;
163         my $version = shift or die(
164                 "Did not provide a value to perl_version()"
165         );
166
167         # Normalize the version
168         $version = $self->_perl_version($version);
169
170         # We don't support the reall old versions
171         unless ( $version >= 5.005 ) {
172                 die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n";
173         }
174
175         $self->{values}->{perl_version} = $version;
176 }
177
178 #Stolen from M::B
179 my %license_urls = (
180     perl         => 'http://dev.perl.org/licenses/',
181     apache       => 'http://apache.org/licenses/LICENSE-2.0',
182     artistic     => 'http://opensource.org/licenses/artistic-license.php',
183     artistic_2   => 'http://opensource.org/licenses/artistic-license-2.0.php',
184     lgpl         => 'http://opensource.org/licenses/lgpl-license.php',
185     lgpl2        => 'http://opensource.org/licenses/lgpl-2.1.php',
186     lgpl3        => 'http://opensource.org/licenses/lgpl-3.0.html',
187     bsd          => 'http://opensource.org/licenses/bsd-license.php',
188     gpl          => 'http://opensource.org/licenses/gpl-license.php',
189     gpl2         => 'http://opensource.org/licenses/gpl-2.0.php',
190     gpl3         => 'http://opensource.org/licenses/gpl-3.0.html',
191     mit          => 'http://opensource.org/licenses/mit-license.php',
192     mozilla      => 'http://opensource.org/licenses/mozilla1.1.php',
193     open_source  => undef,
194     unrestricted => undef,
195     restrictive  => undef,
196     unknown      => undef,
197 );
198
199 sub license {
200         my $self = shift;
201         return $self->{values}->{license} unless @_;
202         my $license = shift or die(
203                 'Did not provide a value to license()'
204         );
205         $self->{values}->{license} = $license;
206
207         # Automatically fill in license URLs
208         if ( $license_urls{$license} ) {
209                 $self->resources( license => $license_urls{$license} );
210         }
211
212         return 1;
213 }
214
215 sub all_from {
216         my ( $self, $file ) = @_;
217
218         unless ( defined($file) ) {
219                 my $name = $self->name or die(
220                         "all_from called with no args without setting name() first"
221                 );
222                 $file = join('/', 'lib', split(/-/, $name)) . '.pm';
223                 $file =~ s{.*/}{} unless -e $file;
224                 unless ( -e $file ) {
225                         die("all_from cannot find $file from $name");
226                 }
227         }
228         unless ( -f $file ) {
229                 die("The path '$file' does not exist, or is not a file");
230         }
231
232         # Some methods pull from POD instead of code.
233         # If there is a matching .pod, use that instead
234         my $pod = $file;
235         $pod =~ s/\.pm$/.pod/i;
236         $pod = $file unless -e $pod;
237
238         # Pull the different values
239         $self->name_from($file)         unless $self->name;
240         $self->version_from($file)      unless $self->version;
241         $self->perl_version_from($file) unless $self->perl_version;
242         $self->author_from($pod)        unless $self->author;
243         $self->license_from($pod)       unless $self->license;
244         $self->abstract_from($pod)      unless $self->abstract;
245
246         return 1;
247 }
248
249 sub provides {
250         my $self     = shift;
251         my $provides = ( $self->{values}->{provides} ||= {} );
252         %$provides = (%$provides, @_) if @_;
253         return $provides;
254 }
255
256 sub auto_provides {
257         my $self = shift;
258         return $self unless $self->is_admin;
259         unless (-e 'MANIFEST') {
260                 warn "Cannot deduce auto_provides without a MANIFEST, skipping\n";
261                 return $self;
262         }
263         # Avoid spurious warnings as we are not checking manifest here.
264         local $SIG{__WARN__} = sub {1};
265         require ExtUtils::Manifest;
266         local *ExtUtils::Manifest::manicheck = sub { return };
267
268         require Module::Build;
269         my $build = Module::Build->new(
270                 dist_name    => $self->name,
271                 dist_version => $self->version,
272                 license      => $self->license,
273         );
274         $self->provides( %{ $build->find_dist_packages || {} } );
275 }
276
277 sub feature {
278         my $self     = shift;
279         my $name     = shift;
280         my $features = ( $self->{values}->{features} ||= [] );
281         my $mods;
282
283         if ( @_ == 1 and ref( $_[0] ) ) {
284                 # The user used ->feature like ->features by passing in the second
285                 # argument as a reference.  Accomodate for that.
286                 $mods = $_[0];
287         } else {
288                 $mods = \@_;
289         }
290
291         my $count = 0;
292         push @$features, (
293                 $name => [
294                         map {
295                                 ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_
296                         } @$mods
297                 ]
298         );
299
300         return @$features;
301 }
302
303 sub features {
304         my $self = shift;
305         while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) {
306                 $self->feature( $name, @$mods );
307         }
308         return $self->{values}->{features}
309                 ? @{ $self->{values}->{features} }
310                 : ();
311 }
312
313 sub no_index {
314         my $self = shift;
315         my $type = shift;
316         push @{ $self->{values}->{no_index}->{$type} }, @_ if $type;
317         return $self->{values}->{no_index};
318 }
319
320 sub read {
321         my $self = shift;
322         $self->include_deps( 'YAML::Tiny', 0 );
323
324         require YAML::Tiny;
325         my $data = YAML::Tiny::LoadFile('META.yml');
326
327         # Call methods explicitly in case user has already set some values.
328         while ( my ( $key, $value ) = each %$data ) {
329                 next unless $self->can($key);
330                 if ( ref $value eq 'HASH' ) {
331                         while ( my ( $module, $version ) = each %$value ) {
332                                 $self->can($key)->($self, $module => $version );
333                         }
334                 } else {
335                         $self->can($key)->($self, $value);
336                 }
337         }
338         return $self;
339 }
340
341 sub write {
342         my $self = shift;
343         return $self unless $self->is_admin;
344         $self->admin->write_meta;
345         return $self;
346 }
347
348 sub version_from {
349         require ExtUtils::MM_Unix;
350         my ( $self, $file ) = @_;
351         $self->version( ExtUtils::MM_Unix->parse_version($file) );
352 }
353
354 sub abstract_from {
355         require ExtUtils::MM_Unix;
356         my ( $self, $file ) = @_;
357         $self->abstract(
358                 bless(
359                         { DISTNAME => $self->name },
360                         'ExtUtils::MM_Unix'
361                 )->parse_abstract($file)
362          );
363 }
364
365 # Add both distribution and module name
366 sub name_from {
367         my ($self, $file) = @_;
368         if (
369                 Module::Install::_read($file) =~ m/
370                 ^ \s*
371                 package \s*
372                 ([\w:]+)
373                 \s* ;
374                 /ixms
375         ) {
376                 my ($name, $module_name) = ($1, $1);
377                 $name =~ s{::}{-}g;
378                 $self->name($name);
379                 unless ( $self->module_name ) {
380                         $self->module_name($module_name);
381                 }
382         } else {
383                 die("Cannot determine name from $file\n");
384         }
385 }
386
387 sub perl_version_from {
388         my $self = shift;
389         if (
390                 Module::Install::_read($_[0]) =~ m/
391                 ^
392                 (?:use|require) \s*
393                 v?
394                 ([\d_\.]+)
395                 \s* ;
396                 /ixms
397         ) {
398                 my $perl_version = $1;
399                 $perl_version =~ s{_}{}g;
400                 $self->perl_version($perl_version);
401         } else {
402                 warn "Cannot determine perl version info from $_[0]\n";
403                 return;
404         }
405 }
406
407 sub author_from {
408         my $self    = shift;
409         my $content = Module::Install::_read($_[0]);
410         if ($content =~ m/
411                 =head \d \s+ (?:authors?)\b \s*
412                 ([^\n]*)
413                 |
414                 =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s*
415                 .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s*
416                 ([^\n]*)
417         /ixms) {
418                 my $author = $1 || $2;
419                 $author =~ s{E<lt>}{<}g;
420                 $author =~ s{E<gt>}{>}g;
421                 $self->author($author);
422         } else {
423                 warn "Cannot determine author info from $_[0]\n";
424         }
425 }
426
427 sub license_from {
428         my $self = shift;
429         if (
430                 Module::Install::_read($_[0]) =~ m/
431                 (
432                         =head \d \s+
433                         (?:licen[cs]e|licensing|copyright|legal)\b
434                         .*?
435                 )
436                 (=head\\d.*|=cut.*|)
437                 \z
438         /ixms ) {
439                 my $license_text = $1;
440                 my @phrases      = (
441                         'under the same (?:terms|license) as (?:perl|the perl programming language) itself' => 'perl', 1,
442                         'GNU general public license'         => 'gpl',         1,
443                         'GNU public license'                 => 'gpl',         1,
444                         'GNU lesser general public license'  => 'lgpl',        1,
445                         'GNU lesser public license'          => 'lgpl',        1,
446                         'GNU library general public license' => 'lgpl',        1,
447                         'GNU library public license'         => 'lgpl',        1,
448                         'BSD license'                        => 'bsd',         1,
449                         'Artistic license'                   => 'artistic',    1,
450                         'GPL'                                => 'gpl',         1,
451                         'LGPL'                               => 'lgpl',        1,
452                         'BSD'                                => 'bsd',         1,
453                         'Artistic'                           => 'artistic',    1,
454                         'MIT'                                => 'mit',         1,
455                         'proprietary'                        => 'proprietary', 0,
456                 );
457                 while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) {
458                         $pattern =~ s{\s+}{\\s+}g;
459                         if ( $license_text =~ /\b$pattern\b/i ) {
460                                 $self->license($license);
461                                 return 1;
462                         }
463                 }
464         }
465
466         warn "Cannot determine license info from $_[0]\n";
467         return 'unknown';
468 }
469
470 sub _extract_bugtracker {
471         my @links   = $_[0] =~ m#L<(\Qhttp://rt.cpan.org/\E[^>]+)>#g;
472         my %links;
473         @links{@links}=();
474         @links=keys %links;
475         return @links;
476 }
477
478 sub bugtracker_from {
479         my $self    = shift;
480         my $content = Module::Install::_read($_[0]);
481         my @links   = _extract_bugtracker($content);
482         unless ( @links ) {
483                 warn "Cannot determine bugtracker info from $_[0]\n";
484                 return 0;
485         }
486         if ( @links > 1 ) {
487                 warn "Found more than on rt.cpan.org link in $_[0]\n";
488                 return 0;
489         }
490
491         # Set the bugtracker
492         bugtracker( $links[0] );
493         return 1;
494 }
495
496 sub requires_from {
497         my $self     = shift;
498         my $content  = Module::Install::_readperl($_[0]);
499         my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg;
500         while ( @requires ) {
501                 my $module  = shift @requires;
502                 my $version = shift @requires;
503                 $self->requires( $module => $version );
504         }
505 }
506
507 sub test_requires_from {
508         my $self     = shift;
509         my $content  = Module::Install::_readperl($_[0]);
510         my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg;
511         while ( @requires ) {
512                 my $module  = shift @requires;
513                 my $version = shift @requires;
514                 $self->test_requires( $module => $version );
515         }
516 }
517
518 # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to
519 # numbers (eg, 5.006001 or 5.008009).
520 # Also, convert double-part versions (eg, 5.8)
521 sub _perl_version {
522         my $v = $_[-1];
523         $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e;
524         $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e;
525         $v =~ s/(\.\d\d\d)000$/$1/;
526         $v =~ s/_.+$//;
527         if ( ref($v) ) {
528                 # Numify
529                 $v = $v + 0;
530         }
531         return $v;
532 }
533
534
535
536
537
538 ######################################################################
539 # MYMETA Support
540
541 sub WriteMyMeta {
542         die "WriteMyMeta has been deprecated";
543 }
544
545 sub write_mymeta_yaml {
546         my $self = shift;
547
548         # We need YAML::Tiny to write the MYMETA.yml file
549         unless ( eval { require YAML::Tiny; 1; } ) {
550                 return 1;
551         }
552
553         # Generate the data
554         my $meta = $self->_write_mymeta_data or return 1;
555
556         # Save as the MYMETA.yml file
557         print "Writing MYMETA.yml\n";
558         YAML::Tiny::DumpFile('MYMETA.yml', $meta);
559 }
560
561 sub write_mymeta_json {
562         my $self = shift;
563
564         # We need JSON to write the MYMETA.json file
565         unless ( eval { require JSON; 1; } ) {
566                 return 1;
567         }
568
569         # Generate the data
570         my $meta = $self->_write_mymeta_data or return 1;
571
572         # Save as the MYMETA.yml file
573         print "Writing MYMETA.json\n";
574         Module::Install::_write(
575                 'MYMETA.json',
576                 JSON->new->pretty(1)->canonical->encode($meta),
577         );
578 }
579
580 sub _write_mymeta_data {
581         my $self = shift;
582
583         # If there's no existing META.yml there is nothing we can do
584         return undef unless -f 'META.yml';
585
586         # We need Parse::CPAN::Meta to load the file
587         unless ( eval { require Parse::CPAN::Meta; 1; } ) {
588                 return undef;
589         }
590
591         # Merge the perl version into the dependencies
592         my $val  = $self->Meta->{values};
593         my $perl = delete $val->{perl_version};
594         if ( $perl ) {
595                 $val->{requires} ||= [];
596                 my $requires = $val->{requires};
597
598                 # Canonize to three-dot version after Perl 5.6
599                 if ( $perl >= 5.006 ) {
600                         $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e
601                 }
602                 unshift @$requires, [ perl => $perl ];
603         }
604
605         # Load the advisory META.yml file
606         my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
607         my $meta = $yaml[0];
608
609         # Overwrite the non-configure dependency hashs
610         delete $meta->{requires};
611         delete $meta->{build_requires};
612         delete $meta->{recommends};
613         if ( exists $val->{requires} ) {
614                 $meta->{requires} = { map { @$_ } @{ $val->{requires} } };
615         }
616         if ( exists $val->{build_requires} ) {
617                 $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } };
618         }
619
620         return $meta;
621 }
622
623 1;