diff options
author | David Golden <dagolden@cpan.org> | 2011-02-15 22:35:53 -0500 |
---|---|---|
committer | David Golden <dagolden@cpan.org> | 2011-02-15 22:50:32 -0500 |
commit | c05760c68edc298aadab73da2781ba0fe1cf24b6 (patch) | |
tree | 8fc3142573184b24aadc4c3dea70f1afd6d67f64 /cpan/CPAN-Meta | |
parent | 279627b48dfab08c484fbbb6c05d3964fa9529d2 (diff) | |
download | perl-c05760c68edc298aadab73da2781ba0fe1cf24b6.tar.gz |
Add CPAN::Meta as a dual-life module
CPAN::Meta version 2.110440 has been added as a dual-life module. It
provides a standard library to read, interpret and write CPAN distribution
metadata files (e.g. META.json and META.yml) which describes a
distribution, its contents, and the requirements for building it and
installing it. The latest CPAN distribution metadata specification is
included as CPAN::Meta::Spec and notes on changes in the specification
over time are given in CPAN::Meta::History.
CPAN::Meta is required for CPAN.pm and CPANPLUS to read META.json and
MYMETA.json files and is required by Module::Build and
ExtUtils::MakeMaker to generate META.json and MYMETA.json files
Diffstat (limited to 'cpan/CPAN-Meta')
55 files changed, 8020 insertions, 0 deletions
diff --git a/cpan/CPAN-Meta/Changes b/cpan/CPAN-Meta/Changes new file mode 100644 index 0000000000..7dabb947e2 --- /dev/null +++ b/cpan/CPAN-Meta/Changes @@ -0,0 +1,178 @@ +Revision history for CPAN-Meta + +2.110440 2011-02-12 22:55:28 EST5EDT + + [BUGFIX] + + - Bump Parse::CPAN::Meta prereq to 1.44, as 1.43 was never released + +2.110420 2011-02-11 15:40:36 EST5EDT + + [BUG FIXES] + + - The as_string() method now always returns a character string; + previously, JSON strings were UTF-8 encoded. + + - The save() method now always saves with UTF-8 encoding for + Perl 5.8.1 or greater; previously, YAML was not encoded + +2.110390 2011-02-07 21:00:47 EST5EDT + + [BUG FIXES] + + - Release 2.110360 had a regression where the save() method would no + longer return true on success. That has been fixed. + +2.110360 2011-02-04 19:46:21 America/New_York + + [OTHER] + + - Remove autodie dependency so CPAN::Meta can be used on older Perls + + - Remove unused Data::Dumper dependency + +2.110350 2011-02-03 19:57:32 America/New_York + + [ENHANCEMENTS] + + - Added "as_string" method similar to "as_struct" + + [OTHER] + + - Bumped Parse::CPAN::Meta prereq to 1.43 and uses that to + determine proper YAML/JSON backends + + - Removed unused prereqs + +2.110330 2011-02-02 09:42:57 EST5EDT + + [ENHANCEMENTS] + + - Saved META.json files are now sorted by key + + - as_struct() method takes an optional "version" argument to return + a down-converted metadata hashref + +2.110320 2011-01-31 23:14:30 EST5EDT + + [ENHANCEMENTS] + + - The 'save' method now allows an optional hashref argument, which can be + used to set the desired meta spec version. Metadata is automatically + converted to the specified output. + +2.110240 2011-01-24 16:28:25 EST5EDT + + - Reading JSON/YAML is delegated entirely to Parse::CPAN::Meta (1.4200) + + - JSON.pm is dropped as a prerequisite and JSON::PP is added to prepare + for CPAN::Meta to be added to the Perl core + + - JSON writing uses the same JSON backend selection as Parse::CPAN::Meta + to allow "upgrading" to a non-core JSON backend module if desired + +2.102400 2010-08-28 14:06:34 America/New_York + + - 'as_struct' method now returns unblessed data (reported by Chris Prather) + +2.102160 2010-08-04 12:27:10 EST5EDT + + - Fix bugtracker conversion bug (RT#60017) + +2.101670 2010-06-15 21:02:42 EST5EDT + + - converting 1.x 'repository' field now puts converted url into the + 'url' sub-field of 'repository' instead of the 'web' sub-field + +2.101610 2010-06-10 18:51:30 EST5EDT + + - fixed converter bug that output 'artistic2' instead of 'artistic_2' + for license in 1.X specs + + - 'artistic2' is now converted to 'artistic_2' if it occurs + + - corrected validation for 'artistic_2' and disallowed 'artistic-2.0' + +2.101600 2010-06-09 10:07:31 EST5EDT + + - improve conversion of restricted/restrictive license keys between + spec versions 1.4 and 2 [reported by Alexander Hartmaier] + +2.101591 2010-06-08 09:56:17 EST5EDT + + - added 'as_struct' method to CPAN::Meta to get a deep copy of + the metadata hash_ref + + - won't add an optional_features 'description' field if missing + + - improved documentation of CPAN::Meta::Converter and how it deals + with bad/missing data + +2.101590 2010-06-07 21:49:36 EST5EDT + + - won't automatically add 'unknown' as repository type when converting; + instead, will only add a repository type if a repository 'url' is + present and it is of the 'svn:' or 'git:' scheme. + + - squelched some uninitialized value warnings [Graham Barr] + +2.101580 2010-06-07 16:44:13 EST5EDT + + - add "lazy_validation" option to constructors + + - add ability to "convert" to same version and clean-up any fixable + errors + + - fix validation bugs (adhere closer to the spec) + + - improve lots of heuristics during conversion + +2.101461 2010-05-26 16:57:02 America/New_York + + - accessors deep clone list and map keys before returning them + + - add custom_keys() and custom() methods + +2.101460 2010-05-25 23:12:27 America/New_York + + - loosen URL validation -- only a scheme and authority are required + without restrictions on either + +2.101450 2010-05-25 17:59:32 America/New_York + + - when downconverting from 2, leave custom keys unchanged + (except in resources, where x_ is changed to X_) + + - when converting to 2, don't prepend x_ to custom keys that already + matched qr{\Ax_}i + +2.101410 2010-05-21 10:39:18 EST5EDT + + - when downconverting from 2, merge test requirements into build requirements + +2.101390 2010-05-19 10:49:50 EST5EDT + + - do not clobber generated_by when converting + +2.101380 2010-05-17 23:39:23 EST5EDT + + - added support for down-converting to older versions of the spec + + - improved test coverage for conversion and validation + +2.101110 2010-04-21 11:06:52 EST5EDT + + - clarified that .XXXXXX versions of the CPAN-Meta distribution will not + change the meaning of the CPAN::Meta::Spec, but may fix typos or + clarify prose + + - fixed a typo regarding dotted-integer versions: keeping components + in the range 0-999 was corrected to a "should" instead of a "must" + + - fixed validation bugs for certain types of nested data structures + (based on a patch provided by Barbie) + +2.101091 2010-04-19 06:32:13 EST5EDT + + - keep the old specs from getting indexed so as not to confuse people + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta.pm b/cpan/CPAN-Meta/lib/CPAN/Meta.pm new file mode 100644 index 0000000000..ef798559fb --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta.pm @@ -0,0 +1,696 @@ +use 5.006; +use strict; +use warnings; +package CPAN::Meta; +BEGIN { + $CPAN::Meta::VERSION = '2.110440'; +} +# ABSTRACT: the distribution metadata for a CPAN dist + + +use Carp qw(carp croak); +use CPAN::Meta::Feature; +use CPAN::Meta::Prereqs; +use CPAN::Meta::Converter; +use CPAN::Meta::Validator; +use Parse::CPAN::Meta 1.44 (); + + +BEGIN { + my @STRING_READERS = qw( + abstract + description + dynamic_config + generated_by + name + release_status + version + ); + + no strict 'refs'; + for my $attr (@STRING_READERS) { + *$attr = sub { $_[0]{ $attr } }; + } +} + + +BEGIN { + my @LIST_READERS = qw( + author + keywords + license + ); + + no strict 'refs'; + for my $attr (@LIST_READERS) { + *$attr = sub { + my $value = $_[0]{ $attr }; + croak "$attr must be called in list context" + unless wantarray; + return @{ Storable::dclone($value) } if ref $value; + return $value; + }; + } +} + +sub authors { $_[0]->author } +sub licenses { $_[0]->license } + + +BEGIN { + my @MAP_READERS = qw( + meta-spec + resources + provides + no_index + + prereqs + optional_features + ); + + no strict 'refs'; + for my $attr (@MAP_READERS) { + (my $subname = $attr) =~ s/-/_/; + *$subname = sub { + my $value = $_[0]{ $attr }; + return Storable::dclone($value) if $value; + return {}; + }; + } +} + + +sub custom_keys { + return grep { /^x_/i } keys %{$_[0]}; +} + +sub custom { + my ($self, $attr) = @_; + my $value = $self->{$attr}; + return Storable::dclone($value) if ref $value; + return $value; +} + + +sub _new { + my ($class, $struct, $options) = @_; + my $self; + + if ( $options->{lazy_validation} ) { + # try to convert to a valid structure; if succeeds, then return it + my $cmc = CPAN::Meta::Converter->new( $struct ); + $self = $cmc->convert( version => 2 ); # valid or dies + return bless $self, $class; + } + else { + # validate original struct + my $cmv = CPAN::Meta::Validator->new( $struct ); + unless ( $cmv->is_valid) { + die "Invalid metadata structure. Errors: " + . join(", ", $cmv->errors) . "\n"; + } + } + + # up-convert older spec versions + my $version = $struct->{'meta-spec'}{version} || '1.0'; + if ( $version == 2 ) { + $self = $struct; + } + else { + my $cmc = CPAN::Meta::Converter->new( $struct ); + $self = $cmc->convert( version => 2 ); + } + + return bless $self, $class; +} + +sub new { + my ($class, $struct, $options) = @_; + my $self = eval { $class->_new($struct, $options) }; + croak($@) if $@; + return $self; +} + + +sub create { + my ($class, $struct, $options) = @_; + my $version = __PACKAGE__->VERSION || 2; + $struct->{generated_by} ||= __PACKAGE__ . " version $version" ; + $struct->{'meta-spec'}{version} ||= int($version); + my $self = eval { $class->_new($struct, $options) }; + croak ($@) if $@; + return $self; +} + + +sub load_file { + my ($class, $file, $options) = @_; + $options->{lazy_validation} = 1 unless exists $options->{lazy_validation}; + + croak "load_file() requires a valid, readable filename" + unless -r $file; + + my $self; + eval { + my $struct = Parse::CPAN::Meta->load_file( $file ); + $self = $class->_new($struct, $options); + }; + croak($@) if $@; + return $self; +} + + +sub load_yaml_string { + my ($class, $yaml, $options) = @_; + $options->{lazy_validation} = 1 unless exists $options->{lazy_validation}; + + my $self; + eval { + my ($struct) = Parse::CPAN::Meta->load_yaml_string( $yaml ); + $self = $class->_new($struct, $options); + }; + croak($@) if $@; + return $self; +} + + +sub load_json_string { + my ($class, $json, $options) = @_; + $options->{lazy_validation} = 1 unless exists $options->{lazy_validation}; + + my $self; + eval { + my $struct = Parse::CPAN::Meta->load_json_string( $json ); + $self = $class->_new($struct, $options); + }; + croak($@) if $@; + return $self; +} + + +sub save { + my ($self, $file, $options) = @_; + + my $version = $options->{version} || '2'; + my $layer = $] ge '5.008001' ? ':utf8' : ''; + + if ( $version ge '2' ) { + carp "'$file' should end in '.json'" + unless $file =~ m{\.json$}; + } + else { + carp "'$file' should end in '.yml'" + unless $file =~ m{\.yml$}; + } + + my $data = $self->as_string( $options ); + open my $fh, ">$layer", $file + or die "Error opening '$file' for writing: $!\n"; + + print {$fh} $data; + close $fh + or die "Error closing '$file': $!\n"; + + return 1; +} + + +# XXX Do we need this if we always upconvert? -- dagolden, 2010-04-14 +sub meta_spec_version { + my ($self) = @_; + return $self->meta_spec->{version}; +} + + +sub effective_prereqs { + my ($self, $features) = @_; + $features ||= []; + + my $prereq = CPAN::Meta::Prereqs->new($self->prereqs); + + return $prereq unless @$features; + + my @other = map {; $self->feature($_)->prereqs } @$features; + + return $prereq->with_merged_prereqs(\@other); +} + + +sub should_index_file { + my ($self, $filename) = @_; + + for my $no_index_file (@{ $self->no_index->{file} || [] }) { + return if $filename eq $no_index_file; + } + + for my $no_index_dir (@{ $self->no_index->{directory} }) { + $no_index_dir =~ s{$}{/} unless $no_index_dir =~ m{/\z}; + return if index($filename, $no_index_dir) == 0; + } + + return 1; +} + + +sub should_index_package { + my ($self, $package) = @_; + + for my $no_index_pkg (@{ $self->no_index->{package} || [] }) { + return if $package eq $no_index_pkg; + } + + for my $no_index_ns (@{ $self->no_index->{namespace} }) { + return if index($package, "${no_index_ns}::") == 0; + } + + return 1; +} + + +sub features { + my ($self) = @_; + + my $opt_f = $self->optional_features; + my @features = map {; CPAN::Meta::Feature->new($_ => $opt_f->{ $_ }) } + keys %$opt_f; + + return @features; +} + + +sub feature { + my ($self, $ident) = @_; + + croak "no feature named $ident" + unless my $f = $self->optional_features->{ $ident }; + + return CPAN::Meta::Feature->new($ident, $f); +} + + +sub as_struct { + my ($self, $options) = @_; + my $backend = Parse::CPAN::Meta->json_backend(); + my $struct = $backend->new->decode( + $backend->new->convert_blessed->encode($self) + ); + if ( $options->{version} ) { + my $cmc = CPAN::Meta::Converter->new( $struct ); + $struct = $cmc->convert( version => $options->{version} ); + } + return $struct; +} + + +sub as_string { + my ($self, $options) = @_; + + my $version = $options->{version} || '2'; + + my $struct; + if ( $self->version ne $version ) { + my $cmc = CPAN::Meta::Converter->new( $self->as_struct ); + $struct = $cmc->convert( version => $version ); + } + else { + $struct = $self->as_struct; + } + + my ($data, $backend); + if ( $version ge '2' ) { + $backend = Parse::CPAN::Meta->json_backend(); + $data = $backend->new->pretty->canonical->encode($struct); + } + else { + $backend = Parse::CPAN::Meta->yaml_backend(); + $data = eval { no strict 'refs'; &{"$backend\::Dump"}($struct) }; + if ( $@ ) { + croak $backend->can('errstr') ? $backend->errstr : $@ + } + } + + return $data; +} + +# Used by JSON::PP, etc. for "convert_blessed" +sub TO_JSON { + return { %{ $_[0] } }; +} + +1; + + + +=pod + +=head1 NAME + +CPAN::Meta - the distribution metadata for a CPAN dist + +=head1 VERSION + +version 2.110440 + +=head1 SYNOPSIS + + my $meta = CPAN::Meta->load_file('META.json'); + + printf "testing requirements for %s version %s\n", + $meta->name, + $meta->version; + + my $prereqs = $meta->requirements_for('configure'); + + for my $module ($prereqs->required_modules) { + my $version = get_local_version($module); + + die "missing required module $module" unless defined $version; + die "version for $module not in range" + unless $prereqs->accepts_module($module, $version); + } + +=head1 DESCRIPTION + +Software distributions released to the CPAN include a F<META.json> or, for +older distributions, F<META.yml>, which describes the distribution, its +contents, and the requirements for building and installing the distribution. +The data structure stored in the F<META.json> file is described in +L<CPAN::Meta::Spec>. + +CPAN::Meta provides a simple class to represent this distribution metadata (or +I<distmeta>), along with some helpful methods for interrogating that data. + +The documentation below is only for the methods of the CPAN::Meta object. For +information on the meaning of individual fields, consult the spec. + +=head1 METHODS + +=head2 new + + my $meta = CPAN::Meta->new($distmeta_struct, \%options); + +Returns a valid CPAN::Meta object or dies if the supplied metadata hash +reference fails to validate. Older-format metadata will be up-converted to +version 2 if they validate against the original stated specification. + +It takes an optional hashref of options. Valid options include: + +=over + +=item * + +lazy_validation -- if true, new will attempt to convert the given metadata +to version 2 before attempting to validate it. This means than any +fixable errors will be handled by CPAN::Meta::Converter before validation. +(Note that this might result in invalid optional data being silently +dropped.) The default is false. + +=back + +=head2 create + + my $meta = CPAN::Meta->create($distmeta_struct, \%options); + +This is same as C<new()>, except that C<generated_by> and C<meta-spec> fields +will be generated if not provided. This means the metadata structure is +assumed to otherwise follow the latest L<CPAN::Meta::Spec>. + +=head2 load_file + + my $meta = CPAN::Meta->load_file($distmeta_file, \%options); + +Given a pathname to a file containing metadata, this deserializes the file +according to its file suffix and constructs a new C<CPAN::Meta> object, just +like C<new()>. It will die if the deserialized version fails to validate +against its stated specification version. + +It takes the same options as C<new()> but C<lazy_validation> defaults to +true. + +=head2 load_yaml_string + + my $meta = CPAN::Meta->load_yaml_string($yaml, \%options); + +This method returns a new CPAN::Meta object using the first document in the +given YAML string. In other respects it is identical to C<load_file()>. + +=head2 load_json_string + + my $meta = CPAN::Meta->load_json_string($json, \%options); + +This method returns a new CPAN::Meta object using the structure represented by +the given JSON string. In other respects it is identical to C<load_file()>. + +=head2 save + + $meta->save($distmeta_file, \%options); + +Serializes the object as JSON and writes it to the given file. The only valid +option is C<version>, which defaults to '2'. On Perl 5.8.1 or later, the file +is saved with UTF-8 encoding. + +For C<version> 2 (or higher), the filename should end in '.json'. L<JSON::PP> +is the default JSON backend. Using another JSON backend requires L<JSON> 2.5 or +later and you must set the C<$ENV{PERL_JSON_BACKEND}> to a supported alternate +backend like L<JSON::XS>. + +For C<version> less than 2, the filename should end in '.yml'. +L<CPAN::Meta::Converter> is used to generate an older metadata structure, which +is serialized to YAML. CPAN::Meta::YAML is the default YAML backend. You may +set the C<$ENV{PERL_YAML_BACKEND}> to a supported alternative backend, though +this is not recommended due to subtle incompatibilities between YAML parsers on +CPAN. + +=head2 meta_spec_version + +This method returns the version part of the C<meta_spec> entry in the distmeta +structure. It is equivalent to: + + $meta->meta_spec->{version}; + +=head2 effective_prereqs + + my $prereqs = $meta->effective_prereqs; + + my $prereqs = $meta->effective_prereqs( \@feature_identifiers ); + +This method returns a L<CPAN::Meta::Prereqs> object describing all the +prereqs for the distribution. If an arrayref of feature identifiers is given, +the prereqs for the identified features are merged together with the +distribution's core prereqs before the CPAN::Meta::Prereqs object is returned. + +=head2 should_index_file + + ... if $meta->should_index_file( $filename ); + +This method returns true if the given file should be indexed. It decides this +by checking the C<file> and C<directory> keys in the C<no_index> property of +the distmeta structure. + +C<$filename> should be given in unix format. + +=head2 should_index_package + + ... if $meta->should_index_package( $package ); + +This method returns true if the given package should be indexed. It decides +this by checking the C<package> and C<namespace> keys in the C<no_index> +property of the distmeta structure. + +=head2 features + + my @feature_objects = $meta->features; + +This method returns a list of L<CPAN::Meta::Feature> objects, one for each +optional feature described by the distribution's metadata. + +=head2 feature + + my $feature_object = $meta->feature( $identifier ); + +This method returns a L<CPAN::Meta::Feature> object for the optional feature +with the given identifier. If no feature with that identifier exists, an +exception will be raised. + +=head2 as_struct + + my $copy = $meta->as_struct( \%options ); + +This method returns a deep copy of the object's metadata as an unblessed has +reference. It takes an optional hashref of options. If the hashref contains +a C<version> argument, the copied metadata will be converted to the version +of the specification and returned. For example: + + my $old_spec = $meta->as_struct( {version => "1.4"} ); + +=head2 as_string + + my $string = $meta->as_string( \%options ); + +This method returns a serialized copy of the object's metadata as a character +string. (The strings are B<not> UTF-8 encoded.) It takes an optional hashref +of options. If the hashref contains a C<version> argument, the copied metadata +will be converted to the version of the specification and returned. For +example: + + my $string = $meta->as_struct( {version => "1.4"} ); + +For C<version> greater than or equal to 2, the string will be serialized as +JSON. For C<version> less than 2, the string will be serialized as YAML. In +both cases, the same rules are followed as in the C<save()> method for choosing +a serialization backend. + +=head1 STRING DATA + +The following methods return a single value, which is the value for the +corresponding entry in the distmeta structure. Values should be either undef +or strings. + +=over 4 + +=item * + +abstract + +=item * + +description + +=item * + +dynamic_config + +=item * + +generated_by + +=item * + +name + +=item * + +release_status + +=item * + +version + +=back + +=head1 LIST DATA + +These methods return lists of string values, which might be represented in the +distmeta structure as arrayrefs or scalars: + +=over 4 + +=item * + +authors + +=item * + +keywords + +=item * + +licenses + +=back + +The C<authors> and C<licenses> methods may also be called as C<author> and +C<license>, respectively, to match the field name in the distmeta structure. + +=head1 MAP DATA + +These readers return hashrefs of arbitrary unblessed data structures, each +described more fully in the specification: + +=over 4 + +=item * + +meta_spec + +=item * + +resources + +=item * + +provides + +=item * + +no_index + +=item * + +prereqs + +=item * + +optional_features + +=back + +=head1 CUSTOM DATA + +A list of custom keys are available from the C<custom_keys> method and +particular keys may be retrieved with the C<custom> method. + + say $meta->custom($_) for $meta->custom_keys; + +If a custom key refers to a data structure, a deep clone is returned. + +=head1 BUGS + +Please report any bugs or feature using the CPAN Request Tracker. +Bugs can be submitted through the web interface at +L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta> + +When submitting a bug or request, please include a test-file or a patch to an +existing test-file that illustrates the bug or desired feature. + +=head1 SEE ALSO + +=over 4 + +=item * + +L<CPAN::Meta::Converter> + +=item * + +L<CPAN::Meta::Validator> + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + + +__END__ + + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm new file mode 100644 index 0000000000..2c6ce857d3 --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm @@ -0,0 +1,1365 @@ +use 5.006; +use strict; +use warnings; +package CPAN::Meta::Converter; +BEGIN { + $CPAN::Meta::Converter::VERSION = '2.110440'; +} +# ABSTRACT: Convert CPAN distribution metadata structures + + +use CPAN::Meta::Validator; +use Storable qw/dclone/; +use version 0.82 (); + +my %known_specs = ( + '2' => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html', + '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html', + '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html', + '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html', + '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html' +); + +my @spec_list = sort { $a <=> $b } keys %known_specs; +my ($LOWEST, $HIGHEST) = @spec_list[0,-1]; + +#--------------------------------------------------------------------------# +# converters +# +# called as $converter->($element, $field_name, $full_meta, $to_version) +# +# defined return value used for field +# undef return value means field is skipped +#--------------------------------------------------------------------------# + +sub _keep { $_[0] } + +sub _keep_or_one { defined($_[0]) ? $_[0] : 1 } + +sub _keep_or_zero { defined($_[0]) ? $_[0] : 0 } + +sub _keep_or_unknown { defined($_[0]) && length($_[0]) ? $_[0] : "unknown" } + +sub _generated_by { + my $gen = shift; + my $sig = __PACKAGE__ . " version " . (__PACKAGE__->VERSION || "<dev>"); + + return $sig unless defined $gen and length $gen; + return $gen if $gen =~ /(, )\Q$sig/; + return "$gen, $sig"; +} + +sub _listify { ! defined $_[0] ? undef : ref $_[0] eq 'ARRAY' ? $_[0] : [$_[0]] } + +sub _prefix_custom { + my $key = shift; + $key =~ s/^(?!x_) # Unless it already starts with x_ + (?:x-?)? # Remove leading x- or x (if present) + /x_/ix; # and prepend x_ + return $key; +} + +sub _ucfirst_custom { + my $key = shift; + $key = ucfirst $key unless $key =~ /[A-Z]/; + return $key; +} + +sub _change_meta_spec { + my ($element, undef, undef, $version) = @_; + $element->{version} = $version; + $element->{url} = $known_specs{$version}; + return $element; +} + +my @valid_licenses_1 = ( + 'perl', + 'gpl', + 'apache', + 'artistic', + 'artistic_2', + 'lgpl', + 'bsd', + 'gpl', + 'mit', + 'mozilla', + 'open_source', + 'unrestricted', + 'restrictive', + 'unknown', +); + +my %license_map_1 = ( + ( map { $_ => $_ } @valid_licenses_1 ), + artistic2 => 'artistic_2', +); + +sub _license_1 { + my ($element) = @_; + return 'unknown' unless defined $element; + if ( $license_map_1{lc $element} ) { + return $license_map_1{lc $element}; + } + return 'unknown'; +} + +my @valid_licenses_2 = qw( + agpl_3 + apache_1_1 + apache_2_0 + artistic_1 + artistic_2 + bsd + freebsd + gfdl_1_2 + gfdl_1_3 + gpl_1 + gpl_2 + gpl_3 + lgpl_2_1 + lgpl_3_0 + mit + mozilla_1_0 + mozilla_1_1 + openssl + perl_5 + qpl_1_0 + ssleay + sun + zlib + open_source + restricted + unrestricted + unknown +); + +my %license_map_2 = ( + ( map { $_ => $_ } @valid_licenses_2 ), + apache => 'apache_2_0', + artistic => 'artistic_1', + artistic2 => 'artistic_2', + gpl => 'gpl_1', + lgpl => 'lgpl_2_1', + mozilla => 'mozilla_1_0', + perl => 'perl_5', + restrictive => 'restricted', +); + +sub _license_2 { + my ($element) = @_; + return [ 'unknown' ] unless defined $element; + $element = [ $element ] unless ref $element eq 'ARRAY'; + my @new_list; + for my $lic ( @$element ) { + next unless defined $lic; + if ( my $new = $license_map_2{lc $lic} ) { + push @new_list, $new; + } + } + return @new_list ? \@new_list : [ 'unknown' ]; +} + +my %license_downgrade_map = qw( + agpl_3 open_source + apache_1_1 apache + apache_2_0 apache + artistic_1 artistic + artistic_2 artistic_2 + bsd bsd + freebsd open_source + gfdl_1_2 open_source + gfdl_1_3 open_source + gpl_1 gpl + gpl_2 gpl + gpl_3 gpl + lgpl_2_1 lgpl + lgpl_3_0 lgpl + mit mit + mozilla_1_0 mozilla + mozilla_1_1 mozilla + openssl open_source + perl_5 perl + qpl_1_0 open_source + ssleay open_source + sun open_source + zlib open_source + open_source open_source + restricted restrictive + unrestricted unrestricted + unknown unknown +); + +sub _downgrade_license { + my ($element) = @_; + if ( ! defined $element ) { + return "unknown"; + } + elsif( ref $element eq 'ARRAY' ) { + if ( @$element == 1 ) { + return $license_downgrade_map{$element->[0]} || "unknown"; + } + } + elsif ( ! ref $element ) { + return $license_downgrade_map{$element} || "unknown"; + } + return "unknown"; +} + +my $no_index_spec_1_2 = { + 'file' => \&_listify, + 'dir' => \&_listify, + 'package' => \&_listify, + 'namespace' => \&_listify, +}; + +my $no_index_spec_1_3 = { + 'file' => \&_listify, + 'directory' => \&_listify, + 'package' => \&_listify, + 'namespace' => \&_listify, +}; + +my $no_index_spec_2 = { + 'file' => \&_listify, + 'directory' => \&_listify, + 'package' => \&_listify, + 'namespace' => \&_listify, + ':custom' => \&_prefix_custom, +}; + +sub _no_index_1_2 { + my (undef, undef, $meta) = @_; + my $no_index = $meta->{no_index} || $meta->{private}; + return unless $no_index; + + # cleanup wrong format + if ( ! ref $no_index ) { + my $item = $no_index; + $no_index = { dir => [ $item ], file => [ $item ] }; + } + elsif ( ref $no_index eq 'ARRAY' ) { + my $list = $no_index; + $no_index = { dir => [ @$list ], file => [ @$list ] }; + } + + # common mistake: files -> file + if ( exists $no_index->{files} ) { + $no_index->{file} = delete $no_index->{file}; + } + # common mistake: modules -> module + if ( exists $no_index->{modules} ) { + $no_index->{module} = delete $no_index->{module}; + } + return _convert($no_index, $no_index_spec_1_2); +} + +sub _no_index_directory { + my ($element, $key, $meta, $version) = @_; + return unless $element; + + # cleanup wrong format + if ( ! ref $element ) { + my $item = $element; + $element = { directory => [ $item ], file => [ $item ] }; + } + elsif ( ref $element eq 'ARRAY' ) { + my $list = $element; + $element = { directory => [ @$list ], file => [ @$list ] }; + } + + if ( exists $element->{dir} ) { + $element->{directory} = delete $element->{dir}; + } + # common mistake: files -> file + if ( exists $element->{files} ) { + $element->{file} = delete $element->{file}; + } + # common mistake: modules -> module + if ( exists $element->{modules} ) { + $element->{module} = delete $element->{module}; + } + my $spec = $version == 2 ? $no_index_spec_2 : $no_index_spec_1_3; + return _convert($element, $spec); +} + +sub _is_module_name { + my $mod = shift; + return unless defined $mod && length $mod; + return $mod =~ m{^[A-Za-z][A-Za-z0-9_]*(?:::[A-Za-z0-9_]+)*$}; +} + +sub _clean_version { + my ($element, $key, $meta, $to_version) = @_; + return 0 if ! defined $element; + + $element =~ s{^\s*}{}; + $element =~ s{\s*$}{}; + $element =~ s{^\.}{0.}; + + return 0 if ! length $element; + return 0 if ( $element eq 'undef' || $element eq '<undef>' ); + + if ( my $v = eval { version->new($element) } ) { + return $v->is_qv ? $v->normal : $element; + } + else { + return 0; + } +} + +sub _version_map { + my ($element) = @_; + return undef unless defined $element; + if ( ref $element eq 'HASH' ) { + my $new_map = {}; + for my $k ( keys %$element ) { + next unless _is_module_name($k); + my $value = $element->{$k}; + if ( ! ( defined $value && length $value ) ) { + $new_map->{$k} = 0; + } + elsif ( $value eq 'undef' || $value eq '<undef>' ) { + $new_map->{$k} = 0; + } + elsif ( _is_module_name( $value ) ) { # some weird, old META have this + $new_map->{$k} = 0; + $new_map->{$value} = 0; + } + else { + $new_map->{$k} = _clean_version($value); + } + } + return $new_map; + } + elsif ( ref $element eq 'ARRAY' ) { + my $hashref = { map { $_ => 0 } @$element }; + return _version_map($hashref); # cleanup any weird stuff + } + elsif ( ref $element eq '' && length $element ) { + return { $element => 0 } + } + return; +} + +sub _prereqs_from_1 { + my (undef, undef, $meta) = @_; + my $prereqs = {}; + for my $phase ( qw/build configure/ ) { + my $key = "${phase}_requires"; + $prereqs->{$phase}{requires} = _version_map($meta->{$key}) + if $meta->{$key}; + } + for my $rel ( qw/requires recommends conflicts/ ) { + $prereqs->{runtime}{$rel} = _version_map($meta->{$rel}) + if $meta->{$rel}; + } + return $prereqs; +} + +my $prereqs_spec = { + configure => \&_prereqs_rel, + build => \&_prereqs_rel, + test => \&_prereqs_rel, + runtime => \&_prereqs_rel, + develop => \&_prereqs_rel, + ':custom' => \&_prefix_custom, +}; + +my $relation_spec = { + requires => \&_version_map, + recommends => \&_version_map, + suggests => \&_version_map, + conflicts => \&_version_map, + ':custom' => \&_prefix_custom, +}; + +sub _cleanup_prereqs { + my ($prereqs, $key, $meta, $to_version) = @_; + return unless $prereqs && ref $prereqs eq 'HASH'; + return _convert( $prereqs, $prereqs_spec, $to_version ); +} + +sub _prereqs_rel { + my ($relation, $key, $meta, $to_version) = @_; + return unless $relation && ref $relation eq 'HASH'; + return _convert( $relation, $relation_spec, $to_version ); +} + + +BEGIN { + my @old_prereqs = qw( + requires + configure_requires + recommends + conflicts + ); + + for ( @old_prereqs ) { + my $sub = "_get_$_"; + my ($phase,$type) = split qr/_/, $_; + if ( ! defined $type ) { + $type = $phase; + $phase = 'runtime'; + } + no strict 'refs'; + *{$sub} = sub { _extract_prereqs($_[2]->{prereqs},$phase,$type) }; + } +} + +sub _get_build_requires { + my ($data, $key, $meta) = @_; + + my $test_h = _extract_prereqs($_[2]->{prereqs}, qw(test requires)) || {}; + my $build_h = _extract_prereqs($_[2]->{prereqs}, qw(build requires)) || {}; + + require Version::Requirements; + my $test_req = Version::Requirements->from_string_hash($test_h); + my $build_req = Version::Requirements->from_string_hash($build_h); + + $test_req->add_requirements($build_req)->as_string_hash; +} + +sub _extract_prereqs { + my ($prereqs, $phase, $type) = @_; + return unless ref $prereqs eq 'HASH'; + return $prereqs->{$phase}{$type}; +} + +sub _downgrade_optional_features { + my (undef, undef, $meta) = @_; + return undef unless exists $meta->{optional_features}; + my $origin = $meta->{optional_features}; + my $features = {}; + for my $name ( keys %$origin ) { + $features->{$name} = { + description => $origin->{$name}{description}, + requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','requires'), + configure_requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','configure_requires'), + build_requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','build_requires'), + recommends => _extract_prereqs($origin->{$name}{prereqs},'runtime','recommends'), + conflicts => _extract_prereqs($origin->{$name}{prereqs},'runtime','conflicts'), + }; + for my $k (keys %{$features->{$name}} ) { + delete $features->{$name}{$k} unless defined $features->{$name}{$k}; + } + } + return $features; +} + +sub _upgrade_optional_features { + my (undef, undef, $meta) = @_; + return undef unless exists $meta->{optional_features}; + my $origin = $meta->{optional_features}; + my $features = {}; + for my $name ( keys %$origin ) { + $features->{$name} = { + description => $origin->{$name}{description}, + prereqs => _prereqs_from_1(undef, undef, $origin->{$name}), + }; + delete $features->{$name}{prereqs}{configure}; + } + return $features; +} + +my $optional_features_2_spec = { + description => \&_keep, + prereqs => \&_cleanup_prereqs, + ':custom' => \&_prefix_custom, +}; + +sub _feature_2 { + my ($element, $key, $meta, $to_version) = @_; + return unless $element && ref $element eq 'HASH'; + _convert( $element, $optional_features_2_spec, $to_version ); +} + +sub _cleanup_optional_features_2 { + my ($element, $key, $meta, $to_version) = @_; + return unless $element && ref $element eq 'HASH'; + my $new_data = {}; + for my $k ( keys %$element ) { + $new_data->{$k} = _feature_2( $element->{$k}, $k, $meta, $to_version ); + } + return unless keys %$new_data; + return $new_data; +} + +sub _optional_features_1_4 { + my ($element) = @_; + return unless $element; + $element = _optional_features_as_map($element); + for my $name ( keys %$element ) { + for my $drop ( qw/requires_packages requires_os excluded_os/ ) { + delete $element->{$name}{$drop}; + } + } + return $element; +} + +sub _optional_features_as_map { + my ($element) = @_; + return unless $element; + if ( ref $element eq 'ARRAY' ) { + my %map; + for my $feature ( @$element ) { + my (@parts) = %$feature; + $map{$parts[0]} = $parts[1]; + } + $element = \%map; + } + return $element; +} + +sub _is_urlish { defined $_[0] && $_[0] =~ m{\A[-+.a-z0-9]+:.+}i } + +sub _url_or_drop { + my ($element) = @_; + return $element if _is_urlish($element); + return; +} + +sub _url_list { + my ($element) = @_; + return unless $element; + $element = _listify( $element ); + $element = [ grep { _is_urlish($_) } @$element ]; + return unless @$element; + return $element; +} + +sub _author_list { + my ($element) = @_; + return [ 'unknown' ] unless $element; + $element = _listify( $element ); + $element = [ map { defined $_ && length $_ ? $_ : 'unknown' } @$element ]; + return [ 'unknown' ] unless @$element; + return $element; +} + +my $resource2_upgrade = { + license => sub { return _is_urlish($_[0]) ? _listify( $_[0] ) : undef }, + homepage => \&_url_or_drop, + bugtracker => sub { + my ($item) = @_; + return unless $item; + if ( $item =~ m{^mailto:(.*)$} ) { return { mailto => $1 } } + elsif( _is_urlish($item) ) { return { web => $item } } + else { return undef } + }, + repository => sub { return _is_urlish($_[0]) ? { url => $_[0] } : undef }, + ':custom' => \&_prefix_custom, +}; + +sub _upgrade_resources_2 { + my (undef, undef, $meta, $version) = @_; + return undef unless exists $meta->{resources}; + return _convert($meta->{resources}, $resource2_upgrade); +} + +my $bugtracker2_spec = { + web => \&_url_or_drop, + mailto => \&_keep, + ':custom' => \&_prefix_custom, +}; + +sub _repo_type { + my ($element, $key, $meta, $to_version) = @_; + return $element if defined $element; + return unless exists $meta->{url}; + my $repo_url = $meta->{url}; + for my $type ( qw/git svn/ ) { + return $type if $repo_url =~ m{\A$type}; + } + return; +} + +my $repository2_spec = { + web => \&_url_or_drop, + url => \&_url_or_drop, + type => \&_repo_type, + ':custom' => \&_prefix_custom, +}; + +my $resources2_cleanup = { + license => \&_url_list, + homepage => \&_url_or_drop, + bugtracker => sub { ref $_[0] ? _convert( $_[0], $bugtracker2_spec ) : undef }, + repository => sub { my $data = shift; ref $data ? _convert( $data, $repository2_spec ) : undef }, + ':custom' => \&_prefix_custom, +}; + +sub _cleanup_resources_2 { + my ($resources, $key, $meta, $to_version) = @_; + return undef unless $resources && ref $resources eq 'HASH'; + return _convert($resources, $resources2_cleanup, $to_version); +} + +my $resource1_spec = { + license => \&_url_or_drop, + homepage => \&_url_or_drop, + bugtracker => \&_url_or_drop, + repository => \&_url_or_drop, + ':custom' => \&_keep, +}; + +sub _resources_1_3 { + my (undef, undef, $meta, $version) = @_; + return undef unless exists $meta->{resources}; + return _convert($meta->{resources}, $resource1_spec); +} + +*_resources_1_4 = *_resources_1_3; + +sub _resources_1_2 { + my (undef, undef, $meta) = @_; + my $resources = $meta->{resources} || {}; + if ( $meta->{license_url} && ! $resources->{license} ) { + $resources->{license} = $meta->license_url + if _is_urlish($meta->{license_url}); + } + return undef unless keys %$resources; + return _convert($resources, $resource1_spec); +} + +my $resource_downgrade_spec = { + license => sub { return ref $_[0] ? $_[0]->[0] : $_[0] }, + homepage => \&_url_or_drop, + bugtracker => sub { return $_[0]->{web} }, + repository => sub { return $_[0]->{url} || $_[0]->{web} }, + ':custom' => \&_ucfirst_custom, +}; + +sub _downgrade_resources { + my (undef, undef, $meta, $version) = @_; + return undef unless exists $meta->{resources}; + return _convert($meta->{resources}, $resource_downgrade_spec); +} + +sub _release_status { + my ($element, undef, $meta) = @_; + return $element if $element && $element =~ m{\A(?:stable|testing|unstable)\z}; + return _release_status_from_version(undef, undef, $meta); +} + +sub _release_status_from_version { + my (undef, undef, $meta) = @_; + my $version = $meta->{version} || ''; + return ( $version =~ /_/ ) ? 'testing' : 'stable'; +} + +my $provides_spec = { + file => \&_keep, + version => \&_clean_version, +}; + +my $provides_spec_2 = { + file => \&_keep, + version => \&_clean_version, + ':custom' => \&_prefix_custom, +}; + +sub _provides { + my ($element, $key, $meta, $to_version) = @_; + return unless defined $element && ref $element eq 'HASH'; + my $spec = $to_version == 2 ? $provides_spec_2 : $provides_spec; + my $new_data = {}; + for my $k ( keys %$element ) { + $new_data->{$k} = _convert($element->{$k}, $spec, $to_version); + } + return $new_data; +} + +sub _convert { + my ($data, $spec, $to_version) = @_; + + my $new_data = {}; + for my $key ( keys %$spec ) { + next if $key eq ':custom' || $key eq ':drop'; + next unless my $fcn = $spec->{$key}; + die "spec for '$key' is not a coderef" + unless ref $fcn && ref $fcn eq 'CODE'; + my $new_value = $fcn->($data->{$key}, $key, $data, $to_version); + $new_data->{$key} = $new_value if defined $new_value; + } + + my $drop_list = $spec->{':drop'}; + my $customizer = $spec->{':custom'} || \&_keep; + + for my $key ( keys %$data ) { + next if $drop_list && grep { $key eq $_ } @$drop_list; + next if exists $spec->{$key}; # we handled it + $new_data->{ $customizer->($key) } = $data->{$key}; + } + + return $new_data; +} + +#--------------------------------------------------------------------------# +# define converters for each conversion +#--------------------------------------------------------------------------# + +# each converts from prior version +# special ":custom" field is used for keys not recognized in spec +my %up_convert = ( + '2-from-1.4' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_2, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # CHANGED TO MANDATORY + 'dynamic_config' => \&_keep_or_one, + # ADDED MANDATORY + 'release_status' => \&_release_status_from_version, + # PRIOR OPTIONAL + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_upgrade_optional_features, + 'provides' => \&_provides, + 'resources' => \&_upgrade_resources_2, + # ADDED OPTIONAL + 'description' => \&_keep, + 'prereqs' => \&_prereqs_from_1, + + # drop these deprecated fields, but only after we convert + ':drop' => [ qw( + build_requires + configure_requires + conflicts + distribution_type + license_url + private + recommends + requires + ) ], + + # other random keys need x_ prefixing + ':custom' => \&_prefix_custom, + }, + '1.4-from-1.3' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_optional_features_1_4, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_4, + # ADDED OPTIONAL + 'configure_requires' => \&_keep, + + # drop these deprecated fields, but only after we convert + ':drop' => [ qw( + license_url + private + )], + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.3-from-1.2' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_3, + + # drop these deprecated fields, but only after we convert + ':drop' => [ qw( + license_url + private + )], + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.2-from-1.1' => { + # PRIOR MANDATORY + 'version' => \&_keep, + # CHANGED TO MANDATORY + 'license' => \&_license_1, + 'name' => \&_keep, + 'generated_by' => \&_generated_by, + # ADDED MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'meta-spec' => \&_change_meta_spec, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + # ADDED OPTIONAL + 'keywords' => \&_keep, + 'no_index' => \&_no_index_1_2, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'resources' => \&_resources_1_2, + + # drop these deprecated fields, but only after we convert + ':drop' => [ qw( + license_url + private + )], + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.1-from-1.0' => { + # CHANGED TO MANDATORY + 'version' => \&_keep, + # IMPLIED MANDATORY + 'name' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + # ADDED OPTIONAL + 'license_url' => \&_url_or_drop, + 'private' => \&_keep, + + # other random keys are OK if already valid + ':custom' => \&_keep + }, +); + +my %down_convert = ( + '1.4-from-2' => { + # MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_downgrade_license, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # OPTIONAL + 'build_requires' => \&_get_build_requires, + 'configure_requires' => \&_get_configure_requires, + 'conflicts' => \&_get_conflicts, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_downgrade_optional_features, + 'provides' => \&_provides, + 'recommends' => \&_get_recommends, + 'requires' => \&_get_requires, + 'resources' => \&_downgrade_resources, + + # drop these unsupported fields (after conversion) + ':drop' => [ qw( + description + prereqs + release_status + )], + + # custom keys will be left unchanged + ':custom' => \&_keep + }, + '1.3-from-1.4' => { + # MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_3, + + # drop these unsupported fields, but only after we convert + ':drop' => [ qw( + configure_requires + )], + + # other random keys are OK if already valid + ':custom' => \&_keep, + }, + '1.2-from-1.3' => { + # MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_1_2, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_3, + + # other random keys are OK if already valid + ':custom' => \&_keep, + }, + '1.1-from-1.2' => { + # MANDATORY + 'version' => \&_keep, + # IMPLIED MANDATORY + 'name' => \&_keep, + 'meta-spec' => \&_change_meta_spec, + # OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'private' => \&_keep, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + + # drop unsupported fields + ':drop' => [ qw( + abstract + author + provides + no_index + keywords + resources + )], + + # other random keys are OK if already valid + ':custom' => \&_keep, + }, + '1.0-from-1.1' => { + # IMPLIED MANDATORY + 'name' => \&_keep, + 'meta-spec' => \&_change_meta_spec, + 'version' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + + # other random keys are OK if already valid + ':custom' => \&_keep, + }, +); + +my %cleanup = ( + '2' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_2, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # CHANGED TO MANDATORY + 'dynamic_config' => \&_keep_or_one, + # ADDED MANDATORY + 'release_status' => \&_release_status, + # PRIOR OPTIONAL + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_cleanup_optional_features_2, + 'provides' => \&_provides, + 'resources' => \&_cleanup_resources_2, + # ADDED OPTIONAL + 'description' => \&_keep, + 'prereqs' => \&_cleanup_prereqs, + + # drop these deprecated fields, but only after we convert + ':drop' => [ qw( + build_requires + configure_requires + conflicts + distribution_type + license_url + private + recommends + requires + ) ], + + # other random keys need x_ prefixing + ':custom' => \&_prefix_custom, + }, + '1.4' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_optional_features_1_4, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_4, + # ADDED OPTIONAL + 'configure_requires' => \&_keep, + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.3' => { + # PRIOR MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'meta-spec' => \&_change_meta_spec, + 'name' => \&_keep, + 'version' => \&_keep, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'keywords' => \&_keep, + 'no_index' => \&_no_index_directory, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + 'resources' => \&_resources_1_3, + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.2' => { + # PRIOR MANDATORY + 'version' => \&_keep, + # CHANGED TO MANDATORY + 'license' => \&_license_1, + 'name' => \&_keep, + 'generated_by' => \&_generated_by, + # ADDED MANDATORY + 'abstract' => \&_keep_or_unknown, + 'author' => \&_author_list, + 'meta-spec' => \&_change_meta_spec, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + # ADDED OPTIONAL + 'keywords' => \&_keep, + 'no_index' => \&_no_index_1_2, + 'optional_features' => \&_optional_features_as_map, + 'provides' => \&_provides, + 'resources' => \&_resources_1_2, + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.1' => { + # CHANGED TO MANDATORY + 'version' => \&_keep, + # IMPLIED MANDATORY + 'name' => \&_keep, + 'meta-spec' => \&_change_meta_spec, + # PRIOR OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + # ADDED OPTIONAL + 'license_url' => \&_url_or_drop, + 'private' => \&_keep, + + # other random keys are OK if already valid + ':custom' => \&_keep + }, + '1.0' => { + # IMPLIED MANDATORY + 'name' => \&_keep, + 'meta-spec' => \&_change_meta_spec, + 'version' => \&_keep, + # IMPLIED OPTIONAL + 'build_requires' => \&_version_map, + 'conflicts' => \&_version_map, + 'distribution_type' => \&_keep, + 'dynamic_config' => \&_keep_or_one, + 'generated_by' => \&_generated_by, + 'license' => \&_license_1, + 'recommends' => \&_version_map, + 'requires' => \&_version_map, + + # other random keys are OK if already valid + ':custom' => \&_keep, + }, +); + +#--------------------------------------------------------------------------# +# Code +#--------------------------------------------------------------------------# + + +sub new { + my ($class,$data) = @_; + + # create an attributes hash + my $self = { + 'data' => $data, + 'spec' => $data->{'meta-spec'}{'version'} || "1.0", + }; + + # create the object + return bless $self, $class; +} + + +sub convert { + my ($self, %args) = @_; + my $args = { %args }; + + my $new_version = $args->{version} || $HIGHEST; + + my ($old_version) = $self->{spec}; + my $converted = dclone $self->{data}; + + if ( $old_version == $new_version ) { + $converted = _convert( $converted, $cleanup{$old_version}, $old_version ); + my $cmv = CPAN::Meta::Validator->new( $converted ); + unless ( $cmv->is_valid ) { + my $errs = join("\n", $cmv->errors); + die "Failed to clean-up $old_version metadata. Errors:\n$errs\n"; + } + return $converted; + } + elsif ( $old_version > $new_version ) { + my @vers = sort { $b <=> $a } keys %known_specs; + for my $i ( 0 .. $#vers-1 ) { + next if $vers[$i] > $old_version; + last if $vers[$i+1] < $new_version; + my $spec_string = "$vers[$i+1]-from-$vers[$i]"; + $converted = _convert( $converted, $down_convert{$spec_string}, $vers[$i+1] ); + my $cmv = CPAN::Meta::Validator->new( $converted ); + unless ( $cmv->is_valid ) { + my $errs = join("\n", $cmv->errors); + die "Failed to downconvert metadata to $vers[$i+1]. Errors:\n$errs\n"; + } + } + return $converted; + } + else { + my @vers = sort { $a <=> $b } keys %known_specs; + for my $i ( 0 .. $#vers-1 ) { + next if $vers[$i] < $old_version; + last if $vers[$i+1] > $new_version; + my $spec_string = "$vers[$i+1]-from-$vers[$i]"; + $converted = _convert( $converted, $up_convert{$spec_string}, $vers[$i+1] ); + my $cmv = CPAN::Meta::Validator->new( $converted ); + unless ( $cmv->is_valid ) { + my $errs = join("\n", $cmv->errors); + die "Failed to upconvert metadata to $vers[$i+1]. Errors:\n$errs\n"; + } + } + return $converted; + } +} + +1; + + + +=pod + +=head1 NAME + +CPAN::Meta::Converter - Convert CPAN distribution metadata structures + +=head1 VERSION + +version 2.110440 + +=head1 SYNOPSIS + + my $struct = decode_json_file('META.json'); + + my $cmc = CPAN::Meta::Converter->new( $struct ); + + my $new_struct = $cmc->convert( version => "2" ); + +=head1 DESCRIPTION + +This module converts CPAN Meta structures from one form to another. The +primary use is to convert older structures to the most modern version of +the specification, but other transformations may be implemented in the +future as needed. (E.g. stripping all custom fields or stripping all +optional fields.) + +=head1 METHODS + +=head2 new + + my $cmc = CPAN::Meta::Converter->new( $struct ); + +The constructor should be passed a valid metadata structure but invalid +structures are accepted. If no meta-spec version is provided, version 1.0 will +be assumed. + +=head2 convert + + my $new_struct = $cmc->convert( version => "2" ); + +Returns a new hash reference with the metadata converted to a different form. +C<convert> will die if any conversion/standardization still results in an +invalid structure. + +Valid parameters include: + +=over + +=item * + +C<version> -- Indicates the desired specification version (e.g. "1.0", "1.1" ... "1.4", "2"). +Defaults to the latest version of the CPAN Meta Spec. + +=back + +Conversion proceeds through each version in turn. For example, a version 1.2 +structure might be converted to 1.3 then 1.4 then finally to version 2. The +conversion process attempts to clean-up simple errors and standardize data. +For example, if C<author> is given as a scalar, it will converted to an array +reference containing the item. (Converting a structure to its own version will +also clean-up and standardize.) + +When data are cleaned and standardized, missing or invalid fields will be +replaced with sensible defaults when possible. This may be lossy or imprecise. +For example, some badly structured META.yml files on CPAN have prerequisite +modules listed as both keys and values: + + requires => { 'Foo::Bar' => 'Bam::Baz' } + +These would be split and each converted to a prerequisite with a minimum +version of zero. + +When some mandatory fields are missing or invalid, the conversion will attempt +to provide a sensible default or will fill them with a value of 'unknown'. For +example a missing or unrecognized C<license> field will result in a C<license> +field of 'unknown'. Fields that may get an 'unknown' include: + +=over 4 + +=item * + +abstract + +=item * + +author + +=item * + +license + +=back + +=head1 BUGS + +Please report any bugs or feature using the CPAN Request Tracker. +Bugs can be submitted through the web interface at +L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta> + +When submitting a bug or request, please include a test-file or a patch to an +existing test-file that illustrates the bug or desired feature. + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + + +__END__ + + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm new file mode 100644 index 0000000000..d3575e5e7e --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm @@ -0,0 +1,116 @@ +use 5.006; +use strict; +use warnings; +package CPAN::Meta::Feature; +BEGIN { + $CPAN::Meta::Feature::VERSION = '2.110440'; +} +# ABSTRACT: an optional feature provided by a CPAN distribution + +use CPAN::Meta::Prereqs; + + +sub new { + my ($class, $identifier, $spec) = @_; + + my %guts = ( + identifier => $identifier, + description => $spec->{description}, + prereqs => CPAN::Meta::Prereqs->new($spec->{prereqs}), + ); + + bless \%guts => $class; +} + + +sub identifier { $_[0]{identifier} } + + +sub description { $_[0]{description} } + + +sub prereqs { $_[0]{prereqs} } + +1; + + + +=pod + +=head1 NAME + +CPAN::Meta::Feature - an optional feature provided by a CPAN distribution + +=head1 VERSION + +version 2.110440 + +=head1 DESCRIPTION + +A CPAN::Meta::Feature object describes an optional feature offered by a CPAN +distribution and specified in the distribution's F<META.json> (or F<META.yml>) +file. + +For the most part, this class will only be used when operating on the result of +the C<feature> or C<features> methods on a L<CPAN::Meta> object. + +=head1 METHODS + +=head2 new + + my $feature = CPAN::Meta::Feature->new( $identifier => \%spec ); + +This returns a new Feature object. The C<%spec> argument to the constructor +should be the same as the value of the C<optional_feature> entry in the +distmeta. It must contain entries for C<description> and C<prereqs>. + +=head2 identifier + +This method returns the feature's identifier. + +=head2 description + +This method returns the feature's long description. + +=head2 prereqs + +This method returns the feature's prerequisites as a L<CPAN::Meta::Prereqs> +object. + +=head1 BUGS + +Please report any bugs or feature using the CPAN Request Tracker. +Bugs can be submitted through the web interface at +L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta> + +When submitting a bug or request, please include a test-file or a patch to an +existing test-file that illustrates the bug or desired feature. + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + + +__END__ + + + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm new file mode 100644 index 0000000000..ab036907a4 --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm @@ -0,0 +1,315 @@ +# vi:tw=72 +use 5.006; +use strict; +use warnings; +package CPAN::Meta::History; +BEGIN { + $CPAN::Meta::History::VERSION = '2.110440'; +} +# ABSTRACT: history of CPAN Meta Spec changes +1; + + + +__END__ +=pod + +=head1 NAME + +CPAN::Meta::History - history of CPAN Meta Spec changes + +=head1 VERSION + +version 2.110440 + +=head1 DESCRIPTION + +The CPAN Meta Spec has gone through several iterations. It was +originally written in HTML and later revised into POD (though published +in HTML generated from the POD). Fields were added, removed or changed, +sometimes by design and sometimes to reflect real-world usage after the +fact. + +This document reconstructs the history of the CPAN Meta Spec based on +change logs, repository commit messages and the published HTML files. +In some cases, particularly prior to version 1.2, the exact version +when certain fields were introduced or changed is inconsistent between +sources. When in doubt, the published HTML files for versions 1.0 to +1.4 as they existed when version 2 was developed are used as the +definitive source. + +Starting with version 2, the specification document is part of the +CPAN-Meta distribution and will be published on CPAN as +L<CPAN::Meta::Spec>. + +Going forward, specification version numbers will be integers and +decimal portions will correspond to a release date for the CPAN::Meta +library. + +=head1 HISTORY + +=head2 Version 2 + +April 2010 + +=over + +=item * + +Revised spec examples as perl data structures rather than YAML + +=item * + +Switched to JSON serialization from YAML + +=item * + +Specified allowed version number formats + +=item * + +Replaced 'requires', 'build_requires', 'configure_requires', +'recommends' and 'conflicts' with new 'prereqs' data structure divided +by I<phase> (configure, build, test, runtime, etc.) and I<relationship> +(requires, recommends, suggests, conflicts) + +=item * + +Added support for 'develop' phase for requirements for maintaining +a list of authoring tools + +=item * + +Changed 'license' to a list and revised the set of valid licenses + +=item * + +Made 'dynamic_config' mandatory to reduce confusion + +=item * + +Changed 'resources' subkey 'repository' to a hash that clarifies +repository type, url for browsing and url for checkout + +=item * + +Changed 'resources' subkey 'bugtracker' to a hash for either web +or mailto resource + +=item * + +Changed specification of 'optional_features': + +=over + +=item * + +Added formal specification and usage guide instead of just example + +=item * + +Changed to use new prereqs data structure instead of individual keys + +=back + +=item * + +Clarified intended use of 'author' as generalized contact list + +=item * + +Added 'release_status' field to indicate stable, testing or unstable +status to provide hints to indexers + +=item * + +Added 'description' field for a longer description of the distribution + +=item * + +Formalized use of "x_" or "X_" for all custom keys not listed in the +official spec + +=back + +=head2 Version 1.4 + +June 2008 + +=over + +=item * + +Noted explicit support for 'perl' in prerequisites + +=item * + +Added 'configure_requires' prerequisite type + +=item * + +Changed 'optional_features' + +=over + +=item * + +Example corrected to show map of maps instead of list of maps +(though descriptive text said 'map' even in v1.3) + +=item * + +Removed 'requires_packages', 'requires_os' and 'excluded_os' +as valid subkeys + +=back + +=back + +=head2 Version 1.3 + +November 2006 + +=over + +=item * + +Clarified that all prerequisites take version range specifications + +=item * + +Added 'no_index' subkey 'directory' and removed 'dir' to match actual +usage in the wild + +=item * + +Added a 'repository' subkey to 'resources' + +=back + +=head2 Version 1.2 + +August 2005 + +=over + +=item * + +Re-wrote and restructured spec in POD syntax + +=item * + +Changed 'name' to be mandatory + +=item * + +Changed 'generated_by' to be mandatory + +=item * + +Changed 'license' to be mandatory + +=item * + +Added required 'abstract' field + +=item * + +Added required 'author' field + +=item * + +Added required 'meta-spec' field to define 'version' (and 'url') of the +CPAN Meta Spec used for metadata + +=item * + +Added 'provides' field + +=item * + +Added 'no_index' field and deprecated 'private' field. 'no_index' +subkeys include 'file', 'dir', 'package' and 'namespace' + +=item * + +Added 'keywords' field + +=item * + +Added 'resources' field with subkeys 'homepage', 'license', and +'bugtracker' + +=item * + +Added 'optional_features' field as an alterate under 'recommends'. +Includes 'description', 'requires', 'build_requires', 'conflicts', +'requires_packages', 'requires_os' and 'excluded_os' as valid subkeys + +=item * + +Removed 'license_uri' field + +=back + +=head2 Version 1.1 + +May 2003 + +=over + +=item * + +Changed 'version' to be mandatory + +=item * + +Added 'private' field + +=item * + +Added 'license_uri' field + +=back + +=head2 Version 1.0 + +March 2003 + +=over + +=item * + +Original release (in HTML format only) + +=item * + +Included 'name', 'version', 'license', 'distribution_type', 'requires', +'recommends', 'build_requires', 'conflicts', 'dynamic_config', +'generated_by' + +=back + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm new file mode 100644 index 0000000000..4fc20939ab --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm @@ -0,0 +1,277 @@ +use 5.006; +use strict; +use warnings; +package CPAN::Meta::Prereqs; +BEGIN { + $CPAN::Meta::Prereqs::VERSION = '2.110440'; +} +# ABSTRACT: a set of distribution prerequisites by phase and type + + +use Carp qw(confess); +use Scalar::Util qw(blessed); +use Version::Requirements 0.101020; # finalize + + +sub __legal_phases { qw(configure build test runtime develop) } +sub __legal_types { qw(requires recommends suggests conflicts) } + +# expect a prereq spec from META.json -- rjbs, 2010-04-11 +sub new { + my ($class, $prereq_spec) = @_; + $prereq_spec ||= {}; + + my %is_legal_phase = map {; $_ => 1 } $class->__legal_phases; + my %is_legal_type = map {; $_ => 1 } $class->__legal_types; + + my %guts; + PHASE: for my $phase (keys %$prereq_spec) { + next PHASE unless $phase =~ /\Ax_/i or $is_legal_phase{$phase}; + + my $phase_spec = $prereq_spec->{ $phase }; + next PHASE unless keys %$phase_spec; + + TYPE: for my $type (keys %$phase_spec) { + next TYPE unless $type =~ /\Ax_/i or $is_legal_type{$type}; + + my $spec = $phase_spec->{ $type }; + + next TYPE unless keys %$spec; + + $guts{prereqs}{$phase}{$type} = Version::Requirements->from_string_hash( + $spec + ); + } + } + + return bless \%guts => $class; +} + + +sub requirements_for { + my ($self, $phase, $type) = @_; + + confess "requirements_for called without phase" unless defined $phase; + confess "requirements_for called without type" unless defined $type; + + unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) { + confess "requested requirements for unknown phase: $phase"; + } + + unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) { + confess "requested requirements for unknown type: $type"; + } + + my $req = ($self->{prereqs}{$phase}{$type} ||= Version::Requirements->new); + + $req->finalize if $self->is_finalized; + + return $req; +} + + +sub with_merged_prereqs { + my ($self, $other) = @_; + + my @other = blessed($other) ? $other : @$other; + + my @prereq_objs = ($self, @other); + + my %new_arg; + + for my $phase ($self->__legal_phases) { + for my $type ($self->__legal_types) { + my $req = Version::Requirements->new; + + for my $prereq (@prereq_objs) { + my $this_req = $prereq->requirements_for($phase, $type); + next unless $this_req->required_modules; + + $req->add_requirements($this_req); + } + + next unless $req->required_modules; + + $new_arg{ $phase }{ $type } = $req->as_string_hash; + } + } + + return (ref $self)->new(\%new_arg); +} + + +sub as_string_hash { + my ($self) = @_; + + my %hash; + + for my $phase ($self->__legal_phases) { + for my $type ($self->__legal_types) { + my $req = $self->requirements_for($phase, $type); + next unless $req->required_modules; + + $hash{ $phase }{ $type } = $req->as_string_hash; + } + } + + return \%hash; +} + + +sub is_finalized { $_[0]{finalized} } + + +sub finalize { + my ($self) = @_; + + $self->{finalized} = 1; + + for my $phase (keys %{ $self->{prereqs} }) { + $_->finalize for values %{ $self->{prereqs}{$phase} }; + } +} + + +sub clone { + my ($self) = @_; + + my $clone = (ref $self)->new( $self->as_string_hash ); +} + +1; + + + +=pod + +=head1 NAME + +CPAN::Meta::Prereqs - a set of distribution prerequisites by phase and type + +=head1 VERSION + +version 2.110440 + +=head1 DESCRIPTION + +A CPAN::Meta::Prereqs object represents the prerequisites for a CPAN +distribution or one of its optional features. Each set of prereqs is +organized by phase and type, as described in L<CPAN::Meta::Prereqs>. + +=head1 METHODS + +=head2 new + + my $prereq = CPAN::Meta::Prereqs->new( \%prereq_spec ); + +This method returns a new set of Prereqs. The input should look like the +contents of the C<prereqs> field described in L<CPAN::Meta::Spec>, meaning +something more or less like this: + + my $prereq = CPAN::Meta::Prereqs->new({ + runtime => { + requires => { + 'Some::Module' => '1.234', + ..., + }, + ..., + }, + ..., + }); + +You can also construct an empty set of prereqs with: + + my $prereqs = CPAN::Meta::Prereqs->new; + +This empty set of prereqs is useful for accumulating new prereqs before finally +dumping the whole set into a structure or string. + +=head2 requirements_for + + my $requirements = $prereqs->requirements_for( $phase, $type ); + +This method returns a L<Version::Requirements> object for the given phase/type +combination. If no prerequisites are registered for that combination, a new +Version::Requirements object will be returned, and it may be added to as +needed. + +If C<$phase> or C<$type> are undefined or otherwise invalid, an exception will +be raised. + +=head2 with_merged_prereqs + + my $new_prereqs = $prereqs->with_merged_prereqs( $other_prereqs ); + + my $new_prereqs = $prereqs->with_merged_prereqs( \@other_prereqs ); + +This method returns a new CPAN::Meta::Prereqs objects in which all the +other prerequisites given are merged into the current set. This is primarily +provided for combining a distribution's core prereqs with the prereqs of one of +its optional features. + +The new prereqs object has no ties to the originals, and altering it further +will not alter them. + +=head2 as_string_hash + +This method returns a hashref containing structures suitable for dumping into a +distmeta data structure. It is made up of hashes and strings, only; there will +be no Prereqs, Version::Requirements, or C<version> objects inside it. + +=head2 is_finalized + +This method returns true if the set of prereqs has been marked "finalized," and +cannot be altered. + +=head2 finalize + +Calling C<finalize> on a Prereqs object will close it for further modification. +Attempting to make any changes that would actually alter the prereqs will +result in an exception being thrown. + +=head2 clone + + my $cloned_prereqs = $prereqs->clone; + +This method returns a Prereqs object that is identical to the original object, +but can be altered without affecting the original object. Finalization does +not survive cloning, meaning that you may clone a finalized set of prereqs and +then modify the clone. + +=head1 BUGS + +Please report any bugs or feature using the CPAN Request Tracker. +Bugs can be submitted through the web interface at +L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta> + +When submitting a bug or request, please include a test-file or a patch to an +existing test-file that illustrates the bug or desired feature. + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + + +__END__ + + + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm new file mode 100644 index 0000000000..8f94c718cb --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm @@ -0,0 +1,1145 @@ +# vi:tw=72 +use 5.006; +use strict; +use warnings; +package CPAN::Meta::Spec; +BEGIN { + $CPAN::Meta::Spec::VERSION = '2.110440'; +} +# ABSTRACT: specification for CPAN distribution metadata +1; + + + +__END__ +=pod + +=head1 NAME + +CPAN::Meta::Spec - specification for CPAN distribution metadata + +=head1 VERSION + +version 2.110440 + +=head1 SYNOPSIS + + my $distmeta = { + name => 'Module-Build', + abstract => 'Build and install Perl modules', + description => "Module::Build is a system for " + . "building, testing, and installing Perl modules. " + . "It is meant to ... blah blah blah ...", + version => '0.36', + author => [ + 'Ken Williams <kwilliams@cpan.org>', + 'Module-Build List <module-build@perl.org>', # additional contact + ], + license => [ 'perl_5' ], + prereqs => { + runtime => { + requires => { + 'perl' => '5.006', + 'ExtUtils::Install' => '0', + 'File::Basename' => '0', + 'File::Compare' => '0', + 'IO::File' => '0', + }, + recommends => { + 'Archive::Tar' => '1.00', + 'ExtUtils::Install' => '0.3', + 'ExtUtils::ParseXS' => '2.02', + }, + }, + build => { + requires => { + 'Test::More' => '0', + }, + } + }, + resources => { + license => ['http://dev.perl.org/licenses/'], + }, + optional_features => { + domination => { + description => 'Take over the world', + prereqs => { + develop => { requires => { 'Genius::Evil' => '1.234' } }, + runtime => { requires => { 'Machine::Weather' => '2.0' } }, + }, + }, + }, + dynamic_config => 1, + keywords => [ qw/ toolchain cpan dual-life / ], + 'meta-spec' => { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + }, + generated_by => 'Module::Build version 0.36', + }; + +=head1 DESCRIPTION + +This document describes version 2 of the CPAN distribution metadata +specification, also known as the "CPAN Meta Spec". + +Revisions of this specification for typo corrections and prose +clarifications may be issued as CPAN::Meta::Spec 2.I<x>. These +revisions will never change semantics or add or remove specified +behavior. + +Distribution metadata describe important properties of Perl +distributions. Distribution building tools like Module::Build, +Module::Install, ExtUtils::MakeMaker or Dist::Zilla should create a +metadata file in accordance with this specification and include it with +the distribution for use by automated tools that index, examine, package +or install Perl distributions. + +=head1 TERMINOLOGY + +=over 4 + +=item distribution + +This is the primary object described by the metadata. In the context of +this document it usually refers to a collection of modules, scripts, +and/or documents that are distributed together for other developers to +use. Examples of distributions are C<Class-Container>, C<libwww-perl>, +or C<DBI>. + +=item module + +This refers to a reusable library of code contained in a single file. +Modules usually contain one or more packages and are often referred +to by the name of a primary package that can be mapped to the file +name. For example, one might refer to C<File::Spec> instead of +F<File/Spec.pm> + +=item package + +This refers to a namespace declared with the Perl C<package> statement. +In Perl, packages often have a version number property given by the +C<$VERSION> variable in the namespace. + +=item consumer + +This refers to code that reads a metadata file, deserializes it into a +data structure in memory, or interprets a data structure of metadata +elements. + +=item producer + +This refers to code that constructs a metadata data structure, +serializes into a bytestream and/or writes it to disk. + +=item must, should, may, etc. + +These terms are interpreted as described in IETF RFC 2119. + +=back + +=head1 DATA TYPES + +Fields in the L</STRUCTURE> section describe data elements, each of +which has an associated data type as described herein. There are four +primitive types: Boolean, String, List and Map. Other types are +subtypes of primitives and define compound data structures or define +constraints on the values of a data element. + +=head2 Boolean + +A I<Boolean> is used to provide a true or false value. It B<must> be +represented as a defined value. + +=head2 String + +A I<String> is data element containing a non-zero length sequence of +Unicode characters, such as an ordinary Perl scalar that is not a +reference. + +=head2 List + +A I<List> is an ordered collection of zero or more data elements. +Elements of a List may be of mixed types. + +Producers B<must> represent List elements using a data structure which +unambiguously indicates that multiple values are possible, such as a +reference to a Perl array (an "arrayref"). + +Consumers expecting a List B<must> consider a String as equivalent to a +List of length 1. + +=head2 Map + +A I<Map> is an unordered collection of zero or more data elements +("values"), indexed by associated String elements ("keys"). The Map's +value elements may be of mixed types. + +=head2 License String + +A I<License String> is a subtype of String with a restricted set of +values. Valid values are described in detail in the description of +the L</license> field. + +=head2 URL + +I<URL> is a subtype of String containing a Uniform Resource Locator or +Identifier. [ This type is called URL and not URI for historical reasons. ] + +=head2 Version + +A I<Version> is a subtype of String containing a value that describes +the version number of packages or distributions. Restrictions on format +are described in detail in the L</Version Formats> section. + +=head2 Version Range + +The I<Version Range> type is a subtype of String. It describes a range +of Versions that may be present or installed to fulfill prerequisites. +It is specified in detail in the L</Version Ranges> section. + +=head1 STRUCTURE + +The metadata structure is a data element of type Map. This section +describes valid keys within the Map. + +Any keys not described in this specification document (whether top-level +or within compound data structures described herein) are considered +I<custom keys> and B<must> begin with an "x" or "X" and be followed by an +underscore; i.e. they must match the pattern: C<< qr{\Ax_}i >>. If a +custom key refers to a compound data structure, subkeys within it do not +need an "x_" or "X_" prefix. + +Consumers of metadata may ignore any or all custom keys. All other keys +not described herein are invalid and should be ignored by consumers. +Producers must not generate or output invalid keys. + +For each key, an example is provided followed by a description. The +description begins with the version of spec in which the key was added +or in which the definition was modified, whether the key is I<required> +or I<optional> and the data type of the corresponding data element. +These items are in parentheses, brackets and braces, respectively. + +If a data type is a Map or Map subtype, valid subkeys will be described +as well. + +Some fields are marked I<Deprecated>. These are shown for historical +context and must not be produced in or consumed from any metadata structure +of version 2 or higher. + +=head2 REQUIRED FIELDS + +=head3 abstract + +Example: + + abstract => 'Build and install Perl modules' + +(Spec 1.2) [required] {String} + +This is a short description of the purpose of the distribution. + +=head3 author + +Example: + + author => [ 'Ken Williams <kwilliams@cpan.org>' ] + +(Spec 1.2) [required] {List of one or more Strings} + +This List indicates the person(s) to contact concerning the +distribution. The preferred form of the contact string is: + + contact-name <email-address> + +This field provides a general contact list independent of other +structured fields provided within the L</resources> field, such as +C<bugtracker>. The addressee(s) can be contacted for any purpose +including but not limited to (security) problems with the distribution, +questions about the distribution or bugs in the distribution. + +A distribution's original author is usually the contact listed within +this field. Co-maintainers, successor maintainers or mailing lists +devoted to the distribution may also be listed in addition to or instead +of the original author. + +=head3 dynamic_config + +Example: + + dynamic_config => 1 + +(Spec 2) [required] {Boolean} + +A boolean flag indicating whether a F<Build.PL> or F<Makefile.PL> (or +similar) must be executed to determine prerequisites. + +This field should be set to a true value if the distribution performs +some dynamic configuration (asking questions, sensing the environment, +etc.) as part of its configuration. This field should be set to a false +value to indicate that prerequisites included in metadata may be +considered final and valid for static analysis. + +This field explicitly B<does not> indicate whether installation may be +safely performed without using a Makefile or Build file, as there may be +special files to install or custom installation targets (e.g. for +dual-life modules that exist on CPAN as well as in the Perl core). This +field only defines whether prerequisites are complete as given in the +metadata. + +=head3 generated_by + +Example: + + generated_by => 'Module::Build version 0.36' + +(Spec 1.0) [required] {String} + +This field indicates the tool that was used to create this metadata. +There are no defined semantics for this field, but it is traditional to +use a string in the form "Generating::Package version 1.23" or the +author's name, if the file was generated by hand. + +=head3 license + +Example: + + license => [ 'perl_5' ] + + license => [ 'apache_2', 'mozilla_1_0' ] + +(Spec 2) [required] {List of one or more License Strings} + +One or more licenses that apply to some or all of the files in the +distribution. If multiple licenses are listed, the distribution +documentation should be consulted to clarify the interpretation of +multiple licenses. + +The following list of license strings are valid: + + string description + ------------- ----------------------------------------------- + agpl_3 GNU Affero General Public License, Version 3 + apache_1_1 Apache Software License, Version 1.1 + apache_2_0 Apache License, Version 2.0 + artistic_1 Artistic License, (Version 1) + artistic_2 Artistic License, Version 2.0 + bsd BSD License (three-clause) + freebsd FreeBSD License (two-clause) + gfdl_1_2 GNU Free Documentation License, Version 1.2 + gfdl_1_3 GNU Free Documentation License, Version 1.3 + gpl_1 GNU General Public License, Version 1 + gpl_2 GNU General Public License, Version 2 + gpl_3 GNU General Public License, Version 3 + lgpl_2_1 GNU Lesser General Public License, Version 2.1 + lgpl_3_0 GNU Lesser General Public License, Version 3.0 + mit MIT (aka X11) License + mozilla_1_0 Mozilla Public License, Version 1.0 + mozilla_1_1 Mozilla Public License, Version 1.1 + openssl OpenSSL License + perl_5 The Perl 5 License (Artistic 1 & GPL 1 or later) + qpl_1_0 Q Public License, Version 1.0 + ssleay Original SSLeay License + sun Sun Internet Standards Source License (SISSL) + zlib zlib License + +The following license strings are also valid and indicate other +licensing not described above: + + string description + ------------- ----------------------------------------------- + open_source Other Open Source Initiative (OSI) approved license + restricted Requires special permission from copyright holder + unrestricted Not an OSI approved license, but not restricted + unknown License not provided in metadata + +All other strings are invalid in the license field. + +=head3 meta-spec + +Example: + + 'meta-spec' => { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + } + +(Spec 1.2) [required] {Map} + +This field indicates the version of the CPAN Meta Spec that should be +used to interpret the metadata. Consumers must check this key as soon +as possible and abort further metadata processing if the meta-spec +version is not supported by the consumer. + +The following keys are valid, but only C<version> is required. + +=over + +=item version + +This subkey gives the integer I<Version> of the CPAN Meta Spec against +which the document was generated. + +=item url + +This is a I<URL> of the metadata specification document corresponding to +the given version. This is strictly for human-consumption and should +not impact the interpretation of the document. + +=back + +=head3 name + +Example: + + name => 'Module-Build' + +(Spec 1.0) [required] {String} + +This field is the name of the distribution. This is often created by +taking the "main package" in the distribution and changing C<::> to +C<->, but the name may be completely unrelated to the packages within +the distribution. C.f. L<http://search.cpan.org/dist/libwww-perl/>. + +=head3 release_status + +Example: + + release_status => 'stable' + +(Spec 2) [required] {String} + +This field provides the release status of this distribution. If the +C<version> field contains an underscore character, then +C<release_status> B<must not> be "stable." + +The C<release_status> field B<must> have one of the following values: + +=over + +=item stable + +This indicates an ordinary, "final" release that should be indexed by PAUSE +or other indexers. + +=item testing + +This indicates a "beta" release that is substantially complete, but has an +elevated risk of bugs and requires additional testing. The distribution +should not be installed over a stable release without an explicit request +or other confirmation from a user. This release status may also be used +for "release candidate" versions of a distribution. + +=item unstable + +This indicates an "alpha" release that is under active development, but has +been released for early feedback or testing and may be missing features or +may have serious bugs. The distribution should not be installed over a +stable release without an explicit request or other confirmation from a +user. + +=back + +Consumers B<may> use this field to determine how to index the +distribution for CPAN or other repositories in addition to or in +replacement of heuristics based on version number or file name. + +=head3 version + +Example: + + version => '0.36' + +(Spec 1.0) [required] {Version} + +This field gives the version of the distribution to which the metadata +structure refers. + +=head2 OPTIONAL FIELDS + +=head3 description + +Example: + + description => "Module::Build is a system for " + . "building, testing, and installing Perl modules. " + . "It is meant to ... blah blah blah ...", + +(Spec 2) [optional] {String} + +A longer, more complete description of the purpose or intended use of +the distribution than the one provided by the C<abstract> key. + +=head3 keywords + +Example: + + keywords => [ qw/ toolchain cpan dual-life / ] + +(Spec 1.1) [optional] {List of zero or more Strings} + +A List of keywords that describe this distribution. Keywords +B<must not> include whitespace. + +=head3 no_index + +Example: + + no_index => { + file => [ 'My/Module.pm' ], + directory => [ 'My/Private' ], + package => [ 'My::Module::Secret' ], + namespace => [ 'My::Module::Sample' ], + } + +(Spec 1.2) [optional] {Map} + +This Map describes any files, directories, packages, and namespaces that +are private to the packaging or implementation of the distribution and +should be ignored by indexing or search tools. + +Valid subkeys are as follows: + +=over + +=item file + +A I<List> of relative paths to files. Paths B<must be> specified with +unix convetions. + +=item directory + +A I<List> of relative paths to directories. Paths B<must be> specified +with unix convetions. + +[ Note: previous editions of the spec had C<dir> instead of C<directory> ] + +=item package + +A I<List> of package names. + +=item namespace + +A I<List> of package namespaces, where anything below the namespace +must be ignored, but I<not> the namespace itself. + +In the example above for C<no_index>, C<My::Module::Sample::Foo> would +be ignored, but C<My::Module::Sample> would not. + +=back + +=head3 optional_features + +Example: + + optional_features => { + sqlite => { + description => 'Provides SQLite support', + prereqs => { + runtime => { + requires => { + 'DBD::SQLite' => '1.25' + } + } + } + } + } + +(Spec 2) [optional] {Map} + +This Map describes optional features with incremental prerequisites. +Each key of the C<optional_features> Map is a String used to identify +the feature and each value is a Map with additional information about +the feature. Valid subkeys include: + +=over + +=item description + +This is a String describing the feature. Every optional feature +should provide a description + +=item prereqs + +This entry is required and has the same structure as that of the +C<L</prereqs>> key. It provides a list of package requirements +that must be satisfied for the feature to be supported or enabled. + +There is one crucial restriction: the preqreqs of an optional feature +B<must not> include C<configure> phase prereqs. + +=back + +Consumers B<must not> include optional features as prerequisites without +explict instruction from users (whether via interactive prompting, +a function parameter or a configuration value, etc. ). + +If an optional feature is used by a consumer to add additional +prerequisites, the consumer should merge the optional feature +prerequisites into those given by the C<prereqs> key using the same +semantics. See L</Merging and Resolving Prerequisites> for details on +merging prerequisites. + +I<Suggestion for disuse:> Because there is currently no way for a +distribution to specify a dependency on an optional feature of another +dependency, the use of C<optional_feature> is discouraged. Instead, +create a separate, installable distribution that ensures the desired +feature is available. For example, if C<Foo::Bar> has a "Baz" feature, +release a separate C<Foo-Bar-Baz> distribution that satisfies +requirements for the feature. + +=head3 prereqs + +Example: + + prereqs => { + runtime => { + requires => { + 'perl' => '5.006', + 'File::Spec' => '0.86', + 'JSON' => '2.16', + }, + recommends => { + 'JSON::XS' => '2.26', + }, + suggests => { + 'Archive::Tar' => '0', + }, + }, + build => { + requires => { + 'Alien::SDL' => '1.00', + }, + }, + test => { + recommends => { + 'Test::Deep' => '0.10', + }, + } + } + +(Spec 2) [optional] {Map} + +This is a Map that describes all the prerequisites of the distribution. +The keys are phases of activity, such as C<configure>, C<build>, C<test> +or C<runtime>. Values are Maps in which the keys name the type of +prerequisite relationship such as C<requires>, C<recommends>, or +C<suggests> and the value provides a set of prerequisite relations. The +set of relations B<must> be specified as a Map of package names to +version ranges. + +The full definition for this field is given in the L</Prereq Spec> +section. + +=head3 provides + +Example: + + provides => { + 'Foo::Bar' => { + file => 'lib/Foo/Bar.pm', + version => 0.27_02 + }, + 'Foo::Bar::Blah' => { + file => 'lib/Foo/Bar/Blah.pm', + }, + 'Foo::Bar::Baz' => { + file => 'lib/Foo/Bar/Baz.pm', + version => 0.3, + }, + } + +(Spec 1.2) [optional] {Map} + +This describes all packages provided by this distribution. This +information is used by distribution and automation mechanisms like +PAUSE, CPAN, and search.cpan.org to build indexes saying in which +distribution various packages can be found. + +The keys of C<provides> are package names that can be found within +the distribution. The values are Maps with the following valid subkeys: + +=over + +=item file + +This field is required. The value must contain a relative file path +from the root of the distribution to the module containing the package. + +=item version + +This field contains a I<Version> String for the package, if one exists. + +=back + +=head3 resources + +Example: + + resources => { + license => [ 'http://dev.perl.org/licenses/' ], + homepage => 'http://sourceforge.net/projects/module-build', + bugtracker => { + web => 'http://github.com/dagolden/cpan-meta-spec/issues', + mailto => 'meta-bugs@example.com', + }, + repository => { + url => 'git://github.com/dagolden/cpan-meta-spec.git', + web => 'http://github.com/dagolden/cpan-meta-spec', + type => 'git', + }, + x_twitter => 'http://twitter.com/cpan_linked/', + } + +(Spec 2) [optional] {Map} + +This field describes resources related to this distribution. + +Valid subkeys include: + +=over + +=item homepage + +The official home of this project on the web. + +=item license + +A List of I<URL>'s that relate to this distribution's license. As with the +top-level C<license> field, distribution documentation should be consulted +to clarify the interpretation of multiple licenses provided here. + +=item bugtracker + +This entry describes the bug tracking system for this distribution. It +is a Map with the following valid keys: + + web - a URL pointing to a web front-end for the bug tracker + mailto - an email address to which bugs can be sent + +=item repository + +This entry describes the source control repository for this distribution. It +is a Map with the following valid keys: + + url - a URL pointing to the repository itself + web - a URL pointing to a web front-end for the repository + type - a lowercase string indicating the VCS used + +Because a url like C<http://myrepo.example.com/> is ambiguous as to +type, producers should provide a C<type> whenever a C<url> key is given. +The C<type> field should be the name of the most common program used +to work with the repository, e.g. git, svn, cvs, darcs, bzr or hg. + +=back + +=head2 DEPRECATED FIELDS + +=head3 build_requires + +I<(Deprecated in Spec 2)> [optional] {String} + +Replaced by C<prereqs> + +=head3 configure_requires + +I<(Deprecated in Spec 2)> [optional] {String} + +Replaced by C<prereqs> + +=head3 conflicts + +I<(Deprecated in Spec 2)> [optional] {String} + +Replaced by C<prereqs> + +=head3 distribution_type + +I<(Deprecated in Spec 2)> [optional] {String} + +This field indicated 'module' or 'script' but was considered +meaningless, since many distributions are hybrids of several kinds of +things. + +=head3 license_uri + +I<(Deprecated in Spec 1.2)> [optional] {URL} + +Replaced by C<license> in C<resources> + +=head3 private + +I<(Deprecated in Spec 1.2)> [optional] {Map} + +This field has been renamed to L</"no_index">. + +=head3 recommends + +I<(Deprecated in Spec 2)> [optional] {String} + +Replaced by C<prereqs> + +=head3 requires + +I<(Deprecated in Spec 2)> [optional] {String} + +Replaced by C<prereqs> + +=head1 VERSION NUMBERS + +=head2 Version Formats + +This section defines the Version type, used by several fields in the +CPAN Meta Spec. + +Version numbers must be treated as strings, not numbers. For +example, C<1.200> B<must not> be serialized as C<1.2>. Version +comparison should be delegated to the Perl L<version> module, version +0.80 or newer. + +Unless otherwise specified, version numbers B<must> appear in one of two +formats: + +=over + +=item Decimal versions + +Decimal versions are regular "decimal numbers", with some limitations. +They B<must> be non-negative and B<must> begin and end with a digit. A +single underscore B<may> be included, but B<must> be between two digits. +They B<must not> use exponential notation ("1.23e-2"). + + version => '1.234' # OK + version => '1.23_04' # OK + + version => '1.23_04_05' # Illegal + version => '1.' # Illegal + version => '.1' # Illegal + +=item Dotted-integer versions + +Dotted-integer (also known as dotted-decimal) versions consist of +positive integers separated by full stop characters (i.e. "dots", +"periods" or "decimal points"). This are equivalent in format to Perl +"v-strings", with some additional restrictions on form. They must be +given in "normal" form, which has a leading "v" character and at least +three integer components. To retain a one-to-one mapping with decimal +versions, all components after the first B<should> be restricted to the +range 0 to 999. The final component B<may> be separated by an +underscore character instead of a period. + + version => 'v1.2.3' # OK + version => 'v1.2_3' # OK + version => 'v1.2.3.4' # OK + version => 'v1.2.3_4' # OK + version => 'v2009.10.31' # OK + + version => 'v1.2' # Illegal + version => '1.2.3' # Illegal + version => 'v1.2_3_4' # Illegal + version => 'v1.2009.10.31' # Not recommended + +=back + +=head2 Version Ranges + +Some fields (prereq, optional_features) indicate the particular +version(s) of some other module that may be required as a prerequisite. +This section details the Version Range type used to provide this +information. + +The simplest format for a Version Range is just the version +number itself, e.g. C<2.4>. This means that B<at least> version 2.4 +must be present. To indicate that B<any> version of a prerequisite is +okay, even if the prerequisite doesn't define a version at all, use +the version C<0>. + +Alternatively, a version range B<may> use the operators E<lt> (less than), +E<lt>= (less than or equal), E<gt> (greater than), E<gt>= (greater than +or equal), == (equal), and != (not equal). For example, the +specification C<E<lt> 2.0> means that any version of the prerequisite +less than 2.0 is suitable. + +For more complicated situations, version specifications B<may> be AND-ed +together using commas. The specification C<E<gt>= 1.2, != 1.5, E<lt> +2.0> indicates a version that must be B<at least> 1.2, B<less than> 2.0, +and B<not equal to> 1.5. + +=head1 PREREQUISITES + +=head2 Prereq Spec + +The C<prereqs> key in the top-level metadata and within +C<optional_features> define the relationship between a distribution and +other packages. The prereq spec structure is a hierarchical data +structure which divides prerequisites into I<Phases> of activity in the +installation process and I<Relationships> that indicate how +prerequisites should be resolved. + +For example, to specify that C<Data::Dumper> is C<required> during the +C<test> phase, this entry would appear in the distribution metadata: + + prereqs => { + test => { + requires => { + 'Data::Dumper' => '2.00' + } + } + } + +=head3 Phases + +Requirements for regular use must be listed in the C<runtime> phase. +Other requirements should be listed in the earliest stage in which they +are required and consumers must accumulate and satisfy requirements +across phases before executing the activity. For example, C<build> +requirements must also be available during the C<test> phase. + + before action requirements that must be met + ---------------- -------------------------------- + perl Build.PL configure + perl Makefile.PL + + make configure, runtime, build + Build + + make test configure, runtime, build, test + Build test + +Consumers that install the distribution must ensure that +I<runtime> requirements are also installed and may install +dependencies from other phases. + + after action requirements that must be met + ---------------- -------------------------------- + make install runtime + Build install + +=over + +=item configure + +The configure phase occurs before any dynamic configuration has been +attempted. Libraries required by the configure phase B<must> be +available for use before the distribution building tool has been +executed. + +=item build + +The build phase is when the distribution's source code is compiled (if +necessary) and otherwise made ready for installation. + +=item test + +The test phase is when the distribution's automated test suite is run. +Any library that is needed only for testing and not for subsequent use +should be listed here. + +=item runtime + +The runtime phase refers not only to when the distribution's contents +are installed, but also to its continued use. Any library that is a +prerequisite for regular use of this distribution should be indicated +here. + +=item develop + +The develop phase's prereqs are libraries needed to work on the +distribution's source code as its author does. These tools might be +needed to build a release tarball, to run author-only tests, or to +perform other tasks related to developing new versions of the +distribution. + +=back + +=head3 Relationships + +=over + +=item requires + +These dependencies B<must> be installed for proper completion of the +phase. + +=item recommends + +Recommended dependencies are I<strongly> encouraged and should be +satisfied except in resource constrained environments. + +=item suggests + +These dependencies are optional, but are suggested for enhanced operation +of the described distribution. + +=item conflicts + +These libraries cannot be installed when the phase is in operation. +This is a very rare situation, and the C<conflicts> relationship should +be used with great caution, or not at all. + +=back + +=head2 Merging and Resolving Prerequisites + +Whenever metadata consumers merge prerequisites, either from different +phases or from C<optional_features>, they should merged in a way which +preserves the intended semantics of the prerequisite structure. Generally, +this means concatenating the version specifications using commas, as +described in the L<Version Ranges> section. + +Another subtle error that can occur in resolving prerequisites comes from +the way that modules in prerequisites are indexed to distribution files on +CPAN. When a module is deleted from a distribution, prerequisites calling +for that module could indicate an older distribution should installed, +potentially overwriting files from a newer distribution. + +For example, as of Oct 31, 2009, the CPAN index file contained these +module-distribution mappings: + + Class::MOP 0.94 D/DR/DROLSKY/Class-MOP-0.94.tar.gz + Class::MOP::Class 0.94 D/DR/DROLSKY/Class-MOP-0.94.tar.gz + Class::MOP::Class::Immutable 0.04 S/ST/STEVAN/Class-MOP-0.36.tar.gz + +Consider the case where "Class::MOP" 0.94 is installed. If a +distribution specified "Class::MOP::Class::Immutable" as a prerequisite, +it could result in Class-MOP-0.36.tar.gz being installed, overwriting +any files from Class-MOP-0.94.tar.gz. + +Consumers of metadata B<should> test whether prerequisites would result +in installed module files being "downgraded" to an older version and +B<may> warn users or ignore the prerequisite that would cause such a +result. + +=head1 SERIALIZATION + +Distribution metadata should be serialized (as a hashref) as +JSON-encoded data and packaged with distributions as the file +F<META.json>. + +In the past, the distribution metadata structure had been packed with +distributions as F<META.yml>, a file in the YAML Tiny format (for which, +see L<YAML::Tiny>). Tools that consume distribution metadata from disk +should be capable of loading F<META.yml>, but should prefer F<META.json> +if both are found. + +=head1 NOTES FOR IMPLEMENTORS + +=head2 Extracting Version Numbers from Perl Modules + +To get the version number from a Perl module, consumers should use the +C<< MM->parse_version($file) >> method provided by L<ExtUtils::MakeMaker> or +the L<Module::Build::ModuleInfo> module provided with L<Module::Build>. For +example, for the module given by C<$mod>, the version may be retrieved in one +of the following ways: + + # via ExtUtils::MakeMaker + my $file = MM->_installed_file_for_module($mod); + my $version = MM->parse_version($file) + +The private C<_installed_file_for_module> method may be replaced with +other methods for locating a module in C<@INC>. + + # via Module::Build + my $info = Module::Build::ModuleInfo->new_from_module($mod); + my $version = $info->version; + +If only a filename is available, the following approach may be used: + + # via Module::Build + my $info = Module::Build::ModuleInfo->new_from_file($file); + my $version = $info->version; + +=head2 Comparing Version Numbers + +The L<version> module provides the most reliable way to compare version +numbers in all the various ways they might be provided or might exist +within modules. Given two strings containing version numbers, C<$v1> and +C<$v2>, they should be converted to C<version> objects before using +ordinary comparison operators. For example: + + use version; + if ( version->new($v1) <=> version->new($v2) ) { + print "Versions are not equal\n"; + } + +If the only comparison needed is whether an installed module is of a +sufficiently high version, a direct test may be done using the string +form of C<eval> and the C<use> function. For example, for module C<$mod> +and version prerequisite C<$prereq>: + + if ( eval "use $mod $prereq (); 1" ) { + print "Module $mod version is OK.\n"; + } + +If the values of C<$mod> and C<$prereq> have not been scrubbed, however, +this presents security implications. + +=head1 SEE ALSO + +CPAN, L<http://www.cpan.org/> + +CPAN.pm, L<http://search.cpan.org/dist/CPAN/> + +CPANPLUS, L<http://search.cpan.org/dist/CPANPLUS/> + +ExtUtils::MakeMaker, L<http://search.cpan.org/dist/ExtUtils-MakeMaker/> + +Module::Build, L<http://search.cpan.org/dist/Module-Build/> + +Module::Install, L<http://search.cpan.org/dist/Module-Install/> + +JSON, L<http://json.org/> + +YAML, L<http://www.yaml.org/> + +=head1 CONTRIBUTORS + +Ken Williams wrote the original CPAN Meta Spec (also known as the +"META.yml spec") in 2003 and maintained it through several revisions +with input from various members of the community. In 2005, Randy +Sims redrafted it from HTML to POD for the version 1.2 release. Ken +continued to maintain the spec through version 1.4. + +In late 2009, David Golden organized the version 2 proposal review +process. David and Ricardo Signes drafted the final version 2 spec +in April 2010 based on the version 1.4 spec and patches contributed +during the proposal process. + +Several others have contributed patches over the years. The full list +of contributors in the repository history currently includes: + + 2shortplanks + Avar Arnfjord Bjarmason + Christopher J. Madsen + Damyan Ivanov + David Golden + Eric Wilhelm + Ken Williams + Lars DIECKOW + Michael G. Schwern + Randy Sims + Ricardo Signes + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm new file mode 100644 index 0000000000..a203621ab8 --- /dev/null +++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm @@ -0,0 +1,1002 @@ +use 5.006; +use strict; +use warnings; +package CPAN::Meta::Validator; +BEGIN { + $CPAN::Meta::Validator::VERSION = '2.110440'; +} +# ABSTRACT: validate CPAN distribution metadata structures + + +#--------------------------------------------------------------------------# +# This code copied and adapted from Test::CPAN::Meta +# by Barbie, <barbie@cpan.org> for Miss Barbell Productions, +# L<http://www.missbarbell.co.uk> +#--------------------------------------------------------------------------# + +#--------------------------------------------------------------------------# +# Specification Definitions +#--------------------------------------------------------------------------# + +my %known_specs = ( + '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html', + '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html', + '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html', + '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html', + '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html' +); +my %known_urls = map {$known_specs{$_} => $_} keys %known_specs; + +my $module_map1 = { 'map' => { ':key' => { name => \&module, value => \&exversion } } }; + +my $module_map2 = { 'map' => { ':key' => { name => \&module, value => \&version } } }; + +my $no_index_2 = { + 'map' => { file => { list => { value => \&string } }, + directory => { list => { value => \&string } }, + 'package' => { list => { value => \&string } }, + namespace => { list => { value => \&string } }, + ':key' => { name => \&custom_2, value => \&anything }, + } +}; + +my $no_index_1_3 = { + 'map' => { file => { list => { value => \&string } }, + directory => { list => { value => \&string } }, + 'package' => { list => { value => \&string } }, + namespace => { list => { value => \&string } }, + ':key' => { name => \&string, value => \&anything }, + } +}; + +my $no_index_1_2 = { + 'map' => { file => { list => { value => \&string } }, + dir => { list => { value => \&string } }, + 'package' => { list => { value => \&string } }, + namespace => { list => { value => \&string } }, + ':key' => { name => \&string, value => \&anything }, + } +}; + +my $no_index_1_1 = { + 'map' => { ':key' => { name => \&string, list => { value => \&string } }, + } +}; + +my $prereq_map = { + map => { + ':key' => { + name => \&phase, + 'map' => { + ':key' => { + name => \&relation, + %$module_map1, + }, + }, + } + }, +}; + +my %definitions = ( + '2' => { + # REQUIRED + 'abstract' => { mandatory => 1, value => \&string }, + 'author' => { mandatory => 1, lazylist => { value => \&string } }, + 'dynamic_config' => { mandatory => 1, value => \&boolean }, + 'generated_by' => { mandatory => 1, value => \&string }, + 'license' => { mandatory => 1, lazylist => { value => \&license } }, + 'meta-spec' => { + mandatory => 1, + 'map' => { + version => { mandatory => 1, value => \&version}, + url => { value => \&url }, + ':key' => { name => \&custom_2, value => \&anything }, + } + }, + 'name' => { mandatory => 1, value => \&string }, + 'release_status' => { mandatory => 1, value => \&release_status }, + 'version' => { mandatory => 1, value => \&version }, + + # OPTIONAL + 'description' => { value => \&string }, + 'keywords' => { lazylist => { value => \&string } }, + 'no_index' => $no_index_2, + 'optional_features' => { + 'map' => { + ':key' => { + name => \&string, + 'map' => { + description => { value => \&string }, + prereqs => $prereq_map, + ':key' => { name => \&custom_2, value => \&anything }, + } + } + } + }, + 'prereqs' => $prereq_map, + 'provides' => { + 'map' => { + ':key' => { + name => \&module, + 'map' => { + file => { mandatory => 1, value => \&file }, + version => { value => \&version }, + ':key' => { name => \&custom_2, value => \&anything }, + } + } + } + }, + 'resources' => { + 'map' => { + license => { lazylist => { value => \&url } }, + homepage => { value => \&url }, + bugtracker => { + 'map' => { + web => { value => \&url }, + mailto => { value => \&string}, + ':key' => { name => \&custom_2, value => \&anything }, + } + }, + repository => { + 'map' => { + web => { value => \&url }, + url => { value => \&url }, + type => { value => \&string }, + ':key' => { name => \&custom_2, value => \&anything }, + } + }, + ':key' => { value => \&string, name => \&custom_2 }, + } + }, + + # CUSTOM -- additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&custom_2, value => \&anything }, + }, + +'1.4' => { + 'meta-spec' => { + mandatory => 1, + 'map' => { + version => { mandatory => 1, value => \&version}, + url => { mandatory => 1, value => \&urlspec }, + ':key' => { name => \&string, value => \&anything }, + }, + }, + + 'name' => { mandatory => 1, value => \&string }, + 'version' => { mandatory => 1, value => \&version }, + 'abstract' => { mandatory => 1, value => \&string }, + 'author' => { mandatory => 1, list => { value => \&string } }, + 'license' => { mandatory => 1, value => \&license }, + 'generated_by' => { mandatory => 1, value => \&string }, + + 'distribution_type' => { value => \&string }, + 'dynamic_config' => { value => \&boolean }, + + 'requires' => $module_map1, + 'recommends' => $module_map1, + 'build_requires' => $module_map1, + 'configure_requires' => $module_map1, + 'conflicts' => $module_map2, + + 'optional_features' => { + 'map' => { + ':key' => { name => \&string, + 'map' => { description => { value => \&string }, + requires => $module_map1, + recommends => $module_map1, + build_requires => $module_map1, + conflicts => $module_map2, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + 'provides' => { + 'map' => { + ':key' => { name => \&module, + 'map' => { + file => { mandatory => 1, value => \&file }, + version => { value => \&version }, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + 'no_index' => $no_index_1_3, + 'private' => $no_index_1_3, + + 'keywords' => { list => { value => \&string } }, + + 'resources' => { + 'map' => { license => { value => \&url }, + homepage => { value => \&url }, + bugtracker => { value => \&url }, + repository => { value => \&url }, + ':key' => { value => \&string, name => \&custom_1 }, + } + }, + + # additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&string, value => \&anything }, +}, + +'1.3' => { + 'meta-spec' => { + mandatory => 1, + 'map' => { + version => { mandatory => 1, value => \&version}, + url => { mandatory => 1, value => \&urlspec }, + ':key' => { name => \&string, value => \&anything }, + }, + }, + + 'name' => { mandatory => 1, value => \&string }, + 'version' => { mandatory => 1, value => \&version }, + 'abstract' => { mandatory => 1, value => \&string }, + 'author' => { mandatory => 1, list => { value => \&string } }, + 'license' => { mandatory => 1, value => \&license }, + 'generated_by' => { mandatory => 1, value => \&string }, + + 'distribution_type' => { value => \&string }, + 'dynamic_config' => { value => \&boolean }, + + 'requires' => $module_map1, + 'recommends' => $module_map1, + 'build_requires' => $module_map1, + 'conflicts' => $module_map2, + + 'optional_features' => { + 'map' => { + ':key' => { name => \&string, + 'map' => { description => { value => \&string }, + requires => $module_map1, + recommends => $module_map1, + build_requires => $module_map1, + conflicts => $module_map2, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + 'provides' => { + 'map' => { + ':key' => { name => \&module, + 'map' => { + file => { mandatory => 1, value => \&file }, + version => { value => \&version }, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + + 'no_index' => $no_index_1_3, + 'private' => $no_index_1_3, + + 'keywords' => { list => { value => \&string } }, + + 'resources' => { + 'map' => { license => { value => \&url }, + homepage => { value => \&url }, + bugtracker => { value => \&url }, + repository => { value => \&url }, + ':key' => { value => \&string, name => \&custom_1 }, + } + }, + + # additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&string, value => \&anything }, +}, + +# v1.2 is misleading, it seems to assume that a number of fields where created +# within v1.1, when they were created within v1.2. This may have been an +# original mistake, and that a v1.1 was retro fitted into the timeline, when +# v1.2 was originally slated as v1.1. But I could be wrong ;) +'1.2' => { + 'meta-spec' => { + mandatory => 1, + 'map' => { + version => { mandatory => 1, value => \&version}, + url => { mandatory => 1, value => \&urlspec }, + ':key' => { name => \&string, value => \&anything }, + }, + }, + + + 'name' => { mandatory => 1, value => \&string }, + 'version' => { mandatory => 1, value => \&version }, + 'license' => { mandatory => 1, value => \&license }, + 'generated_by' => { mandatory => 1, value => \&string }, + 'author' => { mandatory => 1, list => { value => \&string } }, + 'abstract' => { mandatory => 1, value => \&string }, + + 'distribution_type' => { value => \&string }, + 'dynamic_config' => { value => \&boolean }, + + 'keywords' => { list => { value => \&string } }, + + 'private' => $no_index_1_2, + '$no_index' => $no_index_1_2, + + 'requires' => $module_map1, + 'recommends' => $module_map1, + 'build_requires' => $module_map1, + 'conflicts' => $module_map2, + + 'optional_features' => { + 'map' => { + ':key' => { name => \&string, + 'map' => { description => { value => \&string }, + requires => $module_map1, + recommends => $module_map1, + build_requires => $module_map1, + conflicts => $module_map2, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + 'provides' => { + 'map' => { + ':key' => { name => \&module, + 'map' => { + file => { mandatory => 1, value => \&file }, + version => { value => \&version }, + ':key' => { name => \&string, value => \&anything }, + } + } + } + }, + + 'resources' => { + 'map' => { license => { value => \&url }, + homepage => { value => \&url }, + bugtracker => { value => \&url }, + repository => { value => \&url }, + ':key' => { value => \&string, name => \&custom_1 }, + } + }, + + # additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&string, value => \&anything }, +}, + +# note that the 1.1 spec only specifies 'version' as mandatory +'1.1' => { + 'name' => { value => \&string }, + 'version' => { mandatory => 1, value => \&version }, + 'license' => { value => \&license }, + 'generated_by' => { value => \&string }, + + 'license_uri' => { value => \&url }, + 'distribution_type' => { value => \&string }, + 'dynamic_config' => { value => \&boolean }, + + 'private' => $no_index_1_1, + + 'requires' => $module_map1, + 'recommends' => $module_map1, + 'build_requires' => $module_map1, + 'conflicts' => $module_map2, + + # additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&string, value => \&anything }, +}, + +# note that the 1.0 spec doesn't specify optional or mandatory fields +# but we will treat version as mandatory since otherwise META 1.0 is +# completely arbitrary and pointless +'1.0' => { + 'name' => { value => \&string }, + 'version' => { mandatory => 1, value => \&version }, + 'license' => { value => \&license }, + 'generated_by' => { value => \&string }, + + 'license_uri' => { value => \&url }, + 'distribution_type' => { value => \&string }, + 'dynamic_config' => { value => \&boolean }, + + 'requires' => $module_map1, + 'recommends' => $module_map1, + 'build_requires' => $module_map1, + 'conflicts' => $module_map2, + + # additional user defined key/value pairs + # note we can only validate the key name, as the structure is user defined + ':key' => { name => \&string, value => \&anything }, +}, +); + +#--------------------------------------------------------------------------# +# Code +#--------------------------------------------------------------------------# + + +sub new { + my ($class,$data) = @_; + + # create an attributes hash + my $self = { + 'data' => $data, + 'spec' => $data->{'meta-spec'}{'version'} || "1.0", + 'errors' => undef, + }; + + # create the object + return bless $self, $class; +} + + +sub is_valid { + my $self = shift; + my $data = $self->{data}; + my $spec_version = $self->{spec}; + $self->check_map($definitions{$spec_version},$data); + return ! $self->errors; +} + + +sub errors { + my $self = shift; + return () unless(defined $self->{errors}); + return @{$self->{errors}}; +} + + +my $spec_error = "Missing validation action in specification. " + . "Must be one of 'map', 'list', 'lazylist', or 'value'"; + +sub check_map { + my ($self,$spec,$data) = @_; + + if(ref($spec) ne 'HASH') { + $self->_error( "Unknown META specification, cannot validate." ); + return; + } + + if(ref($data) ne 'HASH') { + $self->_error( "Expected a map structure from string or file." ); + return; + } + + for my $key (keys %$spec) { + next unless($spec->{$key}->{mandatory}); + next if(defined $data->{$key}); + push @{$self->{stack}}, $key; + $self->_error( "Missing mandatory field, '$key'" ); + pop @{$self->{stack}}; + } + + for my $key (keys %$data) { + push @{$self->{stack}}, $key; + if($spec->{$key}) { + if($spec->{$key}{value}) { + $spec->{$key}{value}->($self,$key,$data->{$key}); + } elsif($spec->{$key}{'map'}) { + $self->check_map($spec->{$key}{'map'},$data->{$key}); + } elsif($spec->{$key}{'list'}) { + $self->check_list($spec->{$key}{'list'},$data->{$key}); + } elsif($spec->{$key}{'lazylist'}) { + $self->check_lazylist($spec->{$key}{'lazylist'},$data->{$key}); + } else { + $self->_error( "$spec_error for '$key'" ); + } + + } elsif ($spec->{':key'}) { + $spec->{':key'}{name}->($self,$key,$key); + if($spec->{':key'}{value}) { + $spec->{':key'}{value}->($self,$key,$data->{$key}); + } elsif($spec->{':key'}{'map'}) { + $self->check_map($spec->{':key'}{'map'},$data->{$key}); + } elsif($spec->{':key'}{'list'}) { + $self->check_list($spec->{':key'}{'list'},$data->{$key}); + } elsif($spec->{':key'}{'lazylist'}) { + $self->check_lazylist($spec->{':key'}{'lazylist'},$data->{$key}); + } else { + $self->_error( "$spec_error for ':key'" ); + } + + + } else { + $self->_error( "Unknown key, '$key', found in map structure" ); + } + pop @{$self->{stack}}; + } +} + +# if it's a string, make it into a list and check the list +sub check_lazylist { + my ($self,$spec,$data) = @_; + + if ( defined $data && ! ref($data) ) { + $data = [ $data ]; + } + + $self->check_list($spec,$data); +} + +sub check_list { + my ($self,$spec,$data) = @_; + + if(ref($data) ne 'ARRAY') { + $self->_error( "Expected a list structure" ); + return; + } + + if(defined $spec->{mandatory}) { + if(!defined $data->[0]) { + $self->_error( "Missing entries from mandatory list" ); + } + } + + for my $value (@$data) { + push @{$self->{stack}}, $value || "<undef>"; + if(defined $spec->{value}) { + $spec->{value}->($self,'list',$value); + } elsif(defined $spec->{'map'}) { + $self->check_map($spec->{'map'},$value); + } elsif(defined $spec->{'list'}) { + $self->check_list($spec->{'list'},$value); + } elsif(defined $spec->{'lazylist'}) { + $self->check_lazylist($spec->{'lazylist'},$value); + } elsif ($spec->{':key'}) { + $self->check_map($spec,$value); + } else { + $self->_error( "$spec_error associated with '$self->{stack}[-2]'" ); + } + pop @{$self->{stack}}; + } +} + + +sub header { + my ($self,$key,$value) = @_; + if(defined $value) { + return 1 if($value && $value =~ /^--- #YAML:1.0/); + } + $self->_error( "file does not have a valid YAML header." ); + return 0; +} + +sub release_status { + my ($self,$key,$value) = @_; + if(defined $value) { + my $version = $self->{data}{version} || ''; + if ( $version =~ /_/ ) { + return 1 if ( $value =~ /\A(?:testing|unstable)\z/ ); + $self->_error( "'$value' for '$key' is invalid for version '$version'" ); + } + else { + return 1 if ( $value =~ /\A(?:stable|testing|unstable)\z/ ); + $self->_error( "'$value' for '$key' is invalid" ); + } + } + else { + $self->_error( "'$key' is not defined" ); + } + return 0; +} + +# _uri_split taken from URI::Split by Gisle Aas, Copyright 2003 +sub _uri_split { + return $_[0] =~ m,(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?,; +} + +sub url { + my ($self,$key,$value) = @_; + if(defined $value) { + my ($scheme, $auth, $path, $query, $frag) = _uri_split($value); + unless ( defined $scheme && length $scheme ) { + $self->_error( "'$value' for '$key' does not have a URL scheme" ); + return 0; + } + unless ( defined $auth && length $auth ) { + $self->_error( "'$value' for '$key' does not have a URL authority" ); + return 0; + } + return 1; + } + $value ||= ''; + $self->_error( "'$value' for '$key' is not a valid URL." ); + return 0; +} + +sub urlspec { + my ($self,$key,$value) = @_; + if(defined $value) { + return 1 if($value && $known_specs{$self->{spec}} eq $value); + if($value && $known_urls{$value}) { + $self->_error( 'META specification URL does not match version' ); + return 0; + } + } + $self->_error( 'Unknown META specification' ); + return 0; +} + +sub anything { return 1 } + +sub string { + my ($self,$key,$value) = @_; + if(defined $value) { + return 1 if($value || $value =~ /^0$/); + } + $self->_error( "value is an undefined string" ); + return 0; +} + +sub string_or_undef { + my ($self,$key,$value) = @_; + return 1 unless(defined $value); + return 1 if($value || $value =~ /^0$/); + $self->_error( "No string defined for '$key'" ); + return 0; +} + +sub file { + my ($self,$key,$value) = @_; + return 1 if(defined $value); + $self->_error( "No file defined for '$key'" ); + return 0; +} + +sub exversion { + my ($self,$key,$value) = @_; + if(defined $value && ($value || $value =~ /0/)) { + my $pass = 1; + for(split(",",$value)) { $self->version($key,$_) or ($pass = 0); } + return $pass; + } + $value = '<undef>' unless(defined $value); + $self->_error( "'$value' for '$key' is not a valid version." ); + return 0; +} + +sub version { + my ($self,$key,$value) = @_; + if(defined $value) { + return 0 unless($value || $value =~ /0/); + return 1 if($value =~ /^\s*((<|<=|>=|>|!=|==)\s*)?v?\d+((\.\d+((_|\.)\d+)?)?)/); + } else { + $value = '<undef>'; + } + $self->_error( "'$value' for '$key' is not a valid version." ); + return 0; +} + +sub boolean { + my ($self,$key,$value) = @_; + if(defined $value) { + return 1 if($value =~ /^(0|1|true|false)$/); + } else { + $value = '<undef>'; + } + $self->_error( "'$value' for '$key' is not a boolean value." ); + return 0; +} + +my %v1_licenses = ( + 'perl' => 'http://dev.perl.org/licenses/', + 'gpl' => 'http://www.opensource.org/licenses/gpl-license.php', + 'apache' => 'http://apache.org/licenses/LICENSE-2.0', + 'artistic' => 'http://opensource.org/licenses/artistic-license.php', + 'artistic_2' => 'http://opensource.org/licenses/artistic-license-2.0.php', + 'lgpl' => 'http://www.opensource.org/licenses/lgpl-license.phpt', + 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', + 'gpl' => 'http://www.opensource.org/licenses/gpl-license.php', + 'mit' => 'http://opensource.org/licenses/mit-license.php', + 'mozilla' => 'http://opensource.org/licenses/mozilla1.1.php', + 'open_source' => undef, + 'unrestricted' => undef, + 'restrictive' => undef, + 'unknown' => undef, +); + +my %v2_licenses = map { $_ => 1 } qw( + agpl_3 + apache_1_1 + apache_2_0 + artistic_1 + artistic_2 + bsd + freebsd + gfdl_1_2 + gfdl_1_3 + gpl_1 + gpl_2 + gpl_3 + lgpl_2_1 + lgpl_3_0 + mit + mozilla_1_0 + mozilla_1_1 + openssl + perl_5 + qpl_1_0 + ssleay + sun + zlib + open_source + restricted + unrestricted + unknown +); + +sub license { + my ($self,$key,$value) = @_; + my $licenses = $self->{spec} < 2 ? \%v1_licenses : \%v2_licenses; + if(defined $value) { + return 1 if($value && exists $licenses->{$value}); + } else { + $value = '<undef>'; + } + $self->_error( "License '$value' is invalid" ); + return 0; +} + +sub custom_1 { + my ($self,$key) = @_; + if(defined $key) { + # a valid user defined key should be alphabetic + # and contain at least one capital case letter. + return 1 if($key && $key =~ /^[_a-z]+$/i && $key =~ /[A-Z]/); + } else { + $key = '<undef>'; + } + $self->_error( "Custom resource '$key' must be in CamelCase." ); + return 0; +} + +sub custom_2 { + my ($self,$key) = @_; + if(defined $key) { + return 1 if($key && $key =~ /^x_/i); # user defined + } else { + $key = '<undef>'; + } + $self->_error( "Custom key '$key' must begin with 'x_' or 'X_'." ); + return 0; +} + +sub identifier { + my ($self,$key) = @_; + if(defined $key) { + return 1 if($key && $key =~ /^([a-z][_a-z]+)$/i); # spec 2.0 defined + } else { + $key = '<undef>'; + } + $self->_error( "Key '$key' is not a legal identifier." ); + return 0; +} + +sub module { + my ($self,$key) = @_; + if(defined $key) { + return 1 if($key && $key =~ /^[A-Za-z0-9_]+(::[A-Za-z0-9_]+)*$/); + } else { + $key = '<undef>'; + } + $self->_error( "Key '$key' is not a legal module name." ); + return 0; +} + +my @valid_phases = qw/ configure build test runtime develop /; +sub phase { + my ($self,$key) = @_; + if(defined $key) { + return 1 if( length $key && grep { $key eq $_ } @valid_phases ); + return 1 if $key =~ /x_/i; + } else { + $key = '<undef>'; + } + $self->_error( "Key '$key' is not a legal phase." ); + return 0; +} + +my @valid_relations = qw/ requires recommends suggests conflicts /; +sub relation { + my ($self,$key) = @_; + if(defined $key) { + return 1 if( length $key && grep { $key eq $_ } @valid_relations ); + return 1 if $key =~ /x_/i; + } else { + $key = '<undef>'; + } + $self->_error( "Key '$key' is not a legal prereq relationship." ); + return 0; +} + +sub _error { + my $self = shift; + my $mess = shift; + + $mess .= ' ('.join(' -> ',@{$self->{stack}}).')' if($self->{stack}); + $mess .= " [Validation: $self->{spec}]"; + + push @{$self->{errors}}, $mess; +} + +1; + + + +=pod + +=head1 NAME + +CPAN::Meta::Validator - validate CPAN distribution metadata structures + +=head1 VERSION + +version 2.110440 + +=head1 SYNOPSIS + + my $struct = decode_json_file('META.json'); + + my $cmv = CPAN::Meta::Validator->new( $struct ); + + unless ( $cmv->is_valid ) { + my $msg = "Invalid META structure. Errors found:\n"; + $msg .= join( "\n", $cmv->errors ); + die $msg; + } + +=head1 DESCRIPTION + +This module validates a CPAN Meta structure against the version of the +the specification claimed in the C<meta-spec> field of the structure. + +=head1 METHODS + +=head2 new + + my $cmv = CPAN::Meta::Validator->new( $struct ) + +The constructor must be passed a metadata structure. + +=head2 is_valid + + if ( $cmv->is_valid ) { + ... + } + +Returns a boolean value indicating whether the metadata provided +is valid. + +=head2 errors + + warn( join "\n", $cmv->errors ); + +Returns a list of errors seen during validation. + +=begin internals + +=head2 Check Methods + +=over + +=item * check_map($spec,$data) + +Checks whether a map (or hash) part of the data structure conforms to the +appropriate specification definition. +=item * check_list($spec,$data) + +Checks whether a list (or array) part of the data structure conforms to +the appropriate specification definition. +=item * check_lazylist($spec,$data) + +Checks whether a list conforms, but converts strings to a single-element list +=back + +=head2 Validator Methods + +=over + +=item * header($self,$key,$value) + +Validates that the header is valid. + +Note: No longer used as we now read the data structure, not the file.=item * url($self,$key,$value) + +Validates that a given value is in an acceptable URL format +=item * urlspec($self,$key,$value) + +Validates that the URL to a META specification is a known one. +=item * string_or_undef($self,$key,$value) + +Validates that the value is either a string or an undef value. Bit of a +catchall function for parts of the data structure that are completely user +defined. +=item * string($self,$key,$value) + +Validates that a string exists for the given key. +=item * file($self,$key,$value) + +Validate that a file is passed for the given key. This may be made more +thorough in the future. For now it acts like \&string. +=item * exversion($self,$key,$value) + +Validates a list of versions, e.g. '<= 5, >=2, ==3, !=4, >1, <6, 0'. +=item * version($self,$key,$value) + +Validates a single version string. Versions of the type '5.8.8' and '0.00_00' +are both valid. A leading 'v' like 'v1.2.3' is also valid. +=item * boolean($self,$key,$value) + +Validates for a boolean value. Currently these values are '1', '0', 'true', +'false', however the latter 2 may be removed. +=item * license($self,$key,$value) + +Validates that a value is given for the license. Returns 1 if an known license +type, or 2 if a value is given but the license type is not a recommended one. +=item * custom_1($self,$key,$value) + +Validates that the given key is in CamelCase, to indicate a user defined +keyword and only has characters in the class [-_a-zA-Z]. In version 1.X +of the spec, this was only explicitly stated for 'resources'. +=item * custom_2($self,$key,$value) + +Validates that the given key begins with 'x_' or 'X_', to indicate a user +defined keyword and only has characters in the class [-_a-zA-Z] +=item * identifier($self,$key,$value) + +Validates that key is in an acceptable format for the META specification, +for an identifier, i.e. any that matches the regular expression +qr/[a-z][a-z_]/i. +=item * module($self,$key,$value) + +Validates that a given key is in an acceptable module name format, e.g. +'Test::CPAN::Meta::Version'. +=back + +=end internals + +=head1 BUGS + +Please report any bugs or feature using the CPAN Request Tracker. +Bugs can be submitted through the web interface at +L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta> + +When submitting a bug or request, please include a test-file or a patch to an +existing test-file that illustrates the bug or desired feature. + +=head1 AUTHORS + +=over 4 + +=item * + +David Golden <dagolden@cpan.org> + +=item * + +Ricardo Signes <rjbs@cpan.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2010 by David Golden and Ricardo Signes. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + + +__END__ + + + diff --git a/cpan/CPAN-Meta/t/converter-bad.t b/cpan/CPAN-Meta/t/converter-bad.t new file mode 100644 index 0000000000..1225e42184 --- /dev/null +++ b/cpan/CPAN-Meta/t/converter-bad.t @@ -0,0 +1,71 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use CPAN::Meta::Validator; +use CPAN::Meta::Converter; +use File::Spec; +use IO::Dir; +use Parse::CPAN::Meta 1.4400; + +my $data_dir = IO::Dir->new( 't/data-bad' ); +my @files = sort grep { /^\w/ } $data_dir->read; + +sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" } + +#use Data::Dumper; + +for my $f ( reverse sort @files ) { + my $path = File::Spec->catfile('t','data-bad',$f); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded $f" ); + my $original_v = _spec_version($original); + # UPCONVERSION + if ( _spec_version( $original ) lt '2' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => 2 ); + is ( _spec_version($converted), 2, "up converted spec version $original_v to spec version 2"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "up converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } + # UPCONVERSION - partial + if ( _spec_version( $original ) lt '1.4' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.4' ); + is ( _spec_version($converted), 1.4, "up converted spec version $original_v to spec version 1.4"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "up converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } + # DOWNCONVERSION - partial + if ( _spec_version( $original ) gt '1.2' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.2' ); + is ( _spec_version($converted), '1.2', "down converted spec version $original_v to spec version 1.2"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "down converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } + # DOWNCONVERSION + if ( _spec_version( $original ) gt '1.0' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.0' ); + is ( _spec_version($converted), '1.0', "down converted spec version $original_v to spec version 1.0"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "down converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } +} + +done_testing; + diff --git a/cpan/CPAN-Meta/t/converter-fail.t b/cpan/CPAN-Meta/t/converter-fail.t new file mode 100644 index 0000000000..3a82f2d5af --- /dev/null +++ b/cpan/CPAN-Meta/t/converter-fail.t @@ -0,0 +1,39 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use CPAN::Meta::Validator; +use CPAN::Meta::Converter; +use File::Spec; +use IO::Dir; +use Parse::CPAN::Meta 1.4400; + +my $data_dir = IO::Dir->new( 't/data-fail' ); +my @files = sort grep { /^\w/ } $data_dir->read; + +sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" } + +use Data::Dumper; + +for my $f ( reverse sort @files ) { + my $path = File::Spec->catfile('t','data-fail',$f); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded invalid $f" ); + my $original_v = _spec_version($original); + # UPCONVERSION + if ( _spec_version( $original ) lt '2' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + eval { $cmc->convert( version => 2 ) }; + ok ( $@, "error thrown up converting" ); + } + # DOWNCONVERSION + if ( _spec_version( $original ) gt '1.0' ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + eval { $cmc->convert( version => '1.0' ) }; + ok ( $@, "error thrown down converting" ); + } +} + +done_testing; + diff --git a/cpan/CPAN-Meta/t/converter.t b/cpan/CPAN-Meta/t/converter.t new file mode 100644 index 0000000000..53ea5ee6d6 --- /dev/null +++ b/cpan/CPAN-Meta/t/converter.t @@ -0,0 +1,139 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use CPAN::Meta::Validator; +use CPAN::Meta::Converter; +use File::Spec; +use IO::Dir; +use Parse::CPAN::Meta 1.4400; + +my $data_dir = IO::Dir->new( 't/data' ); +my @files = sort grep { /^\w/ } $data_dir->read; + +sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" } + +#use Data::Dumper; + +for my $f ( reverse sort @files ) { + my $path = File::Spec->catfile('t','data',$f); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded $f" ); + my $original_v = _spec_version($original); + # UPCONVERSION + { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => 2 ); + is ( _spec_version($converted), 2, "up converted spec version $original_v to spec version 2"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "up converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } + # UPCONVERSION - partial + if ( _spec_version( $original ) < 2 ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.4' ); + is ( _spec_version($converted), 1.4, "up converted spec version $original_v to spec version 1.4"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "up converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + } + # DOWNCONVERSION - partial + if ( _spec_version( $original ) >= 1.2 ) { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.2' ); + is ( _spec_version($converted), '1.2', "down converted spec version $original_v to spec version 1.2"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "down converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + + if (_spec_version( $original ) == 2) { + is_deeply( + $converted->{build_requires}, + { + 'Test::More' => '0.88', + 'Build::Requires' => '1.1', + 'Test::Requires' => '1.2', + }, + "downconversion from 2 merge test and build requirements", + ); + } + } + # DOWNCONVERSION + { + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => '1.0' ); + is ( _spec_version($converted), '1.0', "down converted spec version $original_v to spec version 1.0"); + my $cmv = CPAN::Meta::Validator->new( $converted ); + ok ( $cmv->is_valid, "down converted META is valid" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) +# . "\nMETA:\n" . Dumper($converted) + ); + + unless ($original_v eq '1.0') { + like ( $converted->{generated_by}, + qr(\Q$original->{generated_by}\E, CPAN::Meta::Converter version \S+$), + "added converter mark to generated_by", + ); + } + } +} + +# specific test for custom key handling +{ + my $path = File::Spec->catfile('t','data','META-1_4.yml'); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded META-1_4.yml" ); + my $cmc = CPAN::Meta::Converter->new( $original ); + my $up_converted = $cmc->convert( version => 2 ); + ok ( $up_converted->{x_whatever} && ! $up_converted->{'x-whatever'}, + "up converted 'x-' to 'x_'" + ); + ok ( $up_converted->{x_whatelse}, + "up converted 'x_' as 'x_'" + ); + ok ( $up_converted->{x_WhatNow} && ! $up_converted->{XWhatNow}, + "up converted 'XFoo' to 'x_Foo'" + ) or diag join("\n", keys %$up_converted); +} + +# specific test for custom key handling +{ + my $path = File::Spec->catfile('t','data','META-2.json'); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded META-2.json" ); + my $cmc = CPAN::Meta::Converter->new( $original ); + my $up_converted = $cmc->convert( version => 1.4 ); + ok ( $up_converted->{x_whatever}, + "down converted 'x_' as 'x_'" + ); +} + +# specific test for upconverting resources +{ + my $path = File::Spec->catfile('t','data','resources.yml'); + my $original = Parse::CPAN::Meta->load_file( $path ); + ok( $original, "loaded resources.yml" ); + my $cmc = CPAN::Meta::Converter->new( $original ); + my $converted = $cmc->convert( version => 2 ); + is_deeply( + $converted->{resources}, + { x_MailingList => 'http://groups.google.com/group/www-mechanize-users', + x_Repository => 'http://code.google.com/p/www-mechanize/source', + homepage => 'http://code.google.com/p/www-mechanize/', + bugtracker => {web => 'http://code.google.com/p/www-mechanize/issues/list',}, + license => ['http://dev.perl.org/licenses/'], + }, + "upconversion of resources" + ); +} + +done_testing; + diff --git a/cpan/CPAN-Meta/t/data-bad/107650337-META.yml b/cpan/CPAN-Meta/t/data-bad/107650337-META.yml new file mode 100644 index 0000000000..84080ef657 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/107650337-META.yml @@ -0,0 +1,25 @@ +--- +name: FabForce-DBDesigner4-DBIC +version: 0.0802 +author: + - 'Renee Baecker <module@renee-baecker.de>' +abstract: create DBIC scheme for DBDesigner4 xml file +license: artistic2 +requires: + FabForce::DBDesigner4: 0.3 + File::Spec: 3.12 +build_requires: + Carp: 0 + Test::CheckManifest: 1 + Test::More: 0 +generated_by: Module::Build version 0.2808 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.2.html + version: 1.2 +provides: + FabForce::DBDesigner4::DBIC: + file: lib/FabForce/DBDesigner4/DBIC.pm + version: 0.0802 +resources: + license: http://dev.perl.org/licenses/ + diff --git a/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml b/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml new file mode 100644 index 0000000000..f37cb284a7 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml @@ -0,0 +1,28 @@ +--- +abstract: 'Generate Catalyst application menus' +author: + - 'David P.C. Wollmann <converter42@gmail.com>' +build_requires: + ExtUtils::MakeMaker: 6.42 + Test::More: 0 +configure_requires: + ExtUtils::MakeMaker: 6.42 +distribution_type: module +generated_by: 'Module::Install version 0.87' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: CatalystX-Menu-Tree +no_index: + directory: + - inc + - t + inc: [] +requires: + Catalyst::Runtime: 0 + MRO::Compat: 0 + perl: 5.8.0 +resources: + license: http://dev.perl.org/licenses/ +version: 0.02 diff --git a/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml b/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml new file mode 100644 index 0000000000..a8be520dd5 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml @@ -0,0 +1,105 @@ +--- +name: PDF-Template +version: 0.29_02 +author: ~ +abstract: PDF::Template +license: perl +requires: + Encode: 0.01 + PDF::Writer: 0.05 + perl: 5.6.0 +build_requires: + IO::Scalar: 0.01 + Test::More: 0.47 +provides: + PDF::Template: + file: lib/PDF/Template.pm + version: 0.29_02 + PDF::Template::Base: + file: lib/PDF/Template/Base.pm + version: ~ + PDF::Template::Constants: + file: lib/PDF/Template/Constants.pm + version: ~ + PDF::Template::Container: + file: lib/PDF/Template/Container.pm + version: ~ + PDF::Template::Container::Always: + file: lib/PDF/Template/Container/Always.pm + version: ~ + PDF::Template::Container::Conditional: + file: lib/PDF/Template/Container/Conditional.pm + version: ~ + PDF::Template::Container::Font: + file: lib/PDF/Template/Container/Font.pm + version: ~ + PDF::Template::Container::Footer: + file: lib/PDF/Template/Container/Footer.pm + version: ~ + PDF::Template::Container::Header: + file: lib/PDF/Template/Container/Header.pm + version: ~ + PDF::Template::Container::Loop: + file: lib/PDF/Template/Container/Loop.pm + version: ~ + PDF::Template::Container::Margin: + file: lib/PDF/Template/Container/Margin.pm + version: ~ + PDF::Template::Container::PageDef: + file: lib/PDF/Template/Container/PageDef.pm + version: ~ + PDF::Template::Container::PdfTemplate: + file: lib/PDF/Template/Container/PdfTemplate.pm + version: ~ + PDF::Template::Container::Row: + file: lib/PDF/Template/Container/Row.pm + version: ~ + PDF::Template::Container::Scope: + file: lib/PDF/Template/Container/Scope.pm + version: ~ + PDF::Template::Container::Section: + file: lib/PDF/Template/Container/Section.pm + version: ~ + PDF::Template::Context: + file: lib/PDF/Template/Context.pm + version: ~ + PDF::Template::Element: + file: lib/PDF/Template/Element.pm + version: ~ + PDF::Template::Element::Bookmark: + file: lib/PDF/Template/Element/Bookmark.pm + version: ~ + PDF::Template::Element::Circle: + file: lib/PDF/Template/Element/Circle.pm + version: ~ + PDF::Template::Element::HorizontalRule: + file: lib/PDF/Template/Element/HorizontalRule.pm + version: ~ + PDF::Template::Element::Image: + file: lib/PDF/Template/Element/Image.pm + version: ~ + PDF::Template::Element::Line: + file: lib/PDF/Template/Element/Line.pm + version: ~ + PDF::Template::Element::PageBreak: + file: lib/PDF/Template/Element/PageBreak.pm + version: ~ + PDF::Template::Element::TextBox: + file: lib/PDF/Template/Element/TextBox.pm + version: ~ + PDF::Template::Element::Var: + file: lib/PDF/Template/Element/Var.pm + version: ~ + PDF::Template::Element::Weblink: + file: lib/PDF/Template/Element/Weblink.pm + version: ~ + PDF::Template::Factory: + file: lib/PDF/Template/Factory.pm + version: ~ + PDF::Template::Iterator: + file: lib/PDF/Template/Iterator.pm + version: ~ + PDF::Template::TextObject: + file: lib/PDF/Template/TextObject.pm + version: ~ +generated_by: Module::Build version 0.2701 diff --git a/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml b/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml new file mode 100644 index 0000000000..868c8cd587 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml @@ -0,0 +1,19 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: XML-RDB +version: 1.3 +version_from: RDB.pm +installdirs: site +requires: + Data::Dumper: 0 + DBI: 1.35 + DBIx::DBSchema: .16 + DBIx::Recordset: .23 + DBIx::Sequence: .04 + Getopt::Std: 0 + IO::File: 1.08 + URI::Escape: 3.16 + XML::DOM: 1.29 + +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.30 diff --git a/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml b/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml new file mode 100644 index 0000000000..9b5d8bd3b1 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml @@ -0,0 +1,13 @@ +# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: WWW-phpBB-Mod-Installer
+version: 0.03
+version_from: lib/WWW/phpBB/Mod/Installer.pm
+installdirs: site
+requires:
+ DBD::mysql: 3.0002
+ DBI: 1.5
+ XML::Xerces: -4
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.30
diff --git a/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml b/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml new file mode 100644 index 0000000000..4d79f42be1 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml @@ -0,0 +1,21 @@ +--- #YAML:1.0 +name: Squatting +version: 0.30 +abstract: A Camping-inspired Web Microframework for Perl +license: mit +generated_by: ExtUtils::MakeMaker version 6.36 +distribution_type: module +requires: + Continuity: 0.991 + Data::Dump: 0 + HTTP::Daemon: 0 + JSON::XS: 0 + Shell::Perl: 0 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.2.html + version: 1.2 +author: + - John BEPPU <beppu@cpan.org> +no_index: + - eg + - t diff --git a/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml b/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml new file mode 100644 index 0000000000..7814f05ce3 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml @@ -0,0 +1,20 @@ +--- +abstract: 'A Form::Sensible::Form::Reflector subclass to reflect off of DBIC schema classes' +author: + - 'Devin Austin <dhoss@cpan.org>' +generated_by: 'Dist::Zilla version 1.100160' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Form-Sensible-Reflector-DBIC +requires: + DBIx::Class: "\"\"" + Data::Dumper: "\"\"" + DateTime: "\"\"" + ExtUtils::MakeMaker: 6.11 + Form::Sensible: "\"\"" + Moose: 0.93 + SQL::Translator: 0.11002 + Test::Simple: 0.88 +version: 0.0341 diff --git a/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml b/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml new file mode 100644 index 0000000000..c7b3930720 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml @@ -0,0 +1,29 @@ +--- #YAML:1.0 +name: Forks-Super +version: 0.16 +abstract: extensions and convenience methods for managing background processes. +author: + - Marty O'Brien <mob@cpan.org> +license: perl +distribution_type: module +configure_requires: + ExtUtils::MakeMaker: 0 +build_requires: + ExtUtils::MakeMaker: 0 +requires: + Test::More: 0 +no_index: + directory: + - t + - inc +generated_by: ExtUtils::MakeMaker version 6.55_02 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +recommends: + - Time::HiRes + - 0 + - YAML + - 0 + - Win32::Process + - 0 diff --git a/cpan/CPAN-Meta/t/data-bad/284247103-META.yml b/cpan/CPAN-Meta/t/data-bad/284247103-META.yml new file mode 100644 index 0000000000..e7390a2bff --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/284247103-META.yml @@ -0,0 +1,63 @@ +--- #YAML:1.0 + +meta-spec: + version: 1.2 + url: http://module-build.sourceforge.net/META-spec-v1.2.html + +name: Daizu +version: 0.3 +abstract: Web publishing system built on Subversion +license: gpl + +resources: + homepage: http://www.daizucms.org/ + license: http://www.gnu.org/licenses/gpl.html + +author: + - 'Geoff Richards <geoff@laxan.com>' + +requires: + Carp::Assert: 0 + Compress::Zlib: 0 + DBD::Pg: 0 + DateTime: 0 + DateTime::Format::Pg: 0.08 + Digest::SHA1: 0 + File::MMagic: 0 + HTML::Entities: 1.32 + HTML::Parser: 0 + HTML::Tagset: 0 + Image::Size: 0 + Math::Round: 0.03 + Path::Class: 0.02 + SVN::Ra: 0 + Template: 2.15 + URI: 0 + XML::LibXML: 1.59 + +build_requires: + Module::Build: 0 + +optional_features: + - syntax-highlight: + description: Automatically syntax-highlight example code in articles + requires: + Text::VimColor: 0.09 + - picture-article: + description: Publish pictures as articles, with automatic thumbnails + requires: + Image::Magick: 0 + - related-links: + description: Add a Related Links box to pages for articles + requires: + Template::Plugin::Class: 0 + +no_index: + file: + - test-repos.dump + +dynamic_config: 0 + +generated_by: Geoff Richards + +# vi:ts=4 sw=4 expandtab diff --git a/cpan/CPAN-Meta/t/data-bad/344981821-META.yml b/cpan/CPAN-Meta/t/data-bad/344981821-META.yml new file mode 100644 index 0000000000..7a51e87ebc --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/344981821-META.yml @@ -0,0 +1,26 @@ +--- +abstract: '' +author: + - 'Tokuhiro Matsuno C<< <tokuhiro __at__ mobilefactory.jp> >>' +build_requires: + Class::DBI: 0 + Class::DBI::Pager: 0 + Sledge::TestPages: 0 + Test::Base: 0 + Test::More: 0 + YAML: 0 +distribution_type: module +generated_by: 'Module::Install version 0.75' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 +name: Sledge-Plugin-Pager +no_index: + directory: + - inc + - t +requires: + Lingua::EN::Inflect: 0 + String::CamelCase: 0 +version: 0.02 diff --git a/cpan/CPAN-Meta/t/data-bad/35478989-META.yml b/cpan/CPAN-Meta/t/data-bad/35478989-META.yml new file mode 100644 index 0000000000..42e0c1081a --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/35478989-META.yml @@ -0,0 +1,17 @@ +--- #YAML:1.0 +name: oEdtk +version: 0.42 +abstract: ~ +license: ~ +author: ~ +generated_by: ExtUtils::MakeMaker version 6.44 +distribution_type: module +requires: + Config::IniFiles: 2.3 + DBI: 1.6 + Spreadsheet::WriteExcel: 1 + Sys::Hostname: Digest::MD5 + Term::ReadKey: POSIX +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 diff --git a/cpan/CPAN-Meta/t/data-bad/476602558-META.yml b/cpan/CPAN-Meta/t/data-bad/476602558-META.yml new file mode 100644 index 0000000000..ee78dc4085 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/476602558-META.yml @@ -0,0 +1,28 @@ +--- +abstract: 'Benchmarking with statistical confidence' +author: + - '-2001 Andrew Ho.' +build_requires: + ExtUtils::MakeMaker: 6.42 + Test::More: 0 +configure_requires: + ExtUtils::MakeMaker: 6.42 +distribution_type: module +generated_by: 'Module::Install version 0.91' +license: gpl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +module_name: Benchmark::Timer +name: Benchmark-Timer +no_index: + delta.pl: [] + directory: + - inc + - t +requires: + Time::HiRes: 0 + perl: 5.005 +resources: + license: http://opensource.org/licenses/gpl-license.php +version: 0.7102 diff --git a/cpan/CPAN-Meta/t/data-bad/98042513-META.yml b/cpan/CPAN-Meta/t/data-bad/98042513-META.yml new file mode 100644 index 0000000000..9a1b25f5dd --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/98042513-META.yml @@ -0,0 +1,16 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Apache-ErrorControl +version: 1.026 +version_from: ErrorControl.pm +installdirs: site +requires: + Apache::Constants: 1.09 + Apache::File: 1.01 + Apache::Request: 1.1 + Class::Date: + HTML::Template::Set: 1.01 + MIME::Entity: 5.404 + +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.17 diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_0.yml b/cpan/CPAN-Meta/t/data-bad/META-1_0.yml new file mode 100644 index 0000000000..9aaaa119c0 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-1_0.yml @@ -0,0 +1,4 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Template-DBI +version: 1.23 diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_1.yml b/cpan/CPAN-Meta/t/data-bad/META-1_1.yml new file mode 100644 index 0000000000..d90b133324 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-1_1.yml @@ -0,0 +1,6 @@ +--- #YAML:1.0 +name: Class-Virtual +version: 1.23 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.1.html + version: 1.1 diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_2.yml b/cpan/CPAN-Meta/t/data-bad/META-1_2.yml new file mode 100644 index 0000000000..ef58965f9a --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-1_2.yml @@ -0,0 +1,34 @@ +--- +name: Test-Harness-Straps +version: 0.30 +author: + - 'Michael G Schwern <schwern@pobox.com>' +license: perl +resources: + license: http://dev.perl.org/licenses/ +requires: + File::Spec: 0.6 +provides: + Test::Harness::Assert: + file: lib/Test/Harness/Assert.pm + version: 0.02 + Test::Harness::Iterator: + file: lib/Test/Harness/Iterator.pm + version: 0.02 + Test::Harness::Iterator::ARRAY: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Iterator::FH: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Point: + file: lib/Test/Harness/Point.pm + version: 0.01 + Test::Harness::Results: + file: lib/Test/Harness/Results.pm + version: 0.01 + Test::Harness::Straps: + file: lib/Test/Harness/Straps.pm + version: 0.30 +generated_by: Module::Build version 0.280801 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.2.html + version: 1.2 diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_3.yml b/cpan/CPAN-Meta/t/data-bad/META-1_3.yml new file mode 100644 index 0000000000..ad215ad92c --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-1_3.yml @@ -0,0 +1,28 @@ +--- +abstract: a modern perl interactive shell +author: Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>) +build_requires: + Test::More: 0 +distribution_type: module +generated_by: Module::Install version 0.67 +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 +name: Devel-REPL +no_index: + directory: + - inc + - t +requires: + Data::Dump::Streamer: 0 + File::HomeDir: 0 + File::Spec: 0 + Lexical::Persistence: 0 + Moose: 0 + MooseX::Getopt: 0 + MooseX::Object::Pluggable: 0 + Term::ReadLine: 0 + namespace::clean: 0 + perl: 5.8.1 +version: 1.001000 diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_4.yml b/cpan/CPAN-Meta/t/data-bad/META-1_4.yml new file mode 100644 index 0000000000..1336f10a48 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-1_4.yml @@ -0,0 +1,128 @@ +--- +author: + - 'Ken Williams <kwilliams@cpan.org>' + - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>." +build_requires: + File::Temp: 0.15 + Test::Harness: 3.16 + Test::More: 0.49 +generated_by: 'Module::Build version 0.3608' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Module-Build +provides: + Module::Build: + file: lib/Module/Build.pm + version: 0.36_08 + Module::Build::Base: + file: lib/Module/Build/Base.pm + version: 0.36_08 + Module::Build::Compat: + file: lib/Module/Build/Compat.pm + version: 0.36_08 + Module::Build::Config: + file: lib/Module/Build/Config.pm + version: 0.36_08 + Module::Build::Cookbook: + file: lib/Module/Build/Cookbook.pm + version: 0.36_08 + Module::Build::Dumper: + file: lib/Module/Build/Dumper.pm + version: 0.36_08 + Module::Build::ModuleInfo: + file: lib/Module/Build/ModuleInfo.pm + version: 0.36_08 + Module::Build::Notes: + file: lib/Module/Build/Notes.pm + version: 0.36_08 + Module::Build::PPMMaker: + file: lib/Module/Build/PPMMaker.pm + version: 0.36_08 + Module::Build::Platform::Amiga: + file: lib/Module/Build/Platform/Amiga.pm + version: 0.36_08 + Module::Build::Platform::Default: + file: lib/Module/Build/Platform/Default.pm + version: 0.36_08 + Module::Build::Platform::EBCDIC: + file: lib/Module/Build/Platform/EBCDIC.pm + version: 0.36_08 + Module::Build::Platform::MPEiX: + file: lib/Module/Build/Platform/MPEiX.pm + version: 0.36_08 + Module::Build::Platform::MacOS: + file: lib/Module/Build/Platform/MacOS.pm + version: 0.36_08 + Module::Build::Platform::RiscOS: + file: lib/Module/Build/Platform/RiscOS.pm + version: 0.36_08 + Module::Build::Platform::Unix: + file: lib/Module/Build/Platform/Unix.pm + version: 0.36_08 + Module::Build::Platform::VMS: + file: lib/Module/Build/Platform/VMS.pm + version: 0.36_08 + Module::Build::Platform::VOS: + file: lib/Module/Build/Platform/VOS.pm + version: 0.36_08 + Module::Build::Platform::Windows: + file: lib/Module/Build/Platform/Windows.pm + version: 0.36_08 + Module::Build::Platform::aix: + file: lib/Module/Build/Platform/aix.pm + version: 0.36_08 + Module::Build::Platform::cygwin: + file: lib/Module/Build/Platform/cygwin.pm + version: 0.36_08 + Module::Build::Platform::darwin: + file: lib/Module/Build/Platform/darwin.pm + version: 0.36_08 + Module::Build::Platform::os2: + file: lib/Module/Build/Platform/os2.pm + version: 0.36_08 + Module::Build::PodParser: + file: lib/Module/Build/PodParser.pm + version: 0.36_08 + Module::Build::Version: + file: lib/Module/Build/Version.pm + version: 0.77 + Module::Build::YAML: + file: lib/Module/Build/YAML.pm + version: 1.40 + inc::latest: + file: lib/inc/latest.pm + version: 0.36_08 + inc::latest::private: + file: lib/inc/latest/private.pm + version: 0.36_08 +recommends: + ExtUtils::Install: 0.3 + ExtUtils::Manifest: 1.54 + version: 0.74 +requires: + Cwd: 0 + Data::Dumper: 0 + ExtUtils::CBuilder: 0.27 + ExtUtils::Install: 0 + ExtUtils::Manifest: 0 + ExtUtils::Mkbootstrap: 0 + ExtUtils::ParseXS: 2.21 + File::Basename: 0 + File::Compare: 0 + File::Copy: 0 + File::Find: 0 + File::Path: 0 + File::Spec: 0.82 + Getopt::Long: 0 + IO::File: 0 + Test::Harness: 0 + Text::Abbrev: 0 + Text::ParseWords: 0 + perl: 5.006001 +resources: + MailingList: mailto:module-build@perl.org + license: http://dev.perl.org/licenses/ + repository: http://github.com/dagolden/module-build/ +version: 0.36_08 diff --git a/cpan/CPAN-Meta/t/data-bad/META-2.json b/cpan/CPAN-Meta/t/data-bad/META-2.json new file mode 100644 index 0000000000..6734399e22 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/META-2.json @@ -0,0 +1,76 @@ +{ + "resources" : { + "license" : [ + "http://dev.perl.org/licenses/" + ] + }, + "generated_by" : "Module::Build version 0.36", + "meta-spec" : { + "version" : "2", + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "version" : "0.36", + "name" : "Module-Build", + "author" : [ + "Ken Williams <kwilliams@cpan.org>", + "Module-Build List <module-build@perl.org>" + ], + "release_status" : "stable", + "license" : [ + "perl_5" + ], + "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah", + "keywords" : [ + "toolchain", + "cpan", + "dual-life" + ], + "prereqs" : { + "runtime" : { + "requires" : { + "File::Copy" : "0", + "IO::File" : "0", + "Data::Dumper" : "0", + "File::Spec" : "0", + "Config" : "0", + "ExtUtils::Install" : "0", + "perl" : "5.006", + "File::Compare" : "0", + "File::Find" : "0", + "File::Path" : "0", + "File::Basename" : "0", + "Cwd" : "0" + }, + "recommends" : { + "YAML" : "0.35", + "ExtUtils::ParseXS" : "2.02", + "Pod::Text" : "0", + "ExtUtils::Install" : "0.3", + "Archive::Tar" : "1.00" + } + }, + "build" : { + "requires" : { + "Test::More" : "0" + } + } + }, + "optional_features" : { + "domination" : { + "prereqs" : { + "develop" : { + "requires" : { + "Genius::Evil" : "1.234" + } + }, + "runtime" : { + "requires" : { + "Machine::Weather" : "2.0" + } + } + }, + "description" : "Take over the world" + } + }, + "abstract" : "Build and install Perl modules" +} diff --git a/cpan/CPAN-Meta/t/data-bad/restrictive-2.json b/cpan/CPAN-Meta/t/data-bad/restrictive-2.json new file mode 100644 index 0000000000..2fdd9fb39a --- /dev/null +++ b/cpan/CPAN-Meta/t/data-bad/restrictive-2.json @@ -0,0 +1,89 @@ +{ + "resources" : { + "license" : [ + "http://dev.perl.org/licenses/" + ], + "repository" : { + "url" : "svn://repo.example.com/foo-bar#fakeanchor", + "web" : "http://www.example.com" + } + }, + "generated_by" : "Module::Build version 0.36", + "meta-spec" : { + "version" : "2", + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "version" : "0.36", + "name" : "Module-Build", + "dynamic_config" : 1, + "author" : [ + "Ken Williams <kwilliams@cpan.org>", + "Module-Build List <module-build@perl.org>" + ], + "release_status" : "stable", + "license" : [ + "restrictive" + ], + "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah", + "keywords" : [ + "toolchain", + "cpan", + "dual-life" + ], + "prereqs" : { + "runtime" : { + "requires" : { + "File::Copy" : "0", + "IO::File" : "0", + "Data::Dumper" : "0", + "File::Spec" : "0", + "Config" : "0", + "ExtUtils::Install" : "0", + "perl" : "5.006", + "File::Compare" : "0", + "File::Find" : "0", + "File::Path" : "0", + "File::Basename" : "0", + "Cwd" : "0" + }, + "recommends" : { + "YAML" : "0.35", + "ExtUtils::ParseXS" : "2.02", + "Pod::Text" : "0", + "ExtUtils::Install" : "0.3", + "Archive::Tar" : "1.00" + } + }, + "build" : { + "requires" : { + "Build::Requires": "1.1", + "Test::More" : "0" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.88", + "Test::Requires" : "1.2" + } + } + }, + "optional_features" : { + "domination" : { + "prereqs" : { + "develop" : { + "requires" : { + "Genius::Evil" : "1.234" + } + }, + "runtime" : { + "requires" : { + "Machine::Weather" : "2.0" + } + } + }, + "description" : "Take over the world" + } + }, + "abstract" : "Build and install Perl modules", + "x_whatever" : "Custom key" +} diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_0.yml b/cpan/CPAN-Meta/t/data-fail/META-1_0.yml new file mode 100644 index 0000000000..44b0bbf6fd --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-1_0.yml @@ -0,0 +1,11 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Template-DBI +version_from: lib/Template/Plugin/DBI.pm +installdirs: site +license: perl +requires: + DBI: 1 + Template: 2.15 +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.17 diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_1.yml b/cpan/CPAN-Meta/t/data-fail/META-1_1.yml new file mode 100644 index 0000000000..e96665f0d3 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-1_1.yml @@ -0,0 +1,15 @@ +--- #YAML:1.0 +name: Class-Virtual +abstract: ~ +license: unknown +generated_by: ExtUtils::MakeMaker version 6.30_03 +author: ~ +distribution_type: module +requires: + Carp::Assert: 0.1 + Class::Data::Inheritable: 0.02 + Class::ISA: 0.31 + Test::More: 0.5 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.1.html + version: 1.1 diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_2.yml b/cpan/CPAN-Meta/t/data-fail/META-1_2.yml new file mode 100644 index 0000000000..4829149914 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-1_2.yml @@ -0,0 +1,34 @@ +--- +name: Test-Harness-Straps +author: + - 'Michael G Schwern <schwern@pobox.com>' +abstract: detailed analysis of test results +license: perl +resources: + license: http://dev.perl.org/licenses/ +requires: + File::Spec: 0.6 +provides: + Test::Harness::Assert: + file: lib/Test/Harness/Assert.pm + version: 0.02 + Test::Harness::Iterator: + file: lib/Test/Harness/Iterator.pm + version: 0.02 + Test::Harness::Iterator::ARRAY: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Iterator::FH: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Point: + file: lib/Test/Harness/Point.pm + version: 0.01 + Test::Harness::Results: + file: lib/Test/Harness/Results.pm + version: 0.01 + Test::Harness::Straps: + file: lib/Test/Harness/Straps.pm + version: 0.30 +generated_by: Module::Build version 0.280801 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.2.html + version: 1.2 diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_3.yml b/cpan/CPAN-Meta/t/data-fail/META-1_3.yml new file mode 100644 index 0000000000..3bbe0718c6 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-1_3.yml @@ -0,0 +1,28 @@ +--- +abstract: a modern perl interactive shell +author: + - Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>) +build_requires: + Test::More: 0 +distribution_type: module +generated_by: Module::Install version 0.67 +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 +name: Devel-REPL +no_index: + directory: + - inc + - t +requires: + Data::Dump::Streamer: 0 + File::HomeDir: 0 + File::Spec: 0 + Lexical::Persistence: 0 + Moose: 0 + MooseX::Getopt: 0 + MooseX::Object::Pluggable: 0 + Term::ReadLine: 0 + namespace::clean: 0 + perl: 5.8.1 diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_4.yml b/cpan/CPAN-Meta/t/data-fail/META-1_4.yml new file mode 100644 index 0000000000..cec4d11ca4 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-1_4.yml @@ -0,0 +1,129 @@ +--- +abstract: 'Build and install Perl modules' +author: + - 'Ken Williams <kwilliams@cpan.org>' + - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>." +build_requires: + File::Temp: 0.15 + Test::Harness: 3.16 + Test::More: 0.49 +generated_by: 'Module::Build version 0.3608' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Module-Build +provides: + Module::Build: + file: lib/Module/Build.pm + version: 0.36_08 + Module::Build::Base: + file: lib/Module/Build/Base.pm + version: 0.36_08 + Module::Build::Compat: + file: lib/Module/Build/Compat.pm + version: 0.36_08 + Module::Build::Config: + file: lib/Module/Build/Config.pm + version: 0.36_08 + Module::Build::Cookbook: + file: lib/Module/Build/Cookbook.pm + version: 0.36_08 + Module::Build::Dumper: + file: lib/Module/Build/Dumper.pm + version: 0.36_08 + Module::Build::ModuleInfo: + file: lib/Module/Build/ModuleInfo.pm + version: 0.36_08 + Module::Build::Notes: + file: lib/Module/Build/Notes.pm + version: 0.36_08 + Module::Build::PPMMaker: + file: lib/Module/Build/PPMMaker.pm + version: 0.36_08 + Module::Build::Platform::Amiga: + file: lib/Module/Build/Platform/Amiga.pm + version: 0.36_08 + Module::Build::Platform::Default: + file: lib/Module/Build/Platform/Default.pm + version: 0.36_08 + Module::Build::Platform::EBCDIC: + file: lib/Module/Build/Platform/EBCDIC.pm + version: 0.36_08 + Module::Build::Platform::MPEiX: + file: lib/Module/Build/Platform/MPEiX.pm + version: 0.36_08 + Module::Build::Platform::MacOS: + file: lib/Module/Build/Platform/MacOS.pm + version: 0.36_08 + Module::Build::Platform::RiscOS: + file: lib/Module/Build/Platform/RiscOS.pm + version: 0.36_08 + Module::Build::Platform::Unix: + file: lib/Module/Build/Platform/Unix.pm + version: 0.36_08 + Module::Build::Platform::VMS: + file: lib/Module/Build/Platform/VMS.pm + version: 0.36_08 + Module::Build::Platform::VOS: + file: lib/Module/Build/Platform/VOS.pm + version: 0.36_08 + Module::Build::Platform::Windows: + file: lib/Module/Build/Platform/Windows.pm + version: 0.36_08 + Module::Build::Platform::aix: + file: lib/Module/Build/Platform/aix.pm + version: 0.36_08 + Module::Build::Platform::cygwin: + file: lib/Module/Build/Platform/cygwin.pm + version: 0.36_08 + Module::Build::Platform::darwin: + file: lib/Module/Build/Platform/darwin.pm + version: 0.36_08 + Module::Build::Platform::os2: + file: lib/Module/Build/Platform/os2.pm + version: 0.36_08 + Module::Build::PodParser: + file: lib/Module/Build/PodParser.pm + version: 0.36_08 + Module::Build::Version: + file: lib/Module/Build/Version.pm + version: 0.77 + Module::Build::YAML: + file: lib/Module/Build/YAML.pm + version: 1.40 + inc::latest: + file: lib/inc/latest.pm + version: 0.36_08 + inc::latest::private: + file: lib/inc/latest/private.pm + version: 0.36_08 +recommends: + ExtUtils::Install: 0.3 + ExtUtils::Manifest: 1.54 + version: 0.74 +requires: + Cwd: 0 + Data::Dumper: 0 + ExtUtils::CBuilder: 0.27 + ExtUtils::Install: 0 + ExtUtils::Manifest: 0 + ExtUtils::Mkbootstrap: 0 + ExtUtils::ParseXS: 2.21 + File::Basename: 0 + File::Compare: 0 + File::Copy: 0 + File::Find: 0 + File::Path: 0 + File::Spec: 0.82 + Getopt::Long: 0 + IO::File: 0 + Test::Harness: 0 + Text::Abbrev: 0 + Text::ParseWords: 0 + perl: 5.006001 +resources: + MailingList: mailto:module-build@perl.org + license: http://dev.perl.org/licenses/ + repository: http://github.com/dagolden/module-build/ + diff --git a/cpan/CPAN-Meta/t/data-fail/META-2.json b/cpan/CPAN-Meta/t/data-fail/META-2.json new file mode 100644 index 0000000000..4cad8f3a24 --- /dev/null +++ b/cpan/CPAN-Meta/t/data-fail/META-2.json @@ -0,0 +1,76 @@ +{ + "resources" : { + "license" : [ + "http://dev.perl.org/licenses/" + ] + }, + "generated_by" : "Module::Build version 0.36", + "meta-spec" : { + "version" : "2", + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "name" : "Module-Build", + "dynamic_config" : 1, + "author" : [ + "Ken Williams <kwilliams@cpan.org>", + "Module-Build List <module-build@perl.org>" + ], + "release_status" : "stable", + "license" : [ + "perl_5" + ], + "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah", + "keywords" : [ + "toolchain", + "cpan", + "dual-life" + ], + "prereqs" : { + "runtime" : { + "requires" : { + "File::Copy" : "0", + "IO::File" : "0", + "Data::Dumper" : "0", + "File::Spec" : "0", + "Config" : "0", + "ExtUtils::Install" : "0", + "perl" : "5.006", + "File::Compare" : "0", + "File::Find" : "0", + "File::Path" : "0", + "File::Basename" : "0", + "Cwd" : "0" + }, + "recommends" : { + "YAML" : "0.35", + "ExtUtils::ParseXS" : "2.02", + "Pod::Text" : "0", + "ExtUtils::Install" : "0.3", + "Archive::Tar" : "1.00" + } + }, + "build" : { + "requires" : { + "Test::More" : "0" + } + } + }, + "optional_features" : { + "domination" : { + "prereqs" : { + "develop" : { + "requires" : { + "Genius::Evil" : "1.234" + } + }, + "runtime" : { + "requires" : { + "Machine::Weather" : "2.0" + } + } + }, + "description" : "Take over the world" + } + }, + "abstract" : "Build and install Perl modules" +} diff --git a/cpan/CPAN-Meta/t/data/META-1_0.yml b/cpan/CPAN-Meta/t/data/META-1_0.yml new file mode 100644 index 0000000000..e72d9ed944 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-1_0.yml @@ -0,0 +1,12 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Template-DBI +version: 2.64 +version_from: lib/Template/Plugin/DBI.pm +installdirs: site +license: perl +requires: + DBI: 1 + Template: 2.15 +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.17 diff --git a/cpan/CPAN-Meta/t/data/META-1_1.yml b/cpan/CPAN-Meta/t/data/META-1_1.yml new file mode 100644 index 0000000000..d77007737f --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-1_1.yml @@ -0,0 +1,16 @@ +--- #YAML:1.0 +name: Class-Virtual +version: 0.06 +abstract: ~ +license: unknown +generated_by: ExtUtils::MakeMaker version 6.30_03 +author: ~ +distribution_type: module +requires: + Carp::Assert: 0.1 + Class::Data::Inheritable: 0.02 + Class::ISA: 0.31 + Test::More: 0.5 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.1.html + version: 1.1 diff --git a/cpan/CPAN-Meta/t/data/META-1_2.yml b/cpan/CPAN-Meta/t/data/META-1_2.yml new file mode 100644 index 0000000000..51c2a963bc --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-1_2.yml @@ -0,0 +1,35 @@ +--- +name: Test-Harness-Straps +version: 0.30 +author: + - 'Michael G Schwern <schwern@pobox.com>' +abstract: detailed analysis of test results +license: perl +resources: + license: http://dev.perl.org/licenses/ +requires: + File::Spec: 0.6 +provides: + Test::Harness::Assert: + file: lib/Test/Harness/Assert.pm + version: 0.02 + Test::Harness::Iterator: + file: lib/Test/Harness/Iterator.pm + version: 0.02 + Test::Harness::Iterator::ARRAY: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Iterator::FH: + file: lib/Test/Harness/Iterator.pm + Test::Harness::Point: + file: lib/Test/Harness/Point.pm + version: 0.01 + Test::Harness::Results: + file: lib/Test/Harness/Results.pm + version: 0.01 + Test::Harness::Straps: + file: lib/Test/Harness/Straps.pm + version: 0.30 +generated_by: Module::Build version 0.280801 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.2.html + version: 1.2 diff --git a/cpan/CPAN-Meta/t/data/META-1_3.yml b/cpan/CPAN-Meta/t/data/META-1_3.yml new file mode 100644 index 0000000000..c26a3e0b74 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-1_3.yml @@ -0,0 +1,29 @@ +--- +abstract: a modern perl interactive shell +author: + - Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>) +build_requires: + Test::More: 0 +distribution_type: module +generated_by: Module::Install version 0.67 +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 +name: Devel-REPL +no_index: + directory: + - inc + - t +requires: + Data::Dump::Streamer: 0 + File::HomeDir: 0 + File::Spec: 0 + Lexical::Persistence: 0 + Moose: 0 + MooseX::Getopt: 0 + MooseX::Object::Pluggable: 0 + Term::ReadLine: 0 + namespace::clean: 0 + perl: 5.8.1 +version: 1.001000 diff --git a/cpan/CPAN-Meta/t/data/META-1_4.yml b/cpan/CPAN-Meta/t/data/META-1_4.yml new file mode 100644 index 0000000000..801f5797c0 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-1_4.yml @@ -0,0 +1,132 @@ +--- +abstract: 'Build and install Perl modules' +author: + - 'Ken Williams <kwilliams@cpan.org>' + - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>." +build_requires: + File::Temp: 0.15 + Test::Harness: 3.16 + Test::More: 0.49 +generated_by: 'Module::Build version 0.3608' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Module-Build +provides: + Module::Build: + file: lib/Module/Build.pm + version: 0.36_08 + Module::Build::Base: + file: lib/Module/Build/Base.pm + version: 0.36_08 + Module::Build::Compat: + file: lib/Module/Build/Compat.pm + version: 0.36_08 + Module::Build::Config: + file: lib/Module/Build/Config.pm + version: 0.36_08 + Module::Build::Cookbook: + file: lib/Module/Build/Cookbook.pm + version: 0.36_08 + Module::Build::Dumper: + file: lib/Module/Build/Dumper.pm + version: 0.36_08 + Module::Build::ModuleInfo: + file: lib/Module/Build/ModuleInfo.pm + version: 0.36_08 + Module::Build::Notes: + file: lib/Module/Build/Notes.pm + version: 0.36_08 + Module::Build::PPMMaker: + file: lib/Module/Build/PPMMaker.pm + version: 0.36_08 + Module::Build::Platform::Amiga: + file: lib/Module/Build/Platform/Amiga.pm + version: 0.36_08 + Module::Build::Platform::Default: + file: lib/Module/Build/Platform/Default.pm + version: 0.36_08 + Module::Build::Platform::EBCDIC: + file: lib/Module/Build/Platform/EBCDIC.pm + version: 0.36_08 + Module::Build::Platform::MPEiX: + file: lib/Module/Build/Platform/MPEiX.pm + version: 0.36_08 + Module::Build::Platform::MacOS: + file: lib/Module/Build/Platform/MacOS.pm + version: 0.36_08 + Module::Build::Platform::RiscOS: + file: lib/Module/Build/Platform/RiscOS.pm + version: 0.36_08 + Module::Build::Platform::Unix: + file: lib/Module/Build/Platform/Unix.pm + version: 0.36_08 + Module::Build::Platform::VMS: + file: lib/Module/Build/Platform/VMS.pm + version: 0.36_08 + Module::Build::Platform::VOS: + file: lib/Module/Build/Platform/VOS.pm + version: 0.36_08 + Module::Build::Platform::Windows: + file: lib/Module/Build/Platform/Windows.pm + version: 0.36_08 + Module::Build::Platform::aix: + file: lib/Module/Build/Platform/aix.pm + version: 0.36_08 + Module::Build::Platform::cygwin: + file: lib/Module/Build/Platform/cygwin.pm + version: 0.36_08 + Module::Build::Platform::darwin: + file: lib/Module/Build/Platform/darwin.pm + version: 0.36_08 + Module::Build::Platform::os2: + file: lib/Module/Build/Platform/os2.pm + version: 0.36_08 + Module::Build::PodParser: + file: lib/Module/Build/PodParser.pm + version: 0.36_08 + Module::Build::Version: + file: lib/Module/Build/Version.pm + version: 0.77 + Module::Build::YAML: + file: lib/Module/Build/YAML.pm + version: 1.40 + inc::latest: + file: lib/inc/latest.pm + version: 0.36_08 + inc::latest::private: + file: lib/inc/latest/private.pm + version: 0.36_08 +recommends: + ExtUtils::Install: 0.3 + ExtUtils::Manifest: 1.54 + version: 0.74 +requires: + Cwd: 0 + Data::Dumper: 0 + ExtUtils::CBuilder: 0.27 + ExtUtils::Install: 0 + ExtUtils::Manifest: 0 + ExtUtils::Mkbootstrap: 0 + ExtUtils::ParseXS: 2.21 + File::Basename: 0 + File::Compare: 0 + File::Copy: 0 + File::Find: 0 + File::Path: 0 + File::Spec: 0.82 + Getopt::Long: 0 + IO::File: 0 + Test::Harness: 0 + Text::Abbrev: 0 + Text::ParseWords: 0 + perl: 5.006001 +resources: + MailingList: mailto:module-build@perl.org + license: http://dev.perl.org/licenses/ + repository: http://github.com/dagolden/module-build/ +version: 0.36_08 +x-whatever: this is a custom field +x_whatelse: so is this +XWhatNow: and this diff --git a/cpan/CPAN-Meta/t/data/META-2.json b/cpan/CPAN-Meta/t/data/META-2.json new file mode 100644 index 0000000000..d737fef231 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/META-2.json @@ -0,0 +1,89 @@ +{ + "resources" : { + "license" : [ + "http://dev.perl.org/licenses/" + ], + "repository" : { + "url" : "svn://repo.example.com/foo-bar#fakeanchor", + "web" : "http://www.example.com" + } + }, + "generated_by" : "Module::Build version 0.36", + "meta-spec" : { + "version" : "2", + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "version" : "0.36", + "name" : "Module-Build", + "dynamic_config" : 1, + "author" : [ + "Ken Williams <kwilliams@cpan.org>", + "Module-Build List <module-build@perl.org>" + ], + "release_status" : "stable", + "license" : [ + "perl_5" + ], + "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah", + "keywords" : [ + "toolchain", + "cpan", + "dual-life" + ], + "prereqs" : { + "runtime" : { + "requires" : { + "File::Copy" : "0", + "IO::File" : "0", + "Data::Dumper" : "0", + "File::Spec" : "0", + "Config" : "0", + "ExtUtils::Install" : "0", + "perl" : "5.006", + "File::Compare" : "0", + "File::Find" : "0", + "File::Path" : "0", + "File::Basename" : "0", + "Cwd" : "0" + }, + "recommends" : { + "YAML" : "0.35", + "ExtUtils::ParseXS" : "2.02", + "Pod::Text" : "0", + "ExtUtils::Install" : "0.3", + "Archive::Tar" : "1.00" + } + }, + "build" : { + "requires" : { + "Build::Requires": "1.1", + "Test::More" : "0" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.88", + "Test::Requires" : "1.2" + } + } + }, + "optional_features" : { + "domination" : { + "prereqs" : { + "develop" : { + "requires" : { + "Genius::Evil" : "1.234" + } + }, + "runtime" : { + "requires" : { + "Machine::Weather" : "2.0" + } + } + }, + "description" : "Take over the world" + } + }, + "abstract" : "Build and install Perl modules", + "x_whatever" : "Custom key" +} diff --git a/cpan/CPAN-Meta/t/data/resources.yml b/cpan/CPAN-Meta/t/data/resources.yml new file mode 100644 index 0000000000..8013137784 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/resources.yml @@ -0,0 +1,49 @@ +--- #YAML:1.0 +name: WWW-Mechanize +version: 1.64 +abstract: Handy web browsing in a Perl object +author: + - Andy Lester <andy@petdance.com> +license: perl +distribution_type: module +configure_requires: + ExtUtils::MakeMaker: 0 +build_requires: + ExtUtils::MakeMaker: 0 +requires: + Carp: 0 + File::Temp: 0 + FindBin: 0 + Getopt::Long: 0 + HTML::Form: 1.038 + HTML::HeadParser: 0 + HTML::Parser: 3.33 + HTML::TokeParser: 2.28 + HTTP::Daemon: 0 + HTTP::Request: 1.3 + HTTP::Server::Simple: 0.35 + HTTP::Server::Simple::CGI: 0 + HTTP::Status: 0 + LWP: 5.829 + LWP::UserAgent: 5.829 + perl: 5.008 + Pod::Usage: 0 + Test::More: 0.34 + Test::Warn: 0.11 + URI: 1.36 + URI::file: 0 + URI::URL: 0 +resources: + bugtracker: http://code.google.com/p/www-mechanize/issues/list + homepage: http://code.google.com/p/www-mechanize/ + license: http://dev.perl.org/licenses/ + MailingList: http://groups.google.com/group/www-mechanize-users + Repository: http://code.google.com/p/www-mechanize/source +no_index: + directory: + - t + - inc +generated_by: ExtUtils::MakeMaker version 6.56 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 diff --git a/cpan/CPAN-Meta/t/data/restricted-2.json b/cpan/CPAN-Meta/t/data/restricted-2.json new file mode 100644 index 0000000000..88886db9fc --- /dev/null +++ b/cpan/CPAN-Meta/t/data/restricted-2.json @@ -0,0 +1,89 @@ +{ + "resources" : { + "license" : [ + "http://dev.perl.org/licenses/" + ], + "repository" : { + "url" : "svn://repo.example.com/foo-bar#fakeanchor", + "web" : "http://www.example.com" + } + }, + "generated_by" : "Module::Build version 0.36", + "meta-spec" : { + "version" : "2", + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "version" : "0.36", + "name" : "Module-Build", + "dynamic_config" : 1, + "author" : [ + "Ken Williams <kwilliams@cpan.org>", + "Module-Build List <module-build@perl.org>" + ], + "release_status" : "stable", + "license" : [ + "restricted" + ], + "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah", + "keywords" : [ + "toolchain", + "cpan", + "dual-life" + ], + "prereqs" : { + "runtime" : { + "requires" : { + "File::Copy" : "0", + "IO::File" : "0", + "Data::Dumper" : "0", + "File::Spec" : "0", + "Config" : "0", + "ExtUtils::Install" : "0", + "perl" : "5.006", + "File::Compare" : "0", + "File::Find" : "0", + "File::Path" : "0", + "File::Basename" : "0", + "Cwd" : "0" + }, + "recommends" : { + "YAML" : "0.35", + "ExtUtils::ParseXS" : "2.02", + "Pod::Text" : "0", + "ExtUtils::Install" : "0.3", + "Archive::Tar" : "1.00" + } + }, + "build" : { + "requires" : { + "Build::Requires": "1.1", + "Test::More" : "0" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.88", + "Test::Requires" : "1.2" + } + } + }, + "optional_features" : { + "domination" : { + "prereqs" : { + "develop" : { + "requires" : { + "Genius::Evil" : "1.234" + } + }, + "runtime" : { + "requires" : { + "Machine::Weather" : "2.0" + } + } + }, + "description" : "Take over the world" + } + }, + "abstract" : "Build and install Perl modules", + "x_whatever" : "Custom key" +} diff --git a/cpan/CPAN-Meta/t/data/restrictive-1_4.yml b/cpan/CPAN-Meta/t/data/restrictive-1_4.yml new file mode 100644 index 0000000000..b780016da2 --- /dev/null +++ b/cpan/CPAN-Meta/t/data/restrictive-1_4.yml @@ -0,0 +1,132 @@ +--- +abstract: 'Build and install Perl modules' +author: + - 'Ken Williams <kwilliams@cpan.org>' + - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>." +build_requires: + File::Temp: 0.15 + Test::Harness: 3.16 + Test::More: 0.49 +generated_by: 'Module::Build version 0.3608' +license: restrictive +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Module-Build +provides: + Module::Build: + file: lib/Module/Build.pm + version: 0.36_08 + Module::Build::Base: + file: lib/Module/Build/Base.pm + version: 0.36_08 + Module::Build::Compat: + file: lib/Module/Build/Compat.pm + version: 0.36_08 + Module::Build::Config: + file: lib/Module/Build/Config.pm + version: 0.36_08 + Module::Build::Cookbook: + file: lib/Module/Build/Cookbook.pm + version: 0.36_08 + Module::Build::Dumper: + file: lib/Module/Build/Dumper.pm + version: 0.36_08 + Module::Build::ModuleInfo: + file: lib/Module/Build/ModuleInfo.pm + version: 0.36_08 + Module::Build::Notes: + file: lib/Module/Build/Notes.pm + version: 0.36_08 + Module::Build::PPMMaker: + file: lib/Module/Build/PPMMaker.pm + version: 0.36_08 + Module::Build::Platform::Amiga: + file: lib/Module/Build/Platform/Amiga.pm + version: 0.36_08 + Module::Build::Platform::Default: + file: lib/Module/Build/Platform/Default.pm + version: 0.36_08 + Module::Build::Platform::EBCDIC: + file: lib/Module/Build/Platform/EBCDIC.pm + version: 0.36_08 + Module::Build::Platform::MPEiX: + file: lib/Module/Build/Platform/MPEiX.pm + version: 0.36_08 + Module::Build::Platform::MacOS: + file: lib/Module/Build/Platform/MacOS.pm + version: 0.36_08 + Module::Build::Platform::RiscOS: + file: lib/Module/Build/Platform/RiscOS.pm + version: 0.36_08 + Module::Build::Platform::Unix: + file: lib/Module/Build/Platform/Unix.pm + version: 0.36_08 + Module::Build::Platform::VMS: + file: lib/Module/Build/Platform/VMS.pm + version: 0.36_08 + Module::Build::Platform::VOS: + file: lib/Module/Build/Platform/VOS.pm + version: 0.36_08 + Module::Build::Platform::Windows: + file: lib/Module/Build/Platform/Windows.pm + version: 0.36_08 + Module::Build::Platform::aix: + file: lib/Module/Build/Platform/aix.pm + version: 0.36_08 + Module::Build::Platform::cygwin: + file: lib/Module/Build/Platform/cygwin.pm + version: 0.36_08 + Module::Build::Platform::darwin: + file: lib/Module/Build/Platform/darwin.pm + version: 0.36_08 + Module::Build::Platform::os2: + file: lib/Module/Build/Platform/os2.pm + version: 0.36_08 + Module::Build::PodParser: + file: lib/Module/Build/PodParser.pm + version: 0.36_08 + Module::Build::Version: + file: lib/Module/Build/Version.pm + version: 0.77 + Module::Build::YAML: + file: lib/Module/Build/YAML.pm + version: 1.40 + inc::latest: + file: lib/inc/latest.pm + version: 0.36_08 + inc::latest::private: + file: lib/inc/latest/private.pm + version: 0.36_08 +recommends: + ExtUtils::Install: 0.3 + ExtUtils::Manifest: 1.54 + version: 0.74 +requires: + Cwd: 0 + Data::Dumper: 0 + ExtUtils::CBuilder: 0.27 + ExtUtils::Install: 0 + ExtUtils::Manifest: 0 + ExtUtils::Mkbootstrap: 0 + ExtUtils::ParseXS: 2.21 + File::Basename: 0 + File::Compare: 0 + File::Copy: 0 + File::Find: 0 + File::Path: 0 + File::Spec: 0.82 + Getopt::Long: 0 + IO::File: 0 + Test::Harness: 0 + Text::Abbrev: 0 + Text::ParseWords: 0 + perl: 5.006001 +resources: + MailingList: mailto:module-build@perl.org + license: http://dev.perl.org/licenses/ + repository: http://github.com/dagolden/module-build/ +version: 0.36_08 +x-whatever: this is a custom field +x_whatelse: so is this +XWhatNow: and this diff --git a/cpan/CPAN-Meta/t/load-bad.t b/cpan/CPAN-Meta/t/load-bad.t new file mode 100644 index 0000000000..d18b65caa6 --- /dev/null +++ b/cpan/CPAN-Meta/t/load-bad.t @@ -0,0 +1,25 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use File::Spec; +use IO::Dir; + +sub _slurp { do { local(@ARGV,$/)=shift(@_); <> } } + +my $data_dir = IO::Dir->new( 't/data-bad' ); +my @files = sort grep { /^\w/ } $data_dir->read; + +for my $f ( sort @files ) { + my $path = File::Spec->catfile('t','data-bad',$f); + my $meta = eval { CPAN::Meta->load_file( $path, { fix_errors => 1 } ) }; + ok( defined $meta, "load_file('$f')" ) or diag $@; + my $string = _slurp($path); + my $method = $path =~ /\.json/ ? "load_json_string" : "load_yaml_string"; + my $meta2 = eval { CPAN::Meta->$method( $string, { fix_errors => 1 } ) }; + ok( defined $meta2, "$method(slurp('$f'))" ) or diag $@; +} + +done_testing; + diff --git a/cpan/CPAN-Meta/t/meta-obj.t b/cpan/CPAN-Meta/t/meta-obj.t new file mode 100644 index 0000000000..522f67dbde --- /dev/null +++ b/cpan/CPAN-Meta/t/meta-obj.t @@ -0,0 +1,240 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; + +use Scalar::Util qw(blessed); + +my $distmeta = { + name => 'Module-Build', + abstract => 'Build and install Perl modules', + description => "Module::Build is a system for building, testing, " + . "and installing Perl modules. It is meant to be an " + . "alternative to ExtUtils::MakeMaker... blah blah blah", + version => '0.36', + author => [ + 'Ken Williams <kwilliams@cpan.org>', + 'Module-Build List <module-build@perl.org>', # additional contact + ], + release_status => 'stable', + license => [ 'perl_5' ], + prereqs => { + runtime => { + requires => { + 'perl' => '5.006', + 'Config' => '0', + 'Cwd' => '0', + 'Data::Dumper' => '0', + 'ExtUtils::Install' => '0', + 'File::Basename' => '0', + 'File::Compare' => '0', + 'File::Copy' => '0', + 'File::Find' => '0', + 'File::Path' => '0', + 'File::Spec' => '0', + 'IO::File' => '0', + }, + recommends => { + 'Archive::Tar' => '1.00', + 'ExtUtils::Install' => '0.3', + 'ExtUtils::ParseXS' => '2.02', + 'Pod::Text' => '0', + 'YAML' => '0.35', + }, + }, + build => { + requires => { + 'Test::More' => '0', + }, + } + }, + resources => { + license => ['http://dev.perl.org/licenses/'], + }, + optional_features => { + domination => { + description => 'Take over the world', + prereqs => { + develop => { requires => { 'Genius::Evil' => '1.234' } }, + runtime => { requires => { 'Machine::Weather' => '2.0' } }, + }, + }, + }, + dynamic_config => 1, + keywords => [ qw/ toolchain cpan dual-life / ], + 'meta-spec' => { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + }, + generated_by => 'Module::Build version 0.36', + x_authority => 'cpan:FLORA', + X_deep => { deep => 'structure' }, +}; + +my $meta = CPAN::Meta->new($distmeta); + +is( + blessed($meta->as_struct), + undef, + "the result of ->as_struct is unblessed", +); + +is_deeply( $meta->as_struct, $distmeta, "->as_struct (deep comparison)" ); +isnt( $meta->as_struct, $distmeta, "->as_struct (is a deep clone)" ); + +my $old_copy = $meta->as_struct( {version => "1.4"} ); +is( $old_copy->{'meta-spec'}{version}, "1.4", "->as_struct (downconversion)" ); + +isnt( $meta->resources, $meta->{resources}, "->resource (map values are deep cloned)"); + +is($meta->name, 'Module-Build', '->name'); +is($meta->abstract, 'Build and install Perl modules', '->abstract'); + +like($meta->description, qr/Module::Build.+blah blah blah/, '->description'); + +is($meta->version, '0.36', '->version'); + +ok($meta->dynamic_config, "->dynamic_config"); + +is_deeply( + [ $meta->author ], + [ + 'Ken Williams <kwilliams@cpan.org>', + 'Module-Build List <module-build@perl.org>', + ], + '->author', +); + +is_deeply( + [ $meta->authors ], + [ + 'Ken Williams <kwilliams@cpan.org>', + 'Module-Build List <module-build@perl.org>', + ], + '->authors', +); + +is_deeply( + [ $meta->license ], + [ qw(perl_5) ], + '->license', +); + +is_deeply( + [ $meta->licenses ], + [ qw(perl_5) ], + '->licenses', +); + +is_deeply( + [ $meta->keywords ], + [ qw/ toolchain cpan dual-life / ], + '->keywords', +); + +is_deeply( + $meta->resources, + { license => [ 'http://dev.perl.org/licenses/' ] }, + '->resources', +); + +is_deeply( + $meta->meta_spec, + { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + }, + '->meta_spec', +); + +is($meta->meta_spec_version, '2', '->meta_spec_version'); + +like($meta->generated_by, qr/Module::Build version 0.36/, '->generated_by'); + +my $basic = $meta->effective_prereqs; + +is_deeply( + $basic->as_string_hash, + $distmeta->{prereqs}, + "->effective_prereqs()" +); + +is_deeply( [ sort $meta->custom_keys ] , [ 'X_deep', 'x_authority' ], + "->custom_keys" +); + +is( $meta->custom('x_authority'), 'cpan:FLORA', "->custom(X)" ); + +is_deeply( $meta->custom('X_deep'), $distmeta->{'X_deep'}, + "->custom(X) [is_deeply]" +); + +isnt( $meta->custom('X_deep'), $distmeta->{'X_deep'}, + "->custom(x) [is a deep clone]" +); + +my $with_features = $meta->effective_prereqs([ qw(domination) ]); + +is_deeply( + $with_features->as_string_hash, + { + develop => { requires => { 'Genius::Evil' => '1.234' } }, + runtime => { + requires => { + 'perl' => '5.006', + 'Config' => '0', + 'Cwd' => '0', + 'Data::Dumper' => '0', + 'ExtUtils::Install' => '0', + 'File::Basename' => '0', + 'File::Compare' => '0', + 'File::Copy' => '0', + 'File::Find' => '0', + 'File::Path' => '0', + 'File::Spec' => '0', + 'IO::File' => '0', + 'Machine::Weather' => '2.0', + }, + recommends => { + 'Archive::Tar' => '1.00', + 'ExtUtils::Install' => '0.3', + 'ExtUtils::ParseXS' => '2.02', + 'Pod::Text' => '0', + 'YAML' => '0.35', + }, + }, + build => { + requires => { + 'Test::More' => '0', + }, + } + }, + "->effective_prereqs([ qw(domination) ])" +); + +my $chk_feature = sub { + my $feature = shift; + + isa_ok($feature, 'CPAN::Meta::Feature'); + + is($feature->identifier, 'domination', '$feature->identifier'); + is($feature->description, 'Take over the world', '$feature->description'); + + is_deeply( + $feature->prereqs->as_string_hash, + { + develop => { requires => { 'Genius::Evil' => '1.234' } }, + runtime => { requires => { 'Machine::Weather' => '2.0' } }, + }, + '$feature->prereqs', + ); +}; + +my @features = $meta->features; +is(@features, 1, "we got one feature"); +$chk_feature->($features[0]); + +$chk_feature->( $meta->feature('domination') ); + +done_testing; diff --git a/cpan/CPAN-Meta/t/no-index.t b/cpan/CPAN-Meta/t/no-index.t new file mode 100644 index 0000000000..4f8df45eb5 --- /dev/null +++ b/cpan/CPAN-Meta/t/no-index.t @@ -0,0 +1,86 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; + +my %distmeta = ( + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + 'meta-spec' => { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + }, + dynamic_config => 1, + generated_by => 'Module::Build version 0.36', +); + +{ + my $meta = CPAN::Meta->new({ %distmeta }); + + ok( + $meta->should_index_package('Foo::Bar::Baz'), + 'we index any old package, without a no_index rule' + ); + + ok( + $meta->should_index_file('lib/Foo/Bar/Baz.pm'), + 'we index any old file, without a no_index rule' + ); +} + +{ + my $meta = CPAN::Meta->new({ + %distmeta, + no_index => { + package => [ 'Foo::Bar' ], + namespace => [ 'Foo::Bar::Baz' ], + } + }); + + ok( + ! $meta->should_index_package('Foo::Bar'), + 'exclude a specific package' + ); + + ok( + $meta->should_index_package('Foo::Bar::Baz'), + 'namespace X does not exclude package X' + ); + + ok( + ! $meta->should_index_package('Foo::Bar::Baz::Quux'), + 'exclude something under a namespace' + ); +} + +{ + my $meta = CPAN::Meta->new({ + %distmeta, + no_index => { + file => [ 'lib/Foo/Bar.pm' ], + directory => [ 'lib/Foo/Bar/Baz' ], + } + }); + + ok( + ! $meta->should_index_file('lib/Foo/Bar.pm'), + 'exclude a specific file' + ); + + ok( + $meta->should_index_file('lib/Foo/Bar/Baz.pm'), + 'do not exclude a file with a name like an excluded dir', + ); + + ok( + ! $meta->should_index_file('lib/Foo/Bar/Baz/Quux.pm'), + 'exclude something under a directory' + ); +} + +done_testing; diff --git a/cpan/CPAN-Meta/t/prereqs-finalize.t b/cpan/CPAN-Meta/t/prereqs-finalize.t new file mode 100644 index 0000000000..040e3f3b24 --- /dev/null +++ b/cpan/CPAN-Meta/t/prereqs-finalize.t @@ -0,0 +1,91 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta::Prereqs; + +sub dies_ok (&@) { + my ($code, $qr, $comment) = @_; + + my $lived = eval { $code->(); 1 }; + + if ($lived) { + fail("$comment: did not die"); + } else { + like($@, $qr, $comment); + } +} + +my $prereqs_struct = { + runtime => { + requires => { + 'Config' => '1.234', + 'Cwd' => '876.5', + 'IO::File' => 0, + 'perl' => '5.005_03', + }, + recommends => { + 'Pod::Text' => 0, + 'YAML' => '0.35', + }, + }, + build => { + requires => { + 'Test' => 0, + }, + } +}; + +my $prereqs = CPAN::Meta::Prereqs->new($prereqs_struct); + +isa_ok($prereqs, 'CPAN::Meta::Prereqs'); + +$prereqs->finalize; + +ok($prereqs->is_finalized, 'cloned obj is not finalized'); + +is_deeply($prereqs->as_string_hash, $prereqs_struct, '...and still round-trip'); + +$prereqs->requirements_for(qw(runtime requires))->add_minimum(Cwd => 10); + +pass('...we can add a minimum if it has no effect'); + +dies_ok + { $prereqs->requirements_for(qw(runtime requires))->add_minimum(Cwd => 1000) } + qr{finalized req}, + '...but we die if it would alter a finalized prereqs'; + +$prereqs->requirements_for(qw(develop suggests)); + +pass('...we can get a V:R object for a previously unconfigured phase'); + +dies_ok + { $prereqs->requirements_for(qw(develop suggests))->add_minimum(Foo => 1) } + qr{finalized req}, + '...but we die if we try to put anything in it'; + +my $clone = $prereqs->clone; + +isa_ok($clone, 'CPAN::Meta::Prereqs', 'cloned prereqs obj'); + +ok(! $clone->is_finalized, 'cloned obj is not finalized'); + +is_deeply($clone->as_string_hash, $prereqs_struct, '...it still round-trips'); + +$clone->requirements_for(qw(runtime requires))->add_minimum(Cwd => 10); + +pass('...we can add minimum if it has no effect'); + +$clone->requirements_for(qw(runtime requires))->add_minimum(Cwd => 1000); + +pass('...or if it has an effect'); + +$clone->requirements_for(qw(develop suggests)); + +pass('...we can get a V:R object for a previously unconfigured phase'); + +$clone->requirements_for(qw(develop suggests))->add_minimum(Foo => 1); + +pass('...and we can add stuff to it'); + +done_testing; diff --git a/cpan/CPAN-Meta/t/prereqs-merge.t b/cpan/CPAN-Meta/t/prereqs-merge.t new file mode 100644 index 0000000000..63e267e84e --- /dev/null +++ b/cpan/CPAN-Meta/t/prereqs-merge.t @@ -0,0 +1,104 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta::Prereqs; + +my $prereq_struct_1 = { + runtime => { + requires => { + 'Config' => 0, + 'Cwd' => 0, + 'perl' => '5.005_03', + }, + recommends => { + 'Pod::Text' => 0, + 'YAML' => 0.35, + }, + }, + build => { + requires => { + 'Test' => 0, + }, + } +}; + +my $prereq_1 = CPAN::Meta::Prereqs->new($prereq_struct_1); + +isa_ok($prereq_1, 'CPAN::Meta::Prereqs', 'first prereq'); + +is_deeply($prereq_1->as_string_hash, $prereq_struct_1, '...and it round trips'); + +my $prereq_struct_2 = { + develop => { + requires => { + 'Dist::Mothra' => '1.230', + }, + suggests => { + 'Blort::Blortex' => '== 10.20', + }, + }, + runtime => { + requires => { + 'Config' => 1, + 'perl' => '< 6', + }, + }, + build => { + suggests => { + 'Module::Build::Bob' => '20100101', + }, + } +}; + +my $prereq_2 = CPAN::Meta::Prereqs->new($prereq_struct_2); + +isa_ok($prereq_2, 'CPAN::Meta::Prereqs', 'second prereq'); + +is_deeply($prereq_1->as_string_hash, $prereq_struct_1, '...and it round trips'); + +my $merged = $prereq_1->with_merged_prereqs($prereq_2); + +my $want = { + develop => { + requires => { + 'Dist::Mothra' => '1.230', + }, + suggests => { + 'Blort::Blortex' => '== 10.20', + }, + }, + runtime => { + requires => { + 'Config' => 1, + 'Cwd' => 0, + 'perl' => '>= 5.005_03, < 6', + }, + recommends => { + 'Pod::Text' => 0, + 'YAML' => 0.35, + }, + }, + build => { + requires => { + 'Test' => 0, + }, + suggests => { + 'Module::Build::Bob' => '20100101', + }, + }, +}; + +is_deeply( + $merged->as_string_hash, + $want, + "we get the right result of merging two prereqs", +); + +is_deeply( + $prereq_2->with_merged_prereqs($prereq_1)->as_string_hash, + $want, + "...and the merge works the same in reverse", +); + +done_testing; diff --git a/cpan/CPAN-Meta/t/prereqs.t b/cpan/CPAN-Meta/t/prereqs.t new file mode 100644 index 0000000000..a24f27274c --- /dev/null +++ b/cpan/CPAN-Meta/t/prereqs.t @@ -0,0 +1,121 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta::Prereqs; + +my $prereq_struct = { + runtime => { + requires => { + 'Config' => 0, + 'Cwd' => 0, + 'Data::Dumper' => 0, + 'ExtUtils::Install' => 0, + 'File::Basename' => 0, + 'File::Compare' => 0, + 'File::Copy' => 0, + 'File::Find' => 0, + 'File::Path' => 0, + 'File::Spec' => 0, + 'IO::File' => 0, + 'perl' => '5.005_03', + }, + recommends => { + 'Archive::Tar' => '1.00', + 'ExtUtils::Install' => 0.3, + 'ExtUtils::ParseXS' => 2.02, + 'Pod::Text' => 0, + 'YAML' => 0.35, + }, + }, + build => { + requires => { + 'Test' => 0, + }, + } +}; + +my $prereq = CPAN::Meta::Prereqs->new($prereq_struct); + +isa_ok($prereq, 'CPAN::Meta::Prereqs'); + +is_deeply($prereq->as_string_hash, $prereq_struct, "round-trip okay"); + +{ + my $req = $prereq->requirements_for(qw(runtime requires)); + my @req_mod = $req->required_modules; + + ok( + (grep { 'Cwd' eq $_ } @req_mod), + "we got the runtime requirements", + ); + + ok( + (! grep { 'YAML' eq $_ } @req_mod), + "...but not the runtime recommendations", + ); + + ok( + (! grep { 'Test' eq $_ } @req_mod), + "...nor the build requirements", + ); +} + +{ + my $req = $prereq->requirements_for(qw(runtime requires)); + my $rec = $prereq->requirements_for(qw(runtime recommends)); + + my $merged = $req->clone->add_requirements($rec); + + my @req_mod = $merged->required_modules; + + ok( + (grep { 'Cwd' eq $_ } @req_mod), + "we got the runtime requirements", + ); + + ok( + (grep { 'YAML' eq $_ } @req_mod), + "...and the runtime recommendations", + ); + + ok( + (! grep { 'Test' eq $_ } @req_mod), + "...but not the build requirements", + ); +} + +{ + my $req = $prereq->requirements_for(qw(runtime suggests)); + my @req_mod = $req->required_modules; + + is(@req_mod, 0, "empty set of runtime/suggests requirements"); +} + +{ + my $req = $prereq->requirements_for(qw(develop suggests)); + my @req_mod = $req->required_modules; + + is(@req_mod, 0, "empty set of develop/suggests requirements"); +} + +{ + my $new_prereq = CPAN::Meta::Prereqs->new; + + $new_prereq + ->requirements_for(qw(runtime requires)) + ->add_minimum(Foo => '1.000'); + + $new_prereq + ->requirements_for(qw(runtime requires)) + ->add_minimum(Bar => '2.976'); + + is_deeply( + $new_prereq->as_string_hash, + { runtime => { requires => { Foo => '1.000', Bar => '2.976' } } }, + 'we can accumulate new requirements on a prereq object', + ); +} + +done_testing; + diff --git a/cpan/CPAN-Meta/t/repository.t b/cpan/CPAN-Meta/t/repository.t new file mode 100644 index 0000000000..b8800d913f --- /dev/null +++ b/cpan/CPAN-Meta/t/repository.t @@ -0,0 +1,225 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; + +# 1.4 repository upgrade +{ + my $label = "(version 1.4) old repository winds up in 'url'"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '1.4', + url => 'http://module-build.sourceforge.net/META-spec-v1.4.html', + }, + resources => { + repository => 'http://example.com/', + }, + }, + { lazy_validation => 1 }, + ); + + is_deeply( + $meta->resources, + { + repository => { + url => 'http://example.com/', + }, + }, + $label, + ); +} + +{ + my $label = "(version 2 ) http in web passed through unchanged"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '2', + }, + resources => { + repository => { + web => 'http://example.com/', + }, + }, + }, + { lazy_validation => 1 }, + ); + + + is_deeply( + $meta->{resources}, + { + repository => { + web => 'http://example.com/', + }, + }, + $label + ); +} + +{ + my $label = "(version 2 ) http in url passed through unchanged"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '2', + }, + resources => { + repository => { + url => 'http://example.com/', + }, + }, + }, + { lazy_validation => 1 }, + ); + + + is_deeply( + $meta->{resources}, + { + repository => { + url => 'http://example.com/', + }, + }, + $label + ); +} + +{ + my $label = "(version 2 ) svn in url adds svn type"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '2', + }, + resources => { + repository => { + url => 'svn://example.com/', + }, + }, + }, + { lazy_validation => 1 }, + ); + + + is_deeply( + $meta->{resources}, + { + repository => { + url => 'svn://example.com/', + type => 'svn', + }, + }, + $label + ); +} + +{ + my $label = "(version 2 ) git in url adds svn type"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '2', + }, + resources => { + repository => { + url => 'git://example.com/', + }, + }, + }, + { lazy_validation => 1 }, + ); + + + is_deeply( + $meta->{resources}, + { + repository => { + url => 'git://example.com/', + type => 'git', + }, + }, + $label + ); +} + +{ + my $label = "(version 2 ) pre-existing type preserved"; + my $meta = CPAN::Meta->new( + { + name => 'Module-Billed', + abstract => 'inscrutable', + version => '1', + author => 'Joe', + release_status => 'stable', + license => 'perl_5', + dynamic_config => 1, + generated_by => 'hand', + 'meta-spec' => { + version => '2', + }, + resources => { + repository => { + url => 'git://example.com/', + type => 'msysgit', + }, + }, + }, + { lazy_validation => 1 }, + ); + + + is_deeply( + $meta->{resources}, + { + repository => { + url => 'git://example.com/', + type => 'msysgit', + }, + }, + $label + ); +} +done_testing; diff --git a/cpan/CPAN-Meta/t/save-load.t b/cpan/CPAN-Meta/t/save-load.t new file mode 100644 index 0000000000..73cac57ea9 --- /dev/null +++ b/cpan/CPAN-Meta/t/save-load.t @@ -0,0 +1,99 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use File::Temp 0.20 (); +use Parse::CPAN::Meta 1.4400; + +my $distmeta = { + name => 'Module-Build', + abstract => 'Build and install Perl modules', + description => "Module::Build is a system for building, testing, " + . "and installing Perl modules. It is meant to be an " + . "alternative to ExtUtils::MakeMaker... blah blah blah", + version => '0.36', + author => [ + 'Ken Williams <kwilliams@cpan.org>', + 'Module-Build List <module-build@perl.org>', # additional contact + ], + release_status => 'stable', + license => [ 'perl_5' ], + prereqs => { + runtime => { + requires => { + 'perl' => '5.006', + 'Config' => '0', + 'Cwd' => '0', + 'Data::Dumper' => '0', + 'ExtUtils::Install' => '0', + 'File::Basename' => '0', + 'File::Compare' => '0', + 'File::Copy' => '0', + 'File::Find' => '0', + 'File::Path' => '0', + 'File::Spec' => '0', + 'IO::File' => '0', + }, + recommends => { + 'Archive::Tar' => '1.00', + 'ExtUtils::Install' => '0.3', + 'ExtUtils::ParseXS' => '2.02', + 'Pod::Text' => '0', + 'YAML' => '0.35', + }, + }, + build => { + requires => { + 'Test::More' => '0', + }, + } + }, + resources => { + license => ['http://dev.perl.org/licenses/'], + }, + optional_features => { + domination => { + description => 'Take over the world', + prereqs => { + develop => { requires => { 'Genius::Evil' => '1.234' } }, + runtime => { requires => { 'Machine::Weather' => '2.0' } }, + }, + }, + }, + dynamic_config => 1, + keywords => [ qw/ toolchain cpan dual-life / ], + 'meta-spec' => { + version => '2', + url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', + }, + generated_by => 'Module::Build version 0.36', +}; + +my $meta = CPAN::Meta->new( $distmeta ); + +my $tmpdir = File::Temp->newdir(); +my $metafile = File::Spec->catfile( $tmpdir, 'META.json' ); + +ok( $meta->save($metafile), "save returns true" ); +ok( -f $metafile, "save meta to file" ); + +ok( my $loaded = Parse::CPAN::Meta->load_file($metafile), 'load saved file' ); +is($loaded->{name}, 'Module-Build', 'name correct'); + + +ok( $loaded = Parse::CPAN::Meta->load_file('t/data/META-1_4.yml'), 'load META-1.4' ); +is($loaded->{name}, 'Module-Build', 'name correct'); + +# Test saving with conversion + +my $metayml = File::Spec->catfile( $tmpdir, 'META.yml' ); + +$meta->save($metayml, {version => "1.4"}); +ok( -f $metayml, "save meta to META.yml with conversion" ); + +ok( $loaded = Parse::CPAN::Meta->load_file($metayml), 'load saved file' ); +is( $loaded->{name}, 'Module-Build', 'name correct'); +is( $loaded->{requires}{perl}, "5.006", 'prereq correct' ); + +done_testing; diff --git a/cpan/CPAN-Meta/t/validator.t b/cpan/CPAN-Meta/t/validator.t new file mode 100644 index 0000000000..e76fcc2eca --- /dev/null +++ b/cpan/CPAN-Meta/t/validator.t @@ -0,0 +1,35 @@ +use strict; +use warnings; +use Test::More 0.88; + +use CPAN::Meta; +use CPAN::Meta::Validator; +use File::Spec; +use IO::Dir; +use Parse::CPAN::Meta 1.4400; + +{ + my $data_dir = IO::Dir->new( 't/data' ); + my @files = sort grep { /^\w/ } $data_dir->read; + + for my $f ( @files ) { + my $meta = Parse::CPAN::Meta->load_file( File::Spec->catfile('t','data',$f) ); + my $cmv = CPAN::Meta::Validator->new({%$meta}); + ok( $cmv->is_valid, "$f validates" ) + or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) ); + } +} + +{ + my $data_dir = IO::Dir->new( 't/data-fail' ); + my @files = sort grep { /^\w/ } $data_dir->read; + + for my $f ( @files ) { + my $meta = Parse::CPAN::Meta->load_file( File::Spec->catfile('t','data-fail',$f) ); + my $cmv = CPAN::Meta::Validator->new({%$meta}); + ok( ! $cmv->is_valid, "invalid $f doesn't validate" ); + } +} + +done_testing; + |