File Coverage

blib/lib/Dist/Zilla/Plugin/ModuleBuildTiny/Fallback.pm
Criterion Covered Total %
statement 95 97 97.9
branch 12 18 66.6
condition 2 6 33.3
subroutine 16 18 88.8
pod 0 4 0.0
total 125 143 87.4


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