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   7492148 use 5.006; # our
  5         12  
2 5     5   18 use strict;
  5         6  
  5         104  
3 5     5   29 use warnings;
  5         7  
  5         340  
4              
5             package Dist::Zilla::Plugin::lib;
6              
7             our $VERSION = '0.001000';
8              
9             # ABSTRACT: A simpler bootstrap for a more civilised world
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 5     5   494 use Moose qw( with around has );
  5         292268  
  5         34  
14 5     5   19967 use MooseX::Types::Moose qw( ArrayRef Str );
  5         42726  
  5         50  
15 5     5   17293 use Path::Tiny qw( path );
  5         7434  
  5         259  
16 5     5   483 use lib qw();
  5         423  
  5         1350  
17              
18             with 'Dist::Zilla::Role::Plugin';
19              
20              
21              
22              
23              
24              
25 4     4 0 713 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         6  
  5         25  
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.001000
80              
81             =head1 SYNOPSIS
82              
83             name = My-Dist
84             ...
85              
86             [lib]
87             lib = inc
88              
89             [Foo]
90              
91             Foo will now be sourced from ./inc
92              
93             =head1 DESCRIPTION
94              
95             Dist::Zilla::Plugin::lib serves as a relatively straight-forward and
96             uncomplicated way to wire certain local paths in your distributions
97             source tree into Perl's C<@INC> library load path.
98              
99             Its primary audiences are twofold.
100              
101             =over 4
102              
103             =item Self-Building Dist::Zilla Plugins
104              
105             Many recent L<Dist::Zilla|Dist::Zilla> plugin workflows champion a
106             state of C<lib/> which are usable "as is" without needing to cycle
107             through a C<dzil build> phase first, and this plugin offers a simple
108             way to stash C<lib/> in C<@INC> without needing to pass C<-Ilib> every
109             time you run C<dzil>.
110              
111             Workflows that require a build cycle to self-build should use
112             L<< C<[Bootstrap::lib]>|Dist::Zilla::Plugin::Bootstrap::lib >> instead.
113              
114             =item Bundled Dist::Zilla Plugins
115              
116             Many heavy C<CPAN> distributions have bundled within them custom C<Dist::Zilla>
117             plugins stashed in C<inc/>
118              
119             Traditionally, these are loaded via C<[=inc::Foo::Package]> exploiting
120             the long held assumption that C<"."> ( C<$CWD> ) is contained in C<@INC>
121              
122             However, that is becoming a less safe assumption, and this plugin
123             aims to make such equivalent behaviour practical without needing to rely
124             on that assumption.
125              
126             =back
127              
128             =for Pod::Coverage mvp_multivalue_args
129              
130             =head1 USAGE
131              
132             Inserting a section in your C<dist.ini> as follows:
133              
134             [lib]
135             lib = some/path
136              
137             [=Some::Plugin]
138              
139             [Some::Other::Plugin]
140              
141             Will prepend C<some/path> (relative to your distribution root) into
142             C<@INC>, and allow loading of not just plugins, but plugin dependencies
143             from the designated path.
144              
145             C<[=Some::Plugin]> will be able to load, as per existing C<Dist::Zilla> convention,
146             via C<inc/Some/Plugin.pm>, and then fall back to searching other C<@INC> paths.
147              
148             C<[Some::Other::Plugin]> will B<also> be able to load from C<inc/>,
149             via C<inc/Dist/Zilla/Plugin/Some/Other/Plugin.pm>
150              
151             =head1 Ensuring dot-in-INC
152              
153             Its not sure when C<"."> in C<@INC> will actually go away, or which parts of the C<dzil>
154             ecosystem will be re-patched to retain this assumption.
155              
156             But the simplest thing that would work with changing the least amount of code would be
157             simply inserting
158              
159             [lib]
160             lib = .
161              
162             Early in your C<dist.ini>
163              
164             This will have a C<mostly> the same effect as retaining C<dot-in-INC> even in the
165             event you run on a newer Perl where that is removed by default.
166              
167             The differences however are subtle and maybe better depending on what you're doing
168              
169             =over 4
170              
171             =item * C<"."> will be prepended to C<@INC>, not appended.
172              
173             This means C<[=inc::Foo]> will actually hit C<inc/> first, not simply as an afterthought
174             if it isn't found in other paths in C<@INC>
175              
176             For instance, currently, I could create a lot of havoc by simply shipping a C<dzil> plugin with
177             the same name as somebody already is using for their private C<inc/> hacks, and then trip them
178             into installing it. Because currently, C<site beats "."> where authors intended to source
179             from C<"."> not C<site>
180              
181             =item * C<"."> will be absolutized to C<< $zilla->root >>
182              
183             As it stands, the C<"."> in C<@INC> is only ever C<".">, which means calling
184             C<chdir> between calls to C<require> effectively changes what C<@INC> means.
185              
186             Given that is the specific threat surface for that issue, it would be silly
187             to repeat that mistake, especially as when you write C<"."> you typically want to
188             imply "Where I am now" not "Wherever the code will be 30 seconds after now after
189             it C<chdir>s to random locations at the discretion of code I haven't even read"
190              
191             There's still some annoying scope for this absolutization going wrong,
192             due to C<Dist::Zilla> not L<< ensuring this path is fixed early on|https://github.com/rjbs/Dist-Zilla/issues/579 >>
193             but C<[lib]> fixes and absolutizes it as early as possible,
194             with the hope we'll know what you meant by C<cwd> before somebody can change C<cwd>
195              
196             ( And if that fails, it will fail spectacularly, not selectively work some of the
197             time if your stars align )
198              
199             =back
200              
201             =head1 Migrating from dot-in-INC code
202              
203             If you have existing code that relies on the C<.>-in-C<@INC> assumption,
204             migrating to use this plugin in way that would seem "proper" would play as follows:
205              
206             =over 4
207              
208             =item 1. Rename your plugins in C<inc/>
209              
210             All those packages called C<inc::Some::Plugin> become
211             C<Some::Plugin>
212              
213             =item 2. Replace your section lines
214              
215             C<inc> is no longer needed as part of the plugin, so
216             replacing all sections
217              
218             -[=inc::Some::Plugin]
219             +[=Some::Plugin]
220              
221             In line with step 1.
222              
223             =item 3. Add a C<[lib]> section before all your plugins
224              
225             And tell it to assume that C<inc/> is now in the load path.
226              
227             +[lib]
228             +lib = inc
229              
230             =back
231              
232             =head1 ATTRIBUTES
233              
234             =head2 C<lib>
235              
236             This attribute can be specified 1 or more times, each time specifying
237             a path which will be assumed to be a path relative to C<< $zilla->root >>
238              
239             Paths specified will be passed to L<< C<lib.pm>|lib >>C<< ->import >> in the
240             same order as they appear in your configuration, after absolutizing them.
241              
242             C<lib.pm> prepends the values to C<< @INC >> in a nature akin to
243              
244             unshift(@INC, @{ $lib })
245              
246             Which is functionally similar to:
247              
248             @INC = ( @{ $lib }, @INC )
249              
250             That is, retaining the specified order in C< @INC >.
251              
252             =head1 AUTHOR
253              
254             Kent Fredric <kentnl@cpan.org>
255              
256             =head1 COPYRIGHT AND LICENSE
257              
258             This software is copyright (c) 2017 by Kent Fredric <kentfredric@gmail.com>.
259              
260             This is free software; you can redistribute it and/or modify it under
261             the same terms as the Perl 5 programming language system itself.
262              
263             =cut