File Coverage

blib/lib/Dist/Zilla/Plugin/CheckSelfDependency.pm
Criterion Covered Total %
statement 50 50 100.0
branch 12 16 75.0
condition 6 9 66.6
subroutine 9 9 100.0
pod 0 1 0.0
total 77 85 90.5


line stmt bran cond sub pod time code
1 6     6   3867504 use strict;
  6         13  
  6         228  
2 6     6   29 use warnings;
  6         9  
  6         367  
3             package Dist::Zilla::Plugin::CheckSelfDependency;
4             # git description: v0.007-16-g646759c
5             $Dist::Zilla::Plugin::CheckSelfDependency::VERSION = '0.008';
6             # ABSTRACT: Check if your distribution declares a dependency on itself
7             # KEYWORDS: plugin validate distribution prerequisites dependencies modules
8             # vim: set ts=8 sw=4 tw=78 et :
9              
10 6     6   27 use Moose;
  6         7  
  6         47  
11             with 'Dist::Zilla::Role::AfterBuild',
12             'Dist::Zilla::Role::FileFinderUser' => {
13             default_finders => [ ':InstallModules' ],
14             },
15             ;
16 6     6   33856 use Module::Metadata 1.000005;
  6         26470  
  6         196  
17 6     6   39 use CPAN::Meta::Requirements;
  6         10  
  6         138  
18 6     6   23 use namespace::autoclean;
  6         8  
  6         53  
