File Coverage

blib/lib/Dist/Zilla/Plugin/Alien.pm
Criterion Covered Total %
statement 68 71 95.7
branch 35 44 79.5
condition 19 24 79.1
subroutine 16 16 100.0
pod 0 2 0.0
total 138 157 87.9


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