File Coverage

blib/lib/Dist/Zilla/Plugin/Alien.pm
Criterion Covered Total %
statement 71 74 95.9
branch 35 44 79.5
condition 19 24 79.1
subroutine 17 17 100.0
pod 0 2 0.0
total 142 161 88.2


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