19              
20             around dump_config => sub
21             {
22             my ($orig, $self) = @_;
23             my $config = $self->$orig;
24              
25             $config->{+__PACKAGE__} = {
26             finder => $self->finder,
27             };
28              
29             return $config;
30             };
31              
32             sub after_build
33             {
34 10     10 0 876734 my $self = shift;
35              
36 6         20 my %prereqs = map { $_ => 1 }
  6         19  
37 6         20 map { keys %$_ }
38 40         5513 map { values %$_ }
39 10         372 grep { defined }
40 10         29 @{ $self->zilla->prereqs->as_string_hash }{qw(configure build runtime test)};
41              
42 10         328 my $develop_prereqs = $self->zilla->prereqs->cpan_meta_prereqs
43             ->merged_requirements(['develop'], [qw(requires recommends suggests)]);
44 10         2027 my $develop_prereqs_hash = $develop_prereqs->as_string_hash;
45              
46 10         373 my $provides = $self->zilla->distmeta->{provides}; # copy, to avoid autovivifying
47              
48 10         311 my @errors;
49             # when 'provides' data is mandatory, we will rely on what it says -
50             # but for now, we will check our modules explicitly for provided packages.
51 10         15 foreach my $file (@{$self->found_files})
  10         53  
52             {
53 10 50 33     5870 $self->log_fatal(sprintf('Could not decode %s: %s', $file->name, $file->added_by))
54             if $file->can('encoding') and $file->encoding eq 'bytes';
55              
56 10         199 my $fh;
57 6 50   6   640 ($file->can('encoding')
  6 50   6   9  
  6         51  
  6         5005  
  6         15  
  6         23  
  10         335  
58             ? open $fh, sprintf('<:encoding(%s)', $file->encoding), \$file->encoded_content
59             : open $fh, '<', \$file->content)
60             or $self->log_fatal('cannot open handle to ' . $file->name . ' content: ' . $!);
61              
62 10         6692 my @packages = Module::Metadata->new_from_handle($fh, $file->name)->packages_inside;
63 10         2734 foreach my $package (@packages)
64             {
65 10 100 100     78 if (exists $prereqs{$package}
      66        
66             or (exists $develop_prereqs_hash->{$package}
67             # you can only have a develop prereq on yourself if you
68             # use 'provides' metadata - so we're darned sure we
69             # matched up the right module names
70             and not exists $provides->{$package}))
71             {
72 5         34 push @errors, $package . ' is listed as a prereq, but is also provided by this dist ('
73             . $file->name . ')!';
74 5         280 next;
75             }
76              
77 5 100       50 next if not exists $develop_prereqs_hash->{$package};
78              
79 3 50       12 my $version = $provides ? $provides->{$package}{version} : $self->zilla->version;
80 3 100       14 if (not $develop_prereqs->accepts_module($package => $version))
81             {
82 1         38 push @errors, "$package $develop_prereqs_hash->{$package} is listed as a develop prereq, "
83             . 'but this dist doesn\'t provide that version ('
84             . $file->name . ' only has ' . $version . ')!';
85             }
86             }
87             }
88              
89 10 100       251 $self->log_fatal(@errors) if @errors;
90             }
91              
92             __PACKAGE__->meta->make_immutable;
93              
94             __END__
95              
96             =pod
97              
98             =encoding UTF-8
99              
100             =head1 NAME
101              
102             Dist::Zilla::Plugin::CheckSelfDependency - Check if your distribution declares a dependency on itself
103              
104             =head1 VERSION
105              
106             version 0.008
107              
108             =head1 SYNOPSIS
109              
110             In your F<dist.ini>:
111              
112             [CheckSelfDependency]
113              
114             =head1 DESCRIPTION
115              
116             =for Pod::Coverage after_build
117              
118             =for stopwords indexable
119              
120             This is a L<Dist::Zilla> plugin that runs in the I<after build> phase, which
121             checks all of your module prerequisites (all phases, all types except develop) to confirm
122             that none of them refer to modules that are B<provided> by this distribution
123             (that is, the metadata declares the module is indexable).
124              
125             In addition, all modules B<in> the distribution are checked against all module
126             prerequisites (all phases, all types B<including> develop). Thus, it is
127             possible to ship a L<Dist::Zilla> plugin and use (depend on) yourself, but
128             errors such as declaring a dependency on C<inc::HelperPlugin> are still caught.
129              
130             While some prereq providers (e.g. L<C<[AutoPrereqs]>|Dist::Zilla::Plugin::AutoPrereqs>)
131             do not inject dependencies found internally, there are many plugins that
132             generate code and also inject the prerequisites needed by that code, without
133             regard to whether some of those modules might be provided by your dist.
134             This problem is particularly acute when packaging low-level toolchain distributions.
135              
136             If such modules are found, the build fails. To remedy the situation, remove
137             the plugin that adds the prerequisite, or remove the prerequisite itself with
138             L<C<[RemovePrereqs]>|Dist::Zilla::Plugin::RemovePrereqs>. (Remember that
139             plugin order is significant -- you need to remove the prereq after it has been
140             added.)
141              
142             =head1 CONFIGURATION OPTIONS
143              
144             =head2 C<finder>
145              
146             =for stopwords FileFinder
147              
148             This is the name of a L<FileFinder|Dist::Zilla::Role::FileFinder> for finding
149             modules to check. The default value is C<:InstallModules>; this option can be
150             used more than once.
151              
152             Other predefined finders are listed in
153             L<Dist::Zilla::Role::FileFinderUser/default_finders>.
154             You can define your own with the
155             L<[FileFinder::ByName]|Dist::Zilla::Plugin::FileFinder::ByName> and
156             L<[FileFinder::Filter]|Dist::Zilla::Plugin::FileFinder::Filter> plugins.
157              
158             =head1 SUPPORT
159              
160             =for stopwords irc
161              
162             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-CheckSelfDependency>
163             (or L<bug-Dist-Zilla-Plugin-CheckSelfDependency@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-CheckSelfDependency@rt.cpan.org>).
164             I am also usually active on irc, as 'ether' at C<irc.perl.org>.
165              
166             =head1 AUTHOR
167              
168             Karen Etheridge <ether@cpan.org>
169              
170             =head1 COPYRIGHT AND LICENSE
171              
172             This software is copyright (c) 2013 by Karen Etheridge.
173              
174             This is free software; you can redistribute it and/or modify it under
175             the same terms as the Perl 5 programming language system itself.
176              
177             =cut