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   6531320 use strict;
  26         249  
  26         746  
2 26     26   136 use warnings;
  26         52  
  26         1561  
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.057';
8              
9 26     26   8554 use Dist::Zilla::App -command;
  26         388878  
  26         313  
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 436579 [ '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 1265487 my ($self, $zilla, $all) = @_;
25              
26 28         78 my $dzil7 = eval { Dist::Zilla::App->VERSION('7.000') };
  28         933  
27              
28             my @plugins = grep $_->isa('Dist::Zilla::Plugin::PromptIfStale'),
29 28 50       217 $dzil7 ? $zilla->plugins : @{ $zilla->plugins };
  28         976  
30              
31 28 100       844 if (not @plugins)
32             {
33 3         22 require Dist::Zilla::Plugin::PromptIfStale;
34 3         94 push @plugins,
35             Dist::Zilla::Plugin::PromptIfStale->new(zilla => $zilla, plugin_name => 'stale_command');
36             }
37              
38 28         74 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   150 if ($all or do { require List::Util; List::Util->VERSION('1.33'); List::Util::any(sub { $_->check_all_prereqs }, @plugins) })
  26         201  
  26         583  
  26         242  
  27         1046  
43             {
44 9 50       42 $_->before_build for grep !$_->isa('Dist::Zilla::Plugin::PromptIfStale'),
45 9         77 $dzil7 ? $zilla->plugins_with(-BeforeBuild) : @{ $zilla->plugins_with(-BeforeBuild) };
46 8 50       7301 $_->gather_files for $dzil7 ? $zilla->plugins_with(-FileGatherer) : @{ $zilla->plugins_with(-FileGatherer) };
  8         38  
47 8 50       45555 $_->set_file_encodings for $dzil7 ? $zilla->plugins_with(-EncodingProvider) : @{ $zilla->plugins_with(-EncodingProvider) };
  8         46  
48 8 50       5080 $_->prune_files for $dzil7 ? $zilla->plugins_with(-FilePruner) : @{ $zilla->plugins_with(-FilePruner) };
  8         35  
49 8 50       4870 $_->munge_files for $dzil7 ? $zilla->plugins_with(-FileMunger) : @{ $zilla->plugins_with(-FileMunger) };
  8         35  
50 8 50       4826 $_->register_prereqs for $dzil7 ? $zilla->plugins_with(-PrereqSource) : @{ $zilla->plugins_with(-PrereqSource) };
  8         39  
51              
52 8 100 100     20187 push @modules, map
53             $all || $_->check_all_prereqs ? $_->_modules_prereq : (),
54             @plugins;
55             }
56              
57 27         156 foreach my $plugin (@plugins)
58             {
59 29 100 100     1240 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       160 return if not @modules;
66              
67 24         160 require List::Util; List::Util->VERSION(1.45);
  24         452  
68 24         316 my ($stale_modules, undef) = $plugins[0]->stale_modules(List::Util::uniq(@modules));
69 24         469 return @$stale_modules;
70             }
71              
72             sub execute
73             {
74 10     10 1 7201 my ($self, $opt) = @_; # $arg
75              
76 10 50       58 $self->app->chrome->logger->mute unless $self->app->global_options->verbose;
77              
78 10         383140 require Try::Tiny;
79             my $zilla = Try::Tiny::try {
80             # parse dist.ini and load, instantiate all plugins
81 10     10   641 $self->zilla;
82             }
83             Try::Tiny::catch {
84 6     6   2580739 my @authordeps;
85              
86             # a plugin or bundle tried to loads another module that isn't installed
87 6 100 66     84 if (/^Can't locate (\S+) .+ at \S+ line/
    100          
88             or /^Compilation failed in require at (\S+) line/)
89             {
90 2   33     13 my $module = $1 || $2;
91 2         8 $module =~ s{/}{::}g;
92 2         10 $module =~ s{\.pm$}{};
93 2         6 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       29 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     27 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     44 push @authordeps, $self->_missing_authordeps($opt->root // '.');
112              
113 6         23894 $self->app->chrome->logger->unmute;
114 6         535 $self->log(join("\n", sort(List::Util::uniq(@authordeps))));
115              
116 6 50       2864 if (@authordeps)
117             {
118 6         47 require Term::ANSIColor;
119 6         130 Term::ANSIColor->VERSION('3.00');
120 6         56 print STDERR Term::ANSIColor::colored("Some authordeps were missing. Run the stale command again to check for regular dependencies.\n", 'bright_yellow');
121 6         587 exit 1;
122             }
123              
124 0         0 undef; # ensure $zilla = undef
125 10         132 };
126              
127 4 50       3002361 exit 2 if not $zilla;
128              
129 4         12 my $error;
130             my @stale_modules = Try::Tiny::try {
131 4     4   189 $self->stale_modules($zilla, $opt->all);
132             }
133             Try::Tiny::catch {
134 1     1   16 $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     5 $self->_missing_authordeps($opt->root // '.');
139 4         39 };
140              
141 4         4501 $self->app->chrome->logger->unmute;
142 4         283 $self->log(join("\n", @stale_modules)); # this might be just a blank line
143 4 50 66     1835 $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   152 my ($self, $root) = @_;
150              
151 7         2110 require Dist::Zilla::Util::AuthorDeps;
152 7         4461 Dist::Zilla::Util::AuthorDeps->VERSION(5.021);
153             my @authordeps = map +(%$_)[0],
154 7         30 @{ Dist::Zilla::Util::AuthorDeps::extract_author_deps(
  7         34  
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.057
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.freenode.org>.
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