File Coverage

blib/lib/Dist/Zilla/Plugin/lib.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod 0 1 0.0
total 33 34 97.0


line stmt bran cond sub pod time code
1 5     5   7369554 use 5.006; # our
  5         12  
2 5     5   19 use strict;
  5         7  
  5         100  
3 5     5   25 use warnings;
  5         7  
  5         317  
4              
5             package Dist::Zilla::Plugin::lib;
6              
7             our $VERSION = '0.001001';
8              
9             # ABSTRACT: A simpler bootstrap for a more civilised world
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 5     5   501 use Moose qw( with around has );
  5         293222  
  5         37  
14 5     5   20048 use MooseX::Types::Moose qw( ArrayRef Str );
  5         43908  
  5         55  
15 5     5   17472 use Path::Tiny qw( path );
  5         7356  
  5         304  
16 5     5   593 use lib qw();
  5         442  
  5         1316  
17              
18             with 'Dist::Zilla::Role::Plugin';
19              
20              
21              
22              
23              
24              
25 4     4 0 689 sub mvp_multivalue_args { return qw( lib ) }
26              
27             has 'lib' => (
28             is => 'ro',
29             isa => ArrayRef [Str],
30             required => 1,
31             );
32              
33             around dump_config => sub {
34             my ( $orig, $self, @args ) = @_;
35             my $config = $self->$orig(@args);
36             my $localconf = $config->{ +__PACKAGE__ } = {};
37              
38             $localconf->{lib} = $self->lib;
39              
40             $localconf->{ q[$] . __PACKAGE__ . '::VERSION' } = $VERSION
41             unless __PACKAGE__ eq ref $self;
42              
43             return $config;
44             };
45              
46             # Injecting at init time
47             around plugin_from_config => sub {
48             my ( $orig, $plugin_class, $name, $payload, $section ) = @_;
49             my $instance = $plugin_class->$orig( $name, $payload, $section );
50             my $root = path( $instance->zilla->root )->absolute; # https://github.com/rjbs/Dist-Zilla/issues/579
51             $instance->log_debug("zilla root: $root");
52              
53             lib->import(
54             map { "$_" }
55             grep { $_->is_dir ? 1 : ( $instance->log("library path \"$_\" does not exist or is not a directory"), undef ) }
56             map { path($_)->absolute($root) } @{ $instance->lib || [] },
57             );
58             $instance->log_debug("\@INC is [@INC]");
59             return $instance;
60             };
61              
62             __PACKAGE__->meta->make_immutable;
63 5     5   21 no Moose;
  5         8  
  5         27  
