File Coverage

blib/lib/Dist/Zilla/Plugin/ModuleBuildTiny/Fallback.pm
Criterion Covered Total %
statement 97 99 97.9
branch 14 20 70.0
condition 4 9 44.4
subroutine 18 20 90.0
pod 0 5 0.0
total 133 153 86.9


line stmt bran cond sub pod time code
1 6     6   15215314 use strict;
  6         17  
  6         187  
2 6     6   43 use warnings;
  6         15  
  6         367  
3             # vim: set ts=8 sts=2 sw=2 tw=115 et :
4             # ABSTRACT: Generate a Build.PL that uses Module::Build::Tiny and Module::Build
5             # KEYWORDS: plugin installer Module::Build Build.PL toolchain legacy ancient backcompat
6              
7             our $VERSION = '0.027';
8              
9             use Moose;
10 6     6   37 with
  6         15  
  6         56  
11             'Dist::Zilla::Role::BeforeBuild',
12             'Dist::Zilla::Role::AfterBuild',
13             'Dist::Zilla::Role::FileGatherer',
14             'Dist::Zilla::Role::BuildPL',
15             'Dist::Zilla::Role::PrereqSource';
16              
17             use Types::Standard qw(Str HashRef ArrayRef ConsumerOf);
18 6     6   39558 use Dist::Zilla::Plugin::ModuleBuild;
  6         421175  
  6         68  
19 6     6   8799 use Dist::Zilla::Plugin::ModuleBuildTiny;
  6         1213060  
  6         253  
20 6     6   2704 use Moose::Util 'find_meta';
  6         537366  
  6         257  
21 6     6   47 use List::Util 1.33 qw(first any);
  6         19  
  6         67  
22 6     6   1850 use Scalar::Util 'blessed';
  6         187  
  6         447  
23 6     6   36 use Path::Tiny;
  6         14  
  6         229  
24 6     6   34 use namespace::autoclean;
  6         94  
  6         285  
25 6     6   37  
  6         15  
  6         62  
26             has mb_version => (
27             is => 'ro', isa => Str,
28             # <mst> 0.28 is IIRC when install_base changed incompatibly
29             default => '0.28',
30             );
31              
32             has mbt_version => (
33             is => 'ro', isa => Str,
34             );
35              
36             has _extra_args => (
37             isa => HashRef,
38             lazy => 1,
39             default => sub { +{} },
40             traits => ['Hash'],
41             handles => { _extra_args => 'elements' },
42             );
43              
44             has plugins => (
45             isa => ArrayRef[ConsumerOf['Dist::Zilla::Role::BuildPL']],
46             init_arg => undef,
47             lazy => 1,
48             default => sub {
49             my $self = shift;
50             my %args = (
51             zilla => $self->zilla,
52             $self->_extra_args,
53             );
54             [
55             Dist::Zilla::Plugin::ModuleBuild->new(
56             plugin_name => 'ModuleBuild, via ModuleBuildTiny::Fallback',
57             %args,
58             mb_version => $self->mb_version,
59             ),
60             Dist::Zilla::Plugin::ModuleBuildTiny->new(
61             plugin_name => 'ModuleBuildTiny, via ModuleBuildTiny::Fallback',
62             %args,
63             $self->mbt_version ? ( version => $self->mbt_version ) : (),
64             ),
65             ]
66             },
67             traits => ['Array'],
68             handles => { plugins => 'elements' },
69             );
70              
71             around BUILDARGS => sub
72             {
73             my $orig = shift;
74             my $self = shift;
75              
76             my $args = $self->$orig(@_);
77              
78             my %extra_args = %$args;
79             delete @extra_args{qw(version mb_version mbt_version zilla plugin_name)};
80              
81             return +{
82             %$args,
83             _extra_args => \%extra_args,
84             };
85             };
86              
87             around dump_config => sub
88             {
89             my ($orig, $self) = @_;
90             my $config = $self->$orig;
91              
92             $config->{+__PACKAGE__} = {
93             mb_version => $self->mb_version,
94             $self->mbt_version ? ( mbt_version => $self->mbt_version ) : (),
95             plugins => [
96             map {
97             my $plugin = $_;
98             my $config = $plugin->dump_config;
99             +{
100             class => find_meta($plugin)->name,
101             name => $plugin->plugin_name,
102             version => $plugin->VERSION,
103             (keys %$config ? (config => $config) : ()),
104             }
105             } $self->plugins
106             ],
107             blessed($self) ne __PACKAGE__ ? ( version => $VERSION ) : (),
108             };
109              
110             return $config;
111             };
112             {
113             my $self = shift;
114              
115 6     6 0 388623 my @plugins = grep $_->isa(__PACKAGE__), @{ $self->zilla->plugins };
116             $self->log_fatal('two [ModuleBuildTiny::Fallback] plugins detected!') if @plugins > 1;
117 6         19 }
  6         189  
