222
222
'namespace' => \&_listify,
225
my $no_index_spec_2 = {
226
'file' => \&_listify,
227
'directory' => \&_listify,
228
'package' => \&_listify,
229
'namespace' => \&_listify,
230
':custom' => \&_prefix_custom,
225
233
sub _no_index_1_2 {
226
234
my (undef, undef, $meta) = @_;
227
return _convert($meta->{private}, $no_index_spec_1_2);
235
my $no_index = $meta->{no_index} || $meta->{private};
236
return unless $no_index;
238
# cleanup wrong format
239
if ( ! ref $no_index ) {
240
my $item = $no_index;
241
$no_index = { dir => [ $item ], file => [ $item ] };
243
elsif ( ref $no_index eq 'ARRAY' ) {
244
my $list = $no_index;
245
$no_index = { dir => [ @$list ], file => [ @$list ] };
248
# common mistake: files -> file
249
if ( exists $no_index->{files} ) {
250
$no_index->{file} = delete $no_index->{file};
252
# common mistake: modules -> module
253
if ( exists $no_index->{modules} ) {
254
$no_index->{module} = delete $no_index->{module};
256
return _convert($no_index, $no_index_spec_1_2);
230
259
sub _no_index_directory {
260
my ($element, $key, $meta, $version) = @_;
232
261
return unless $element;
263
# cleanup wrong format
264
if ( ! ref $element ) {
266
$element = { directory => [ $item ], file => [ $item ] };
268
elsif ( ref $element eq 'ARRAY' ) {
270
$element = { directory => [ @$list ], file => [ @$list ] };
233
273
if ( exists $element->{dir} ) {
234
274
$element->{directory} = delete $element->{dir};
236
return _convert($element, $no_index_spec_1_3);
276
# common mistake: files -> file
277
if ( exists $element->{files} ) {
278
$element->{file} = delete $element->{file};
280
# common mistake: modules -> module
281
if ( exists $element->{modules} ) {
282
$element->{module} = delete $element->{module};
284
my $spec = $version == 2 ? $no_index_spec_2 : $no_index_spec_1_3;
285
return _convert($element, $spec);
288
sub _is_module_name {
290
return unless defined $mod && length $mod;
291
return $mod =~ m{^[A-Za-z][A-Za-z0-9_]*(?:::[A-Za-z0-9_]+)*$};
295
my ($element, $key, $meta, $to_version) = @_;
296
return 0 if ! defined $element;
298
$element =~ s{^\s*}{};
299
$element =~ s{\s*$}{};
300
$element =~ s{^\.}{0.};
302
return 0 if ! length $element;
303
return 0 if ( $element eq 'undef' || $element eq '<undef>' );
305
if ( my $v = eval { version->new($element) } ) {
306
return $v->is_qv ? $v->normal : $element;
239
313
sub _version_map {
240
314
my ($element) = @_;
241
315
return undef unless defined $element;
242
return $element unless ref $element eq 'HASH';
244
for my $k ( keys %$element ) {
245
my $value = $element->{$k};
246
$new_map->{$k} = (defined $value && length $value) ? $value : 0;
316
if ( ref $element eq 'HASH' ) {
318
for my $k ( keys %$element ) {
319
next unless _is_module_name($k);
320
my $value = $element->{$k};
321
if ( ! ( defined $value && length $value ) ) {
324
elsif ( $value eq 'undef' || $value eq '<undef>' ) {
327
elsif ( _is_module_name( $value ) ) { # some weird, old META have this
329
$new_map->{$value} = 0;
332
$new_map->{$k} = _clean_version($value);
337
elsif ( ref $element eq 'ARRAY' ) {
338
my $hashref = { map { $_ => 0 } @$element };
339
return _version_map($hashref); # cleanup any weird stuff
341
elsif ( ref $element eq '' && length $element ) {
342
return { $element => 0 }
347
sub _prereqs_from_1 {
252
348
my (undef, undef, $meta) = @_;
253
349
my $prereqs = {};
254
350
for my $phase ( qw/build configure/ ) {
363
configure => \&_prereqs_rel,
364
build => \&_prereqs_rel,
365
test => \&_prereqs_rel,
366
runtime => \&_prereqs_rel,
367
develop => \&_prereqs_rel,
368
':custom' => \&_prefix_custom,
371
my $relation_spec = {
372
requires => \&_version_map,
373
recommends => \&_version_map,
374
suggests => \&_version_map,
375
conflicts => \&_version_map,
376
':custom' => \&_prefix_custom,
379
sub _cleanup_prereqs {
380
my ($prereqs, $key, $meta, $to_version) = @_;
381
return unless $prereqs && ref $prereqs eq 'HASH';
382
return _convert( $prereqs, $prereqs_spec, $to_version );
386
my ($relation, $key, $meta, $to_version) = @_;
387
return unless $relation && ref $relation eq 'HASH';
388
return _convert( $relation, $relation_spec, $to_version );
267
393
my @old_prereqs = qw(
332
457
for my $name ( keys %$origin ) {
333
458
$features->{$name} = {
334
459
description => $origin->{$name}{description},
335
prereqs => _prereqs(undef, undef, $origin->{$name}),
460
prereqs => _prereqs_from_1(undef, undef, $origin->{$name}),
337
462
delete $features->{$name}{prereqs}{configure};
339
464
return $features;
467
my $optional_features_2_spec = {
468
description => \&_keep,
469
prereqs => \&_cleanup_prereqs,
470
':custom' => \&_prefix_custom,
474
my ($element, $key, $meta, $to_version) = @_;
475
return unless $element && ref $element eq 'HASH';
476
_convert( $element, $optional_features_2_spec, $to_version );
479
sub _cleanup_optional_features_2 {
480
my ($element, $key, $meta, $to_version) = @_;
481
return unless $element && ref $element eq 'HASH';
483
for my $k ( keys %$element ) {
484
$new_data->{$k} = _feature_2( $element->{$k}, $k, $meta, $to_version );
486
return unless keys %$new_data;
342
490
sub _optional_features_1_4 {
343
491
my ($element) = @_;
344
492
return unless $element;
345
for my $drop ( qw/requires_packages requires_os excluded_os/ ) {
346
delete $element->{$drop};
493
$element = _optional_features_as_map($element);
494
for my $name ( keys %$element ) {
495
for my $drop ( qw/requires_packages requires_os excluded_os/ ) {
496
delete $element->{$name}{$drop};
502
sub _optional_features_as_map {
504
return unless $element;
505
if ( ref $element eq 'ARRAY' ) {
507
for my $feature ( @$element ) {
508
my (@parts) = %$feature;
509
$map{$parts[0]} = $parts[1];
359
my $resource2_spec = {
526
return unless $element;
527
$element = _listify( $element );
528
$element = [ grep { _is_urlish($_) } @$element ];
529
return unless @$element;
535
return [ 'unknown' ] unless $element;
536
$element = _listify( $element );
537
$element = [ map { defined $_ && length $_ ? $_ : 'unknown' } @$element ];
538
return [ 'unknown' ] unless @$element;
542
my $resource2_upgrade = {
360
543
license => sub { return _is_urlish($_[0]) ? _listify( $_[0] ) : undef },
361
544
homepage => \&_url_or_drop,
362
bugtracker => sub { return _is_urlish($_[0]) ? { web => $_[0] } : undef },
547
if ( $item =~ m{^mailto:(.*)$} ) { return { mailto => $1 } }
548
elsif( _is_urlish($item) ) { return { web => $_[0] } }
549
else { return undef }
363
551
repository => sub { return _is_urlish($_[0]) ? { web => $_[0] } : undef },
364
552
':custom' => \&_prefix_custom,
555
sub _upgrade_resources_2 {
368
556
my (undef, undef, $meta, $version) = @_;
369
557
return undef unless exists $meta->{resources};
370
return _convert($meta->{resources}, $resource2_spec);
558
return _convert($meta->{resources}, $resource2_upgrade);
561
my $bugtracker2_spec = {
562
web => \&_url_or_drop,
564
':custom' => \&_prefix_custom,
568
my ($element, $key, $meta, $to_version) = @_;
569
return $element if defined $element;
570
return unless exists $meta->{url};
571
my $repo_url = $meta->{url};
572
for my $type ( qw/git svn/ ) {
573
return $type if $repo_url =~ m{\A$type};
578
my $repository2_spec = {
579
web => \&_url_or_drop,
580
url => \&_url_or_drop,
581
type => \&_repo_type,
582
':custom' => \&_prefix_custom,
585
my $resources2_cleanup = {
586
license => \&_url_list,
587
homepage => \&_url_or_drop,
588
bugtracker => sub { ref $_[0] ? _convert( $_[0], $bugtracker2_spec ) : undef },
589
repository => sub { my $data = shift; ref $data ? _convert( $data, $repository2_spec ) : undef },
590
':custom' => \&_prefix_custom,
593
sub _cleanup_resources_2 {
594
my ($resources, $key, $meta, $to_version) = @_;
595
return undef unless $resources && ref $resources eq 'HASH';
596
return _convert($resources, $resources2_cleanup, $to_version);
373
599
my $resource1_spec = {
409
640
sub _release_status {
641
my ($element, undef, $meta) = @_;
642
return $element if $element && $element =~ m{\A(?:stable|testing|unstable)\z};
643
return _release_status_from_version(undef, undef, $meta);
646
sub _release_status_from_version {
410
647
my (undef, undef, $meta) = @_;
411
648
my $version = $meta->{version} || '';
412
649
return ( $version =~ /_/ ) ? 'testing' : 'stable';
652
my $provides_spec = {
654
version => \&_clean_version,
657
my $provides_spec_2 = {
659
version => \&_clean_version,
660
':custom' => \&_prefix_custom,
664
my ($element, $key, $meta, $to_version) = @_;
665
return unless defined $element && ref $element eq 'HASH';
666
my $spec = $to_version == 2 ? $provides_spec_2 : $provides_spec;
668
for my $k ( keys %$element ) {
669
$new_data->{$k} = _convert($element->{$k}, $spec, $to_version);
416
675
my ($data, $spec, $to_version) = @_;
418
677
my $new_data = {};
419
for my $key ( %$spec ) {
678
for my $key ( keys %$spec ) {
420
679
next if $key eq ':custom' || $key eq ':drop';
421
680
next unless my $fcn = $spec->{$key};
422
681
die "spec for '$key' is not a coderef"
1007
'abstract' => \&_keep_or_unknown,
1008
'author' => \&_author_list,
1009
'generated_by' => \&_generated_by,
1010
'license' => \&_license_2,
1011
'meta-spec' => \&_change_meta_spec,
1013
'version' => \&_keep,
1014
# CHANGED TO MANDATORY
1015
'dynamic_config' => \&_keep_or_one,
1017
'release_status' => \&_release_status,
1019
'keywords' => \&_keep,
1020
'no_index' => \&_no_index_directory,
1021
'optional_features' => \&_cleanup_optional_features_2,
1022
'provides' => \&_provides,
1023
'resources' => \&_cleanup_resources_2,
1025
'description' => \&_keep,
1026
'prereqs' => \&_cleanup_prereqs,
1028
# drop these deprecated fields, but only after we convert
1040
# other random keys need x_ prefixing
1041
':custom' => \&_prefix_custom,
1045
'abstract' => \&_keep_or_unknown,
1046
'author' => \&_author_list,
1047
'generated_by' => \&_generated_by,
1048
'license' => \&_license_1,
1049
'meta-spec' => \&_change_meta_spec,
1051
'version' => \&_keep,
1053
'build_requires' => \&_version_map,
1054
'conflicts' => \&_version_map,
1055
'distribution_type' => \&_keep,
1056
'dynamic_config' => \&_keep_or_one,
1057
'keywords' => \&_keep,
1058
'no_index' => \&_no_index_directory,
1059
'optional_features' => \&_optional_features_1_4,
1060
'provides' => \&_provides,
1061
'recommends' => \&_version_map,
1062
'requires' => \&_version_map,
1063
'resources' => \&_resources_1_4,
1065
'configure_requires' => \&_keep,
1067
# other random keys are OK if already valid
1068
':custom' => \&_keep
1072
'abstract' => \&_keep_or_unknown,
1073
'author' => \&_author_list,
1074
'generated_by' => \&_generated_by,
1075
'license' => \&_license_1,
1076
'meta-spec' => \&_change_meta_spec,
1078
'version' => \&_keep,
1080
'build_requires' => \&_version_map,
1081
'conflicts' => \&_version_map,
1082
'distribution_type' => \&_keep,
1083
'dynamic_config' => \&_keep_or_one,
1084
'keywords' => \&_keep,
1085
'no_index' => \&_no_index_directory,
1086
'optional_features' => \&_optional_features_as_map,
1087
'provides' => \&_provides,
1088
'recommends' => \&_version_map,
1089
'requires' => \&_version_map,
1090
'resources' => \&_resources_1_3,
1092
# other random keys are OK if already valid
1093
':custom' => \&_keep
1097
'version' => \&_keep,
1098
# CHANGED TO MANDATORY
1099
'license' => \&_license_1,
1101
'generated_by' => \&_generated_by,
1103
'abstract' => \&_keep_or_unknown,
1104
'author' => \&_author_list,
1105
'meta-spec' => \&_change_meta_spec,
1107
'build_requires' => \&_version_map,
1108
'conflicts' => \&_version_map,
1109
'distribution_type' => \&_keep,
1110
'dynamic_config' => \&_keep_or_one,
1111
'recommends' => \&_version_map,
1112
'requires' => \&_version_map,
1114
'keywords' => \&_keep,
1115
'no_index' => \&_no_index_1_2,
1116
'optional_features' => \&_optional_features_as_map,
1117
'provides' => \&_provides,
1118
'resources' => \&_resources_1_2,
1120
# other random keys are OK if already valid
1121
':custom' => \&_keep
1124
# CHANGED TO MANDATORY
1125
'version' => \&_keep,
1128
'meta-spec' => \&_change_meta_spec,
1130
'build_requires' => \&_version_map,
1131
'conflicts' => \&_version_map,
1132
'distribution_type' => \&_keep,
1133
'dynamic_config' => \&_keep_or_one,
1134
'generated_by' => \&_generated_by,
1135
'license' => \&_license_1,
1136
'recommends' => \&_version_map,
1137
'requires' => \&_version_map,
1139
'license_url' => \&_url_or_drop,
1140
'private' => \&_keep,
1142
# other random keys are OK if already valid
1143
':custom' => \&_keep
1148
'meta-spec' => \&_change_meta_spec,
1149
'version' => \&_keep,
1151
'build_requires' => \&_version_map,
1152
'conflicts' => \&_version_map,
1153
'distribution_type' => \&_keep,
1154
'dynamic_config' => \&_keep_or_one,
1155
'generated_by' => \&_generated_by,
1156
'license' => \&_license_1,
1157
'recommends' => \&_version_map,
1158
'requires' => \&_version_map,
1160
# other random keys are OK if already valid
1161
':custom' => \&_keep,
745
1165
#--------------------------------------------------------------------------#
747
1167
#--------------------------------------------------------------------------#
850
1276
my $new_struct = $cmc->convert( version => "2" );
852
Returns a new hash reference with the metadata converted to a
1278
Returns a new hash reference with the metadata converted to a different form.
1279
C<convert> will die if any conversion/standardization still results in an
855
1282
Valid parameters include:
1288
C<version> -- Indicates the desired specification version (e.g. "1.0", "1.1" ... "1.4", "2").
1289
Defaults to the latest version of the CPAN Meta Spec.
1293
Conversion proceeds through each version in turn. For example, a version 1.2
1294
structure might be converted to 1.3 then 1.4 then finally to version 2. The
1295
conversion process attempts to clean-up simple errors and standardize data.
1296
For example, if C<author> is given as a scalar, it will converted to an array
1297
reference containing the item. (Converting a structure to its own version will
1298
also clean-up and standardize.)
1300
When data are cleaned and standardized, missing or invalid fields will be
1301
replaced with sensible defaults when possible. This may be lossy or imprecise.
1302
For example, some badly structured META.yml files on CPAN have prerequisite
1303
modules listed as both keys and values:
1305
requires => { 'Foo::Bar' => 'Bam::Baz' }
1307
These would be split and each converted to a prerequisite with a minimum
1310
When some mandatory fields are missing or invalid, the conversion will attempt
1311
to provide a sensible default or will fill them with a value of 'unknown'. For
1312
example a missing or unrecognized C<license> field will result in a C<license>
1313
field of 'unknown'. Fields that may get an 'unknown' include:
863
Indicates the desired specification version (e.g. "1.0", "1.1" ... "1.4", "2").
864
Converting a structure to its own version will just return a copy of the
865
structure. Defaults to the latest version of the CPAN Meta Spec.
869
The conversion process attempts to clean-up and standardize data during
870
converstion. For example, if C<author> is given as a scalar, it will converted
871
to an array reference containing the item.
873
Conversion proceeds through each version in turn. For example, a version 1.2
874
structure is converted to 1.3 then 1.4 then finally version 2. C<convert> will
875
die if any conversion results in an invalid structure.
879
1333
Please report any bugs or feature using the CPAN Request Tracker.