64              
65             1;
66              
67             __END__
68              
69             =pod
70              
71             =encoding UTF-8
72              
73             =head1 NAME
74              
75             Dist::Zilla::Plugin::lib - A simpler bootstrap for a more civilised world
76              
77             =head1 VERSION
78              
79             version 0.001001
80              
81             =head1 SYNOPSIS
82              
83             name = My-Dist
84             author = Mr CPAN Person <person@cpan.example.org>
85             license = Perl_5
86             ...
87              
88             ; push ./inc into @INC
89             [lib]
90             lib = inc
91              
92             ; loads inc/My/GatherDir.pm
93             [=My::GatherDir]
94              
95             =head1 DESCRIPTION
96              
97             Dist::Zilla::Plugin::lib serves as a relatively straight-forward and
98             uncomplicated way to wire certain local paths in your distributions
99             source tree into Perl's C<@INC> library load path.
100              
101             Its primary audiences are twofold.
102              
103             =over 4
104              
105             =item Self-Building Dist::Zilla Plugins
106              
107             Many recent L<Dist::Zilla|Dist::Zilla> plugin workflows champion a
108             state of C<lib/> which are usable "as is" without needing to cycle
109             through a C<dzil build> phase first, and this plugin offers a simple
110             way to stash C<lib/> in C<@INC> without needing to pass C<-Ilib> every
111             time you run C<dzil>.
112              
113             Workflows that require a build cycle to self-build should use
114             L<< C<[Bootstrap::lib]>|Dist::Zilla::Plugin::Bootstrap::lib >> instead.
115              
116             =item Bundled Dist::Zilla Plugins
117              
118             Many heavy C<CPAN> distributions have bundled within them custom C<Dist::Zilla>
119             plugins stashed in C<inc/>
120              
121             Traditionally, these are loaded via C<[=inc::Foo::Package]> exploiting
122             the long held assumption that C<"."> ( C<$CWD> ) is contained in C<@INC>
123              
124             However, that is becoming a L<less safe assumption|/RELATED READING>, and this
125             plugin aims to make such equivalent behaviour practical without needing to
126             rely on that assumption.
127              
128             =back
129              
130             =for Pod::Coverage mvp_multivalue_args
131              
132             =head1 USAGE
133              
134             Inserting a section in your C<dist.ini> as follows:
135              
136             [lib]
137             lib = some/path
138              
139             [=Some::Plugin]
140              
141             [Some::Other::Plugin]
142              
143             Will prepend C<some/path> (relative to your distribution root) into
144             C<@INC>, and allow loading of not just plugins, but plugin dependencies
145             from the designated path.
146              
147             C<[=Some::Plugin]> will be able to load, as per existing C<Dist::Zilla> convention,
148             via C<inc/Some/Plugin.pm>, and then fall back to searching other C<@INC> paths.
149              
150             C<[Some::Other::Plugin]> will B<also> be able to load from C<inc/>,
151             via C<inc/Dist/Zilla/Plugin/Some/Other/Plugin.pm>
152              
153             =head1 Ensuring dot-in-INC
154              
155             Its not sure when C<"."> in C<@INC> will actually go away, or which parts of the C<dzil>
156             ecosystem will be re-patched to retain this assumption.
157              
158             But the simplest thing that would work with changing the least amount of code would be
159             simply inserting
160              
161             [lib]
162             lib = .
163              
164             Early in your C<dist.ini>
165              
166             This will have a C<mostly> the same effect as retaining C<dot-in-INC> even in the
167             event you run on a newer Perl where that is removed by default.
168              
169             The differences however are subtle and maybe better depending on what you're doing
170              
171             =over 4
172              
173             =item * C<"."> will be prepended to C<@INC>, not appended.
174              
175             This means C<[=inc::Foo]> will actually hit C<inc/> first, not simply as an afterthought
176             if it isn't found in other paths in C<@INC>
177              
178             For instance, currently, I could create a lot of havoc by simply shipping a C<dzil> plugin with
179             the same name as somebody already is using for their private C<inc/> hacks, and then trip them
180             into installing it. Because currently, C<site beats "."> where authors intended to source
181             from C<"."> not C<site>
182              
183             =item * C<"."> will be absolutized to C<< $zilla->root >>
184              
185             As it stands, the C<"."> in C<@INC> is only ever C<".">, which means calling
186             C<chdir> between calls to C<require> effectively changes what C<@INC> means.
187              
188             Given that is the specific threat surface for that issue, it would be silly
189             to repeat that mistake, especially as when you write C<"."> you typically want to
190             imply "Where I am now" not "Wherever the code will be 30 seconds after now after
191             it C<chdir>s to random locations at the discretion of code I haven't even read"
192              
193             There's still some annoying scope for this absolutization going wrong,
194             due to C<Dist::Zilla> not L<< ensuring this path is fixed early on|https://github.com/rjbs/Dist-Zilla/issues/579 >>
195             but C<[lib]> fixes and absolutizes it as early as possible,
196             with the hope we'll know what you meant by C<cwd> before somebody can change C<cwd>
197              
198             ( And if that fails, it will fail spectacularly, not selectively work some of the
199             time if your stars align )
200              
201             =back
202              
203             =head1 Migrating from dot-in-INC code
204              
205             If you have existing code that relies on the C<.>-in-C<@INC> assumption,
206             migrating to use this plugin in way that would seem "proper" would play as follows:
207              
208             =over 4
209              
210             =item 1. Rename your plugins in C<inc/>
211              
212             All those packages called C<inc::Some::Plugin> become
213             C<Some::Plugin>
214              
215             =item 2. Replace your section lines
216              
217             C<inc> is no longer needed as part of the plugin, so
218             replacing all sections
219              
220             -[=inc::Some::Plugin]
221             +[=Some::Plugin]
222              
223             In line with step 1.
224              
225             =item 3. Add a C<[lib]> section before all your plugins
226              
227             And tell it to assume that C<inc/> is now in the load path.
228              
229             +[lib]
230             +lib = inc
231              
232             =back
233              
234             =head1 ATTRIBUTES
235              
236             =head2 C<lib>
237              
238             This attribute can be specified 1 or more times, each time specifying
239             a path which will be assumed to be a path relative to C<< $zilla->root >>
240              
241             Paths specified will be passed to L<< C<lib.pm>|lib >>C<< ->import >> in the
242             same order as they appear in your configuration, after absolutizing them.
243              
244             C<lib.pm> prepends the values to C<< @INC >> in a nature akin to
245              
246             unshift(@INC, @{ $lib })
247              
248             Which is functionally similar to:
249              
250             @INC = ( @{ $lib }, @INC )
251              
252             That is, retaining the specified order in C< @INC >.
253              
254             =head1 RELATED READING
255              
256             =head2 C<dot-in-INC>
257              
258             =over 4
259              
260             =item * L<< Todd Rinaldo - How removing C<"."> from C<@INC> is about to break CPAN|http://blogs.perl.org/users/todd_rinaldo/2016/11/how-removing-from-inc-is-about-to-break-cpan.html >>
261              
262             =item * L<< Todd Rinaldo - What happened to C<"."> in C<@INC>|http://blogs.perl.org/users/todd_rinaldo/2016/11/what-happened-to-dot-in-inc.html >>
263              
264             =back
265              
266             =head1 AUTHOR
267              
268             Kent Fredric <kentnl@cpan.org>
269              
270             =head1 COPYRIGHT AND LICENSE
271              
272             This software is copyright (c) 2017 by Kent Fredric <kentfredric@gmail.com>.
273              
274             This is free software; you can redistribute it and/or modify it under
275             the same terms as the Perl 5 programming language system itself.
276              
277             =cut