App-CPANMetaUtils

 view release on metacpan or  search on metacpan

script/gen-cpan-meta  view on Meta::CPAN

#!perl

our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2020-08-27'; # DATE
our $DIST = 'App-CPANMetaUtils'; # DIST
our $VERSION = '0.011'; # VERSION

use 5.010001;
use strict;
use warnings;

use ExtUtils::MakeMaker;
use File::chdir;
use Perinci::CmdLine::Any;
use Perinci::Sub::Util qw(err);

our %SPEC;

$SPEC{gen_cpan_meta} = {
    v => 1.1,
    summary => 'Generate CPAN META for a distribution',
    description => <<'_',

NOTE: EARLY VERSION.

This utility assumes it is run in the top-level directory of a Perl distribution
and will try to generate a CPAN META structure for the distribution. For
example: `abstract` will be searched from POD, `name` from the shortest package
name, `version` from the main module, `prereqs` using <pm:App::ScanPrereqs> and
so on. Finally it will validate its generated META.json first before outputing
it, printing found errors to stderr.

This utility can be used to generate (at least the preliminary version of)
`META.json` for Perl distributions that do not yet have `META.json`. It is
usually not useful for distributions that use a distribution builder tool like
<pm:Dist::Zilla>, because in that case the tool will generate `META.json` for
you.

_
    args => {
        dir => {
            summary => 'Instead of current dir, use this directory as the '.
                'top-level dist directory',
            schema => 'dirname*',
            pos => 0,
        },
        # XXX option to output to file (default META.json)
        # XXX option to overwrite existing file
    },
};
sub gen_cpan_meta {
    require App::ScanPrereqs;
    require CPAN::Meta::Validator;
    require File::Find::Wanted;
    require File::Slurper;
    require JSON::MaybeXS;

    my %args = @_;

    local $CWD = $args{dir} if defined $args{dir};

    my $meta = {};

    (-d "lib") or return [412, "lib/ directory expected"];
    my @lib_files =
        sort { length($a) <=> length($b) }
        File::Find::Wanted::find_wanted(
            sub { -f && /\.pm$/ }, "lib");

    @lib_files or return [412, "Can't find any .pm files under lib/"];

    # pick the shortest module to be the dist name
    my $pkg = $lib_files[0];
    $pkg =~ s!lib/!!; $pkg =~ s/\.pm$//; $pkg =~ s!/!::!g;

    # name
    {
        (my $name = $pkg) =~ s/::/-/g;
        $meta->{name} = $name;
    }

    # version
    {
        my $v = MM->parse_version($lib_files[0]);
        $v = undef if defined($v) && $v eq 'undef';
        defined $v or return [412, "Can't extract version from $lib_files[0]"];
        $meta->{version} = $v;
    }

    my $ct = File::Slurper::read_text($lib_files[0]);

script/gen-cpan-meta  view on Meta::CPAN

            files => [grep {-d} "lib", "bin", "script", "scripts"]);
        return err("Can't scan runtime prereqs", $res) unless $res->[0] == 200;
        my %runtime_prereqs;
        for my $e (@{ $res->[2] }) {
            $runtime_prereqs{$e->{module}} = $e->{version};
        }

        $res = App::ScanPrereqs::scan_prereqs(
            scanner => "regular",
            files => [grep {-d} "t", "xt"]);
        return err("Can't scan test prereqs", $res) unless $res->[0] == 200;
        my %test_prereqs;
        for my $e (@{ $res->[2] }) {
            my $v;
            if (defined $runtime_prereqs{$e->{module}}) {
                $v = version->parse($e->{version})
                    > version->parse($runtime_prereqs{$e->{module}}) ?
                    $e->{version} : $runtime_prereqs{$e->{module}};
;
                # use test version if larger
                $runtime_prereqs{$e->{module}} = $v;
            } else {
                $v = $e->{version};
                $test_prereqs{$e->{module}} = $v;
            }
        }
        $meta->{prereqs}{runtime}{requires} = \%runtime_prereqs;
        $meta->{prereqs}{test}{requires} = \%test_prereqs;
    }

    # author
    {
        my $author;
        if ($ct =~ /^=head1 AUTHORS?\R\R(.+)/m) {
            $author = $1;
        } else {
            $author = 'John Doe <john.doe@example.com>';
        }
        $meta->{author} = [$author];
    }

    # license (assumed to be perl5)
    {
        $meta->{license} = ["perl_5"];
    }

    # dynamic_config (assumed to be 0)
    {
        $meta->{dynamic_config} = 0;
    }

    # release_status (assumed to be stable)
    {
        $meta->{release_status} = 'stable';
    }

    # XXX resources

    # XXX x_authority?

    # let's validate it first
    {
        my $cmv = CPAN::Meta::Validator->new($meta);
        unless ($cmv->is_valid) {
            print "WARN: Error from validator: $_\n" for $cmv->errors;
        }
    }

    [200, "OK", JSON::MaybeXS->new->canonical(1)->pretty->encode($meta)];
}

Perinci::CmdLine::Any->new(
        url => '/main/gen_cpan_meta',
)->run;

# ABSTRACT: Generate CPAN META for a distribution
# PODNAME: gen-cpan-meta

__END__

=pod

=encoding UTF-8

=head1 NAME

gen-cpan-meta - Generate CPAN META for a distribution

=head1 VERSION

This document describes version 0.011 of gen-cpan-meta (from Perl distribution App-CPANMetaUtils), released on 2020-08-27.

=head1 SYNOPSIS

Usage:

 % gen-cpan-meta [--config-path=path | -c] [--config-profile=profile | -P]
     [--format=name] [--json] [--(no)naked-res] [--no-config | -C]
     [--no-env] [--page-result[=program]] [dir]

=head1 DESCRIPTION

NOTE: EARLY VERSION.

This utility assumes it is run in the top-level directory of a Perl distribution
and will try to generate a CPAN META structure for the distribution. For
example: C<abstract> will be searched from POD, C<name> from the shortest package
name, C<version> from the main module, C<prereqs> using L<App::ScanPrereqs> and
so on. Finally it will validate its generated META.json first before outputing
it, printing found errors to stderr.

This utility can be used to generate (at least the preliminary version of)
C<META.json> for Perl distributions that do not yet have C<META.json>. It is
usually not useful for distributions that use a distribution builder tool like
L<Dist::Zilla>, because in that case the tool will generate C<META.json> for
you.

=head1 OPTIONS

C<*> marks required options.

=head2 Main options

=over

=item B<--dir>=I<s>

Instead of current dir, use this directory as the top-level dist directory.

=back

=head2 Configuration options

=over

=item B<--config-path>=I<s>, B<-c>

Set path to configuration file.

=item B<--config-profile>=I<s>, B<-P>

Set configuration profile to use.

=item B<--no-config>, B<-C>

Do not use any configuration file.

=back

=head2 Environment options

=over

=item B<--no-env>

Do not read environment for default options.

=back

=head2 Output options

=over

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:



( run in 1.576 second using v1.01-cache-2.11-cpan-39bf76dae61 )