File Coverage

blib/lib/Dist/Zilla/App/Command/dumpphases.pm
Criterion Covered Total %
statement 83 86 96.5
branch 9 12 75.0
condition 6 7 85.7
subroutine 13 14 92.8
pod n/a
total 111 119 93.2


line stmt bran cond sub pod time code
1 6     6   93909 use 5.006;
  6         15  
2 6     6   22 use strict;
  6         6  
  6         97  
3 6     6   24 use warnings;
  6         8  
  6         315  
4              
5             package Dist::Zilla::App::Command::dumpphases;
6              
7             our $VERSION = '1.000008';
8              
9             # ABSTRACT: Dump a textual representation of each phase's parts.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13              
14              
15              
16              
17              
18              
19              
20              
21              
22              
23              
24              
25 6     6   410 use Dist::Zilla::App '-command';
  6         491038  
  6         49  
26 6     6   11774 use Try::Tiny qw( try catch );
  6         8  
  6         402  
27 6     6   23 use Scalar::Util qw( blessed );
  6         7  
  6         4191  
28              
29             ## no critic ( ProhibitAmbiguousNames)
30 0     0   0 sub abstract { return 'Dump a textual representation of each phase\'s parts' }
31             ## use critic
32              
33              
34              
35              
36              
37              
38              
39              
40              
41              
42              
43              
44              
45              
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63             sub opt_spec {
64 5     5   224183 return [ 'color-theme=s', 'color theme to use, ( eg: basic::blue )' ];
65             }
66              
67             sub validate_args {
68 5     5   2069 my ( $self, $opt, undef ) = @_;
69             try {
70 5   100 5   141 $self->_load_color_theme( $opt->color_theme || 'basic::blue' );
71             }
72             catch {
73 1     1   256 my $error = shift;
74 1         4 require Carp;
75 1         9 my $message = $error . qq[\n\n];
76 1         3 $message .= sprintf "^ Was seen attempting to load theme <%s>\n", $opt->color_theme;
77 1         9 $message .= sprintf 'available themes are: %s', ( join q{, }, $self->_available_themes );
78 1         209 Carp::croak($message);
79 5         39 };
80 4         88 return;
81             }
82              
83             sub _available_themes {
84 1     1   2 my (undef) = @_;
85 1         405 require Path::ScanINC;
86 1         4378 my (@theme_dirs) = Path::ScanINC->new()->all_dirs( 'Dist', 'Zilla', 'dumpphases', 'Theme' );
87 1 50       643 if ( not @theme_dirs ) {
88 0         0 require Carp;
89             ## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars)
90 0         0 Carp::cluck('Found no theme dirs in @INC matching Dist/Zilla/dumpphases/Theme/');
91             }
92 1         11 my (%themes);
93 1         5 require Path::Tiny;
94 1         2 for my $dir (@theme_dirs) {
95 3         53 my $it = Path::Tiny->new($dir)->iterator(
96             {
97             recurse => 1,
98             follow_symlinks => 0,
99             },
100             );
101 3         94 while ( my $item = $it->() ) {
102 15 100       1134 next unless $item =~ /[.]pm\z/msx;
103 12 50       73 next if -d $item;
104 12         216 my $theme_name = $item->relative($dir);
105 12         1250 $theme_name =~ s{[.]pm\z}{}msx;
106 12         79 $theme_name =~ s{/}{::}msxg;
107 12         32 $themes{$theme_name} = 1;
108             }
109             }
110             ## no critic (Variables::ProhibitUnusedVarsStricter)
111 1         36 return ( my (@list) = sort keys %themes );
112             }
113              
114             sub _load_color_theme {
115 9     9   86 my ( undef, $color_theme ) = @_;
116 9         55 require Module::Runtime;
117 9         34 my $theme_module = Module::Runtime::compose_module_name( 'Dist::Zilla::dumpphases::Theme', $color_theme );
118 9         543 Module::Runtime::require_module($theme_module);
119 8         77 return $theme_module;
120             }
121              
122             sub execute {
123 4     4   23 my ( $self, $opt, undef ) = @_;
124              
125 4   100     18 my $theme_module = $self->_load_color_theme( $opt->color_theme || 'basic::blue' );
126 4         18 my $theme = $theme_module->new();
127              
128 4         62 my $seen_plugins = {};
129              
130 4         1639 require Dist::Zilla::Util::RoleDB;
131 4         1213222 my $zilla;
132 4         144 for my $phase ( Dist::Zilla::Util::RoleDB->new()->phases ) {
133 96         215108 my ($label);
134 96         2431 $label = $phase->name;
135 96         520 $label =~ s/\A-//msx;
136 96         423 $label =~ s/([[:lower:]])([[:upper:]])/$1 $2/gmsx;
137              
138 96         86 my @plugins;
139 96   66     236 $zilla ||= $self->zilla;
140 96         4712544 push @plugins, @{ $zilla->plugins_with( $phase->name ) };
  96         2102  
141 96 100       23900 next unless @plugins;
142              
143 4         28 $theme->print_section_header( 'Phase: ', $label );
144 4         490 $theme->print_section_prelude( 'description: ', $phase->description );
145 4         121738 $theme->print_section_prelude( 'role: ', $phase->name );
146 4         256 $theme->print_section_prelude( 'phase_method: ', $phase->phase_method );
147              
148 4         96 for my $plugin (@plugins) {
149 4         138 $seen_plugins->{ $plugin->plugin_name } = 1;
150 4         112 $theme->print_star_assoc( $plugin->plugin_name, blessed($plugin) );
151             }
152             }
153 4         127 my @unrecognised;
154 4         41 for my $plugin ( @{ $zilla->plugins } ) {
  4         77  
155 44 100       966 next if exists $seen_plugins->{ $plugin->plugin_name };
156 40         161 push @unrecognised, $plugin;
157             }
158 4 50       15 if (@unrecognised) {
159 4         15 $theme->print_section_header( 'Unrecognised: ', 'Phase not known' );
160 4         112 $theme->print_section_prelude( 'description: ', 'These plugins exist but were not in any predefined phase to scan for' );
161 4         91 for my $plugin (@unrecognised) {
162 40         1817 $theme->print_star_assoc( $plugin->plugin_name, blessed($plugin) );
163             }
164             }
165 4         263 return 0;
166             }
167              
168             1;
169              
170             __END__
171              
172             =pod
173              
174             =encoding UTF-8
175              
176             =head1 NAME
177              
178             Dist::Zilla::App::Command::dumpphases - Dump a textual representation of each phase's parts.
179              
180             =head1 VERSION
181              
182             version 1.000008
183              
184             =head1 SYNOPSIS
185              
186             cd $PROJECT;
187             dzil dumpphases
188              
189             dzil dumpphases --color-theme=basic::plain # plain text
190             dzil dumpphases --color-theme=basic::green # green text
191              
192             If you are using an HTML-enabled POD viewer, you should see a screenshot of this in action:
193              
194             ( Everyone else can visit L<http://kentnl.github.io/screenshots/Dist-Zilla-App-Command-dumpphases/example_01.png> )
195              
196             =begin MetaPOD::JSON v1.1.0
197              
198             {
199             "namespace":"Dist::Zilla::App::Command::dumpphases",
200             "inherits":"Dist::Zilla::App::Command",
201             "interface":"class"
202             }
203              
204              
205             =end MetaPOD::JSON
206              
207             =for html <center>
208             <img src="http://kentnl.github.io/screenshots/Dist-Zilla-App-Command-dumpphases/example_01.png"
209             alt="Screenshot"
210             width="721"
211             height="1007" />
212             </center>
213              
214             =head1 SEE ALSO
215              
216             =over 4
217              
218             =item * L<<
219             C<Dist::Zilla::Plugin::ReportPhase>|Dist::Zilla::Plugin::ReportPhase
220             >>
221              
222             Will report what phases are triggering as they happen.
223              
224             =back
225              
226             =head1 DESCRIPTION
227              
228             Working out what Plugins will execute in which order during which phase can be a
229             little confusing sometimes.
230              
231             This Command exists primarily to make developing Plugin Bundles and debugging
232             dist.ini a bit easier, especially for newbies who may not fully understand
233             Bundles yet.
234              
235             If you want to turn colors off, use L<< C<Term::ANSIcolor>'s environment variable|Term::ANSIColor >>
236             C<ANSI_COLORS_DISABLED>. E.g:
237              
238             ANSI_COLORS_DISABLED=1 dzil dumpphases
239              
240             Alternatively, since 0.3.0 you can specify a color-free theme:
241              
242             dzil dumpphases --color-theme=basic::plain
243              
244             =head1 TERMINOLOGY
245              
246             Technically speaking, this utility deals with more than just "phases", it will in fact dump all plugins used,
247             and it will in the process of doing so, dump things that are part of the clearly defined "phases" that occur
248             within C<Dist::Zilla>.
249              
250             However, if you want to be pedantic, and understand how L<< C<Dist::Zilla>|Dist::Zilla >> works, then you must understand,
251             many of the things this module calls "phases" are not so much phases.
252              
253             At its core, C<Dist::Zilla> has an array, on which all L<< C<Plugin>s|Dist::Zilla::Role::Plugin >> are stored.
254              
255             A C<Plugin>, in itself, will not do very much ( at least, not unless they do instantiation-time changes like
256             L<< C<[Bootstrap::lib]>|Dist::Zilla::Plugin::Bootstrap::lib >> )
257              
258             There are 3 Primary kinds of plugin
259              
260             =over 4
261              
262             =item * Auxiliary Plugins
263              
264             Plugins which exist to augment other plugins ( For instance, L<< C<-FileFinder>'s|Dist::Zilla::Role::FileFinder >> ).
265              
266             C<Dist::Zilla> itself essentially ignores these, and their consumption is entirely regulated by other C<plugin>s.
267              
268             =item * Phase Plugins
269              
270             Plugins which hook into a specific and determinate phase of the C<Dist::Zilla> build/test/release cycle.
271              
272             These all provide primary methods, which C<Dist::Zilla> directly calls somewhere in its core code base.
273              
274             Good examples of Phase plugins perform L<< C<-FileGatherer>|Dist::Zilla::Role::FileGatherer >>
275              
276             =item * A Third Kind
277              
278             There's a third kind of Plugin, which is somewhere between the other two, which I presently lack a name for.
279              
280             Like the Phases, they provide primary methods, which are called by C<Dist::Zilla> directly, and they provide
281             information for infrastructural components of the C<Dist::Zilla> development process.
282              
283             However, they're not strictly "phases", because exactly when they will be called ( or if they will be called at all )
284             is heavily dependent on usage.
285              
286             For instance, L<< C<-VersionProvider>|Dist::Zilla::Role::VersionProvider >>, which is dependent on a few variables,
287             and is called only when its needed, the first time its needed.
288              
289             Which means it could occur as early as creating C<META.json> or it could occur as late as just before it writes the distribution
290             out to disk.
291              
292             =back
293              
294             This C<App::Command> command will indeed list all of the above, but for the sake of ease of use, the "Third kind" is informally
295             under the umbrella of a "phase".
296              
297             =head1 METHODS
298              
299             =head2 C<opt_spec>
300              
301             This command takes one optional parameter
302              
303             =over 4
304              
305             =item * C<color-theme>
306              
307             dzil dumpphases --color-theme=<THEME>
308              
309             The name of a color theme to use.
310              
311             Existing themes are:
312              
313             =over 4
314              
315             =item * C<basic::blue>
316              
317             =item * C<basic::green>
318              
319             =item * C<basic::red>
320              
321             =item * C<basic::plain>
322              
323             =back
324              
325             =back
326              
327             =head1 AUTHOR
328              
329             Kent Fredric <kentnl@cpan.org>
330              
331             =head1 COPYRIGHT AND LICENSE
332              
333             This software is copyright (c) 2016 by Kent Fredric <kentnl@cpan.org>.
334              
335             This is free software; you can redistribute it and/or modify it under
336             the same terms as the Perl 5 programming language system itself.
337              
338             =cut