3 use warnings FATAL => 'all';
5 use ExtUtils::MakeMaker ();
9 our $VERSION = '0.003000';
10 $VERSION = eval $VERSION;
12 my $MM_VER = eval $ExtUtils::MakeMaker::VERSION;
15 author manifest_include readme_generator
20 warnings->import(FATAL => 'all');
21 if (!(@MM::ISA == 1 && $MM::ISA[0] eq 'Distar::MM')) {
22 @Distar::MM::ISA = @MM::ISA;
23 @MM::ISA = qw(Distar::MM);
25 goto &Exporter::import;
42 '' => qr{Changes|MANIFEST|README|LICENSE|META\.yml},
43 'maint' => qr{[^.].*},
46 sub manifest_include {
50 sub readme_generator {
51 die "readme_generator unsupported" if @_ && $_[0];
54 sub write_manifest_skip {
56 my @files = @Manifest;
58 while (my ($dir, $spec) = splice(@files, 0, 2)) {
59 my $re = ($dir ? $dir.'/' : '').
60 ((ref($spec) eq 'Regexp')
64 # print ref as well as stringification in case of overload ""
65 : die "spec must be string or regexp, was: ${spec} (${\ref $spec})");
68 my $dist_name = $mm->{DISTNAME};
69 my $include = join '|', map "${_}\$", @parts;
70 my $final = "^(?:\Q$dist_name\E-v?[0-9_.]+/|(?!$include))";
71 open my $skip, '>', 'MANIFEST.SKIP'
72 or die "can't open MANIFEST.SKIP: $!";
73 print $skip "${final}\n";
81 my ($class, $args) = @_;
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;
87 return $class->SUPER::new({
89 MIN_PERL_VERSION => '5.006',
91 AUTHOR => ($MM_VER >= 6.5702 ? $Distar::Author : join(', ', @$Distar::Author)),
93 (exists $args->{ABSTRACT} ? () : (ABSTRACT_FROM => $args->{VERSION_FROM})),
96 realclean => { FILES => (
97 ($args->{realclean}{FILES}||'')
98 . ' Distar/ MANIFEST.SKIP MANIFEST MANIFEST.bak'
105 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
106 my $maniskip_tracked = !$?;
108 Distar::write_manifest_skip($self)
109 unless $maniskip_tracked;
110 $self->SUPER::flush(@_);
113 sub special_targets {
115 my $targets = $self->SUPER::special_targets(@_);
116 my $phony_targets = join ' ', qw(
131 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
137 my $pre_tar = $self->{TAR};
138 my $out = $self->SUPER::init_dist(@_);
140 my $tar = $self->{TAR};
143 my $version = `$tar --version`;
144 if ($version =~ /GNU tar/) {
147 elsif (!$pre_tar && `gtar --version`) {
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';
156 $tarflags = '--owner=0 --group=0 '.$tarflags;
168 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
171 warn "$warn too large! Max is ".(2**21-1).".\n"
172 ."Dist creation will likely fail. Install GNU tar to work around.\n";
177 $self->{TARFLAGS} = $tarflags;
184 my $out = $self->SUPER::tarfile_target(@_);
185 my $verify = <<'END_FRAG';
186 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
188 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
196 if (open my $fh, '<', 'maint/Makefile.include') {
197 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
198 $include =~ s/\n?\z/\n/;
202 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
204 my $distar_lib = File::Basename::dirname(__FILE__);
205 my $helpers = File::Spec->catdir($distar_lib, File::Spec->updir, 'helpers');
207 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
208 my $authors = $self->{AUTHOR};
209 $_ = ref $_ ? $_ : [$_ || ()]
210 for $licenses, $authors;
213 DISTAR_LIB => $self->quote_literal($distar_lib),
214 HELPERS => $self->quote_literal($helpers),
215 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR_LIB)', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
216 BRANCH => $self->{BRANCH} ||= 'master',
217 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
218 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
219 DISTTEST_MAKEFILE_PARAMS => '',
220 AUTHORS => $self->quote_literal(join(', ', @$authors)),
221 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
222 GET_CHANGELOG => '$(ABSPERLRUN) $(HELPERS)/get-changelog $(VERSION) $(CHANGELOG)',
224 -e File::Spec->catdir($distar_lib, File::Spec->updir, '.git')
225 ? 'git -C $(DISTAR_LIB) pull'
226 : '$(ECHO) "Distar code is not in a git repo, unable to update!"'
230 my $dist_test = $self->SUPER::dist_test(@_);
231 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
235 "\n\n# --- Distar section:\n\n",
236 (map "$_ = $vars{$_}\n", sort keys %vars),
239 preflight: check-version check-manifest check-cpan-upload
240 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
242 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
244 $(ABSPERLRUN) $(HELPERS)/check-manifest
246 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
248 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
251 $(GET_CHANGELOG) -p"Release commit for $(VERSION)" | git commit -a -F -
252 $(GET_CHANGELOG) -p"release v$(VERSION)" | git tag -a -F - "v$(VERSION)"
253 $(RM_RF) $(DISTVNAME)
254 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
255 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
258 pushrelease$(FAKE_RELEASE) ::
259 cpan-upload $(DISTVNAME).tar$(SUFFIX)
260 git push origin v$(VERSION) HEAD
261 distdir: readmefile licensefile
262 readmefile: create_distdir
263 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
264 $(DISTVNAME)/README: $(VERSION_FROM)
265 $(NOECHO) $(MKPATH) $(DISTVNAME)
266 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
267 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
268 distsignature: readmefile licensefile
269 licensefile: create_distdir
270 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE
271 $(DISTVNAME)/LICENSE: Makefile.PL
272 $(NOECHO) $(MKPATH) $(DISTVNAME)
273 $(ABSPERLRUN) $(HELPERS)/generate-license $(AUTHORS) $(LICENSES) >$(DISTVNAME)/LICENSE
274 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE
275 disttest: distmanicheck
276 distmanicheck: create_distdir
277 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
279 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
282 $(RM_F) $(FIRST_MAKEFILE)
285 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
287 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
288 $(RM_F) $(FIRST_MAKEFILE)
302 Distar - Additions to ExtUtils::MakeMaker for dist authors
308 use ExtUtils::MakeMaker;
309 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
313 F<maint/Makefile.PL.include>:
315 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
316 use lib 'Distar/lib';
319 author 'A. U. Thor <author@cpan.org>';
321 manifest_include t => 'test-helper.pl';
322 manifest_include corpus => '.txt';
327 $ make bump # bump version
328 $ make bump V=2.000000 # bump to specific version
329 $ make bumpminor # bump minor version component
330 $ make bumpmajor # bump major version component
331 $ make nextrelease # add version heading to Changes file
332 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
333 $ make preflight # check that repo and file state is release ready
334 $ make release # check releasetest and preflight, commits and tags,
335 # builds and uploads to CPAN, and pushes commits and
337 $ make release FAKE_RELEASE=1
338 # builds a release INCLUDING committing and tagging,
339 # but does not upload to cpan or push anything to git
343 L<ExtUtils::MakeMaker> works well enough as development tool for
344 builting and testing, but using it to release is annoying and error prone.
345 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
346 author tool. This includes extra commands for releasing and safety checks, and
347 automatic generation of some files. It doesn't require any non-core modules and
348 is compatible with old versions of perl.
352 =head2 author( $author )
354 Set the author to include in generated META files. Can be a single entry, or
357 =head2 manifest_include( $dir, $pattern )
359 Add a pattern to include files in the MANIFEST file, and thus in the generated
362 The pattern can be either a regex, or a path suffix. It will be applied to the
363 full path past the directory specified.
365 The default files that are always included are: F<.pm> and F<.pod> files in
366 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
367 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
368 the dist root, and all files in F<maint>.
370 =head1 AUTOGENERATED FILES
374 =item F<MANIFEST.SKIP>
376 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
377 explicitly allowed via C<manifest_include> or the included defaults. It will be
378 created (or updated) at C<perl Makefile.PL> time.
382 The F<README> file will be generated at dist generation time, inside the built
383 dist. It will be generated using C<pod2text> on the main module.
385 If a F<README> file exists in the repo, it will be used directly instead of
390 =head1 MAKE COMMMANDS
394 test will be adjusted to include F<xt/> tests by default. This will only apply
395 for authors, not users installing from CPAN.
399 Releases the dist. Before releasing, checks will be done on the dist using the
400 C<preflight> and C<releasetest> commands.
402 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
403 It will also create a git tag for the release, and push the tag and branch.
407 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
408 pushing to git. A release commit will still be created and tagged locally.
412 Performs a number of checks on the files and repository, ensuring it is in a
413 sane state to do a release. The checks are:
417 =item * All version numbers match
419 =item * The F<MANIFEST> file is up to date
421 =item * The branch is correct
423 =item * There is no existing tag for the version
425 =item * There are no unmerged upstream changes
427 =item * There are no outstanding local changes
429 =item * There is an appropriate staged Changes heading
431 =item * cpan-upload is available
437 Test the dist preparing for a release. This generates a dist dir and runs the
438 tests from inside it. This ensures all appropriate files are included inside
439 the dist. C<RELEASE_TESTING> will be set in the environment.
443 Adds an appropriate changelog heading for the release, and prompts to stage the
448 Bumps the version number. This will try to preserve the length and format of
449 the version number. The least significant digit will be incremented. Versions
450 with underscores will preserve the underscore in the same position.
452 Optionally accepts a C<V> option to set the version to a specific value.
454 The version changes will automatically be committed. Unstaged modifications to
455 the files will be left untouched.
459 The V option will be passed along to the version bumping script. It can accept
460 a space separated list of options, including an explicit version number.
468 Updates version numbers even if they do not match the current expected version
473 Attempts to convert the updated version to a stable version, removing any
478 Attempts to convert the updated version to an alpha version, adding an
479 underscore in an appropriate place.
485 Like bump, but increments the minor segment of the version. This will treat
486 numeric versions as x.yyyzzz format, incrementing the yyy segment.
490 Like bumpminor, but bumping the major segment.
494 Updates Distar and re-runs C<perl Makefile.PL>
498 IRC: #web-simple on irc.perl.org
500 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
502 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
506 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
510 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
512 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
514 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
516 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
520 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
525 This library is free software and may be distributed under the same terms
526 as perl itself. See L<http://dev.perl.org/licenses/>.