From 5588da20f7917c3b5b6b0f6f2125cbbd4d80f0d9 Mon Sep 17 00:00:00 2001 From: Shoichi Kaji Date: Thu, 4 Jan 2024 18:38:36 +0900 Subject: [PATCH] try to load initial requirements from Build.PL/Makefile.PL too --- lib/App/cpm/CLI.pm | 59 ++++++++++++++++++++++++++++++++++++----- lib/App/cpm/Tutorial.pm | 19 +++++++++++-- script/cpm | 15 +++++------ xt/19_buildfile.t | 48 +++++++++++++++++++++++++++++++++ xt/19_metafile.t | 46 ++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 xt/19_buildfile.t diff --git a/lib/App/cpm/CLI.pm b/lib/App/cpm/CLI.pm index 890b65f..7329fd0 100644 --- a/lib/App/cpm/CLI.pm +++ b/lib/App/cpm/CLI.pm @@ -17,6 +17,7 @@ use App::cpm::Worker; use App::cpm::version; use App::cpm; use CPAN::Meta; +use Command::Runner; use Config; use Cwd (); use File::Copy (); @@ -28,6 +29,7 @@ use Module::CPANfile; use Module::cpmfile; use Parallel::Pipes::App; use Pod::Text (); +use local::lib (); sub new { my ($class, %option) = @_; @@ -151,11 +153,7 @@ sub parse_options { $self->{argv} = \@ARGV; } } elsif (!$self->{dependency_file}) { - if (-f "cpm.yml") { - $self->{dependency_file} = { type => "cpmfile", path => "cpm.yml" }; - } elsif (-f "cpanfile") { - $self->{dependency_file} = { type => "cpanfile", path => "cpanfile" }; - } + $self->{dependency_file} = $self->locate_dependency_file; } return 1; } @@ -186,7 +184,6 @@ sub _search_inc { return \@INC if $self->{global}; my $base = $self->{local_lib}; - require local::lib; my @local_lib = ( local::lib->resolve_path(local::lib->install_base_arch_path($base)), local::lib->resolve_path(local::lib->install_base_perl_path($base)), @@ -261,7 +258,7 @@ sub cmd_version { sub cmd_install { my $self = shift; - die "Need arguments or cpmfile/cpanfile/metafile\n" if !$self->{argv} && !$self->{dependency_file}; + die "Need arguments or cpm.yml/cpanfile/Build.PL/Makefile.PL\n" if !$self->{argv} && !$self->{dependency_file}; local %ENV = %ENV; @@ -484,6 +481,54 @@ sub initial_task { return (\@package, \@dist, undef); } +sub locate_dependency_file { + my $self = shift; + if (-f "cpm.yml") { + return { type => "cpmfile", path => "cpm.yml" }; + } + if (-f "cpanfile") { + return { type => "cpanfile", path => "cpanfile" }; + } + if (-f 'META.json') { + my $meta = CPAN::Meta->load_file('META.json'); + if (!$meta->dynamic_config) { + return { type => 'metafile', path => 'META.json' }; + } + } + if (-f 'Build.PL' || -f 'Makefile.PL') { + my $build_file = -f 'Build.PL' ? 'Build.PL' : 'Makefile.PL'; + warn "Executing $build_file to generate MYMETA.json and to determine requirements...\n"; + local %ENV = ( + PERL5_CPAN_IS_RUNNING => 1, + PERL5_CPANPLUS_IS_RUNNING => 1, + PERL5_CPANM_IS_RUNNING => 1, + PERL_MM_USE_DEFAULT => 1, + %ENV, + ); + if (!$self->{global}) { + local $SIG{__WARN__} = sub { }; # catch 'Attempting to write ...' + local::lib->setup_env_hash_for($self->{local_lib}, 0); + } + my $runner = Command::Runner->new( + command => [ $^X, $build_file ], + timeout => 60, + redirect => 1, + ); + my $res = $runner->run; + if ($res->{timeout}) { + die "Error: timed out (>60s).\n$res->{stdout}"; + } + if ($res->{result} != 0) { + die "Error: failed to execute $build_file.\n$res->{stdout}"; + } + if (!-f 'MYMETA.json') { + die "Error: No MYMETA.json after executing $build_file\n"; + } + return { type => 'metafile', path => 'MYMETA.json' }; + } + return; +} + sub load_dependency_file { my $self = shift; diff --git a/lib/App/cpm/Tutorial.pm b/lib/App/cpm/Tutorial.pm index d53e69f..31a4fd3 100644 --- a/lib/App/cpm/Tutorial.pm +++ b/lib/App/cpm/Tutorial.pm @@ -70,8 +70,23 @@ And cpm can install modules from git repositories directly. =head2 cpanfile and dist/url/mirror/git syntax -If you omit arguments, and there exists C in the current directory, -then cpm loads modules from cpanfile, and install them +If you omit arguments, and there exists one of + +=over 4 + +=item L + +=item L + +=item L (with dynamic_config false) + +=item C + +=item C + +=back + +in the current directory, then cpm loads modules from the file, and install them $ cat cpanfile requires 'Moose', '2.000'; diff --git a/script/cpm b/script/cpm index 2897379..7ffe37a 100644 --- a/script/cpm +++ b/script/cpm @@ -16,20 +16,19 @@ cpm - a fast CPAN module installer # install modules into local/ > cpm install Module1 Module2 ... - # install modules with verbose messages - > cpm install -v Module - - # from cpmfile/cpanfile (with cpanfile.snapshot if any) + # install modules from one of + # * cpm.yml + # * cpanfile + # * META.json (with dynamic_config false) + # * Build.PL + # * Makefile.PL > cpm install - # from metafile (META.json or MYMETA.json) - > perl Makefile.PL && cpm install --metafile MYMETA.json - # install module into current @INC instead of local/ > cpm install -g Module # read modules from STDIN by specifying "-" as an argument - > echo Module1 Module2 | cpm install - + > cat module-list.txt | cpm install - # prefer TRIAL release > cpm install --dev Moose diff --git a/xt/19_buildfile.t b/xt/19_buildfile.t new file mode 100644 index 0000000..710888e --- /dev/null +++ b/xt/19_buildfile.t @@ -0,0 +1,48 @@ +use strict; +use warnings; +use Test::More; + +use lib "xt/lib"; +use CLI; +use Path::Tiny; +use File::pushd 'tempd'; + +subtest build_pl => sub { + my $guard = tempd; + with_same_local { + cpm_install 'Module::Build'; + + Path::Tiny->new("Build.PL")->spew(<<'EOF'); +use Module::Build; +my $builder = Module::Build->new( + module_name => 'TEST_MODULE', + dist_version => '0.1', + dist_author => 'skaji', + dist_abstract => 'test', + no_index => {}, + requires => { 'File::pushd' => 0 }, +); +$builder->create_build_script; +EOF + my $r = cpm_install; + like $r->err, qr/Executing Build.PL/; + like $r->err, qr/DONE install File-pushd-/; + }; +}; + +subtest makefile_pl => sub { + my $guard = tempd; + Path::Tiny->new("Makefile.PL")->spew(<<'EOF'); +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'TEST_MODULE', + PREREQ_PM => { 'File::pushd' => 0 }, +); +EOF + my $r = cpm_install; + like $r->err, qr/Executing Makefile.PL/; + like $r->err, qr/DONE install File-pushd-/; +}; + +done_testing; diff --git a/xt/19_metafile.t b/xt/19_metafile.t index 467837c..d412a83 100644 --- a/xt/19_metafile.t +++ b/xt/19_metafile.t @@ -5,6 +5,7 @@ use Test::More; use lib "xt/lib"; use CLI; use Path::Tiny; +use File::pushd 'tempd'; subtest basic => sub { my $metafile = Path::Tiny->tempfile; @@ -46,4 +47,49 @@ EOF like $r->err, qr/DONE install common-sense-/; }; +subtest dynamic_config => sub { + my $guard = tempd; + Path::Tiny->new('META.json')->spew(<<'EOF'); +{ + "name": "_", + "version": "1", + "dynamic_config": 1, + "meta-spec": { + "version": 2 + }, + "prereqs": { + "runtime": { + "requires": { + "File::pushd": "0" + } + } + } +} +EOF + my $r = cpm_install; + isnt $r->exit, 0; + unlike $r->err, qr/DONE install File-pushd-/; + + Path::Tiny->new('META.json')->spew(<<'EOF'); +{ + "name": "_", + "version": "1", + "dynamic_config": 0, + "meta-spec": { + "version": 2 + }, + "prereqs": { + "runtime": { + "requires": { + "File::pushd": "0" + } + } + } +} +EOF + $r = cpm_install; + is $r->exit, 0; + like $r->err, qr/DONE install File-pushd-/; +}; + done_testing;