File Coverage

blib/lib/Dist/Inkt.pm
Criterion Covered Total %
statement 29 152 19.0
branch 0 28 0.0
condition 0 39 0.0
subroutine 10 30 33.3
pod 0 11 0.0
total 39 260 15.0


line stmt bran cond sub pod time code
1             package Dist::Inkt;
2              
3 1     1   653 use 5.010001;
  1         4  
4              
5             our $AUTHORITY = 'cpan:TOBYINK';
6             our $VERSION = '0.024';
7              
8 1     1   478 use Moose;
  1         383208  
  1         8  
9 1     1   7653 use Module::Metadata;
  1         5835  
  1         33  
10 1     1   434 use List::MoreUtils qw(uniq);
  1         6301  
  1         10  
11 1     1   1101 use Types::Standard -types;
  1         50098  
  1         12  
12 1     1   4642 use Types::Path::Tiny -types;
  1         27716  
  1         12  
13 1     1   957 use Path::Tiny 'path';
  1         2  
  1         48  
14 1     1   485 use Path::Iterator::Rule;
  1         8059  
  1         30  
15 1     1   7 use Module::Runtime qw(use_package_optimistically);
  1         1  
  1         8  
16 1     1   434 use namespace::autoclean;
  1         6071  
  1         4  
17              
18             sub builder_id {
19 0     0 0   my $real_class = shift->_real_class;
20 0           sprintf('%s version %s', $real_class, $real_class->VERSION);
21             }
22              
23             sub _real_class {
24 0     0     my $self = shift;
25 0           my ($real_class) = grep !/__ANON__/, Moose::Util::find_meta($self)->class_precedence_list;
26 0           $real_class;
27             }
28              
29             has name => (
30             is => 'ro',
31             isa => Str,
32             required => 1,
33             );
34              
35             has lead_module => (
36             is => 'ro',
37             isa => Str,
38             lazy => 1,
39             builder => '_build_lead_module',
40             );
41              
42             sub _build_lead_module
43             {
44 0     0     my $self = shift;
45 0           (my $name = $self->name) =~ s/-/::/g;
46 0           return $name;
47             }
48              
49             has version => (
50             is => 'ro',
51             isa => Str,
52             lazy => 1,
53             builder => '_build_version',
54             );
55              
56             sub _build_version
57             {
58 0     0     my $self = shift;
59 0           my $mm = 'Module::Metadata'->new_from_module(
60             $self->lead_module,
61             inc => [$self->sourcefile('lib')],
62             );
63 0           return $mm->{version}{original};
64             }
65              
66             has rootdir => (
67             is => 'ro',
68             isa => AbsDir,
69             required => 1,
70             coerce => 1,
71             handles => {
72             sourcefile => 'child',
73             },
74             );
75              
76             has targetdir_pattern => (
77             is => 'ro',
78             isa => Str,
79             lazy => 1,
80             builder => '_build_targetdir_pattern',
81             );
82              
83             sub _build_targetdir_pattern {
84 0     0     '%(name)s-%(version)s'
85             }
86              
87             has targetdir => (
88             is => 'ro',
89             isa => Path,
90             lazy => 1,
91             coerce => 1,
92             builder => '_build_targetdir',
93             handles => {
94             targetfile => 'child',
95             cleartarget => 'remove_tree',
96             },
97             );
98              
99             sub _build_targetdir
100             {
101 0     0     my $self = shift;
102            
103 0           require Text::sprintfn;
104 0           my $name = Text::sprintfn::sprintfn(
105             $self->targetdir_pattern,
106             {
107             name => $self->name,
108             version => $self->version,
109             },
110             );
111            
112 0           $self->rootdir->child($name);
113             }
114              
115             has metadata => (
116             is => 'ro',
117             isa => InstanceOf['CPAN::Meta'],
118             lazy => 1,
119             builder => '_build_metadata',
120             );
121              
122             sub _build_metadata
123             {
124 0     0     require CPAN::Meta;
125 0           my $self = shift;
126 0           my $meta = 'CPAN::Meta'->new({
127             name => $self->name,
128             version => $self->version,
129             no_index => { directory => [qw/ eg examples inc t xt /] },
130             generated_by => $self->builder_id,
131             dynamic_config => 0,
132             });
133 0           for (qw/ license author /) {
134 0 0 0       $meta->{$_} = [] if @{$meta->{$_}}==1 && $meta->{$_}[0] eq 'unknown';
  0            
135             }
136 0 0         if ($self->sourcefile('meta/META.PL')->exists)
137             {
138 0           local $_ = $meta;
139 0           my $filename = $self->sourcefile('meta/META.PL')->absolute->stringify;
140 0           do($filename);
141             }
142 0           return $meta;
143             }
144              
145             has project_uri => (
146             is => 'ro',
147             isa => Str,
148             lazy => 1,
149             builder => '_build_project_uri',
150             );
151              
152             sub _build_project_uri
153             {
154 0     0     my $self = shift;
155 0           sprintf('http://purl.org/NET/cpan-uri/dist/%s/project', $self->name);
156             }
157              
158             has targets => (
159             is => 'ro',
160             isa => ArrayRef[Str],
161             builder => '_build_targets',
162             );
163              
164 0     0     sub _build_targets { [] }
165              
166             has rights_for_generated_files => (
167             is => 'ro',
168             isa => HashRef[ArrayRef],
169             default => sub {
170             +{
171             COPYRIGHT => [ 'None' => 'public-domain' ],
172             };
173             },
174             );
175              
176       0     sub _inherited_rights {}
177              
178             sub new_from_ini
179             {
180 0     0 0   my $self = shift;
181 0           my $ini = shift;
182 0           my (%args) = @_;
183            
184 0 0         if (defined $ini)
185             {
186 0           $ini = File->assert_coerce($ini);
187             }
188             else
189             {
190 0           require Cwd;
191 0           $ini = path(Cwd::cwd)->child('dist.ini');
192 0 0         $ini->exists or confess("Could not find dist.ini; bailing out");
193             }
194            
195 0           my @lines = grep /^;;/, $ini->lines_utf8;
196 0           chomp @lines;
197            
198             my %config = map {
199 0           s/(?:^;;\s*)|(?:\s*$)//g;
  0            
200 0           my ($key, $value) = split /\s*=\s*/, $_, 2;
201 0           $key => scalar(eval($value));
202             } @lines;
203            
204 0   0       my $class = delete($config{class}) || 'Dist::Inkt::Profile::Simple';
205            
206 0   0       $config{rootdir} ||= $ini->dirname;
207            
208 0           use_package_optimistically($class)->new(%config, %args);
209             }
210              
211             sub BUILD
212             {
213 0     0 0   my $self = shift;
214 0 0         return if $self->{_already_built}++;
215            
216 0           $self->PopulateModel;
217 0           $self->PopulateMetadata;
218            
219 0           my $die = 0;
220            
221 0           my $l = $self->metadata->{license};
222 0 0 0       unless ($l and ref($l) eq 'ARRAY' and @$l and $l->[0] ne 'unknown')
      0        
      0        
223             {
224 0           $self->log("ERROR: licence unknown!");
225 0           $die++;
226             }
227            
228 0           my $a = $self->metadata->{author};
229 0 0 0       unless ($a and ref($a) eq 'ARRAY' and @$a and $a->[0] ne 'unknown')
      0        
      0        
230             {
231 0           $self->log("ERROR: author unknown!");
232 0           $die++;
233             }
234            
235 0           my $b = $self->metadata->{abstract};
236 0 0 0       unless (defined($b) and $b ne 'unknown')
237             {
238 0           $self->log("ERROR: abstract unknown!");
239 0           $die++;
240             }
241            
242 0 0         die "Incomplete metadata; stopped" if $die;
243             }
244              
245       0 0   sub PopulateModel {}
246       0 0   sub PopulateMetadata {}
247              
248             sub BuildTargets
249             {
250 0     0 0   my $self = shift;
251            
252 0           $self->cleartarget;
253 0           $self->targetdir->mkpath;
254            
255 0 0         $self->Build_Files if $self->DOES('Dist::Inkt::Role::CopyFiles');
256            
257 0           for my $target (uniq @{ $self->targets })
  0            
258             {
259 0 0 0       next if $self->DOES('Dist::Inkt::Role::CopyFiles') && $target eq 'Files';
260            
261 0           my $method = "Build_$target";
262 0           $self->$method;
263             }
264             }
265              
266             sub BuildManifest
267             {
268 0     0 0   my $self = shift;
269            
270 0           my $file = $self->targetfile('MANIFEST');
271 0           $self->log("Writing $file");
272 0   0       $self->rights_for_generated_files->{'MANIFEST'} ||= [
273             'None', 'public-domain'
274             ];
275            
276 0           my $rule = 'Path::Iterator::Rule'->new->file;
277 0           my $root = $self->targetdir;
278 0           my @files = map { path($_)->relative($root) } $rule->all($root);
  0            
279            
280 0           $file->spew(map "$_\n", sort 'MANIFEST', @files);
281             }
282              
283             sub BuildTarball
284             {
285 0     0 0   my $self = shift;
286 0   0       my $file = path($_[0] || sprintf('%s.tar.gz', $self->targetdir));
287 0           $self->log("Writing $file");
288            
289 0           require Archive::Tar;
290 0           my $tar = 'Archive::Tar'->new;
291            
292 0           my $rule = 'Path::Iterator::Rule'->new->file;
293 0           my $root = $self->targetdir;
294 0           my $pfx = $root->basename;
295 0           for ($rule->all($root))
296             {
297 0           my $abs = path($_);
298 0           $tar->add_files($abs);
299 0           $tar->rename(substr("$abs", 1), "$pfx/".$abs->relative($root));
300             }
301            
302 0           $tar->write($file, Archive::Tar::COMPRESS_GZIP());
303             }
304              
305             has should_compress => (
306             is => 'ro',
307             isa => Bool,
308             default => sub { !$ENV{PERL_DIST_INKT_NOTARBALL} },
309             );
310              
311             sub BuildAll
312             {
313 0     0 0   my $self = shift;
314 0           $self->BuildTargets;
315 0           $self->BuildManifest;
316 0 0         if ($self->should_compress) {
317 0           $self->BuildTarball;
318 0           $self->cleartarget;
319             }
320             }
321              
322             sub BuildTravisYml
323             {
324 0     0 0   my $self = shift;
325            
326 0           $self->log("Generating .travis.yml");
327 0           my $yml = $self->sourcefile(".travis.yml")->openw;
328            
329 0   0       my $perl_ver = $self->metadata->{prereqs}{runtime}{requires}{perl} || '5.014';
330            
331 0           print {$yml} "language: perl\n";
  0            
332 0           print {$yml} "perl:\n";
  0            
333 0           for my $v (8, 10, 12, 14, 16, 18, 20)
334             {
335 0           my $formatted = sprintf("5.%03d000", $v);
336 0 0         $formatted = '5.008001' if $formatted eq '5.008000';
337            
338 0 0         if ($formatted ge $perl_ver)
339             {
340 0           print {$yml} " - \"5.$v\"\n";
  0            
341             }
342             }
343            
344 0           my $class = $self->_real_class;
345            
346             ## no Test::Tabs
347            
348 0           print {$yml} <<"TAIL";
  0            
349             matrix:
350             include:
351             - perl: 5.18.2
352             env: COVERAGE=1
353             before_install:
354             - export DIST_INKT_PROFILE="$class"
355             - git clone git://github.com/tobyink/perl-travis-helper
356             - source perl-travis-helper/init
357             - build-perl
358             - perl -V
359             - build-dist
360             - cd \$BUILD_DIR
361             install:
362             - cpan-install --toolchain
363             - cpan-install --deps
364             - cpan-install --coverage
365             before_script:
366             - coverage-setup
367             script:
368             - prove -l \$(test-dirs)
369             after_success:
370             - coverage-report
371              
372             TAIL
373              
374             ## use Test::Tabs
375            
376 0           return;
377             }
378              
379             sub log
380             {
381 0     0 0   my $self = shift;
382 0           my ($fmt, @args) = @_;
383 0           printf STDERR "$fmt\n", @args;
384             }
385              
386             1;
387              
388             __END__
389              
390             =pod
391              
392             =encoding utf-8
393              
394             =for stopwords gzipped tarball
395              
396             =head1 NAME
397              
398             Dist::Inkt - yet another distribution builder
399              
400             =head1 STATUS
401              
402             Experimental.
403              
404             =head1 DESCRIPTION
405              
406             L<Dist::Zilla> didn't have the prerequisite amount of crazy for me, so
407             I wrote this instead.
408              
409             Dist::Inkt itself does virtually nothing; it creates an empty directory,
410             generates a MANIFEST file, and then wraps it all up into a gzipped
411             tarball. But it provides various hooks along the way for subclasses
412             to grab hold of. So the general idea is that you write a subclass of
413             Dist::Inkt, which consumes various Moose::Roles to do the actual work
414             of populating the distribution with files.
415              
416             As such, Dist::Inkt is not so much a distribution builder, as it is a
417             framework for writing your own distribution builder.
418              
419             Several roles of varying utility are bundled with Dist::Inkt, as is
420             L<Dist::Inkt::Profile::Simple>, a subclass of Dist::Inkt which consumes
421             most of these roles.
422              
423             =head1 COMPANIONS
424              
425             Dist::Inkt does just one thing - building the tarball from some
426             checkout of the repo.
427              
428             Although roles could theoretically be written for other tasks, out of
429             the box, Dist::Inkt doesn't do any of the following:
430              
431             =over
432              
433             =item B<< Minting new distributions >>
434              
435             I'm writing a separate tool, L<Dist::Inktly::Minty> for that.
436              
437             =item B<< Test suite running >>
438              
439             Use L<App::Prove> or L<App::ForkProve>.
440              
441             =item B<< CPAN Uploading >>
442              
443             Use L<CPAN::Uploader>.
444              
445             =item B<< Changing the version number across many files >>
446              
447             Use L<Perl::Version>.
448              
449             =item B<< Integration with version control tools >>
450              
451             Just use C<hg> or C<svn> or C<git> of whatever as you normally would.
452             None of the files generated by Dist::Inkt should probably be checked
453             into your repo.
454              
455             =back
456              
457             =head1 BUGS
458              
459             Please report any bugs to
460             L<http://rt.cpan.org/Dist/Display.html?Queue=Dist-Inkt>.
461              
462             =head1 SEE ALSO
463              
464             If you are not me, then you may well want one of these instead:
465              
466             =over
467              
468             =item *
469              
470             L<Dist::Zilla>
471              
472             =item *
473              
474             L<Dist::Milla>
475              
476             =item *
477              
478             L<Minilla>
479              
480             =back
481              
482             Various extensions for Dist::Inkt:
483              
484             =over
485              
486             =item *
487              
488             L<Dist::Inkt::DOAP>
489              
490             =item *
491              
492             L<Dist::Inkt::Profile::TOBYINK>
493              
494             =back
495              
496             =head1 AUTHOR
497              
498             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
499              
500             =head1 COPYRIGHT AND LICENCE
501              
502             This software is copyright (c) 2013-2014 by Toby Inkster.
503              
504             This is free software; you can redistribute it and/or modify it under
505             the same terms as the Perl 5 programming language system itself.
506              
507             =head1 DISCLAIMER OF WARRANTIES
508              
509             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
510             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
511             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
512