File Coverage

blib/lib/Dist/Zilla/Plugin/Run/Role/Runner.pm
Criterion Covered Total %
statement 120 126 95.2
branch 57 64 89.0
condition 16 21 76.1
subroutine 24 24 100.0
pod 0 2 0.0
total 217 237 91.5


line stmt bran cond sub pod time code
1 12     12   121657 use strict;
  12         39  
  12         400  
2 12     12   92 use warnings;
  12         37  
  12         1094  
3             package Dist::Zilla::Plugin::Run::Role::Runner;
4             # vim: set ts=8 sts=2 sw=2 tw=115 et :
5              
6             our $VERSION = '0.049';
7              
8 12     12   95 use Moose::Role;
  12         42  
  12         155  
9 12     12   61651 use namespace::autoclean;
  12         44  
  12         98  
10 12     12   813 use File::Spec (); # core
  12         43  
  12         256  
11 12     12   377 use Config (); # core
  12         37  
  12         350  
12 12     12   89 use Moose::Util 'find_meta';
  12         35  
  12         139  
13              
14             has perlpath => (
15             is => 'ro',
16             isa => 'Str',
17             lazy => 1,
18             builder => 'current_perl_path',
19             );
20              
21             has censor_commands => (
22             is => 'ro',
23             isa => 'Bool',
24             default => 0,
25             );
26              
27             has [ qw(run run_if_trial run_no_trial run_if_release run_no_release) ] => (
28             is => 'ro',
29             isa => 'ArrayRef[Str]',
30             default => sub { [] },
31             );
32              
33             has eval => (
34             is => 'ro',
35             isa => 'ArrayRef[Str]',
36             default => sub { [] },
37             );
38              
39             has fatal_errors => (
40             is => 'ro',
41             isa => 'Bool',
42             default => 1,
43             );
44              
45             has quiet => (
46             is => 'ro',
47             isa => 'Bool',
48             default => 0,
49             );
50              
51             around dump_config => sub
52             {
53             my ($orig, $self) = @_;
54             my $config = $self->$orig;
55              
56             $config->{+__PACKAGE__} = {
57             version => $VERSION,
58             (map +($_ => $self->$_ ? 1 : 0), qw(fatal_errors quiet)),
59             map
60             @{ $self->$_ }
61             # look for user:password URIs
62             ? ( $_ => [ map $self->censor_commands || /\b\w+:[^@]+@\b/ ? 'REDACTED' : $_, @{ $self->$_ } ] )
63             : (),
64             qw(run run_if_trial run_no_trial run_if_release run_no_release eval),
65             };
66              
67             return $config;
68             };
69              
70             around BUILDARGS => sub {
71             my ( $orig, $class, @args ) = @_;
72             my $built = $class->$orig(@args);
73              
74             foreach my $dep (qw( notexist_fatal )) {
75             if ( exists $built->{$dep} ) {
76             warn(" !\n ! $class attribute '$dep' is deprecated and has no effect.\n !\n");
77             delete $built->{$dep};
78             }
79             }
80             return $built;
81             };
82              
83             sub _is_trial {
84 28     28   151 my $self = shift;
85              
86             # we want to avoid provoking other plugins prematurely, but also be as
87             # accurate as we can with this status
88              
89 28         1165 my $release_status_attr = find_meta($self->zilla)->find_attribute_by_name('release_status');
90              
91 28 100 66     9296 return ( $self->zilla->is_trial ? 1 : 0 ) if
    100          
92             not $release_status_attr # legacy (before Dist::Zilla 5.035)
93             or $release_status_attr->has_value($self->zilla);
94              
95             # otherwise, only use the logic that does not require zilla->version
96             # before Dist::Zilla 5.035, this is what $zilla->is_trial returned
97 8 100       1229 return eval { $self->zilla->_release_status_from_env =~ /\A(?:testing|unstable)\z/ } ? 1 : 0;
  8         403  
98             }
99              
100             sub _call_script {
101 52     52   689 my ( $self, $params ) = @_;
102              
103 52         243 foreach my $run_cmd (@{$self->run}) {
  52         2727  
104 43         1448 $self->_run_cmd($run_cmd, $params);
105             }
106              
107 47         50965 foreach my $run_cmd (@{$self->run_if_trial}) {
  47         3789  
108 4 100       90 if ($self->_is_trial) {
109 2         294 $self->_run_cmd($run_cmd, $params);
110             } else {
111 2         287 $self->log_debug([ 'not executing, because no trial: %s', $run_cmd ]);
112             }
113             }
114              
115 47         4567 foreach my $run_cmd (@{$self->run_no_trial}) {
  47         3170  
116 6 100       87 if ($self->_is_trial) {
117 3         559 $self->log_debug([ 'not executing, because trial: %s', $run_cmd ]);
118             } else {
119 3         628 $self->_run_cmd($run_cmd, $params);
120             }
121             }
122              
123 47 100 66     7423 my $is_release = defined $ENV{'DZIL_RELEASING'} && $ENV{'DZIL_RELEASING'} == 1 ? 1 : 0;
124              
125 47         228 foreach my $run_cmd (@{$self->run_if_release}) {
  47         2933  
126 0 0       0 if ($is_release) {
127 0         0 $self->_run_cmd($run_cmd, $params);
128             } else {
129 0         0 $self->log_debug([ 'not executing, because no release: %s', $run_cmd ]);
130             }
131             }
132              
133 47         207 foreach my $run_cmd (@{$self->run_no_release}) {
  47         2942  
134 0 0       0 if ($is_release) {
135 0         0 $self->log_debug([ 'not executing, because release: %s', $run_cmd ]);
136             } else {
137 0         0 $self->_run_cmd($run_cmd, $params);
138             }
139             }
140              
141 47 100       186 if (my @code = @{ $self->eval }) {
  47         2683  
142 18         152 my $code = join "\n", @code;
143              
144 18         126 $self->_eval_cmd($code, $params);
145             }
146             }
147              
148             sub _run_cmd {
149 50     50   479 my ( $self, $run_cmd, $params, $dry_run ) = @_;
150              
151 50 100       449 if ($dry_run) {
152 1         7 $self->log_debug([ 'dry run, would run: %s', $run_cmd ]);
153 1         462 return;
154             }
155              
156 49 50       440 return if not $run_cmd;
157              
158 49         5744 require IPC::Open3; # core
159              
160 49         28403 my $command = $self->build_formatter($params)->format($run_cmd);
161 49 100       10343 $self->${ $self->quiet ? \'log_debug' : \'log' }([ 'executing: %s', $command ]);
  49         2597  
162              
163             # autoflush STDOUT so we can see command output right away
164 49         21581 local $| = 1;
165             # combine STDOUT and STDERR for ease of proxying through the logger
166 49         389 my $pid = IPC::Open3::open3(my ($in, $out), undef, $command);
167 49 50       419126 binmode $out, ':crlf' if $^O eq 'MSWin32';
168 49         1101654 while(defined(my $line = <$out>)){
169 8         87 chomp($line); # logger appends its own newline
170 8 100       29 $self->${ $self->quiet ? \'log_debug' : \'log' }($line);
  8         1172  
171             }
172              
173             # zombie repellent
174 49         7123 waitpid($pid, 0);
175              
176 49 100       1527 if (my $status = ($? >> 8)) {
177 10 100       411 $self->${ $self->fatal_errors ? \'log_fatal' : $self->quiet ? \'log_debug' : \'log'}
  10 100       1339  
178             ([ 'command exited with status %s (%s)', $status, $? ]);
179             }
180             else {
181 39         1521 $self->log_debug('command executed successfully');
182             }
183             }
184              
185             sub _eval_cmd {
186 20     20   129 my ( $self, $code, $params, $dry_run ) = @_;
187              
188 20 100       103 if ($dry_run) {
189 1         9 $self->log_debug([ 'dry run, would evaluate: %s', $code ]);
190 1         315 return;
191             }
192              
193 19         115 $code = $self->build_formatter($params)->format($code);
194 19 100       4296 $self->${ $self->quiet ? \'log_debug' : \'log' }([ 'evaluating: %s', $code ]);
  19         905  
195              
196 19         6814 my $sub = __eval_wrapper($code);
197 19         102 $sub->($self);
198 19         2978 my $error = $@;
199              
200 19 100 66     601 if (defined $error and $error ne '') {
201 8 100 100     376 if ($self->fatal_errors and $self->quiet and not $self->zilla->logger->get_debug) {
      66        
202 1         216 $self->log([ 'evaluated: %s', $code]);
203             }
204              
205 8 100       534 $self->${ $self->fatal_errors ? \'log_fatal' : $self->quiet ? \'log_debug' : \'log'}
  8 100       305  
206             ([ 'evaluation died: %s', $error ]);
207             }
208             }
209              
210             sub __eval_wrapper {
211 19     19   62 my $code = shift;
212 19     19   237 sub { eval $code };
  19     1   2398  
  1         8  
  1         9  
  1         225  
213             }
214              
215             around mvp_multivalue_args => sub {
216             my ($original, $self) = @_;
217              
218             my @res = $self->$original();
219              
220             push @res, qw( run run_no_trial run_if_trial run_if_release run_no_release eval );
221              
222             @res;
223             };
224              
225             my $path_separator = (File::Spec->catfile(qw(a b)) =~ m/^a(.+?)b$/)[0];
226              
227             sub build_formatter {
228 70     70 0 84505 my ( $self, $params ) = @_;
229              
230 70         7215 require String::Formatter;
231 70         40820 String::Formatter->VERSION(0.102082);
232              
233             my $codes = {
234             # not always available
235             # explicitly pass a string (not an object) [rt-72008]
236             a => sub {
237 26 100   26   2298 return "$params->{archive}" if defined $params->{archive};
238 12         174 $self->log('attempting to use %a in a non-Release plugin');
239 12         3987 '';
240             },
241              
242             # source dir
243             o => sub {
244 64   66 64   7432 my $dir = $params->{source_dir} || $self->zilla->root;
245 64 50       3717 return $dir ? "$dir" : '';
246             },
247              
248             # build dir or mint dir
249             d => sub {
250 36     36   2161 require Path::Tiny;
251             # stringify build directory
252 36   100     1032 my $dir = $params->{dir} || $self->zilla->built_in;
253 36 100       1746 return Path::Tiny::path($dir)->canonpath if $dir;
254 4         58 $self->log('attempting to use %d in before_build');
255 4         2083 '';
256             },
257              
258             # distribution name
259 30     30   2297 n => sub { $self->zilla->name },
260              
261             # backward compatibility (don't error)
262             s => '',
263              
264             # portability
265             p => $path_separator,
266 58     58   19592 x => sub { $self->perlpath },
267 70         3613 };
268              
269             # available during build, not mint
270 70 100       602 unless( $params->{minting} ){
271 68     33   967 $codes->{v} = sub { $self->zilla->version };
  33         6817  
272 68 100   18   808 $codes->{t} = sub { $self->_is_trial ? '-TRIAL' : '' };
  18         4962  
273             }
274              
275             # positional replacement of %s (backward compatible)
276 70 100       252 if( my @pos = @{ $params->{pos} || [] } ){
  70 100       766  
277             # where are you defined-or // operator?
278             $codes->{s} = sub {
279 41     41   2834 my $s = shift(@pos);
280 41 100       241 $s = $s->() if ref $s eq 'CODE';
281 41 100       7972 defined($s) ? $s : '';
282 61         633 };
283             }
284              
285 70         1033 return String::Formatter->new({ codes => $codes });
286             }
287              
288 37     37 0 4520 sub current_perl_path { $^X }
289              
290             1;