File Coverage

lib/Dist/Zilla/App/Command/bakeini.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1 1     1   664 use 5.006;
  1         2  
  1         32  
2 1     1   3 use strict;
  1         2  
  1         24  
3 1     1   4 use warnings;
  1         7  
  1         62  
4              
5             package Dist::Zilla::App::Command::bakeini;
6              
7             our $VERSION = '0.002000';
8              
9             # ABSTRACT: bake dist.ini to not need the bundles.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 1     1   280 use Dist::Zilla::App '-command';
  0            
  0            
14              
15             ## no critic (NamingConventions::ProhibitAmbiguousNames)
16             sub abstract { return 'bake dist.ini from dist.ini.meta' }
17              
18             sub opt_spec {
19             ## no critic (RegularExpressions::ProhibitFixedStringMatches,RegularExpressions::RequireLineBoundaryMatching)
20              
21             return (
22             [ 'root=s' => 'the root of the dist; defaults to .' ],
23             [
24             'comments=s' => 'include all, authordeps or none comments; defaults to all',
25             {
26             default => 'all',
27             regex => qr/\A(?:all|authordeps|none)\z/sx,
28             },
29             ],
30             );
31             }
32              
33             sub validate_args {
34             my ( undef, $opt, undef ) = @_;
35             require Path::Tiny;
36              
37             my $root = $opt->root;
38             $root = Path::Tiny::path($root) if defined $root;
39             $root = Path::Tiny::cwd() if not defined $root;
40              
41             return if $root->child('dist.ini.meta')->is_file;
42             require Carp;
43             Carp::croak("dist.ini.meta not found in $root");
44             }
45              
46             sub execute {
47             my ( undef, $opt, undef ) = @_;
48             require Path::Tiny;
49              
50             my $root = $opt->root;
51             $root = Path::Tiny::path($root) if defined $root;
52             $root = Path::Tiny::cwd() if not defined $root;
53              
54             my $file = $root->child('dist.ini.meta');
55              
56             require Dist::Zilla::Util::ExpandINI;
57             Dist::Zilla::Util::ExpandINI->VERSION('0.003000');
58             my $state = Dist::Zilla::Util::ExpandINI->new( comments => $opt->comments );
59             $state->_load_file($file);
60             $state->_expand();
61             my $out = $root->child('dist.ini')->openw_utf8;
62             my $return = print {$out} "; This file is generated from dist.ini.meta by dzil bakeini.\n",
63             "; Edit that file or the bundles contained within for long-term changes.\n";
64              
65             if ( not $return ) {
66             require Carp;
67             Carp::croak("Error writing to dist.ini! $? $! $@");
68             }
69             $state->_store_handle($out);
70             return;
71             }
72              
73             1;
74              
75             __END__
76              
77             =pod
78              
79             =encoding UTF-8
80              
81             =head1 NAME
82              
83             Dist::Zilla::App::Command::bakeini - bake dist.ini to not need the bundles.
84              
85             =head1 VERSION
86              
87             version 0.002000
88              
89             =head1 SYNOPSIS
90              
91             cp dist.ini dist.ini.meta
92             dzil bakeini
93              
94             less dist.ini # no more bundles :D
95              
96             =head1 DESCRIPTION
97              
98             =head2 The Quibbles
99              
100             There's several long standing point of contention surrounding the use of bundles.
101              
102             A few poignant ones that bother me are:
103              
104             =over 4
105              
106             =item * Bundles change over time and configuration parameters can change in validity
107              
108             For example, I might add a requirement in a later incarnation of a bundle that a given parameter be specified. But that creates
109             a confusing backwards compatibility problem for people who merely want to check out and build the code.
110              
111             =item * Some contributors tend not to like dealing with bundles due to bundle complexity
112              
113             Bundles often declare far more dependencies than contributors B<need> to build one specific distribution, and the bundle
114             obscures the visibility of what plugins are being used.
115              
116             This also manifests as a difficulty to work around problems produced by bundles such as bundles C<use>-ing broken modules,
117             which is not straight forward to iron out with the C<@Filter> bundle.
118              
119             C<@Filter> is also complicated for end users who are not familiar with C<dzil> to use, and C<@Filter> also lacks abilities to
120             re-order plugins if that is necessary to avoid a bug.
121              
122             Additionally, routing configuration to a single plugin within a bundle can be confusing with messy syntax, especially if the
123             bundle doesn't C<do> C<ConfigSlicer> or something like that.
124              
125             And the effort of learning and using those tools is high if all you want to do is I<temporarily> change a build setting for the
126             point of local use or local testing.
127              
128             =back
129              
130             =head2 The Benefits and Method
131              
132             So this command attempts to avoid these problems by separating the bundle from its configuration until configuration is wanted
133             updated.
134              
135             This means C<Dist::Zilla> based distributions B<DON'T> have their build configuration radically changed simply because somebody
136             upgraded a bundle, and the configuration is I<MORE> local to the distribution instead of being more global.
137              
138             This means bundle specific configuration demands B<ONLY> need to be satisfied during the baking process, but B<NOT> every
139             subsequent build, and are thus B<NOT> prone to causing a sea of unusable C<dist.ini>s if a bundle gets changed.
140              
141             =head2 The Downsides
142              
143             The biggest known downside of this approach at present is with much more advanced bundle usage.
144              
145             Because the bundle itself is being taken out of the loop, that means C<dist.ini> will B<NOT> be able to automatically have new
146             plugins added to it in response to changes in the tree. C<dzil bakeini> will have to be run subsequently to take tree changes
147             into consideration and emit updated configuration.
148              
149             And because the bundle itself is being taken out of the loop, that means C<ENV> based controls in bundles will be bound at the
150             time of calling C<dzil bakeini>, which means if you're like C<@ETHER> and have an "Airplane mode", then:
151              
152             AIRPLANE=1 dzil build
153              
154             Won't work on a baked C<dist.ini>, and you will instead need:
155              
156             AIRPLANE=1 dzil bakeini && dzil build
157              
158             Though, that could be beneficial too depending on how you use it.
159              
160             # Get on the plane
161             AIRPLANE=1 dzil bakeini
162              
163             # dzil runs everything in airplane mode now
164             dzil build
165              
166             # Get off the plane
167             dzil bakeini
168              
169             # dzil runs normally
170             dzil build
171              
172             =head1 TIPS AND TRICKS
173              
174             =head2 C<bakeini> dependent behavior in a bundle
175              
176             If you want to codify some unique behavior to how your bundle performs under C<dzil bakeini>, ( for instance, to change the C<prereqs> advertised as being C<develop.requires> )
177              
178             Here, L<< C<::Util::CurrentCmd>|Dist::Zilla::Util::CurrentCmd >> comes in handy:
179              
180             use Dist::Zilla::Util::CurrentCmd qw(current_cmd);
181              
182             my @config;
183             ...
184             if ( 'bakeini' eq ( current_cmd() || '' ) ) {
185             push @config, [ 'baked dist prereqs', 'Dist::Zilla::Plugin::Prereqs', { 'Foo::Bar' => 2 }];
186             } else {
187             ...
188             }
189              
190             =head1 PARAMETERS
191              
192             =head2 C<--comments>
193              
194             C<--comments> allows to control which comments are copied into the target C<dist.ini>
195              
196             =head3 C<all>
197              
198             B<DEFAULT> Inject all comments regardless
199              
200             =head3 C<authordeps>
201              
202             Inject all comments that are C<Dist::Zilla> C<AuthorDeps>
203              
204             =head3 C<none>
205              
206             Inject no comments.
207              
208             =head1 AUTHOR
209              
210             Kent Fredric <kentnl@cpan.org>
211              
212             =head1 COPYRIGHT AND LICENSE
213              
214             This software is copyright (c) 2014 by Kent Fredric <kentfredric@gmail.com>.
215              
216             This is free software; you can redistribute it and/or modify it under
217             the same terms as the Perl 5 programming language system itself.
218              
219             =cut