File Coverage

blib/lib/Dist/Zilla/Plugin/Manifest/Write.pm
Criterion Covered Total %
statement 160 171 93.5
branch 27 40 67.5
condition 8 13 61.5
subroutine 30 31 96.7
pod 3 3 100.0
total 228 258 88.3


line stmt bran cond sub pod time code
1             # ---------------------------------------------------------------------- copyright and license ---
2             #
3             # file: lib/Dist/Zilla/Plugin/Manifes/Write.pm
4             #
5             # Copyright © 2015, 2016 Van de Bugger.
6             #
7             # This file is part of perl-Dist-Zilla-Plugin-Manifest-Write.
8             #
9             # perl-Dist-Zilla-Plugin-Manifest-Write is free software: you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by the Free Software
11             # Foundation, either version 3 of the License, or (at your option) any later version.
12             #
13             # perl-Dist-Zilla-Plugin-Manifest-Write is distributed in the hope that it will be useful, but
14             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15             # PARTICULAR PURPOSE. See the GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License along with
18             # perl-Dist-Zilla-Plugin-Manifest-Write. If not, see <http://www.gnu.org/licenses/>.
19             #
20             # ---------------------------------------------------------------------- copyright and license ---
21              
22             #pod =for :this This is C<Dist::Zilla::Plugin::Manifest::Write> module documentation. Read this if you are going to hack or
23             #pod extend C<Manifest::Write>.
24             #pod
25             #pod =for :those If you want to have annotated distribution manifest, read the L<plugin user
26             #pod manual|Dist::Zilla::Plugin::Manifest::Write::Manual>. General topics like getting source, building, installing, bug
27             #pod reporting and some others are covered in the F<README>.
28             #pod
29             #pod =head1 DESCRIPTION
30             #pod
31             #pod In order to add a manifest file to the distribution, C<Dist::Zilla::Plugin::Manifest::Write> class consumes
32             #pod C<Dist::Zilla::Role::FileGatherer> role. To meet the role requirements, the class implements
33             #pod C<gather_files> method. Other methods are supporting helpers for this one.
34             #pod
35             #pod Most of attributes are initialized by builders for easier customization by subclassing. Code is
36             #pod also divided into small methods for the same purpose.
37             #pod
38             #pod =head1 SEE ALSO
39             #pod
40             #pod =for :list
41             #pod = L<Dist::Zilla>
42             #pod = L<Dist::Zilla::Role>
43             #pod = L<Dist::Zilla::Role::Plugin>
44             #pod = L<Dist::Zilla::Role::FileInjector>
45             #pod = L<Dist::Zilla::Role::FileGatherer>
46             #pod = L<Dist::Zilla::Plugin::Manifest>
47             #pod = L<Dist::Zilla::Plugin::Manifest::Write::Manual>
48             #pod
49             #pod =cut
50              
51             # --------------------------------------------------------------------------------------------------
52              
53             package Dist::Zilla::Plugin::Manifest::Write;
54              
55 2     2   2827571 use Moose; # Let `perlcritic` shut up: it complains on code (`$VERSION`) before `strict`.
  2         5  
  2         17  
56 2     2   14458 use namespace::autoclean;
  2         5  
  2         24  
57              
58             # PODNAME: Dist::Zilla::Plugin::Manifest::Write
59             # ABSTRACT: Have annotated distribution manifest
60             our $VERSION = 'v0.9.5_01'; # TRIAL VERSION
61              
62             with 'Dist::Zilla::Role::FileGatherer';
63             with 'Dist::Zilla::Role::BeforeBuild';
64             with 'Dist::Zilla::Role::BeforeArchive';
65             with 'Dist::Zilla::Role::ErrorLogger';
66             with 'Dist::Zilla::Role::FileFinderUser' => {
67             finder_arg_names => [ qw{ exclude_files } ],
68             default_finders => [ ':NoFiles' ],
69             };
70              
71 2     2   2034 use Dist::Zilla::File::FromCode;
  2         162793  
  2         136  
72 2     2   15 use List::Util;
  2         4  
  2         206  
73 2     2   2014 use Module::Util qw{ is_valid_module_name };
  2         4207  
  2         141  
74 2     2   1539 use Readonly;
  2         9304  
  2         196  
75 2     2   2092 use Set::Object qw{};
  2         18652  
  2         65  
76 2     2   17 use String::RewritePrefix;
  2         7  
  2         31  
77              
78 2     2   568 use Dist::Zilla::Role::File 5.023 (); # Hint for `AutoPrereqs`.
  2         66  
  2         6976  
