File Coverage

blib/lib/Dist/Zilla/Plugin/Alien.pm
Criterion Covered Total %
statement 52 56 92.8
branch 15 26 57.6
condition 9 15 60.0
subroutine 13 13 100.0
pod 0 1 0.0
total 89 111 80.1


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::Alien;
2             our $AUTHORITY = 'cpan:GETTY';
3             # ABSTRACT: Use Alien::Base with Dist::Zilla
4             $Dist::Zilla::Plugin::Alien::VERSION = '0.022';
5 4     4   1978648 use Moose;
  4         477753  
  4         32  
6             extends 'Dist::Zilla::Plugin::ModuleBuild';
7             with 'Dist::Zilla::Role::PrereqSource', 'Dist::Zilla::Role::FileGatherer';
8              
9              
10 4     4   30089 use URI;
  4         18323  
  4         5891  
11              
12             has name => (
13             isa => 'Str',
14             is => 'rw',
15             lazy_build => 1,
16             );
17             sub _build_name {
18 4     4   9 my ( $self ) = @_;
19 4         130 my $name = $self->zilla->name;
20 4         149 $name =~ s/^Alien-//g;
21 4         147 return $name;
22             }
23              
24             has bins => (
25             isa => 'Str',
26             is => 'rw',
27             predicate => 'has_bins',
28             );
29              
30             has split_bins => (
31             isa => 'ArrayRef',
32             is => 'rw',
33             lazy_build => 1,
34             );
35 4 50   4   181 sub _build_split_bins { $_[0]->has_bins ? [split(/\s+/,$_[0]->bins)] : [] }
36              
37             has repo => (
38             isa => 'Str',
39             is => 'rw',
40             required => 1,
41             );
42              
43             has repo_uri => (
44             isa => 'URI',
45             is => 'rw',
46             lazy_build => 1,
47             );
48             sub _build_repo_uri {
49 4     4   17 my ( $self ) = @_;
50 4         169 URI->new($self->repo);
51             }
52              
53             has pattern_prefix => (
54             isa => 'Str',
55             is => 'rw',
56             lazy_build => 1,
57             );
58             sub _build_pattern_prefix {
59 4     4   10 my ( $self ) = @_;
60 4         156 return $self->name.'-';
61             }
62              
63             has pattern_version => (
64             isa => 'Str',
65             is => 'rw',
66             lazy_build => 1,
67             );
68 4     4   153 sub _build_pattern_version { '([\d\.]+)' }
69              
70             has pattern_suffix => (
71             isa => 'Str',
72             is => 'rw',
73             lazy_build => 1,
74             );
75 4     4   155 sub _build_pattern_suffix { '\\.tar\\.gz' }
76              
77             has pattern => (
78             isa => 'Str',
79             is => 'rw',
80             lazy_build => 1,
81             );
82             sub _build_pattern {
83 4     4   9 my ( $self ) = @_;
84 4         172 join("",
85             $self->pattern_prefix.
86             $self->pattern_version.
87             $self->pattern_suffix
88             );
89             }
90              
91             has exact_filename => (
92             isa => 'Str',
93             is => 'rw',
94             );
95              
96             has build_command => (
97             isa => 'ArrayRef[Str]',
98             is => 'rw',
99             );
100              
101             has install_command => (
102             isa => 'ArrayRef[Str]',
103             is => 'rw',
104             );
105              
106             has isolate_dynamic => (
107             isa => 'Int',
108             is => 'rw',
109             );
110              
111             has autoconf_with_pic => (
112             isa => 'Int',
113             is => 'rw',
114             );
115              
116             has inline_auto_include => (
117             isa => 'ArrayRef[Str]',
118             is => 'rw',
119             default => sub { [] },
120             );
121              
122             has msys => (
123             isa => 'Int',
124             is => 'rw',
125             );
126              
127             has bin_requires => (
128             isa => 'ArrayRef[Str]',
129             is => 'rw',
130             default => sub { [] },
131             );
132              
133             sub _bin_requires_hash {
134 10     10   21 my($self) = @_;
135 10 100       30 my %bin_requires = map { /^\s*(.*?)\s*=\s*(.*)\s*$/ ? ($1 => $2) : ($_ => 0) } @{ $self->bin_requires };
  8         68  
  10         512  
136 10         31 \%bin_requires;
137             }
138              
139             has helper => (
140             isa => 'ArrayRef[Str]',
141             is => 'rw',
142             default => sub { [] },
143             );
144              
145             sub _helper_hash {
146 9     9   15 my($self) = @_;
147 9 0       16 my %helper = map { /^\s*(.*?)\s*=\s*(.*)\s*$/ ? ($1 => $2) : ($_ => '') } @{ $self->helper };
  0         0  
  9         358  
148 9         26 \%helper;
149             }
150              
151             has stage_install => (
152             isa => 'Int',
153             is => 'rw',
154             );
155              
156             has provides_cflags => (
157             isa => 'Str',
158             is => 'rw',
159             );
160              
161             has provides_libs => (
162             isa => 'Str',
163             is => 'rw',
164             );
165              
166             has version_check => (
167             isa => 'Str',
168             is => 'rw',
169             );
170              
171             # multiple build/install commands return as an arrayref
172             around mvp_multivalue_args => sub {
173             my ($orig, $self) = @_;
174             return ($self->$orig, 'build_command', 'install_command', 'inline_auto_include', 'bin_requires', 'helper');
175             };
176              
177             sub register_prereqs {
178 4     4 0 9655 my ( $self ) = @_;
179              
180 4         14 my $ab_version = '0.002';
181 4         12 my $configure_requires = {};
182              
183 4 50 33     180 if(defined $self->isolate_dynamic || defined $self->autoconf_with_pic || grep /(?<!\%)\%c/, @{ $self->build_command || [] }) {
  4 50 33     186  
184 0         0 $ab_version = '0.005';
185             }
186              
187 4 100 100     11 if(@{ $self->inline_auto_include } || @{ $self->bin_requires } || defined $self->msys) {
  4   100     173  
  3         127  
188 3         9 $ab_version = '0.006';
189 3 100       14 if(@{ $self->bin_requires }) {
  3         122  
190 1         5 $configure_requires = $self->_bin_requires_hash;
191             }
192             }
193            
194 4 50       174 if(defined $self->stage_install) {
195 0         0 $ab_version = '0.016';
196             }
197            
198 4 50 33     9 if(@{ $self->helper } || grep /(?<!\%)\%\{([a-zA-Z_][a-zA-Z_0-9]+)\}/, @{ $self->build_command || [] }, @{ $self->install_command || [] } ) {
  4 50       160  
  4 50       158  
  4         184  
199 0         0 $ab_version = '0.020';
200             }
201              
202             $self->zilla->register_prereqs({
203             type => 'requires',
204             phase => 'configure',
205             },
206             'Alien::Base::ModuleBuild' => $ab_version,
207             'File::ShareDir' => '1.03',
208 4 50       140 @{ $self->split_bins } > 0 ? ('Path::Class' => '0.013') : (),
  4         304  
209             %$configure_requires,
210             );
211             $self->zilla->register_prereqs({
212             type => 'requires',
213             phase => 'runtime',
214             },
215             'Alien::Base' => $ab_version,
216             'File::ShareDir' => '1.03',
217 4 50       3069 @{ $self->split_bins } > 0 ? ('Path::Class' => '0.013') : (),
  4         190  
218             );
219             }
220              
221             has "+mb_class" => (
222             default => 'Alien::Base::ModuleBuild',
223             );
224              
225             after gather_files => sub {
226             my ( $self ) = @_;
227              
228             my $template = <<'__EOT__';
229             #!/usr/bin/env perl
230             # PODNAME: {{ $bin }}
231             # ABSTRACT: Command {{ $bin }} of {{ $dist->name }}
232              
233             $|=1;
234              
235             use strict;
236             use warnings;
237             use File::ShareDir ':ALL';
238             use Path::Class;
239              
240             my $abs = file(dist_dir('{{ $dist->name }}'),'bin','{{ $bin }}')->cleanup->absolute;
241              
242             exec($abs, @ARGV) or print STDERR "couldn't exec {{ $bin }}: $!";
243              
244             __EOT__
245              
246             for (@{$self->split_bins}) {
247             my $content = $self->fill_in_string(
248             $template,
249             {
250             dist => \($self->zilla),
251             bin => $_,
252             },
253             );
254              
255             my $file = Dist::Zilla::File::InMemory->new({
256             content => $content,
257             name => 'bin/'.$_,
258             mode => 0755,
259             });
260              
261             $self->add_file($file);
262             }
263             };
264              
265             around module_build_args => sub {
266             my ($orig, $self, @args) = @_;
267             my $pattern = $self->pattern;
268             my $exact_filename = $self->exact_filename;
269              
270             my $bin_requires = $self->_bin_requires_hash;
271             my $helper = $self->_helper_hash;
272              
273             return {
274             %{ $self->$orig(@args) },
275             alien_name => $self->name,
276             alien_repository => {
277             protocol => $self->repo_uri->scheme eq 'file'
278             ? 'local'
279             : $self->repo_uri->scheme,
280             host => $self->repo_uri->can('port') # local files do not have port
281             ? ( $self->repo_uri->default_port == $self->repo_uri->port
282             ? $self->repo_uri->host
283             : $self->repo_uri->host_port )
284             : '',
285             location => $self->repo_uri->path,
286             # NOTE Not using a compiled regex here for serialisation
287             # in case it adds flags not in older versions of perl.
288             # In particular, the compiled regex was adding the u
289             # modifier, but then getting serialised as
290             # (?^u:$pattern) which fails to parse under perl less
291             # than v5.014.
292             defined $exact_filename ? (exact_filename => $exact_filename) : (pattern => "^$pattern\$"),
293             },
294             (alien_build_commands => $self->build_command)x!! $self->build_command,
295             (alien_install_commands => $self->install_command)x!! $self->install_command,
296             (alien_inline_auto_include => $self->inline_auto_include)x!! $self->inline_auto_include,
297             defined $self->autoconf_with_pic ? (alien_autoconf_with_pic => $self->autoconf_with_pic) : (),
298             defined $self->isolate_dynamic ? (alien_isolate_dynamic => $self->isolate_dynamic) : (),
299             defined $self->msys ? (alien_msys => $self->msys) : (),
300             defined $self->stage_install ? (alien_stage_install => $self->stage_install) : (),
301             defined $self->provides_libs ? (alien_provides_libs => $self->provides_libs) : (),
302             defined $self->version_check ? (alien_version_check => $self->version_check) : (),
303             defined $self->provides_cflags ? (alien_provides_cflags => $self->provides_cflags) : (),
304             %$bin_requires ? ( alien_bin_requires => $bin_requires ) : (),
305             %$helper ? ( alien_helper => $helper ): (),
306             };
307             };
308              
309             __PACKAGE__->meta->make_immutable;
310 4     4   27 no Moose;
  4         7  
  4         34  
