fix adding license to manifest
[p5sagit/Distar.git] / lib / Distar.pm
CommitLineData
42e08a83 1package Distar;
362ec4af 2use strict;
3use warnings FATAL => 'all';
42e08a83 4use base qw(Exporter);
ca3b3b8a 5use ExtUtils::MakeMaker ();
6use ExtUtils::MM ();
8aac77fc 7use File::Spec ();
42e08a83 8
2b085b99 9our $VERSION = '0.003000';
37e295d8 10$VERSION = eval $VERSION;
11
e076eedb 12my $MM_VER = eval $ExtUtils::MakeMaker::VERSION;
13
42e08a83 14our @EXPORT = qw(
be032607 15 author manifest_include readme_generator
42e08a83 16);
17
18sub import {
2852faf3 19 strict->import;
20 warnings->import(FATAL => 'all');
f5cc9f53 21 if (!(@MM::ISA == 1 && $MM::ISA[0] eq 'Distar::MM')) {
22 @Distar::MM::ISA = @MM::ISA;
23 @MM::ISA = qw(Distar::MM);
24 }
788b7f10 25 goto &Exporter::import;
42e08a83 26}
27
e076eedb 28sub author {
29 our $Author = shift;
30 $Author = [ $Author ]
31 if !ref $Author;
32}
42e08a83 33
34our @Manifest = (
35 'lib' => '.pm',
7b9318ce 36 'lib' => '.pod',
42e08a83 37 't' => '.t',
38 't/lib' => '.pm',
39 'xt' => '.t',
40 'xt/lib' => '.pm',
1d950b4a 41 '' => qr{[^/]*\.PL},
f1ef306e 42 '' => qr{Changes|MANIFEST|README|LICENSE|META\.yml},
42e08a83 43 'maint' => qr{[^.].*},
44);
45
46sub manifest_include {
47 push @Manifest, @_;
48}
49
6e83c113 50sub readme_generator {
f6286f60 51 die "readme_generator unsupported" if @_ && $_[0];
6e83c113 52}
53
42e08a83 54sub write_manifest_skip {
0fa73f76 55 my ($mm) = @_;
42e08a83 56 my @files = @Manifest;
57 my @parts;
58 while (my ($dir, $spec) = splice(@files, 0, 2)) {
59 my $re = ($dir ? $dir.'/' : '').
60 ((ref($spec) eq 'Regexp')
61 ? $spec
62 : !ref($spec)
63 ? ".*\Q${spec}\E"
a3e39afd 64 # print ref as well as stringification in case of overload ""
42e08a83 65 : die "spec must be string or regexp, was: ${spec} (${\ref $spec})");
66 push @parts, $re;
67 }
0fa73f76 68 my $dist_name = $mm->{DISTNAME};
69 my $include = join '|', map "${_}\$", @parts;
70 my $final = "^(?:\Q$dist_name\E-v?[0-9_.]+/|(?!$include))";
19916679 71 open my $skip, '>', 'MANIFEST.SKIP'
72 or die "can't open MANIFEST.SKIP: $!";
42e08a83 73 print $skip "${final}\n";
74 close $skip;
75}
76
ca3b3b8a 77{
78 package Distar::MM;
ca3b3b8a 79
80 sub new {
81 my ($class, $args) = @_;
4762e03a 82 my %test = %{$args->{test}||{}};
83 my $tests = $test{TESTS} || 't/*.t';
84 $tests !~ /\b\Q$_\E\b/ and $tests .= " $_"
85 for 'xt/*.t', 'xt/*/*.t';
86 $test{TESTS} = $tests;
ca3b3b8a 87 return $class->SUPER::new({
180e908e 88 LICENSE => 'perl_5',
53e1282f 89 MIN_PERL_VERSION => '5.006',
15f10a18 90 ($Distar::Author ? (
d0f7a429 91 AUTHOR => ($MM_VER >= 6.5702 ? $Distar::Author : join(', ', @$Distar::Author)),
92 ) : ()),
1f136c70 93 (exists $args->{ABSTRACT} ? () : (ABSTRACT_FROM => $args->{VERSION_FROM})),
4a4bb570 94 %$args,
4762e03a 95 test => \%test,
0a3fdb23 96 realclean => { FILES => (
97 ($args->{realclean}{FILES}||'')
98 . ' Distar/ MANIFEST.SKIP MANIFEST MANIFEST.bak'
99 ) },
ca3b3b8a 100 });
101 }
102
eddb1ce6 103 sub flush {
104 my $self = shift;
5371ff52 105 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
106 my $maniskip_tracked = !$?;
107
108 Distar::write_manifest_skip($self)
109 unless $maniskip_tracked;
eddb1ce6 110 $self->SUPER::flush(@_);
111 }
112
7efea54c 113 sub special_targets {
114 my $self = shift;
115 my $targets = $self->SUPER::special_targets(@_);
f57289e3 116 my $phony_targets = join ' ', qw(
117 preflight
7b418de8 118 check-version
5baee32c 119 check-manifest
b0780d0a 120 check-cpan-upload
f57289e3 121 releasetest
122 release
123 readmefile
124 distmanicheck
125 nextrelease
126 refresh
127 bump
128 bumpmajor
129 bumpminor
130 );
131 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
7efea54c 132 $targets;
133 }
134
42d0b436 135 sub init_dist {
136 my $self = shift;
137 my $pre_tar = $self->{TAR};
138 my $out = $self->SUPER::init_dist(@_);
139
140 my $tar = $self->{TAR};
141 my $gtar;
142 my $set_user;
143 my $version = `$tar --version`;
144 if ($version =~ /GNU tar/) {
145 $gtar = 1;
146 }
147 elsif (!$pre_tar && `gtar --version`) {
148 $tar = 'gtar';
149 $gtar = 1;
150 }
151 my $tarflags = $self->{TARFLAGS};
152 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
153 if ($flags =~ s/c// && $flags =~ s/f//) {
154 $tarflags = '--format=ustar -c'.$flags.'f';
155 if ($gtar) {
156 $tarflags = '--owner=0 --group=0 '.$tarflags;
157 $set_user = 1;
158 }
159 }
160 }
161
162 if (!$set_user) {
163 my $warn = '';
164 if ($> >= 2**21) {
165 $warn .= "uid ($>)";
166 }
167 if ($) >= 2**21) {
168 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
169 }
170 if ($warn) {
171 warn "$warn too large! Max is ".(2**21-1).".\n"
172 ."Dist creation will likely fail. Install GNU tar to work around.\n";
173 }
174 }
175
176 $self->{TAR} = $tar;
177 $self->{TARFLAGS} = $tarflags;
178
179 $out;
180 }
181
ee801c00 182 sub tarfile_target {
183 my $self = shift;
184 my $out = $self->SUPER::tarfile_target(@_);
185 my $verify = <<'END_FRAG';
186 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
187END_FRAG
188 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
189 $out;
190 }
191
ca3b3b8a 192 sub dist_test {
193 my $self = shift;
8ab5ea70 194
66a2ecde 195 my $include = '';
196 if (open my $fh, '<', 'maint/Makefile.include') {
197 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
198 $include =~ s/\n?\z/\n/;
199 }
b0401762 200
66a2ecde 201 my @bump_targets =
202 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
81d518f6 203
8aac77fc 204 my $distar = File::Spec->catdir(
205 File::Spec->catpath((File::Spec->splitpath(__FILE__))[0,1], ''),
206 File::Spec->updir,
207 );
208 my $helpers = File::Spec->catdir($distar, 'helpers');
209
c97878e5 210 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
211 my $authors = $self->{AUTHOR};
212 $_ = ref $_ ? $_ : [$_ || ()]
213 for $licenses, $authors;
214
66a2ecde 215 my %vars = (
8aac77fc 216 DISTAR => $self->quote_literal($distar),
217 HELPERS => $self->quote_literal($helpers),
a5b3931e 218 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR)/lib', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
190976f8 219 BRANCH => $self->{BRANCH} ||= 'master',
9b920c5c 220 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
b0780d0a 221 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
f0bbeff7 222 DISTTEST_MAKEFILE_PARAMS => '',
c97878e5 223 AUTHORS => $self->quote_literal(join(', ', @$authors)),
224 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
66a2ecde 225 );
226
f0bbeff7 227 my $dist_test = $self->SUPER::dist_test(@_);
228 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
229
66a2ecde 230 join('',
f0bbeff7 231 $dist_test,
66a2ecde 232 "\n\n# --- Distar section:\n\n",
233 (map "$_ = $vars{$_}\n", sort keys %vars),
234 <<'END',
81d518f6 235
b0780d0a 236preflight: check-version check-manifest check-cpan-upload
8aac77fc 237 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
7b418de8 238check-version:
8aac77fc 239 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
5baee32c 240check-manifest:
8aac77fc 241 $(ABSPERLRUN) $(HELPERS)/check-manifest
b0780d0a 242check-cpan-upload:
243 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
3e632431 244releasetest:
f0bbeff7 245 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
49beea48 246release: preflight
247 $(MAKE) releasetest
42e08a83 248 git commit -a -m "Release commit for $(VERSION)"
401ece0b 249 git tag v$(VERSION) -m "release v$(VERSION)"
49beea48 250 $(RM_RF) $(DISTVNAME)
251 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
263b723e 252 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
253pushrelease ::
254 $(NOECHO) $(NOOP)
255pushrelease$(FAKE_RELEASE) ::
65a1f7d9 256 cpan-upload $(DISTVNAME).tar$(SUFFIX)
2c636792 257 git push origin v$(VERSION) HEAD
c97878e5 258distdir: readmefile licensefile
75f8311c 259readmefile: create_distdir
5c5deb0a 260 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
f6286f60 261$(DISTVNAME)/README: $(VERSION_FROM)
262 $(NOECHO) $(MKPATH) $(DISTVNAME)
263 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
8aac77fc 264 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
c97878e5 265distsignature: readmefile licensefile
266licensefile: create_distdir
267 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE
268$(DISTVNAME)/LICENSE: Makefile.PL
269 $(NOECHO) $(MKPATH) $(DISTVNAME)
270 $(ABSPERLRUN) $(HELPERS)/generate-license $(AUTHORS) $(LICENSES) >$(DISTVNAME)/LICENSE
c97878e5 271 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE
de048fa8 272disttest: distmanicheck
792c9e91 273distmanicheck: create_distdir
274 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
e7a78651 275nextrelease:
8aac77fc 276 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
0edb27b8 277refresh:
41e593ee 278 cd $(DISTAR) && git pull || $(TRUE)
e9f66489 279 $(RM_F) $(FIRST_MAKEFILE)
0edb27b8 280 $(REMAKE)
8ab5ea70 281END
66a2ecde 282 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
283%s:
8aac77fc 284 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
66a2ecde 285 $(RM_F) $(FIRST_MAKEFILE)
286 $(REMAKE)
42e08a83 287END
66a2ecde 288 $include,
289 "\n",
290 );
42e08a83 291 }
292}
293
42e08a83 2941;
edb4539a 295__END__
296
297=head1 NAME
298
299Distar - Additions to ExtUtils::MakeMaker for dist authors
300
301=head1 SYNOPSIS
302
303F<Makefile.PL>:
304
305 use ExtUtils::MakeMaker;
83e12da3 306 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
edb4539a 307
308 WriteMakefile(...);
309
310F<maint/Makefile.PL.include>:
311
312 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
313 use lib 'Distar/lib';
314 use Distar 0.001;
315
316 author 'A. U. Thor <author@cpan.org>';
317
318 manifest_include t => 'test-helper.pl';
319 manifest_include corpus => '.txt';
320
321make commmands:
322
323 $ perl Makefile.PL
324 $ make bump # bump version
325 $ make bump V=2.000000 # bump to specific version
326 $ make bumpminor # bump minor version component
327 $ make bumpmajor # bump major version component
328 $ make nextrelease # add version heading to Changes file
329 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
330 $ make preflight # check that repo and file state is release ready
83e12da3 331 $ make release # check releasetest and preflight, commits and tags,
332 # builds and uploads to CPAN, and pushes commits and
333 # tag
334 $ make release FAKE_RELEASE=1
335 # builds a release INCLUDING committing and tagging,
336 # but does not upload to cpan or push anything to git
edb4539a 337
338=head1 DESCRIPTION
339
340L<ExtUtils::MakeMaker> works well enough as development tool for
341builting and testing, but using it to release is annoying and error prone.
342Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
343author tool. This includes extra commands for releasing and safety checks, and
344automatic generation of some files. It doesn't require any non-core modules and
345is compatible with old versions of perl.
346
347=head1 FUNCTIONS
348
349=head2 author( $author )
350
351Set the author to include in generated META files. Can be a single entry, or
352an arrayref.
353
354=head2 manifest_include( $dir, $pattern )
355
356Add a pattern to include files in the MANIFEST file, and thus in the generated
357dist files.
358
359The pattern can be either a regex, or a path suffix. It will be applied to the
360full path past the directory specified.
361
362The default files that are always included are: F<.pm> and F<.pod> files in
363F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
364F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
365the dist root, and all files in F<maint>.
366
367=head1 AUTOGENERATED FILES
368
369=over 4
370
371=item F<MANIFEST.SKIP>
372
373The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
374explicitly allowed via C<manifest_include> or the included defaults. It will be
375created (or updated) at C<perl Makefile.PL> time.
376
377=item F<README>
378
379The F<README> file will be generated at dist generation time, inside the built
380dist. It will be generated using C<pod2text> on the main module.
381
382If a F<README> file exists in the repo, it will be used directly instead of
383generating the file.
384
385=back
386
387=head1 MAKE COMMMANDS
388
389=head2 test
390
391test will be adjusted to include F<xt/> tests by default. This will only apply
392for authors, not users installing from CPAN.
393
394=head2 release
395
396Releases the dist. Before releasing, checks will be done on the dist using the
397C<preflight> and C<releasetest> commands.
398
399Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
400It will also create a git tag for the release, and push the tag and branch.
401
83e12da3 402=head3 FAKE_RELEASE
263b723e 403
404If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
405pushing to git. A release commit will still be created and tagged locally.
406
edb4539a 407=head2 preflight
408
409Performs a number of checks on the files and repository, ensuring it is in a
410sane state to do a release. The checks are:
411
412=over 4
413
414=item * All version numbers match
415
416=item * The F<MANIFEST> file is up to date
417
418=item * The branch is correct
419
420=item * There is no existing tag for the version
421
422=item * There are no unmerged upstream changes
423
424=item * There are no outstanding local changes
425
426=item * There is an appropriate staged Changes heading
427
428=item * cpan-upload is available
429
430=back
431
432=head2 releasetest
433
434Test the dist preparing for a release. This generates a dist dir and runs the
435tests from inside it. This ensures all appropriate files are included inside
436the dist. C<RELEASE_TESTING> will be set in the environment.
437
438=head2 nextrelease
439
440Adds an appropriate changelog heading for the release, and prompts to stage the
441change.
442
443=head2 bump
444
445Bumps the version number. This will try to preserve the length and format of
83e12da3 446the version number. The least significant digit will be incremented. Versions
447with underscores will preserve the underscore in the same position.
edb4539a 448
449Optionally accepts a C<V> option to set the version to a specific value.
450
451The version changes will automatically be committed. Unstaged modifications to
452the files will be left untouched.
453
83e12da3 454=head3 V
455
456The V option will be passed along to the version bumping script. It can accept
457a space separated list of options, including an explicit version number.
458
459Options:
460
461=over 4
462
463=item --force
464
465Updates version numbers even if they do not match the current expected version
466number.
467
468=item --stable
469
470Attempts to convert the updated version to a stable version, removing any
471underscore.
472
473=item --alpha
474
475Attempts to convert the updated version to an alpha version, adding an
476underscore in an appropriate place.
477
478=back
479
edb4539a 480=head2 bumpminor
481
482Like bump, but increments the minor segment of the version. This will treat
483numeric versions as x.yyyzzz format, incrementing the yyy segment.
484
485=head2 bumpmajor
486
487Like bumpminor, but bumping the major segment.
488
489=head2 refresh
490
491Updates Distar and re-runs C<perl Makefile.PL>
492
493=head1 SUPPORT
494
495IRC: #web-simple on irc.perl.org
496
497Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
498
499Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
500
501=head1 AUTHOR
502
503mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
504
505=head1 CONTRIBUTORS
506
507haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
508
83e12da3 509ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
edb4539a 510
511frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
512
513Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
514
515=head1 COPYRIGHT
516
517Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
518as listed above.
519
520=head1 LICENSE
521
522This library is free software and may be distributed under the same terms
523as perl itself. See L<http://dev.perl.org/licenses/>.
524
525=cut