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);
134 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
135 my $maniskip_tracked = !$?;
137 Distar::write_manifest_skip($self)
138 unless $maniskip_tracked;
139 $self->SUPER::flush(@_);
142 sub special_targets {
144 my $targets = $self->SUPER::special_targets(@_);
145 my $phony_targets = join ' ', qw(
160 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
166 my $pre_tar = $self->{TAR};
167 my $out = $self->SUPER::init_dist(@_);
169 my $tar = $self->{TAR};
172 my $version = `$tar --version`;
173 if ($version =~ /GNU tar/) {
176 elsif (!$pre_tar && `gtar --version`) {
180 my $tarflags = $self->{TARFLAGS};
181 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
182 if ($flags =~ s/c// && $flags =~ s/f//) {
183 $tarflags = '--format=ustar -c'.$flags.'f';
185 $tarflags = '--owner=0 --group=0 '.$tarflags;
197 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
200 warn "$warn too large! Max is ".(2**21-1).".\n"
201 ."Dist creation will likely fail. Install GNU tar to work around.\n";
206 $self->{TARFLAGS} = $tarflags;
213 my $out = $self->SUPER::tarfile_target(@_);
214 my $verify = <<'END_FRAG';
215 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
217 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
225 if (open my $fh, '<', 'maint/Makefile.include') {
226 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
227 $include =~ s/\n?\z/\n/;
231 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
233 my $distar = File::Spec->catdir(
234 File::Spec->catpath((File::Spec->splitpath(__FILE__))[0,1], ''),
237 my $helpers = File::Spec->catdir($distar, 'helpers');
240 DISTAR => $self->quote_literal($distar),
241 HELPERS => $self->quote_literal($helpers),
242 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR)/lib', '-mDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
243 BRANCH => $self->{BRANCH} ||= 'master',
244 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
245 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
246 DISTTEST_MAKEFILE_PARAMS => '',
249 my $dist_test = $self->SUPER::dist_test(@_);
250 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
254 "\n\n# --- Distar section:\n\n",
255 (map "$_ = $vars{$_}\n", sort keys %vars),
258 preflight: check-version check-manifest check-cpan-upload
259 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
261 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
263 $(ABSPERLRUN) $(HELPERS)/check-manifest
265 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
267 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
270 git commit -a -m "Release commit for $(VERSION)"
271 git tag v$(VERSION) -m "release v$(VERSION)"
272 $(RM_RF) $(DISTVNAME)
273 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
274 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
277 pushrelease$(FAKE_RELEASE) ::
278 cpan-upload $(DISTVNAME).tar$(SUFFIX)
279 git push origin v$(VERSION) HEAD
281 readmefile: create_distdir
282 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
283 $(DISTVNAME)/README: $(VERSION_FROM)
284 $(NOECHO) $(MKPATH) $(DISTVNAME)
285 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
286 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
287 distsignature: readmefile
288 disttest: distmanicheck
289 distmanicheck: create_distdir
290 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
292 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
294 cd $(DISTAR) && git pull || $(TRUE)
295 $(RM_F) $(FIRST_MAKEFILE)
298 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
300 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
301 $(RM_F) $(FIRST_MAKEFILE)
315 Distar - Additions to ExtUtils::MakeMaker for dist authors
321 use ExtUtils::MakeMaker;
322 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
326 F<maint/Makefile.PL.include>:
328 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
329 use lib 'Distar/lib';
332 author 'A. U. Thor <author@cpan.org>';
334 manifest_include t => 'test-helper.pl';
335 manifest_include corpus => '.txt';
340 $ make bump # bump version
341 $ make bump V=2.000000 # bump to specific version
342 $ make bumpminor # bump minor version component
343 $ make bumpmajor # bump major version component
344 $ make nextrelease # add version heading to Changes file
345 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
346 $ make preflight # check that repo and file state is release ready
347 $ make release # check releasetest and preflight, commits and tags,
348 # builds and uploads to CPAN, and pushes commits and
350 $ make release FAKE_RELEASE=1
351 # builds a release INCLUDING committing and tagging,
352 # but does not upload to cpan or push anything to git
356 L<ExtUtils::MakeMaker> works well enough as development tool for
357 builting and testing, but using it to release is annoying and error prone.
358 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
359 author tool. This includes extra commands for releasing and safety checks, and
360 automatic generation of some files. It doesn't require any non-core modules and
361 is compatible with old versions of perl.
365 =head2 author( $author )
367 Set the author to include in generated META files. Can be a single entry, or
370 =head2 manifest_include( $dir, $pattern )
372 Add a pattern to include files in the MANIFEST file, and thus in the generated
375 The pattern can be either a regex, or a path suffix. It will be applied to the
376 full path past the directory specified.
378 The default files that are always included are: F<.pm> and F<.pod> files in
379 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
380 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
381 the dist root, and all files in F<maint>.
383 =head1 AUTOGENERATED FILES
387 =item F<MANIFEST.SKIP>
389 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
390 explicitly allowed via C<manifest_include> or the included defaults. It will be
391 created (or updated) at C<perl Makefile.PL> time.
395 The F<README> file will be generated at dist generation time, inside the built
396 dist. It will be generated using C<pod2text> on the main module.
398 If a F<README> file exists in the repo, it will be used directly instead of
403 =head1 MAKE COMMMANDS
407 test will be adjusted to include F<xt/> tests by default. This will only apply
408 for authors, not users installing from CPAN.
412 Releases the dist. Before releasing, checks will be done on the dist using the
413 C<preflight> and C<releasetest> commands.
415 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
416 It will also create a git tag for the release, and push the tag and branch.
420 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
421 pushing to git. A release commit will still be created and tagged locally.
425 Performs a number of checks on the files and repository, ensuring it is in a
426 sane state to do a release. The checks are:
430 =item * All version numbers match
432 =item * The F<MANIFEST> file is up to date
434 =item * The branch is correct
436 =item * There is no existing tag for the version
438 =item * There are no unmerged upstream changes
440 =item * There are no outstanding local changes
442 =item * There is an appropriate staged Changes heading
444 =item * cpan-upload is available
450 Test the dist preparing for a release. This generates a dist dir and runs the
451 tests from inside it. This ensures all appropriate files are included inside
452 the dist. C<RELEASE_TESTING> will be set in the environment.
456 Adds an appropriate changelog heading for the release, and prompts to stage the
461 Bumps the version number. This will try to preserve the length and format of
462 the version number. The least significant digit will be incremented. Versions
463 with underscores will preserve the underscore in the same position.
465 Optionally accepts a C<V> option to set the version to a specific value.
467 The version changes will automatically be committed. Unstaged modifications to
468 the files will be left untouched.
472 The V option will be passed along to the version bumping script. It can accept
473 a space separated list of options, including an explicit version number.
481 Updates version numbers even if they do not match the current expected version
486 Attempts to convert the updated version to a stable version, removing any
491 Attempts to convert the updated version to an alpha version, adding an
492 underscore in an appropriate place.
498 Like bump, but increments the minor segment of the version. This will treat
499 numeric versions as x.yyyzzz format, incrementing the yyy segment.
503 Like bumpminor, but bumping the major segment.
507 Updates Distar and re-runs C<perl Makefile.PL>
511 IRC: #web-simple on irc.perl.org
513 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
515 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
519 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
523 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
525 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
527 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
529 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
533 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
538 This library is free software and may be distributed under the same terms
539 as perl itself. See L<http://dev.perl.org/licenses/>.