311             1;
312              
313             __END__
314              
315             =pod
316              
317             =head1 NAME
318              
319             Dist::Zilla::Plugin::Alien - Use Alien::Base with Dist::Zilla
320              
321             =head1 VERSION
322              
323             version 0.022
324              
325             =head1 SYNOPSIS
326              
327             In your I<dist.ini>:
328              
329             name = Alien-myapp
330              
331             [Alien]
332             repo = http://myapp.org/releases
333             bins = myapp myapp_helper
334             # the following parameters are based on the dist name automatically
335             name = myapp
336             pattern_prefix = myapp-
337             pattern_version = ([\d\.]+)
338             pattern_suffix = \.tar\.gz
339             pattern = myapp-([\d\.]+)\.tar\.gz
340              
341             # commands used to build (optional)
342             build_command = %c --prefix=%s
343             # ...
344              
345             # commands uses to install (optional)
346             install_command = make install
347              
348             =head1 DESCRIPTION
349              
350             This is a simple wrapper around Alien::Base, to make it very simple to
351             generate a distribution that uses it. You only need to make a module like
352             in this case Alien::myapp which extends Alien::Base and additionally a url
353             that points to the path where the downloadable .tar.gz of the application
354             or library can be found. For more informations about the parameter, please
355             checkout also the L<Alien::Base> documentation. The I<repo> paramter is
356             automatically taken apart to supply the procotol, host and other parameters
357             for L<Alien::Base>.
358              
359             B<Warning>: Please be aware that L<Alien::Base> uses L<Module::Build>, which
360             means you shouldn't have L<Dist::Zilla::Plugin::MakeMaker> loaded. For our
361             case, this means, you can't just easily use it together with the common
362             L<Dist::Zilla::PluginBundle::Basic>, because this includes it. As alternative
363             you can use L<Dist::Zilla::PluginBundle::Alien> which is also included in this
364             distribution.
365              
366             =head1 ATTRIBUTES
367              
368             =head2 repo
369              
370             The only required parameter, defines the path for the packages of the product
371             you want to alienfy. This must not include the filename.
372              
373             To indicate a local repository use the C<file:> scheme:
374              
375             # located in the base directory
376             repo = file:.
377              
378             # located in the inc/ directory relative to the base
379             repo = file:inc
380              
381             =head2 pattern
382              
383             The pattern is used to define the filename to be expected from the repo of the
384             alienfied product. It is set together out of I<pattern_prefix>,
385             I<pattern_version> and I<pattern_suffix>. I<pattern_prefix> is by default
386             L</name> together with a dash.
387              
388             =head2 exact_filename
389              
390             Instead of providing a pattern you may use this to set the exact filename.
391              
392             =head2 bins
393              
394             A space or tab seperated list of all binaries that should be wrapped to be executable
395             from the perl environment (if you use perlbrew or local::lib this also
396             guarantees that its available via the PATH).
397              
398             =head2 name
399              
400             The name of the Alien package, this is used for the pattern matching filename.
401             If none is given, then the name of the distribution is used, but the I<Alien->
402             is cut off.
403              
404             =head2 build_command
405              
406             The ordered sequence of commands used to build the distribution (passed to the
407             C<alien_build_commands> option). This is optional.
408              
409             # configure then make
410             build_command = %c --prefix=%s
411             build_command = make
412              
413             =head2 install_command
414              
415             The ordered sequence of commands used to install the distribution (passed to the
416             C<alien_install_commands> option). This is optional.
417              
418             install_command = make install
419              
420             =head2 isolate_dynamic
421              
422             If set to true, then dynamic libraries will be isolated from the static libraries
423             when C<install_type=share> is used. This is recommended for XS modules where
424             static libraries are more reliable. Dynamic libraries (.dll, .so, etc) are still
425             available and can easily be used by FFI modules.
426              
427             isolate_dynamic = 1
428              
429             Usage of this attribute will bump the requirement of L<Alien::Base> up to 0.005
430             for your distribution.
431              
432             =head2 autoconf_with_pic
433              
434             If set to true (the default), then C<--with-pic> will be passed to autoconf style
435             C<configure> scripts. This usually enables position independent code which is
436             desirable if you are using static libraries to build XS modules. Usually, if the
437             autoconf does not recognize C<--with-pic> it will ignore it, but some C<configure>
438             scripts which are not managed by autoconf may complain and die with this option.
439              
440             ; only if you know configure will die with --with-pic
441             autoconf_with_pic = 0
442              
443             Usage of this attribute will bump the requirement of L<Alien::Base> up to 0.005
444             for your distribution.
445              
446             =head2 inline_auto_include
447              
448             List of header files to automatically include (see L<Inline::C#auto_include>) when
449             the Alien module is used with L<Inline::C> or L<Inline::CPP>.
450              
451             =head2 msys
452              
453             Force the use of L<Alien::MSYS> when building on Windows. Normally this is only
454             done if L<Alien::Base::ModuleBuild> can detect that you are attempting to use
455             an autotools style C<configure> script.
456              
457             =head2 bin_requires
458              
459             Require the use of a binary tool Alien distribution. You can optionally specify
460             a version using the equal C<=> sign.
461              
462             [Alien]
463             bin_requires = Alien::patch
464             bin_requires = Alien::gmake = 0.03
465              
466             =head2 stage_install
467              
468             If set to true, Alien packages are installed directly into the blib
469             directory by the `./Build' command rather than to the final location during the
470             `./Build install` step.
471              
472             =head2 helper
473              
474             Defines helpers. You can specify the content of the helper (which will be evaluated
475             in L<Alien::Base::ModuleBuild> during the build/install step) using the equal C<=> sign.
476              
477             [Alien]
478             helper = mytool = 'mytool --foo --bar'
479              
480             =head2 provides_cflags
481              
482             Sets the C<alien_provides_cflags> property for L<Alien::Base::ModuleBuild>.
483              
484             =head2 provides_libs
485              
486             Sets the C<alien_provides_libs> property for L<Alien::Base::ModuleBuild>.
487              
488             =head2 version_check
489              
490             Sets the C<alien_version_check> property for L<Alien::Base::ModuleBuild>.
491              
492             =head1 InstallRelease
493              
494             The method L<Alien::Base> is using would compile the complete Alien 2 times, if
495             you use it in combination with L<Dist::Zilla::Plugin::InstallRelease>. One time
496             at the test, and then again after release. With a small trick, you can avoid
497             this. You can use L<Dist::Zilla::Plugin::Run> to add an additional test which
498             installs out of the unpacked distribution for the testing:
499              
500             [Run::Test]
501             run_if_release = ./Build install
502              
503             This will do the trick :). Be aware, that you need to add this plugin after
504             I<[ModuleBuild]>. You can use L<Dist::Zilla::PluginBundle::Author::GETTY>,
505             which directly use this trick in the right combination.
506              
507             =head1 AUTHOR
508              
509             Torsten Raudssus <torsten@raudss.us>
510              
511             =head1 COPYRIGHT AND LICENSE
512              
513             This software is copyright (c) 2013 by Torsten Raudssus.
514              
515             This is free software; you can redistribute it and/or modify it under
516             the same terms as the Perl 5 programming language system itself.
517              
518             =cut