118 6 100       300  
119             my %files;
120              
121             {
122             my $self = shift;
123              
124             foreach my $plugin ($self->plugins)
125 5     5 0 44635 {
126             if ($plugin->can('gather_files'))
127 5         214 {
128             # if a Build.PL was created, save it and cache its content
129 10 50       463 $plugin->gather_files;
130             if (my $build_pl = first { $_->name eq 'Build.PL' } @{ $self->zilla->files })
131             {
132 10         57 $self->log_debug('setting aside Build.PL created by ' . blessed($plugin));
133 10 50   32   11730 $files{ blessed $plugin }{file} = $build_pl;
  32         1226  
  10         265  
134             $files{ blessed $plugin }{content} = $build_pl->content;
135 10         470  
136 10         2581 # we leave MBT's version of Build.PL in place; we will fold all additional content (and
137 10         46 # Module::Build's code)into this object later
138             $self->zilla->prune_file($build_pl) if blessed($plugin) eq 'Dist::Zilla::Plugin::ModuleBuild';
139             }
140             }
141 10 100       877 }
142              
143             return;
144             }
145              
146 5         23 {
147             my $self = shift;
148              
149             # we don't need MB's configure_requires because if Module::Build runs,
150             # configure_requires wasn't being respected anyway
151 5     5 0 14463 my ($mb, $mbt) = $self->plugins;
152             $mbt->register_prereqs;
153             }
154              
155 5         235 my $self = shift;
156 5         39  
157             $self->log('share/ files present: did you forget to include [ShareDir]?')
158             if any { path('share')->subsumes($_->name) } @{ $self->zilla->files }
159             and not @{ $self->zilla->plugins_with(-ShareDir) };
160 5     5 0 30613 }
161              
162             {
163 15     15   1855 my $self = shift;
  5         180  
164 5 100 66     29  
  1         168  
165             my ($mb, $mbt) = $self->plugins;
166              
167             # remove the MBT file that we left in since gather_files
168             if (my $file = $files{'Dist::Zilla::Plugin::ModuleBuildTiny'}{file})
169 5     5 0 77620 {
170             $self->zilla->prune_file($file);
171 5         224  
172             $self->log([ 'something else changed the content of the Module::Build::Tiny version of Build.PL -- maybe you should switch back to [ModuleBuildTiny]? (%s)', $file->added_by ])
173             if $file->content ne $files{'Dist::Zilla::Plugin::ModuleBuildTiny'}{content};
174 5 50       102 }
175              
176 5         148 # let [ModuleBuild] create (or update) the Build.PL file and its content
177             if (my $file = $files{'Dist::Zilla::Plugin::ModuleBuild'}{file}) { push @{ $self->zilla->files }, $file }
178              
179 5 100       443 $self->log_debug('generating Build.PL content from [ModuleBuild]');
180             $mb->setup_installer;
181              
182             # find the file object, save its content, and delete it from the file list
183 5 50       923 my $mb_build_pl = $files{'Dist::Zilla::Plugin::ModuleBuild'}{file}
  5         15  
  5         129  
184             || first { $_->name eq 'Build.PL' } @{ $self->zilla->files };
185 5         214 $self->zilla->prune_file($mb_build_pl);
186 5         1643 my $mb_content = $mb_build_pl->content;
187              
188             # comment out the 'use' line; save the required version
189             $mb_content =~ s/This (?:Build.PL|file) /This section /m;
190 5   33 0   29550 $mb_content =~ s/^use (Module::Build) ([\d.]+);/require $1; $1->VERSION($2);/m;
  0            
191 5         166 $mb_content =~ s/^(?!$)/ /mg;
192 5         376  
193             # now let [ModuleBuildTiny] create (or update) the Build.PL file and its content
194             if (my $file = $files{'Dist::Zilla::Plugin::ModuleBuildTiny'}{file}) { push @{ $self->zilla->files }, $file }
195 5         336 $self->log_debug('generating Build.PL content from [ModuleBuildTiny]');
196 5         69 $mbt->setup_installer;
197 5         155  
198             # find the file object, and fold [ModuleBuild]'s content into it
199             my $mbt_build_pl = $files{'Dist::Zilla::Plugin::ModuleBuildTiny'}{file}
200 5 50       29 || first { $_->name eq 'Build.PL' } @{ $self->zilla->files };
  5         89  
  5         151  
201 5         158 my $mbt_content = $mbt_build_pl->content;
202 5         1573  
203             # extract everything added to the head of the file, to put back on top
204             # when we are done -- we presume this is content or code meant to stay on top
205             $mbt_content =~ s/\A(.*)(\Q# This Build.PL for ${\ $self->zilla->name }\E)/$2/s;
206 5   33 0   15335 my $preamble = $1;
  0            
207 5         19  
208             # comment out the 'use' line; adjust preamble comments
209             $mbt_content =~ s/^(use Module::Build::Tiny [\d.]+;)$/# $1/m;
210             $mbt_content =~ s/This (?:Build.PL|file) /This section /;
211 5         312 $mbt_content =~ s/^(?!$)/ /mg;
  5         160  
212 5         341  
213             # ensure MBT interface is still usable
214             $mbt_content =~ s/(Build_PL)/Module::Build::Tiny::$1/;
215 5         57  
216 5         49 my $message = join('', <DATA>);
217 5         45  
218             my $configure_requires = $self->zilla->prereqs->as_string_hash->{configure}{requires};
219             delete $configure_requires->{perl};
220 5         46  
221             # prereq specifications don't always provide exact versions - we just weed
222 5         205 # those out for now, as this shouldn't occur that frequently.
223             delete @{$configure_requires}{ grep !version::is_strict($configure_requires->{$_}), keys %$configure_requires };
224 5         186  
225 5         2115 $mbt_build_pl->content(
226             ( defined $preamble ? $preamble : '' )
227             . <<"FALLBACK1"
228             # This Build.PL for ${\ $self->zilla->name } was generated by
229 5         38 # ${\ ref $self } ${ \($self->VERSION) }
  5         83  
230             use strict;
231 5 50       23 use warnings;
232              
233             my %configure_requires = (
234 5         169 FALLBACK1
235 5         173 . join('', map
  5         227  
236             " '$_' => '$configure_requires->{$_}',\n",
237             sort keys %$configure_requires)
238             . <<'FALLBACK2'
239             );
240              
241             my %errors = map {
242             eval "require $_; $_->VERSION($configure_requires{$_}); 1";
243             $_ => $@,
244             } keys %configure_requires;
245              
246             if (!grep $_, values %errors)
247             {
248             FALLBACK2
249             . $mbt_content . "}\n"
250             . <<'FALLBACK3'
251             else
252             {
253             if (not $ENV{PERL_MB_FALLBACK_SILENCE_WARNING})
254             {
255             warn <<'EOW'
256             FALLBACK3
257             . $message . <<'FALLBACK4'
258              
259              
260             Errors from configure prereqs:
261             EOW
262             . do {
263             require Data::Dumper; Data::Dumper->new([ \%errors ])->Indent(2)->Terse(1)->Sortkeys(1)->Dump;
264             };
265              
266             sleep 10 if -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT));
267             }
268              
269             FALLBACK4
270             . $mb_content . "}\n"
271             );
272              
273             return;
274             }
275              
276             __PACKAGE__->meta->make_immutable;
277              
278             #pod =pod
279 5         1133 #pod
280             #pod =head1 SYNOPSIS
281             #pod
282             #pod In your F<dist.ini>:
283             #pod
284             #pod [ModuleBuildTiny::Fallback]
285             #pod
286             #pod =head1 DESCRIPTION
287             #pod
288             #pod This is a L<Dist::Zilla> plugin that provides a F<Build.PL> in your
289             #pod distribution that attempts to use L<Module::Build::Tiny> when available,
290             #pod falling back to L<Module::Build> when it is missing.
291             #pod
292             #pod This is useful when your distribution is installing on an older perl (before
293             #pod approximately 5.10.1) with a toolchain that has not been updated, where
294             #pod C<configure_requires> metadata is not understood and respected -- or where
295             #pod F<Build.PL> is being run manually without the user having read and understood
296             #pod the contents of F<META.yml> or F<META.json>.
297             #pod
298             #pod When the L<Module::Build> fallback code is run, an added preamble is printed:
299             #pod
300             #pod =for stopwords cpanminus
301             #pod
302             #pod =for comment This section was inserted from the DATA section at build time
303             #pod
304             #pod =begin :verbatim
305             #pod
306             #pod *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***
307             #pod
308             #pod If you're seeing this warning, your toolchain is really, really old* and
309             #pod you'll almost certainly have problems installing CPAN modules from this
310             #pod century. But never fear, dear user, for we have the technology to fix this!
311             #pod
312             #pod If you're using CPAN.pm to install things, then you can upgrade it using:
313             #pod
314             #pod cpan CPAN
315             #pod
316             #pod If you're using CPANPLUS to install things, then you can upgrade it using:
317             #pod
318             #pod cpanp CPANPLUS
319             #pod
320             #pod If you're using cpanminus, you shouldn't be seeing this message in the first
321             #pod place, so please file an issue on github.
322             #pod
323             #pod This public service announcement was brought to you by the Perl Toolchain
324             #pod Gang, the irc.perl.org #toolchain IRC channel, and the number 42.
325             #pod
326             #pod ----
327             #pod
328             #pod * Alternatively, you are running this file manually, in which case you need to
329             #pod learn to first fulfill all configure requires prerequisites listed in META.yml
330             #pod or META.json -- or use a cpan client to install this distribution.
331             #pod
332             #pod You can also silence this warning for future installations by setting the
333             #pod PERL_MB_FALLBACK_SILENCE_WARNING environment variable, but please don't do
334             #pod that until you fix your toolchain as described above.
335             #pod
336             #pod
337             #pod =end :verbatim
338             #pod
339             #pod =for stopwords ModuleBuild
340             #pod
341             #pod This plugin internally calls both the
342             #pod L<[ModuleBuildTiny]|Dist::Zilla::Plugin::ModuleBuildTiny>
343             #pod and L<[ModuleBuild]|Dist::Zilla::Plugin::ModuleBuild> plugins to fetch their
344             #pod normal F<Build.PL> file contents, combining them together into the final
345             #pod F<Build.PL> for the distribution.
346             #pod
347             #pod You are warned if anything else added content into F<Build.PL> (e.g. some
348             #pod additional build-time dependency checks), as that code will not run in the
349             #pod fallback case. It is up to you to decide whether it is still a good idea to use
350             #pod this plugin in this situation.
351             #pod
352             #pod =for Pod::Coverage before_build gather_files register_prereqs after_build setup_installer
353             #pod
354             #pod =head1 CONFIGURATION OPTIONS
355             #pod
356             #pod =head2 mb_version
357             #pod
358             #pod Optional. Specifies the minimum version of L<Module::Build> needed for proper
359             #pod fallback execution. Defaults to 0.28.
360             #pod
361             #pod =head2 mbt_version
362             #pod
363             #pod Optional.
364             #pod Passed to L<[ModuleBuildTiny]|Dist::Zilla::Plugin::ModuleBuildTiny> as C<version>:
365             #pod the minimum version of L<Module::Build::Tiny> to depend on (in
366             #pod C<configure_requires> as well as a C<use> assertion in F<Build.PL>).
367             #pod
368             #pod =head1 ACKNOWLEDGEMENTS
369             #pod
370             #pod =for stopwords Rabbitson ribasushi mst
371             #pod
372             #pod Peter Rabbitson (ribasushi), for inspiration, and Matt Trout (mst), for not stopping me.
373             #pod
374             #pod =head1 SEE ALSO
375             #pod
376             #pod =for :list
377             #pod * L<Dist::Zilla::Plugin::MakeMaker::Fallback> (which can happily run alongside this plugin)
378             #pod * L<Dist::Zilla::Plugin::ModuleBuildTiny>
379             #pod * L<Dist::Zilla::Plugin::ModuleBuild>
380             #pod
381             #pod =cut
382              
383             =pod
384              
385             =encoding UTF-8
386              
387             =head1 NAME
388              
389             Dist::Zilla::Plugin::ModuleBuildTiny::Fallback - Generate a Build.PL that uses Module::Build::Tiny and Module::Build
390              
391             =head1 VERSION
392              
393             version 0.027
394              
395             =head1 SYNOPSIS
396              
397             In your F<dist.ini>:
398              
399             [ModuleBuildTiny::Fallback]
400              
401             =head1 DESCRIPTION
402              
403             This is a L<Dist::Zilla> plugin that provides a F<Build.PL> in your
404             distribution that attempts to use L<Module::Build::Tiny> when available,
405             falling back to L<Module::Build> when it is missing.
406              
407             This is useful when your distribution is installing on an older perl (before
408             approximately 5.10.1) with a toolchain that has not been updated, where
409             C<configure_requires> metadata is not understood and respected -- or where
410             F<Build.PL> is being run manually without the user having read and understood
411             the contents of F<META.yml> or F<META.json>.
412              
413             When the L<Module::Build> fallback code is run, an added preamble is printed:
414              
415             =for stopwords cpanminus
416              
417             =for comment This section was inserted from the DATA section at build time
418              
419             *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***
420              
421             If you're seeing this warning, your toolchain is really, really old* and
422             you'll almost certainly have problems installing CPAN modules from this
423             century. But never fear, dear user, for we have the technology to fix this!
424              
425             If you're using CPAN.pm to install things, then you can upgrade it using:
426              
427             cpan CPAN
428              
429             If you're using CPANPLUS to install things, then you can upgrade it using:
430              
431             cpanp CPANPLUS
432              
433             If you're using cpanminus, you shouldn't be seeing this message in the first
434             place, so please file an issue on github.
435              
436             This public service announcement was brought to you by the Perl Toolchain
437             Gang, the irc.perl.org #toolchain IRC channel, and the number 42.
438              
439             ----
440              
441             * Alternatively, you are running this file manually, in which case you need to
442             learn to first fulfill all configure requires prerequisites listed in META.yml
443             or META.json -- or use a cpan client to install this distribution.
444              
445             You can also silence this warning for future installations by setting the
446             PERL_MB_FALLBACK_SILENCE_WARNING environment variable, but please don't do
447             that until you fix your toolchain as described above.
448              
449             =for stopwords ModuleBuild
450              
451             This plugin internally calls both the
452             L<[ModuleBuildTiny]|Dist::Zilla::Plugin::ModuleBuildTiny>
453             and L<[ModuleBuild]|Dist::Zilla::Plugin::ModuleBuild> plugins to fetch their
454             normal F<Build.PL> file contents, combining them together into the final
455             F<Build.PL> for the distribution.
456              
457             You are warned if anything else added content into F<Build.PL> (e.g. some
458             additional build-time dependency checks), as that code will not run in the
459             fallback case. It is up to you to decide whether it is still a good idea to use
460             this plugin in this situation.
461              
462             =for Pod::Coverage before_build gather_files register_prereqs after_build setup_installer
463              
464             =head1 CONFIGURATION OPTIONS
465              
466             =head2 mb_version
467              
468             Optional. Specifies the minimum version of L<Module::Build> needed for proper
469             fallback execution. Defaults to 0.28.
470              
471             =head2 mbt_version
472              
473             Optional.
474             Passed to L<[ModuleBuildTiny]|Dist::Zilla::Plugin::ModuleBuildTiny> as C<version>:
475             the minimum version of L<Module::Build::Tiny> to depend on (in
476             C<configure_requires> as well as a C<use> assertion in F<Build.PL>).
477              
478             =head1 ACKNOWLEDGEMENTS
479              
480             =for stopwords Rabbitson ribasushi mst
481              
482             Peter Rabbitson (ribasushi), for inspiration, and Matt Trout (mst), for not stopping me.
483              
484             =head1 SEE ALSO
485              
486             =over 4
487              
488             =item *
489              
490             L<Dist::Zilla::Plugin::MakeMaker::Fallback> (which can happily run alongside this plugin)
491              
492             =item *
493              
494             L<Dist::Zilla::Plugin::ModuleBuildTiny>
495              
496             =item *
497              
498             L<Dist::Zilla::Plugin::ModuleBuild>
499              
500             =back
501              
502             =head1 SUPPORT
503              
504             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-ModuleBuildTiny-Fallback>
505             (or L<bug-Dist-Zilla-Plugin-ModuleBuildTiny-Fallback@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-ModuleBuildTiny-Fallback@rt.cpan.org>).
506              
507             There is also a mailing list available for users of this distribution, at
508             L<http://dzil.org/#mailing-list>.
509              
510             There is also an irc channel available for users of this distribution, at
511             L<C<#distzilla> on C<irc.perl.org>|irc://irc.perl.org/#distzilla>.
512              
513             I am also usually active on irc, as 'ether' at C<irc.perl.org> and C<irc.libera.chat>.
514              
515             =head1 AUTHOR
516              
517             Karen Etheridge <ether@cpan.org>
518              
519             =head1 COPYRIGHT AND LICENCE
520              
521             This software is copyright (c) 2014 by Karen Etheridge.
522              
523             This is free software; you can redistribute it and/or modify it under
524             the same terms as the Perl 5 programming language system itself.
525              
526             =cut
527              
528             *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***
529              
530             If you're seeing this warning, your toolchain is really, really old* and
531             you'll almost certainly have problems installing CPAN modules from this
532             century. But never fear, dear user, for we have the technology to fix this!
533              
534             If you're using CPAN.pm to install things, then you can upgrade it using:
535              
536             cpan CPAN
537              
538             If you're using CPANPLUS to install things, then you can upgrade it using:
539              
540             cpanp CPANPLUS
541              
542             If you're using cpanminus, you shouldn't be seeing this message in the first
543             place, so please file an issue on github.
544              
545             This public service announcement was brought to you by the Perl Toolchain
546             Gang, the irc.perl.org #toolchain IRC channel, and the number 42.
547              
548             ----
549              
550             * Alternatively, you are running this file manually, in which case you need to
551             learn to first fulfill all configure requires prerequisites listed in META.yml
552             or META.json -- or use a cpan client to install this distribution.
553              
554             You can also silence this warning for future installations by setting the
555             PERL_MB_FALLBACK_SILENCE_WARNING environment variable, but please don't do
556             that until you fix your toolchain as described above.