79             # We do not consume the role but just require the specified version. Before this version
80             # `_added_by` was a `Str`, not `ArrayRef`.
81              
82             # --------------------------------------------------------------------------------------------------
83              
84             # File deeds:
85             Readonly our $SOURCE => 1;
86             Readonly our $META => 2;
87             Readonly our $OTHER => 3;
88             # File breeds:
89             Readonly our $ADDED => 4;
90             Readonly our $BUILT => 5;
91              
92             # --------------------------------------------------------------------------------------------------
93              
94             #pod =head1 FUNCTIONS
95             #pod
96             #pod I would expect to find these functions in C<Dist::Zilla>. Actually, C<Dist::Zilla::Util> defines
97             #pod the function C<expand_config_package_name>, but that function "is likely to change or go away" and
98             #pod there is no reverse transformation.
99             #pod
100             #pod =cut
101              
102             # --------------------------------------------------------------------------------------------------
103              
104             #pod =func __plugin_moniker
105             #pod
106             #pod $str = __plugin_moniker( 'Dist::Zilla::Plugin::Name' ); # 'Name'
107             #pod $str = __plugin_moniker( 'Non::Standard::Name' ); # '=Non::Standard::Name'
108             #pod $str = __plugin_moniker( $plugin );
109             #pod
110             #pod The function takes either reference to a plugin object or a string, package name, and returns
111             #pod C<Dist::Zilla> plugin moniker: If its package name begins with C<Dist::Zilla::Plugin::>, this
112             #pod common prefix is dropped, otherwise the package name prepended with C<=>.
113             #pod
114             #pod =cut
115              
116             {
117              
118             my $package2moniker = {
119             'Dist::Zilla::Plugin::' => '',
120             'Dist::Zilla::Role::' => '*',
121             '' => '=',
122             };
123              
124             sub __plugin_moniker($) { ## no critic ( ProhibitSubroutinePrototypes )
125 89     89   132 my ( $arg ) = @_;
126 89 50       345 if ( my $blessed = blessed( $arg ) ) {
127 89         111 $arg = $blessed;
128             };
129 89         398 return String::RewritePrefix->rewrite( $package2moniker, $arg );
130             };
131              
132             }
133              
134             # --------------------------------------------------------------------------------------------------
135              
136             #pod =func __package_name
137             #pod
138             #pod $str = __package_name( 'Name' ); # returns 'Dist::Zilla::Plugin::Name'
139             #pod $str = __package_name( '=Name' ); # returns 'Name'
140             #pod $str = __package_name( $plugin );
141             #pod
142             #pod This is operation opposite to C<__plugin_moniker>. It takes either reference to plugin object, or
143             #pod string, plugin moniker, and returns package name.
144             #pod
145             #pod This function is similar to C<expand_config_package_name> from C<Dist::Zilla::Util>, with minor
146             #pod difference: this function works with plugins only (not with plugin bundles and stashes), and
147             #pod accepts also reference to plugin object.
148             #pod
149             #pod =cut
150              
151             {
152              
153             my $moniker2package = {
154             '=' => '',
155             '' => 'Dist::Zilla::Plugin::',
156             };
157              
158             sub __package_name($) { ## no critic ( ProhibitSubroutinePrototypes )
159 0     0   0 my ( $arg ) = @_;
160 0 0       0 if ( my $blessed = blessed( $arg ) ) {
161 0         0 return $blessed;
162             };
163 0         0 return String::RewritePrefix->rewrite( $moniker2package, $arg );
164             };
165              
166             }
167              
168             # --------------------------------------------------------------------------------------------------
169              
170             #pod =Method BUILDARGS
171             #pod
172             #pod The method splits values of C<source_providers> option into separate plugin names using whitespaces
173             #pod as delimiters, combines result of splitting with C<source_provider> option values, then filters out
174             #pod empty values. Resulting C<ArrayRef> saved as C<source_providers> options.
175             #pod
176             #pod The same for C<metainfo_providers> and C<metainfo_provider> options.
177             #pod
178             #pod =cut
179              
180             around BUILDARGS => sub {
181             my ( $orig, $class, $args ) = @_;
182             for my $type ( qw{ source metainfo } ) {
183             my $provider = $type . '_provider';
184             my $providers = $type . '_providers';
185             if ( exists( $args->{ $provider } ) or exists( $args->{ $providers } ) ) {
186             $args->{ $providers } = [
187             grep( # Filter out empty values.
188             { $_ ne '' }
189             @{ $args->{ $provider } or [] }, # Get singular option values as-is.
190             map( { split( m{\s+}x, $_ ) } @{ $args->{ $providers } or [] } )
191             # Split plural option values.
192             )
193             ];
194             };
195             };
196             return $class->$orig( $args );
197             };
198              
199             # --------------------------------------------------------------------------------------------------
200              
201             #pod =attr manifest
202             #pod
203             #pod Name of manifest file to write.
204             #pod
205             #pod C<Str>, read-only. Default value is C<'MANIFEST'>.
206             #pod
207             #pod =cut
208              
209             has manifest => (
210             isa => 'Str',
211             is => 'ro',
212             default => 'MANIFEST',
213             );
214              
215             # --------------------------------------------------------------------------------------------------
216              
217             #pod =attr source_providers
218             #pod
219             #pod List of plugin names. Enlisted plugins are considered as source file providers. A file added to
220             #pod distribution by any of these plugins is considered as source file.
221             #pod
222             #pod C<ArrayRef[Str]>, read-only, default value is empty array. Init argument (and config file
223             #pod multi-value option) name is C<source_provider>. (C<BUILDARGS> also handles C<source_providers>
224             #pod option.)
225             #pod
226             #pod =cut
227              
228             has source_providers => (
229             isa => 'ArrayRef[Str]',
230             is => 'ro',
231             required => 1,
232             lazy => 1,
233             builder => '_build_source_providers',
234             );
235              
236             sub _build_source_providers {
237 2     2   110 return [];
238             };
239              
240             # --------------------------------------------------------------------------------------------------
241              
242             #pod =attr metainfo_providers
243             #pod
244             #pod Like C<source_providers> but enlists meta info file providers.
245             #pod
246             #pod C<ArrayRef[Str]>, read-only, default value is C<CPANFile>, C<Manifest>, C<MetaYAML>, C<MetaJSON>,
247             #pod and the plugin itself. Init argument (and config file multi-value option) name is
248             #pod C<metainfo_provider>. (C<BUILDARGS> also handles C<metainfo_providers> option.)
249             #pod
250             #pod Note: Do not confuse C<Manifest::Write>'s term I<metainfo providers> with C<Dist::Zilla>'s
251             #pod C<MetaProvider> role. Plugins do C<MetaProvider> role provide I<metadata>, while C<Manifest::Write>
252             #pod is interested in plugins which adds I<files> containing metadata to the distribution (such plugins
253             #pod do C<FileInjector> role, not C<MetaProvider>).
254             #pod
255             #pod =cut
256              
257             has metainfo_providers => (
258             isa => 'ArrayRef[Str]',
259             is => 'ro',
260             required => 1,
261             lazy => 1,
262             builder => '_build_metainfo_providers',
263             );
264              
265             sub _build_metainfo_providers {
266 14     14   29 my ( $self ) = @_;
267 14         512 my @list = ( qw{ CPANFile Manifest MetaYAML MetaJSON }, $self->plugin_name );
268 14 50       681 if ( $self->strict >= 0 ) {
269 14         48 @list = grep( { $self->_is_injector( $_ ) } @list );
  70         654  
270             };
271 14         1327 return \@list;
272             };
273              
274             sub _is_injector {
275 70     70   95 my ( $self, $name ) = @_;
276 70         2072 my $plugin = $self->zilla->plugin_named( $name );
277 70   66     23416 return $plugin && $plugin->does( 'Dist::Zilla::Role::FileInjector' );
278             };
279              
280             # --------------------------------------------------------------------------------------------------
281              
282             #pod =attr strict
283             #pod
284             #pod Strictness of checking source and metainfo provider names: -1 (no checks), 0 (some mistakes are
285             #pod fatal, some are not), or 1 (all mistakes are fatal).
286             #pod
287             #pod C<Int>, read-only. Default is 1.
288             #pod
289             #pod See L<Dist::Zilla::Plugin::Manifest::Write::Manual/"strict">.
290             #pod
291             #pod =cut
292              
293             has strict => (
294             isa => 'Int',
295             is => 'ro',
296             default => 1,
297             );
298              
299             # --------------------------------------------------------------------------------------------------
300              
301             #pod =attr show_mungers
302             #pod
303             #pod If C<1>, file mungers will be included into annotation. By default mungers are not included.
304             #pod
305             #pod C<Bool>, read-only. Default is C<0>.
306             #pod
307             #pod =cut
308              
309             has show_mungers => (
310             isa => 'Bool',
311             is => 'ro',
312             default => 0,
313             );
314              
315             # --------------------------------------------------------------------------------------------------
316              
317             #pod =attr deeds
318             #pod
319             #pod This attribute maps internal file deed constants (C<SOURCE>, C<META>, C<OTHER>) to user-visible
320             #pod names used in manifest (project name, C<metainfo>, and C<3rd party> respectively).
321             #pod
322             #pod C<HashRef[Str]>, read-only.
323             #pod
324             #pod =cut
325              
326             has deeds => (
327             isa => 'HashRef[Str]',
328             is => 'ro',
329             lazy => 1,
330             builder => '_build_deeds',
331             init_arg => undef,
332             );
333              
334             sub _build_deeds {
335 17     17   37 my ( $self ) = @_;
336             return {
337 17         533 $SOURCE => $self->zilla->name,
338             $META => 'metainfo',
339             $OTHER => '3rd party',
340             };
341             };
342              
343             # --------------------------------------------------------------------------------------------------
344              
345             #pod =attr breeds
346             #pod
347             #pod This attribute maps internal file deed constants (C<$ADDED> and C<$BUILT>) to user-visible names
348             #pod used in manifest. By default user-visible breed names are the same as internal identifiers.
349             #pod
350             #pod C<HashRef[Str]>, read-only.
351             #pod
352             #pod =cut
353              
354             has breeds => (
355             isa => 'HashRef[Str]',
356             is => 'ro',
357             lazy => 1,
358             builder => '_build_breeds',
359             init_arg => undef,
360             );
361              
362             sub _build_breeds {
363 17     17   31 my ( $self ) = @_;
364             return {
365 17         88 $ADDED => 'added',
366             $BUILT => 'built',
367             };
368             };
369              
370             # --------------------------------------------------------------------------------------------------
371              
372             #pod =attr _providers
373             #pod
374             #pod This attribute maps provider names to file deeds. It makes C<_file_deed> method implementation
375             #pod simpler and faster.
376             #pod
377             #pod C<HashRef[Str]>, read-only, not an init arg.
378             #pod
379             #pod =cut
380              
381             has _providers => (
382             isa => 'HashRef[Int]',
383             is => 'ro',
384             required => 1,
385             lazy => 1,
386             builder => '_build_providers',
387             init_arg => undef,
388             );
389              
390             sub _build_providers {
391 18     18   32 my ( $self ) = @_;
392 18         40 my $providers = {};
393 18         28 for my $provider ( @{ $self->source_providers } ) {
  18         806  
394 26         210 $providers->{ $provider } = $SOURCE;
395             };
396 18         107 for my $provider ( @{ $self->metainfo_providers } ) {
  18         723  
397 30 100 66     185 if ( exists( $providers->{ $provider } ) and $providers->{ $provider } != $META ) {
398             # The same plugin name may be specified in the same option multiple times.
399 1         11 $self->log_error( [
400             "%s cannot be a source provider and a metainfo provider simultaneously",
401             $provider
402             ] );
403             } else {
404 29         130 $providers->{ $provider } = $META;
405             };
406             };
407 18         1028 return $providers;
408             };
409              
410             # --------------------------------------------------------------------------------------------------
411              
412             #pod =attr _dw
413             #pod
414             #pod Max length of user-visible deed names.
415             #pod
416             #pod C<Int>, read-only, not an init arg.
417             #pod
418             #pod =cut
419              
420             has _dw => (
421             isa => 'Int',
422             is => 'ro',
423             lazy => 1,
424             builder => '_build_dw',
425             init_arg => undef,
426             );
427              
428             sub _build_dw {
429 17     17   29 my ( $self ) = @_;
430 17         27 return List::Util::max( map( { length( $_ ) } values( %{ $self->deeds } ) ) );
  51         741  
  17         658  
431             };
432              
433             # --------------------------------------------------------------------------------------------------
434              
435             #pod =method before_build
436             #pod
437             #pod This method is called by C<Dist::Zilla> automatically before build. The method checks validity of
438             #pod source and metainfo provider names.
439             #pod
440             #pod =cut
441              
442             sub before_build {
443 18     18 1 1391116 my ( $self ) = @_;
444 18 100       860 if ( $self->strict >= 0 ) {
445 17 100       682 my $log_warning = $self->strict > 0 ? 'log_error' : 'log';
446 17         509 my $zilla = $self->zilla;
447 17         105 for my $provider ( @{ $self->source_providers }, @{ $self->metainfo_providers } ) {
  17         663  
  17         765  
448 53 100       3519 if ( my $plugin = $zilla->plugin_named( $provider ) ) {
449 49 100       5414 if ( not $plugin->does( 'Dist::Zilla::Role::FileInjector' ) ) {
450 1         36 $self->log_error( [ "%s does not do FileInjector role", $provider ] );
451             };
452             } else {
453 4         1621 $self->$log_warning( [ "%s is not a plugin", $provider ] );
454             };
455             };
456 17         1682 $self->_providers(); # Initiate building the attribute. It can report errors.
457 17         126 $self->abort_if_error();
458             };
459 17         742 return;
460             };
461              
462             # --------------------------------------------------------------------------------------------------
463              
464             #pod =method before_archive
465             #pod
466             #pod This method is called by C<Dist::Zilla> automatically before build the archive. The method prunes
467             #pod files found by file finders specified in the C<exclude_files> option.
468             #pod
469             #pod =cut
470              
471             sub before_archive {
472 2     2 1 35049 my ( $self ) = @_;
473 2         71 my $zilla = $self->zilla;
474 2         12 for my $file ( @{ $self->found_files } ) {
  2         12  
475 3         2448 $zilla->prune_file( $file );
476             };
477 2         176 return;
478             };
479              
480             # --------------------------------------------------------------------------------------------------
481              
482             #pod =method gather_files
483             #pod
484             #pod This is the main method of the class. It adds a file with name C<< $self->manifest >> to the
485             #pod distribution. File content is specified by C<CodeRef> to postpone actual file creation. Being
486             #pod evaluated, the code iterates through all the files in distribution in alphabetical order, and
487             #pod fulfills the manifest with filenames and comments.
488             #pod
489             #pod =cut
490              
491             sub gather_files {
492 17     17 1 155511 my ( $self, $arg ) = @_;
493 17         540 my $zilla = $self->zilla;
494             my $file = Dist::Zilla::File::FromCode->new( {
495             name => $self->manifest,
496             code_return_type => 'bytes',
497             code => sub {
498 17     17   749143 my @list;
499 17         34 my $files = Set::Object->new( @{ $zilla->files } );
  17         549  
500 17         476 $files->remove( @{ $self->found_files } );
  17         154  
501             # Process all files in alphbetical order.
502 17         14137 for my $file ( sort( { $a->name cmp $b->name } @{ $files } ) ) {
  132         10477  
  17         1171  
503 88         1406 push( @list, {
504             name => $self->_file_name( $file ),
505             comment => $self->_file_comment( $file )
506             } );
507             };
508 17         240 $self->abort_if_error(); # `_file_comment` methods may generate errors.
509             # Find width of filename column.
510 17         807 my $width = List::Util::max( map( { length( $_->{ name } ) } @list ) );
  88         143  
511             # Output formats.
512 17         59 my $head = "# This file was generated with %s %s\n";
513 17         28 my $body = "%*s # %s\n";
514             return
515             join(
516             '',
517             sprintf( $head, blessed( $self ), $self->VERSION ),
518 17         328 map( { sprintf( $body, - $width, $_->{ name }, $_->{ comment } ) } @list ),
  88         477  
519             );
520             },
521 17         856 } );
522 17         3441 $self->add_file( $file );
523 17         5886 return;
524             };
525              
526             # --------------------------------------------------------------------------------------------------
527              
528             #pod =method _file_name
529             #pod
530             #pod $str = $self->_file_name( $file );
531             #pod
532             #pod Returns filename to be used in manifest. If filename does not include special characters (spaces,
533             #pod backslashes (C<\>), apostrophes (C<'>), hashes (C<#>)), it is the same as real filename, otherwise
534             #pod filename encoded like Perl single-quoted string: backslashes and apostrophes are escaped, and
535             #pod entire filename is enclosed into apostrophes.
536             #pod
537             #pod =cut
538              
539             sub _file_name {
540 88     88   203 my ( $self, $file ) = @_;
541 88         264 my $name = $file->name;
542 88 100       3892 if ( $name =~ m{[\ '\\#]}x ) {
543 5         16 $name =~ s{([\\'])}{\\$1}gx;
544 5         11 $name = "'" . $name . "'";
545             };
546 88         239 return $name;
547             };
548              
549             # --------------------------------------------------------------------------------------------------
550              
551             #pod =method _file_comment
552             #pod
553             #pod $str = $self->_file_comment( $file ); # Without leading sharp.
554             #pod
555             #pod The method returns comment to be used with the specified file. Comment should not include leading
556             #pod sharp character (C<#>).
557             #pod
558             #pod =cut
559              
560             sub _file_comment {
561 88     88   142 my ( $self, $file ) = @_;
562 88         166 my $history = $self->_file_history( $file );
563 88         237 my $deed = $self->_file_deed( $file, $history );
564 88         183 my $breed = $self->_file_breed( $file, $history );
565 88         148 my $adder = $self->_file_adder( $file, $history );
566 88         272 my @mungers = $self->_file_mungers( $file, $history );
567             my $comment =
568             sprintf(
569             "%*s file %s by %s",
570             $self->_dw,
571             $self->deeds->{ $deed } || $deed || '(*UNKNOWN*)',
572 88 100 50     3287 $self->breeds->{ $breed } || $breed || '(*UNKNOWN*)',
      50        
573             $adder
574             ) .
575             (
576             @mungers ? (
577             ' and munged by ' . join( ', ', @mungers )
578             ) : (
579             ''
580             )
581             );
582 88         503 return $comment;
583             };
584              
585             # --------------------------------------------------------------------------------------------------
586              
587             #pod =method _file_history
588             #pod
589             #pod $arrayref = $self->_file_history( $file );
590             #pod
591             #pod The method calls C<_file_added_by> then does post-processing: all C<filename set> records are
592             #pod filtered out as insignificant and makes sure the log is not empty.
593             #pod
594             #pod =cut
595              
596             sub _file_history {
597 88     88   96 my ( $self, $file ) = @_;
598 88         156 my $added_by = $file->{ added_by };
599 88         159 my $history = $self->_file_added_by( $file );
600             # Filter out 'filename set' entries.
601 88         134 $history = [ grep( { $_->{ action } ne 'filename set' } @$history ) ];
  134         309  
602             # Just in case make sure history is not empty.
603 88 50       231 if ( not @$history ) {
604 0         0 $self->log_error( [ '%s file history is empty', $file->name ] );
605             };
606 88         123 return $history;
607             };
608              
609             # --------------------------------------------------------------------------------------------------
610              
611             #pod =method _file_added_by
612             #pod
613             #pod $arrayref = $self->_file_added_by( $file );
614             #pod
615             #pod The method parses file's C<added_by> log. Internally, C<added_by> log is a list of strings. Here
616             #pod are few examples:
617             #pod
618             #pod content added by COPYING (Dist::Zilla::Plugin::GenerateFile line 114)
619             #pod filename set by GatherFromManifest (Dist::Zilla::Plugin::GatherFromManifest line 125)
620             #pod encoded_content added by GatherFromManifest (Dist::Zilla::Plugin::GatherFromManifest line 126)
621             #pod text from coderef added by MetaJSON (Dist::Zilla::Plugin::MetaJSON line 83)
622             #pod content set by TemplateFiles (Dist::Zilla::Plugin::TemplateFiles line 35)
623             #pod content set by OurPkgVersion (Dist::Zilla::Plugin::OurPkgVersion line 82)
624             #pod content set by PodWeaver (Dist::Zilla::Plugin::PodWeaver line 175)
625             #pod
626             #pod Thus, each string in C<added_by> log follows the format:
627             #pod
628             #pod <action> by <name> (<package> line <number>)
629             #pod
630             #pod The method parses these strings and returns a more convenient for further processing form:
631             #pod
632             #pod [ { action => …, name => …, package => …, line => … }, { … }, … ]
633             #pod
634             #pod Do not call this method directly, use C<_file_history> instead.
635             #pod
636             #pod =cut
637              
638             sub _file_added_by {
639 88     88   85 my ( $self, $file ) = @_;
640 88         110 my $added_by = $file->{ added_by };
641             # ^ Do not use accessor — it will convert array of strings into single string.
642 88         116 my $history = [];
643 88         104 my $n = 0;
644 88         187 for my $entry ( @$added_by ) {
645 134         126 ++ $n;
646 134 50       1218 if ( $entry =~ m{\A (.*?) \s by \s (.*) \s \( ([a-z_0-9:]+) \s line \s (\d+) \) \z}ix ) {
647 134         408 my ( $action, $name, $package, $line ) = ( $1, $2, $3, $4 );
648 134         610 push(
649             @$history,
650             { action => $action, name => $name, package => $package, line => $line }
651             );
652             } else {
653             $self->log_error( [
654             "Can't parse entry #%d in file %s added_by log:\n%s",
655             $n, $file->name,
656             join(
657             "\n",
658             map(
659 0 0       0 { ( $_ == $n ? '>>> ' : ' ' ) . $added_by->[ $_ - 1 ] }
  0         0  
660             1 .. @$added_by
661             )
662             )
663             ] );
664             };
665             };
666 88         133 return $history;
667             };
668              
669             # --------------------------------------------------------------------------------------------------
670              
671             #pod =method _file_deed
672             #pod
673             #pod $str = $self->_file_deed( $file, $history ); # $SOURCE, $META, or $OTHER.
674             #pod
675             #pod Returns internal identifier of file deed.
676             #pod
677             #pod =cut
678              
679             sub _file_deed {
680 88     88   101 my ( $self, $file, $history ) = @_;
681 88         122 my $deed;
682 88 50       180 if ( my $first = $history->[ 0 ] ) {
683 88   66     3653 $deed = $self->_providers->{ $first->{ name } } || $OTHER;
684             } else {
685 0         0 $self->log_error( [ "can't find file %s deed: file history is empty", $file->name ] );
686             };
687 88         211 return $deed;
688             };
689              
690             # --------------------------------------------------------------------------------------------------
691              
692             #pod =method _file_breed
693             #pod
694             #pod $str = $self->_file_breed( $file, $history ); # ADDED or BUILT.
695             #pod
696             #pod Returns internal identifier of file breed, either C<$ADDED> or C<$BUILT>.
697             #pod
698             #pod Current implementation checks file object class: if it is a C<Dist::Zilla::File::OnDisk>, the file
699             #pod is added to distribution, otherwise the file is built.
700             #pod
701             #pod =cut
702              
703             sub _file_breed {
704 88     88   101 my ( $self, $file, $history ) = @_;
705 88         76 my $breed;
706 88 100       503 if ( $file->isa( 'Dist::Zilla::File::OnDisk' ) ) {
707 38         169 $breed = $ADDED;
708             } else {
709 50         218 $breed = $BUILT;
710             };
711 88         320 return $breed;
712             };
713              
714             # --------------------------------------------------------------------------------------------------
715              
716             #pod =method _file_adder
717             #pod
718             #pod $str = $self->_file_adder( $file, $history );
719             #pod
720             #pod Returns moniker of the plugin added the file to the distribution.
721             #pod
722             #pod =cut
723              
724             sub _file_adder {
725 88     88   84 my ( $self, $file, $history ) = @_;
726 88         87 my $adder = '(*UNKNOWN*)';
727 88 50       162 if ( my $first = $history->[ 0 ] ) {
728 88         148 my $name = $first->{ name };
729 88 50       2599 if ( my $plugin = $self->zilla->plugin_named( $name ) ) {
730 88         9609 $adder = __plugin_moniker( $plugin );
731             # Just in case make sure found plugin does `FileInjector` role.
732 88 50       4255 $plugin->does( 'Dist::Zilla::Role::FileInjector' ) or
733             $self->log_error( [
734             "oops: found file adder %s does not do FileInjector role", $name
735             ] );
736             } else {
737 0         0 $self->log_error( [
738             "can't find file %s adder: %s is not a plugin", $file->name, $name
739             ] );
740             };
741             } else {
742 0         0 $self->log_error( [ "can't find file %s adder: file history is empty", $file->name ] );
743             };
744 88         6531 return $adder;
745             };
746              
747             # --------------------------------------------------------------------------------------------------
748              
749             #pod =method _file_mungers
750             #pod
751             #pod @list = $self->_file_mungers( $file, $history );
752             #pod
753             #pod If C<show_mungers> attribute is C<true>, returns list of monikers of the plugins munged the file.
754             #pod Otherwise returns empty list.
755             #pod
756             #pod =cut
757              
758             sub _file_mungers {
759 88     88   109 my ( $self, $file, $history ) = @_;
760 88         88 my @mungers;
761 88 100       3594 if ( $self->show_mungers ) {
762 4         12 for my $i ( 1 .. @$history - 1 ) {
763 1         6 push( @mungers, $self->_file_munger( $file, $history->[ $i ] ) );
764             };
765             };
766 88         234 return @mungers;
767             };
768              
769             # --------------------------------------------------------------------------------------------------
770              
771             #pod =method _file_munger
772             #pod
773             #pod $str = $self->_file_munger( $file, $history->[ $n ] );
774             #pod
775             #pod The method is supposed to return a moniker of plugin munged the file. But… see
776             #pod L<Dist::Zilla::Plugin::Manifest::Write/"Correctness of Information">.
777             #pod
778             #pod =cut
779              
780             sub _file_munger {
781 1     1   2 my ( $self, $file, $entry ) = @_;
782             # Try to find a plugin with given name.
783 1 50       29 if ( my $plugin = $self->zilla->plugin_named( $entry->{ name } ) ) {
784             # Bingo! Return (correct) plugin moniker.
785 1         148 return __plugin_moniker( $plugin );
786             };
787             # Oops, bad luck. We have:
788             # * a plugin name which is not a plugin name but moniker of *some* plugin.
789             # * a package name which can be a plugin package name or not.
790             # We have to guess.
791             # BTW, I have tried to mark guessed monikers with a question mark, but *all* file mungers
792             # will carry this mark. Looks ugly,so I rejected it.
793 0           return __plugin_moniker( $entry->{ package } );
794             };
795              
796             # --------------------------------------------------------------------------------------------------
797              
798             #pod =method mvp_multivalue_args
799             #pod
800             #pod This method tells C<Dist::Zilla> that C<source_provider>, C<source_providers>,
801             #pod C<metainfo_provider>, and C<metainfo_providers> are multi-value options (i. e. can be specified in
802             #pod several times).
803             #pod
804             #pod =cut
805              
806             around mvp_multivalue_args => sub {
807             my ( $orig, $self ) = @_;
808             return (
809             $self->$orig(),
810             qw{ source_provider source_providers metainfo_provider metainfo_providers }
811             );
812             };
813              
814             # --------------------------------------------------------------------------------------------------
815              
816             __PACKAGE__->meta->make_immutable;
817              
818             1;
819              
820             # --------------------------------------------------------------------------------------------------
821              
822             #pod =head1 SYNOPSIS
823             #pod
824             #pod package ManifestWithFileSize;
825             #pod
826             #pod use Moose;
827             #pod use namespace::autoclean;
828             #pod extends 'Dist::Zilla::Plugin::Manifest::Write';
829             #pod our $VERSION = '0.007';
830             #pod
831             #pod # Overload any method or modify it with all the Moose power, e. g.:
832             #pod around _file_comment => sub {
833             #pod my ( $orig, $self, $file ) = @_;
834             #pod my $comment = $self->$orig( $file );
835             #pod if ( $file->name ne $self->manifest ) { # Avoid infinite recursion.
836             #pod $comment .= sprintf( ' (%d bytes)', length( $file->encoded_content ) );
837             #pod };
838             #pod return $comment;
839             #pod };
840             #pod
841             #pod __PACKAGE__->meta->make_immutable;
842             #pod 1;
843             #pod
844             #pod =example Manifest with File Size
845             #pod
846             #pod A module shown in Synopsis is a real example. Its result looks like:
847             #pod
848             #pod # This file was generated with ManifestWithFileSize 0.007
849             #pod MANIFEST # metainfo file built by =ManifestWithFileSize
850             #pod dist.ini # Dummy file added by GatherDir (207 bytes)
851             #pod lib/Dummy.pm # Dummy file added by GatherDir (22 bytes)
852             #pod
853             #pod
854             #pod =head1 COPYRIGHT AND LICENSE
855             #pod
856             #pod Copyright (C) 2015, 2016 Van de Bugger
857             #pod
858             #pod License GPLv3+: The GNU General Public License version 3 or later
859             #pod <http://www.gnu.org/licenses/gpl-3.0.txt>.
860             #pod
861             #pod This is free software: you are free to change and redistribute it. There is
862             #pod NO WARRANTY, to the extent permitted by law.
863             #pod
864             #pod
865             #pod =cut
866              
867             # ------------------------------------------------------------------------------------------------
868             #
869             # file: doc/what.pod
870             #
871             # This file is part of perl-Dist-Zilla-Plugin-Manifest-Write.
872             #
873             # ------------------------------------------------------------------------------------------------
874              
875             #pod =encoding UTF-8
876             #pod
877             #pod =head1 WHAT?
878             #pod
879             #pod C<Dist-Zilla-Plugin-Manifest-Write> (or C<Manifest::Write> for brevity) is a plugin for C<Dist::Zilla>, a replacement
880             #pod for standard plugin C<Manifest>. C<Manifest::Write> writes I<annotated> distribution manifest: each
881             #pod filename is followed by a comment explaining origin of the file: if it is a part of software, meta
882             #pod information, or 3rd-party file. Also it can B<I<exclude> built files from distribution>, e. g.
883             #pod extra tests have to be built (to run) but need not be distributed.
884             #pod
885             #pod =cut
886              
887             # end of file #
888              
889              
890             # end of file #
891              
892             __END__
893              
894             =pod
895              
896             =encoding UTF-8
897              
898             =head1 NAME
899              
900             Dist::Zilla::Plugin::Manifest::Write - Have annotated distribution manifest
901              
902             =head1 VERSION
903              
904             Version v0.9.5_01, released on 2016-11-26 21:21 UTC.
905             This is a B<trial release>.
906              
907             =head1 WHAT?
908              
909             C<Dist-Zilla-Plugin-Manifest-Write> (or C<Manifest::Write> for brevity) is a plugin for C<Dist::Zilla>, a replacement
910             for standard plugin C<Manifest>. C<Manifest::Write> writes I<annotated> distribution manifest: each
911             filename is followed by a comment explaining origin of the file: if it is a part of software, meta
912             information, or 3rd-party file. Also it can B<I<exclude> built files from distribution>, e. g.
913             extra tests have to be built (to run) but need not be distributed.
914              
915             This is C<Dist::Zilla::Plugin::Manifest::Write> module documentation. Read this if you are going to hack or
916             extend C<Manifest::Write>.
917              
918             If you want to have annotated distribution manifest, read the L<plugin user
919             manual|Dist::Zilla::Plugin::Manifest::Write::Manual>. General topics like getting source, building, installing, bug
920             reporting and some others are covered in the F<README>.
921              
922             =head1 SYNOPSIS
923              
924             package ManifestWithFileSize;
925              
926             use Moose;
927             use namespace::autoclean;
928             extends 'Dist::Zilla::Plugin::Manifest::Write';
929             our $VERSION = '0.007';
930              
931             # Overload any method or modify it with all the Moose power, e. g.:
932             around _file_comment => sub {
933             my ( $orig, $self, $file ) = @_;
934             my $comment = $self->$orig( $file );
935             if ( $file->name ne $self->manifest ) { # Avoid infinite recursion.
936             $comment .= sprintf( ' (%d bytes)', length( $file->encoded_content ) );
937             };
938             return $comment;
939             };
940              
941             __PACKAGE__->meta->make_immutable;
942             1;
943              
944             =head1 DESCRIPTION
945              
946             In order to add a manifest file to the distribution, C<Dist::Zilla::Plugin::Manifest::Write> class consumes
947             C<Dist::Zilla::Role::FileGatherer> role. To meet the role requirements, the class implements
948             C<gather_files> method. Other methods are supporting helpers for this one.
949              
950             Most of attributes are initialized by builders for easier customization by subclassing. Code is
951             also divided into small methods for the same purpose.
952              
953             =head1 CLASS METHODS
954              
955             =head2 BUILDARGS
956              
957             The method splits values of C<source_providers> option into separate plugin names using whitespaces
958             as delimiters, combines result of splitting with C<source_provider> option values, then filters out
959             empty values. Resulting C<ArrayRef> saved as C<source_providers> options.
960              
961             The same for C<metainfo_providers> and C<metainfo_provider> options.
962              
963             =head1 OBJECT ATTRIBUTES
964              
965             =head2 manifest
966              
967             Name of manifest file to write.
968              
969             C<Str>, read-only. Default value is C<'MANIFEST'>.
970              
971             =head2 source_providers
972              
973             List of plugin names. Enlisted plugins are considered as source file providers. A file added to
974             distribution by any of these plugins is considered as source file.
975              
976             C<ArrayRef[Str]>, read-only, default value is empty array. Init argument (and config file
977             multi-value option) name is C<source_provider>. (C<BUILDARGS> also handles C<source_providers>
978             option.)
979              
980             =head2 metainfo_providers
981              
982             Like C<source_providers> but enlists meta info file providers.
983              
984             C<ArrayRef[Str]>, read-only, default value is C<CPANFile>, C<Manifest>, C<MetaYAML>, C<MetaJSON>,
985             and the plugin itself. Init argument (and config file multi-value option) name is
986             C<metainfo_provider>. (C<BUILDARGS> also handles C<metainfo_providers> option.)
987              
988             Note: Do not confuse C<Manifest::Write>'s term I<metainfo providers> with C<Dist::Zilla>'s
989             C<MetaProvider> role. Plugins do C<MetaProvider> role provide I<metadata>, while C<Manifest::Write>
990             is interested in plugins which adds I<files> containing metadata to the distribution (such plugins
991             do C<FileInjector> role, not C<MetaProvider>).
992              
993             =head2 strict
994              
995             Strictness of checking source and metainfo provider names: -1 (no checks), 0 (some mistakes are
996             fatal, some are not), or 1 (all mistakes are fatal).
997              
998             C<Int>, read-only. Default is 1.
999              
1000             See L<Dist::Zilla::Plugin::Manifest::Write::Manual/"strict">.
1001              
1002             =head2 show_mungers
1003              
1004             If C<1>, file mungers will be included into annotation. By default mungers are not included.
1005              
1006             C<Bool>, read-only. Default is C<0>.
1007              
1008             =head2 deeds
1009              
1010             This attribute maps internal file deed constants (C<SOURCE>, C<META>, C<OTHER>) to user-visible
1011             names used in manifest (project name, C<metainfo>, and C<3rd party> respectively).
1012              
1013             C<HashRef[Str]>, read-only.
1014              
1015             =head2 breeds
1016              
1017             This attribute maps internal file deed constants (C<$ADDED> and C<$BUILT>) to user-visible names
1018             used in manifest. By default user-visible breed names are the same as internal identifiers.
1019              
1020             C<HashRef[Str]>, read-only.
1021              
1022             =head2 _providers
1023              
1024             This attribute maps provider names to file deeds. It makes C<_file_deed> method implementation
1025             simpler and faster.
1026              
1027             C<HashRef[Str]>, read-only, not an init arg.
1028              
1029             =head2 _dw
1030              
1031             Max length of user-visible deed names.
1032              
1033             C<Int>, read-only, not an init arg.
1034              
1035             =head1 OBJECT METHODS
1036              
1037             =head2 before_build
1038              
1039             This method is called by C<Dist::Zilla> automatically before build. The method checks validity of
1040             source and metainfo provider names.
1041              
1042             =head2 before_archive
1043              
1044             This method is called by C<Dist::Zilla> automatically before build the archive. The method prunes
1045             files found by file finders specified in the C<exclude_files> option.
1046              
1047             =head2 gather_files
1048              
1049             This is the main method of the class. It adds a file with name C<< $self->manifest >> to the
1050             distribution. File content is specified by C<CodeRef> to postpone actual file creation. Being
1051             evaluated, the code iterates through all the files in distribution in alphabetical order, and
1052             fulfills the manifest with filenames and comments.
1053              
1054             =head2 _file_name
1055              
1056             $str = $self->_file_name( $file );
1057              
1058             Returns filename to be used in manifest. If filename does not include special characters (spaces,
1059             backslashes (C<\>), apostrophes (C<'>), hashes (C<#>)), it is the same as real filename, otherwise
1060             filename encoded like Perl single-quoted string: backslashes and apostrophes are escaped, and
1061             entire filename is enclosed into apostrophes.
1062              
1063             =head2 _file_comment
1064              
1065             $str = $self->_file_comment( $file ); # Without leading sharp.
1066              
1067             The method returns comment to be used with the specified file. Comment should not include leading
1068             sharp character (C<#>).
1069              
1070             =head2 _file_history
1071              
1072             $arrayref = $self->_file_history( $file );
1073              
1074             The method calls C<_file_added_by> then does post-processing: all C<filename set> records are
1075             filtered out as insignificant and makes sure the log is not empty.
1076              
1077             =head2 _file_added_by
1078              
1079             $arrayref = $self->_file_added_by( $file );
1080              
1081             The method parses file's C<added_by> log. Internally, C<added_by> log is a list of strings. Here
1082             are few examples:
1083              
1084             content added by COPYING (Dist::Zilla::Plugin::GenerateFile line 114)
1085             filename set by GatherFromManifest (Dist::Zilla::Plugin::GatherFromManifest line 125)
1086             encoded_content added by GatherFromManifest (Dist::Zilla::Plugin::GatherFromManifest line 126)
1087             text from coderef added by MetaJSON (Dist::Zilla::Plugin::MetaJSON line 83)
1088             content set by TemplateFiles (Dist::Zilla::Plugin::TemplateFiles line 35)
1089             content set by OurPkgVersion (Dist::Zilla::Plugin::OurPkgVersion line 82)
1090             content set by PodWeaver (Dist::Zilla::Plugin::PodWeaver line 175)
1091              
1092             Thus, each string in C<added_by> log follows the format:
1093              
1094             <action> by <name> (<package> line <number>)
1095              
1096             The method parses these strings and returns a more convenient for further processing form:
1097              
1098             [ { action => …, name => …, package => …, line => … }, { … }, … ]
1099              
1100             Do not call this method directly, use C<_file_history> instead.
1101              
1102             =head2 _file_deed
1103              
1104             $str = $self->_file_deed( $file, $history ); # $SOURCE, $META, or $OTHER.
1105              
1106             Returns internal identifier of file deed.
1107              
1108             =head2 _file_breed
1109              
1110             $str = $self->_file_breed( $file, $history ); # ADDED or BUILT.
1111              
1112             Returns internal identifier of file breed, either C<$ADDED> or C<$BUILT>.
1113              
1114             Current implementation checks file object class: if it is a C<Dist::Zilla::File::OnDisk>, the file
1115             is added to distribution, otherwise the file is built.
1116              
1117             =head2 _file_adder
1118              
1119             $str = $self->_file_adder( $file, $history );
1120              
1121             Returns moniker of the plugin added the file to the distribution.
1122              
1123             =head2 _file_mungers
1124              
1125             @list = $self->_file_mungers( $file, $history );
1126              
1127             If C<show_mungers> attribute is C<true>, returns list of monikers of the plugins munged the file.
1128             Otherwise returns empty list.
1129              
1130             =head2 _file_munger
1131              
1132             $str = $self->_file_munger( $file, $history->[ $n ] );
1133              
1134             The method is supposed to return a moniker of plugin munged the file. But… see
1135             L<Dist::Zilla::Plugin::Manifest::Write/"Correctness of Information">.
1136              
1137             =head2 mvp_multivalue_args
1138              
1139             This method tells C<Dist::Zilla> that C<source_provider>, C<source_providers>,
1140             C<metainfo_provider>, and C<metainfo_providers> are multi-value options (i. e. can be specified in
1141             several times).
1142              
1143             =head1 FUNCTIONS
1144              
1145             I would expect to find these functions in C<Dist::Zilla>. Actually, C<Dist::Zilla::Util> defines
1146             the function C<expand_config_package_name>, but that function "is likely to change or go away" and
1147             there is no reverse transformation.
1148              
1149             =head2 __plugin_moniker
1150              
1151             $str = __plugin_moniker( 'Dist::Zilla::Plugin::Name' ); # 'Name'
1152             $str = __plugin_moniker( 'Non::Standard::Name' ); # '=Non::Standard::Name'
1153             $str = __plugin_moniker( $plugin );
1154              
1155             The function takes either reference to a plugin object or a string, package name, and returns
1156             C<Dist::Zilla> plugin moniker: If its package name begins with C<Dist::Zilla::Plugin::>, this
1157             common prefix is dropped, otherwise the package name prepended with C<=>.
1158              
1159             =head2 __package_name
1160              
1161             $str = __package_name( 'Name' ); # returns 'Dist::Zilla::Plugin::Name'
1162             $str = __package_name( '=Name' ); # returns 'Name'
1163             $str = __package_name( $plugin );
1164              
1165             This is operation opposite to C<__plugin_moniker>. It takes either reference to plugin object, or
1166             string, plugin moniker, and returns package name.
1167              
1168             This function is similar to C<expand_config_package_name> from C<Dist::Zilla::Util>, with minor
1169             difference: this function works with plugins only (not with plugin bundles and stashes), and
1170             accepts also reference to plugin object.
1171              
1172             =head1 EXAMPLES
1173              
1174             =head2 Manifest with File Size
1175              
1176             A module shown in Synopsis is a real example. Its result looks like:
1177              
1178             # This file was generated with ManifestWithFileSize 0.007
1179             MANIFEST # metainfo file built by =ManifestWithFileSize
1180             dist.ini # Dummy file added by GatherDir (207 bytes)
1181             lib/Dummy.pm # Dummy file added by GatherDir (22 bytes)
1182              
1183             =head1 SEE ALSO
1184              
1185             =over 4
1186              
1187             =item L<Dist::Zilla>
1188              
1189             =item L<Dist::Zilla::Role>
1190              
1191             =item L<Dist::Zilla::Role::Plugin>
1192              
1193             =item L<Dist::Zilla::Role::FileInjector>
1194              
1195             =item L<Dist::Zilla::Role::FileGatherer>
1196              
1197             =item L<Dist::Zilla::Plugin::Manifest>
1198              
1199             =item L<Dist::Zilla::Plugin::Manifest::Write::Manual>
1200              
1201             =back
1202              
1203             =head1 AUTHOR
1204              
1205             Van de Bugger <van.de.bugger@gmail.com>
1206              
1207             =head1 COPYRIGHT AND LICENSE
1208              
1209             Copyright (C) 2015, 2016 Van de Bugger
1210              
1211             License GPLv3+: The GNU General Public License version 3 or later
1212             <http://www.gnu.org/licenses/gpl-3.0.txt>.
1213              
1214             This is free software: you are free to change and redistribute it. There is
1215             NO WARRANTY, to the extent permitted by law.
1216              
1217             =cut