3 use warnings FATAL => 'all';
5 use ExtUtils::MakeMaker ();
9 our $VERSION = '0.002000';
10 $VERSION = eval $VERSION;
12 my $MM_VER = eval $ExtUtils::MakeMaker::VERSION;
15 author manifest_include readme_generator
20 warnings->import(FATAL => 'all');
21 shift->export_to_level(1,@_);
38 '' => qr{Changes|MANIFEST|README|LICENSE|META\.yml},
39 'maint' => qr{[^.].*},
42 sub manifest_include {
46 sub readme_generator {
47 die "readme_generator unsupported" if @_ && $_[0];
50 sub write_manifest_skip {
52 my @files = @Manifest;
54 while (my ($dir, $spec) = splice(@files, 0, 2)) {
55 my $re = ($dir ? $dir.'/' : '').
56 ((ref($spec) eq 'Regexp')
60 # print ref as well as stringification in case of overload ""
61 : die "spec must be string or regexp, was: ${spec} (${\ref $spec})");
64 my $dist_name = $mm->{DISTNAME};
65 my $include = join '|', map "${_}\$", @parts;
66 my $final = "^(?:\Q$dist_name\E-v?[0-9_.]+/|(?!$include))";
67 open my $skip, '>', 'MANIFEST.SKIP'
68 or die "can't open MANIFEST.SKIP: $!";
69 print $skip "${final}\n";
77 { map +($_ => _clone($struct->{$_})), keys %$struct };
79 elsif (ref eq 'ARRAY') {
91 @MM::ISA = (__PACKAGE__);
94 my ($class, $args) = @_;
95 my %test = %{$args->{test}||{}};
96 my $tests = $test{TESTS} || 't/*.t';
97 $tests !~ /\b\Q$_\E\b/ and $tests .= " $_"
98 for 'xt/*.t', 'xt/*/*.t';
99 $test{TESTS} = $tests;
100 return $class->SUPER::new({
102 MIN_PERL_VERSION => '5.006',
104 AUTHOR => ($MM_VER >= 6.5702 ? $Distar::Author : join(', ', @$Distar::Author)),
106 (exists $args->{ABSTRACT} ? () : (ABSTRACT_FROM => $args->{VERSION_FROM})),
109 realclean => { FILES => (
110 ($args->{realclean}{FILES}||'')
111 . ' Distar/ MANIFEST.SKIP MANIFEST MANIFEST.bak'
118 my $meta = { Distar::_clone($self->SUPER::metafile_data(@_) };
120 my $spec_ver = ($meta->{'meta-spec'} && $meta->{'meta-spec'}{version} || 1.4;
121 my $resources = $meta->{resources} ||= {};
124 my $no_index_dir = ${ $meta->{no_index}||={} }{directory} ||= [];
126 @$no_index_dir = grep !$seen{$_}++, @$no_index_dir, grep -d, qw(t xt);
129 $resources->{bugtracker} ||= do {
130 (my $queue = $meta->{name} || $self->{NAME}) =~ s/::/-/g;
131 my $rt_link = 'https://rt.cpan.org/Dist/Display.html?Name='.$queue;
132 $spec_ver < 2 ? $rt_link : {
134 mailto => "bug-$queue\@rt.cpan.org",
139 my $license = $meta->{license} = [
140 map { $_ eq 'perl' ? 'perl_5' : $_ }
141 map { ref ? @$_ : $_ }
142 ( $meta->{license} || $self->{LICENSE} || 'perl_5' )
145 $resources->{license} ||= [ 'http://dev.perl.org/licenses/' ]
146 if @$license == 1 && $license->[0] eq 'perl_5';
154 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
155 my $maniskip_tracked = !$?;
157 Distar::write_manifest_skip($self)
158 unless $maniskip_tracked;
159 $self->SUPER::flush(@_);
162 sub special_targets {
164 my $targets = $self->SUPER::special_targets(@_);
165 my $phony_targets = join ' ', qw(
180 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
186 my $pre_tar = $self->{TAR};
187 my $out = $self->SUPER::init_dist(@_);
189 my $tar = $self->{TAR};
192 my $version = `$tar --version`;
193 if ($version =~ /GNU tar/) {
196 elsif (!$pre_tar && `gtar --version`) {
200 my $tarflags = $self->{TARFLAGS};
201 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
202 if ($flags =~ s/c// && $flags =~ s/f//) {
203 $tarflags = '--format=ustar -c'.$flags.'f';
205 $tarflags = '--owner=0 --group=0 '.$tarflags;
217 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
220 warn "$warn too large! Max is ".(2**21-1).".\n"
221 ."Dist creation will likely fail. Install GNU tar to work around.\n";
226 $self->{TARFLAGS} = $tarflags;
233 my $out = $self->SUPER::tarfile_target(@_);
234 my $verify = <<'END_FRAG';
235 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
237 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
245 if (open my $fh, '<', 'maint/Makefile.include') {
246 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
247 $include =~ s/\n?\z/\n/;
251 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
253 my $distar = File::Spec->catdir(
254 File::Spec->catpath((File::Spec->splitpath(__FILE__))[0,1], ''),
257 my $helpers = File::Spec->catdir($distar, 'helpers');
260 DISTAR => $self->quote_literal($distar),
261 HELPERS => $self->quote_literal($helpers),
262 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR)/lib', '-mDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
263 BRANCH => $self->{BRANCH} ||= 'master',
264 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
265 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
266 DISTTEST_MAKEFILE_PARAMS => '',
269 my $dist_test = $self->SUPER::dist_test(@_);
270 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
274 "\n\n# --- Distar section:\n\n",
275 (map "$_ = $vars{$_}\n", sort keys %vars),
278 preflight: check-version check-manifest check-cpan-upload
279 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
281 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
283 $(ABSPERLRUN) $(HELPERS)/check-manifest
285 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
287 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
290 git commit -a -m "Release commit for $(VERSION)"
291 git tag v$(VERSION) -m "release v$(VERSION)"
292 $(RM_RF) $(DISTVNAME)
293 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
294 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
297 pushrelease$(FAKE_RELEASE) ::
298 cpan-upload $(DISTVNAME).tar$(SUFFIX)
299 git push origin v$(VERSION) HEAD
301 readmefile: create_distdir
302 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
303 $(DISTVNAME)/README: $(VERSION_FROM)
304 $(NOECHO) $(MKPATH) $(DISTVNAME)
305 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
306 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
307 distsignature: readmefile
308 disttest: distmanicheck
309 distmanicheck: create_distdir
310 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
312 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
314 cd $(DISTAR) && git pull || $(TRUE)
315 $(RM_F) $(FIRST_MAKEFILE)
318 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
320 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
321 $(RM_F) $(FIRST_MAKEFILE)
335 Distar - Additions to ExtUtils::MakeMaker for dist authors
341 use ExtUtils::MakeMaker;
342 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
346 F<maint/Makefile.PL.include>:
348 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
349 use lib 'Distar/lib';
352 author 'A. U. Thor <author@cpan.org>';
354 manifest_include t => 'test-helper.pl';
355 manifest_include corpus => '.txt';
360 $ make bump # bump version
361 $ make bump V=2.000000 # bump to specific version
362 $ make bumpminor # bump minor version component
363 $ make bumpmajor # bump major version component
364 $ make nextrelease # add version heading to Changes file
365 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
366 $ make preflight # check that repo and file state is release ready
367 $ make release # check releasetest and preflight, commits and tags,
368 # builds and uploads to CPAN, and pushes commits and
370 $ make release FAKE_RELEASE=1
371 # builds a release INCLUDING committing and tagging,
372 # but does not upload to cpan or push anything to git
376 L<ExtUtils::MakeMaker> works well enough as development tool for
377 builting and testing, but using it to release is annoying and error prone.
378 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
379 author tool. This includes extra commands for releasing and safety checks, and
380 automatic generation of some files. It doesn't require any non-core modules and
381 is compatible with old versions of perl.
385 =head2 author( $author )
387 Set the author to include in generated META files. Can be a single entry, or
390 =head2 manifest_include( $dir, $pattern )
392 Add a pattern to include files in the MANIFEST file, and thus in the generated
395 The pattern can be either a regex, or a path suffix. It will be applied to the
396 full path past the directory specified.
398 The default files that are always included are: F<.pm> and F<.pod> files in
399 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
400 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
401 the dist root, and all files in F<maint>.
403 =head1 AUTOGENERATED FILES
407 =item F<MANIFEST.SKIP>
409 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
410 explicitly allowed via C<manifest_include> or the included defaults. It will be
411 created (or updated) at C<perl Makefile.PL> time.
415 The F<README> file will be generated at dist generation time, inside the built
416 dist. It will be generated using C<pod2text> on the main module.
418 If a F<README> file exists in the repo, it will be used directly instead of
423 =head1 MAKE COMMMANDS
427 test will be adjusted to include F<xt/> tests by default. This will only apply
428 for authors, not users installing from CPAN.
432 Releases the dist. Before releasing, checks will be done on the dist using the
433 C<preflight> and C<releasetest> commands.
435 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
436 It will also create a git tag for the release, and push the tag and branch.
440 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
441 pushing to git. A release commit will still be created and tagged locally.
445 Performs a number of checks on the files and repository, ensuring it is in a
446 sane state to do a release. The checks are:
450 =item * All version numbers match
452 =item * The F<MANIFEST> file is up to date
454 =item * The branch is correct
456 =item * There is no existing tag for the version
458 =item * There are no unmerged upstream changes
460 =item * There are no outstanding local changes
462 =item * There is an appropriate staged Changes heading
464 =item * cpan-upload is available
470 Test the dist preparing for a release. This generates a dist dir and runs the
471 tests from inside it. This ensures all appropriate files are included inside
472 the dist. C<RELEASE_TESTING> will be set in the environment.
476 Adds an appropriate changelog heading for the release, and prompts to stage the
481 Bumps the version number. This will try to preserve the length and format of
482 the version number. The least significant digit will be incremented. Versions
483 with underscores will preserve the underscore in the same position.
485 Optionally accepts a C<V> option to set the version to a specific value.
487 The version changes will automatically be committed. Unstaged modifications to
488 the files will be left untouched.
492 The V option will be passed along to the version bumping script. It can accept
493 a space separated list of options, including an explicit version number.
501 Updates version numbers even if they do not match the current expected version
506 Attempts to convert the updated version to a stable version, removing any
511 Attempts to convert the updated version to an alpha version, adding an
512 underscore in an appropriate place.
518 Like bump, but increments the minor segment of the version. This will treat
519 numeric versions as x.yyyzzz format, incrementing the yyy segment.
523 Like bumpminor, but bumping the major segment.
527 Updates Distar and re-runs C<perl Makefile.PL>
531 IRC: #web-simple on irc.perl.org
533 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
535 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
539 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
543 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
545 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
547 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
549 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
553 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
558 This library is free software and may be distributed under the same terms
559 as perl itself. See L<http://dev.perl.org/licenses/>.