File Coverage

blib/lib/Dist/Zilla/App/Command/stale.pm
Criterion Covered Total %
statement 80 82 97.5
branch 30 42 71.4
condition 21 28 75.0
subroutine 12 13 92.3
pod 3 4 75.0
total 146 169 86.3


line stmt bran cond sub pod time code
1 26     26   7729763 use strict;
  26         312  
  26         775  
2 26     26   208 use warnings;
  26         99  
  26         1691  
3             package Dist::Zilla::App::Command::stale;
4             # vim: set ts=8 sts=2 sw=2 tw=115 et :
5             # ABSTRACT: print your distribution's prerequisites and plugins that are out of date
6              
7             our $VERSION = '0.058';
8              
9 26     26   9886 use Dist::Zilla::App -command;
  26         474743  
  26         218  
10              
11 0     0 1 0 sub abstract { "print your distribution's stale prerequisites and plugins" }
12              
13             sub opt_spec
14             {
15 10     10 1 580532 [ 'root=s' => 'the root of the distribution; defaults to .' ],
16             [ 'all' , 'check all plugins and prerequisites, regardless of plugin configuration' ]
17             # TODO?
18             # [ 'plugins', 'check all plugins' ],
19             # [ 'prereqs', 'check all prerequisites' ],
20             }
21              
22             sub stale_modules
23             {
24 28     28 0 1426126 my ($self, $zilla, $all) = @_;
25              
26 28         100 my $dzil7 = eval { Dist::Zilla::App->VERSION('7.000') };
  28         966  
27              
28             my @plugins = grep $_->isa('Dist::Zilla::Plugin::PromptIfStale'),
29 28 50       240 $dzil7 ? $zilla->plugins : @{ $zilla->plugins };
  28         1118  
30              
31 28 100       1071 if (not @plugins)
32             {
33 3         27 require Dist::Zilla::Plugin::PromptIfStale;
34 3         134 push @plugins,
35             Dist::Zilla::Plugin::PromptIfStale->new(zilla => $zilla, plugin_name => 'stale_command');
36             }
37              
38 28         94 my @modules;
39              
40             # ugh, we need to do nearly a full build to get the prereqs
41             # (this really should be abstracted better in Dist::Zilla::Dist::Builder)
42 28 100 100 27   177 if ($all or do { require List::Util; List::Util->VERSION('1.33'); List::Util::any(sub { $_->check_all_prereqs }, @plugins) })
  26         241  
  26         435  
  26         311  
  27         1253  
43             {
44 9 50       47 $_->before_build for grep !$_->isa('Dist::Zilla::Plugin::PromptIfStale'),
45 9         98 $dzil7 ? $zilla->plugins_with(-BeforeBuild) : @{ $zilla->plugins_with(-BeforeBuild) };
46 8 50       8507 $_->gather_files for $dzil7 ? $zilla->plugins_with(-FileGatherer) : @{ $zilla->plugins_with(-FileGatherer) };
  8         52  
47 8 50       57395 $_->set_file_encodings for $dzil7 ? $zilla->plugins_with(-EncodingProvider) : @{ $zilla->plugins_with(-EncodingProvider) };
  8         69  
48 8 50       5921 $_->prune_files for $dzil7 ? $zilla->plugins_with(-FilePruner) : @{ $zilla->plugins_with(-FilePruner) };
  8         58  
49 8 50       5846 $_->munge_files for $dzil7 ? $zilla->plugins_with(-FileMunger) : @{ $zilla->plugins_with(-FileMunger) };
  8         43  
50 8 50       5707 $_->register_prereqs for $dzil7 ? $zilla->plugins_with(-PrereqSource) : @{ $zilla->plugins_with(-PrereqSource) };
  8         55  
51              
52 8 100 100     24614 push @modules, map
53             $all || $_->check_all_prereqs ? $_->_modules_prereq : (),
54             @plugins;
55             }
56              
57 27         186 foreach my $plugin (@plugins)
58             {
59 29 100 100     1439 push @modules,
    100 100        
60             ( $all || $plugin->check_authordeps ? $plugin->_authordeps : () ),
61             $plugin->_modules_extra,
62             ( $all || $plugin->check_all_plugins ? $plugin->_modules_plugin : () );
63             }
64              
65 27 100       229 return if not @modules;
66              
67 24         177 require List::Util; List::Util->VERSION(1.45);
  24         584  
68 24         412 my ($stale_modules, undef) = $plugins[0]->stale_modules(List::Util::uniq(@modules));
69 24         888 return @$stale_modules;
70             }
71              
72             sub execute
73             {
74 10     10 1 8225 my ($self, $opt) = @_; # $arg
75              
76 10 50       66 $self->app->chrome->logger->mute unless $self->app->global_options->verbose;
77              
78 10         481808 require Try::Tiny;
79             my $zilla = Try::Tiny::try {
80             # parse dist.ini and load, instantiate all plugins
81 10     10   652 $self->zilla;
82             }
83             Try::Tiny::catch {
84 6     6   3163383 my @authordeps;
85              
86             # a plugin or bundle tried to loads another module that isn't installed
87 6 100 66     98 if (/^Can't locate (\S+) .+ at \S+ line/
    100          
88             or /^Compilation failed in require at (\S+) line/)
89             {
90 2   33     11 my $module = $1 || $2;
91 2         8 $module =~ s{/}{::}g;
92 2         13 $module =~ s{\.pm$}{};
93 2         7 push @authordeps, $module;
94             }
95             # ...or at the wrong version
96             elsif (/^(\S+) version \S+ required--this is only version \S+ at \S+ line/)
97             {
98 1         5 push @authordeps, $1;
99             }
100             else
101             {
102             # a plugin was referenced in dist.ini or a bundle
103 3 100       36 push @authordeps, $1 if /Required plugin(?: bundle)? \[?(\S+)\]? isn't installed\./;
104              
105             # some plugins are not installed; need to run authordeps --missing
106 3 50 66     46 die $_ unless
107             m/Run 'dzil authordeps' to see a list of all required plugins/m
108             or m/ version \(.+\) (does )?not match required version: /m;
109             }
110              
111 6   50     48 push @authordeps, $self->_missing_authordeps($opt->root // '.');
112              
113 6         23181 $self->app->chrome->logger->unmute;
114 6         547 $self->log(join("\n", sort(List::Util::uniq(@authordeps))));
115              
116 6 50       2910 if (@authordeps)
117             {
118 6         47 require Term::ANSIColor;
119 6         126 Term::ANSIColor->VERSION('3.00');
120 6         75 print STDERR Term::ANSIColor::colored("Some authordeps were missing. Run the stale command again to check for regular dependencies.\n", 'bright_yellow');
121 6         1013 exit 1;
122             }
123              
124 0         0 undef; # ensure $zilla = undef
125 10         126 };
126              
127 4 50       3733444 exit 2 if not $zilla;
128              
129 4         15 my $error;
130             my @stale_modules = Try::Tiny::try {
131 4     4   256 $self->stale_modules($zilla, $opt->all);
132             }
133             Try::Tiny::catch {
134 1     1   27 $error = $_;
135              
136             # if there was an error during the build, fall back to fetching
137             # authordeps, in the hopes that we can report something helpful
138 1   50     6 $self->_missing_authordeps($opt->root // '.');
139 4         53 };
140              
141 4         5112 $self->app->chrome->logger->unmute;
142 4         352 $self->log(join("\n", @stale_modules)); # this might be just a blank line
143 4 50 66     3191 $self->log([ 'got error from stale_modules check: %s', $error ]) if $error and not @stale_modules;
144             }
145              
146             # as in Dist::Zilla::App::Command::alldeps
147             sub _missing_authordeps
148             {
149 7     7   162 my ($self, $root) = @_;
150              
151 7         2141 require Dist::Zilla::Util::AuthorDeps;
152 7         9198 Dist::Zilla::Util::AuthorDeps->VERSION(5.021);
153             my @authordeps = map +(%$_)[0],
154 7         39 @{ Dist::Zilla::Util::AuthorDeps::extract_author_deps(
  7         43  
155             $root, # repository root
156             1, # --missing
157             )
158             };
159             }
160              
161             1;
162              
163             __END__
164              
165             =pod
166              
167             =encoding UTF-8
168              
169             =head1 NAME
170              
171             Dist::Zilla::App::Command::stale - print your distribution's prerequisites and plugins that are out of date
172              
173             =head1 VERSION
174              
175             version 0.058
176              
177             =head1 SYNOPSIS
178              
179             $ dzil stale --all | cpanm
180              
181             =head1 DESCRIPTION
182              
183             This is a command plugin for L<Dist::Zilla>. It provides the C<stale> command,
184             which acts as L<[PromptIfStale]|Dist::Zilla::Plugin::PromptIfStale> would
185             during the build: compares the locally-installed version of a module(s) with
186             the latest indexed version, and print all modules that are thus found to be
187             stale. You could pipe that list to a CPAN client like L<cpanm> to update all
188             of the modules in one quick go.
189              
190             When a L<[PromptIfStale]|Dist::Zilla::Plugin::PromptIfStale> configuration is
191             present in F<dist.ini>, its configuration is honoured (unless C<--all> is
192             used); if there is no such configuration, behaviour is as for C<--all>.
193              
194             =for stopwords thusly
195              
196             If not everything can be installed in one pass (typically, if a plugin used by
197             F<dist.ini> is missing), a message will be printed to C<STDERR> and the exit
198             code will be 1. This allows you to chain commands thusly:
199              
200             dzil stale --all | cpanm && dzil build && dzil test --release
201              
202             =head1 OPTIONS
203              
204             =head2 --all
205              
206             Checks all plugins and prerequisites (as well as any additional modules listed
207             in a local L<[PromptIfStale]|Dist::Zilla::Plugin::PromptIfStale>
208             configuration, if there is one).
209              
210             I have a shell alias: C<alias unstale="dzil stale --all | cpanm"> which I use
211             quite regularly! You should do this too.
212              
213             =for Pod::Coverage stale_modules
214              
215             =head1 SEE ALSO
216              
217             =over 4
218              
219             =item *
220              
221             L<Dist::Zilla::Plugin::PromptIfStale>
222              
223             =back
224              
225             =head1 SUPPORT
226              
227             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-PromptIfStale>
228             (or L<bug-Dist-Zilla-Plugin-PromptIfStale@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-PromptIfStale@rt.cpan.org>).
229              
230             There is also a mailing list available for users of this distribution, at
231             L<http://dzil.org/#mailing-list>.
232              
233             There is also an irc channel available for users of this distribution, at
234             L<C<#distzilla> on C<irc.perl.org>|irc://irc.perl.org/#distzilla>.
235              
236             I am also usually active on irc, as 'ether' at C<irc.perl.org> and C<irc.libera.chat>.
237              
238             =head1 AUTHOR
239              
240             Karen Etheridge <ether@cpan.org>
241              
242             =head1 COPYRIGHT AND LICENCE
243              
244             This software is copyright (c) 2013 by Karen Etheridge.
245              
246             This is free software; you can redistribute it and/or modify it under
247             the same terms as the Perl 5 programming language system itself.
248              
249             =cut