3 use warnings FATAL => 'all';
5 use ExtUtils::MakeMaker ();
10 our $VERSION = '0.003000';
11 $VERSION = eval $VERSION;
13 my $MM_VER = eval $ExtUtils::MakeMaker::VERSION;
16 author manifest_include readme_generator
21 warnings->import(FATAL => 'all');
22 if (!(@MM::ISA == 1 && $MM::ISA[0] eq 'Distar::MM')) {
23 @Distar::MM::ISA = @MM::ISA;
24 @MM::ISA = qw(Distar::MM);
26 goto &Exporter::import;
43 '' => qr{Changes|MANIFEST|README|LICENSE|META\.yml},
44 'maint' => qr{[^.].*},
47 sub manifest_include {
51 sub readme_generator {
52 die "readme_generator unsupported" if @_ && $_[0];
55 sub write_manifest_skip {
57 my @files = @Manifest;
59 while (my ($dir, $spec) = splice(@files, 0, 2)) {
60 my $re = ($dir ? $dir.'/' : '').
61 ((ref($spec) eq 'Regexp')
65 # print ref as well as stringification in case of overload ""
66 : die "spec must be string or regexp, was: ${spec} (${\ref $spec})");
69 my $dist_name = $mm->{DISTNAME};
70 my $include = join '|', map "${_}\$", @parts;
71 my $final = "^(?:\Q$dist_name\E-v?[0-9_.]+/|(?!$include))";
72 open my $skip, '>', 'MANIFEST.SKIP'
73 or die "can't open MANIFEST.SKIP: $!";
74 print $skip "${final}\n";
82 my ($class, $args) = @_;
83 my %test = %{$args->{test}||{}};
84 my $tests = $test{TESTS} || 't/*.t';
85 $tests !~ /\b\Q$_\E\b/ and $tests .= " $_"
86 for 'xt/*.t', 'xt/*/*.t';
87 $test{TESTS} = $tests;
88 return $class->SUPER::new({
90 MIN_PERL_VERSION => '5.006',
92 AUTHOR => ($MM_VER >= 6.5702 ? $Distar::Author : join(', ', @$Distar::Author)),
94 (exists $args->{ABSTRACT} ? () : (ABSTRACT_FROM => $args->{VERSION_FROM})),
97 realclean => { FILES => (
98 ($args->{realclean}{FILES}||'')
99 . ' Distar/ MANIFEST.SKIP MANIFEST MANIFEST.bak'
106 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
107 my $maniskip_tracked = !$?;
109 Distar::write_manifest_skip($self)
110 unless $maniskip_tracked;
111 $self->SUPER::flush(@_);
114 sub special_targets {
116 my $targets = $self->SUPER::special_targets(@_);
117 my $phony_targets = join ' ', qw(
132 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
138 my $pre_tar = $self->{TAR};
139 my $out = $self->SUPER::init_dist(@_);
141 my $tar = $self->{TAR};
144 my $version = `$tar --version`;
145 if ($version =~ /GNU tar/) {
148 elsif (!$pre_tar && `gtar --version`) {
152 my $tarflags = $self->{TARFLAGS};
153 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
154 if ($flags =~ s/c// && $flags =~ s/f//) {
155 $tarflags = '--format=ustar -c'.$flags.'f';
157 $tarflags = '--owner=0 --group=0 '.$tarflags;
169 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
172 warn "$warn too large! Max is ".(2**21-1).".\n"
173 ."Dist creation will likely fail. Install GNU tar to work around.\n";
178 $self->{TARFLAGS} = $tarflags;
185 my $out = $self->SUPER::tarfile_target(@_);
186 my $verify = <<'END_FRAG';
187 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
189 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
197 if (open my $fh, '<', 'maint/Makefile.include') {
198 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
199 $include =~ s/\n?\z/\n/;
203 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
205 my $distar_lib = File::Basename::dirname(__FILE__);
206 my $helpers = File::Spec->catdir($distar_lib, File::Spec->updir, 'helpers');
208 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
209 my $authors = $self->{AUTHOR};
210 $_ = ref $_ ? $_ : [$_ || ()]
211 for $licenses, $authors;
214 DISTAR_LIB => $self->quote_literal($distar_lib),
215 HELPERS => $self->quote_literal($helpers),
216 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR_LIB)', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
217 BRANCH => $self->{BRANCH} ||= 'master',
218 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
219 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
220 DISTTEST_MAKEFILE_PARAMS => '',
221 AUTHORS => $self->quote_literal(join(', ', @$authors)),
222 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
223 GET_CHANGELOG => '$(ABSPERLRUN) $(HELPERS)/get-changelog $(VERSION) $(CHANGELOG)',
225 -e File::Spec->catdir($distar_lib, File::Spec->updir, '.git')
226 ? 'git -C $(DISTAR_LIB) pull'
227 : '$(ECHO) "Distar code is not in a git repo, unable to update!"'
231 my $dist_test = $self->SUPER::dist_test(@_);
232 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
236 "\n\n# --- Distar section:\n\n",
237 (map "$_ = $vars{$_}\n", sort keys %vars),
240 preflight: check-version check-manifest check-cpan-upload
241 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
243 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
245 $(ABSPERLRUN) $(HELPERS)/check-manifest
247 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
249 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
252 $(GET_CHANGELOG) -p"Release commit for $(VERSION)" | git commit -a -F -
253 $(GET_CHANGELOG) -p"release v$(VERSION)" | git tag -a -F - "v$(VERSION)"
254 $(RM_RF) $(DISTVNAME)
255 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
256 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
259 pushrelease$(FAKE_RELEASE) ::
260 cpan-upload $(DISTVNAME).tar$(SUFFIX)
261 git push origin v$(VERSION) HEAD
262 distdir: readmefile licensefile
263 readmefile: create_distdir
264 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
265 $(DISTVNAME)/README: $(VERSION_FROM)
266 $(NOECHO) $(MKPATH) $(DISTVNAME)
267 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
268 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
269 distsignature: readmefile licensefile
270 licensefile: create_distdir
271 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE
272 $(DISTVNAME)/LICENSE: Makefile.PL
273 $(NOECHO) $(MKPATH) $(DISTVNAME)
274 $(ABSPERLRUN) $(HELPERS)/generate-license $(AUTHORS) $(LICENSES) >$(DISTVNAME)/LICENSE
275 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE
276 disttest: distmanicheck
277 distmanicheck: create_distdir
278 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
280 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
283 $(RM_F) $(FIRST_MAKEFILE)
286 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
288 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
289 $(RM_F) $(FIRST_MAKEFILE)
303 Distar - Additions to ExtUtils::MakeMaker for dist authors
309 use ExtUtils::MakeMaker;
310 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
314 F<maint/Makefile.PL.include>:
316 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
317 use lib 'Distar/lib';
320 author 'A. U. Thor <author@cpan.org>';
322 manifest_include t => 'test-helper.pl';
323 manifest_include corpus => '.txt';
328 $ make bump # bump version
329 $ make bump V=2.000000 # bump to specific version
330 $ make bumpminor # bump minor version component
331 $ make bumpmajor # bump major version component
332 $ make nextrelease # add version heading to Changes file
333 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
334 $ make preflight # check that repo and file state is release ready
335 $ make release # check releasetest and preflight, commits and tags,
336 # builds and uploads to CPAN, and pushes commits and
338 $ make release FAKE_RELEASE=1
339 # builds a release INCLUDING committing and tagging,
340 # but does not upload to cpan or push anything to git
344 L<ExtUtils::MakeMaker> works well enough as development tool for
345 builting and testing, but using it to release is annoying and error prone.
346 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
347 author tool. This includes extra commands for releasing and safety checks, and
348 automatic generation of some files. It doesn't require any non-core modules and
349 is compatible with old versions of perl.
353 =head2 author( $author )
355 Set the author to include in generated META files. Can be a single entry, or
358 =head2 manifest_include( $dir, $pattern )
360 Add a pattern to include files in the MANIFEST file, and thus in the generated
363 The pattern can be either a regex, or a path suffix. It will be applied to the
364 full path past the directory specified.
366 The default files that are always included are: F<.pm> and F<.pod> files in
367 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
368 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
369 the dist root, and all files in F<maint>.
371 =head1 AUTOGENERATED FILES
375 =item F<MANIFEST.SKIP>
377 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
378 explicitly allowed via C<manifest_include> or the included defaults. It will be
379 created (or updated) at C<perl Makefile.PL> time.
383 The F<README> file will be generated at dist generation time, inside the built
384 dist. It will be generated using C<pod2text> on the main module.
386 If a F<README> file exists in the repo, it will be used directly instead of
391 =head1 MAKE COMMMANDS
395 test will be adjusted to include F<xt/> tests by default. This will only apply
396 for authors, not users installing from CPAN.
400 Releases the dist. Before releasing, checks will be done on the dist using the
401 C<preflight> and C<releasetest> commands.
403 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
404 It will also create a git tag for the release, and push the tag and branch.
408 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
409 pushing to git. A release commit will still be created and tagged locally.
413 Performs a number of checks on the files and repository, ensuring it is in a
414 sane state to do a release. The checks are:
418 =item * All version numbers match
420 =item * The F<MANIFEST> file is up to date
422 =item * The branch is correct
424 =item * There is no existing tag for the version
426 =item * There are no unmerged upstream changes
428 =item * There are no outstanding local changes
430 =item * There is an appropriate staged Changes heading
432 =item * cpan-upload is available
438 Test the dist preparing for a release. This generates a dist dir and runs the
439 tests from inside it. This ensures all appropriate files are included inside
440 the dist. C<RELEASE_TESTING> will be set in the environment.
444 Adds an appropriate changelog heading for the release, and prompts to stage the
449 Bumps the version number. This will try to preserve the length and format of
450 the version number. The least significant digit will be incremented. Versions
451 with underscores will preserve the underscore in the same position.
453 Optionally accepts a C<V> option to set the version to a specific value.
455 The version changes will automatically be committed. Unstaged modifications to
456 the files will be left untouched.
460 The V option will be passed along to the version bumping script. It can accept
461 a space separated list of options, including an explicit version number.
469 Updates version numbers even if they do not match the current expected version
474 Attempts to convert the updated version to a stable version, removing any
479 Attempts to convert the updated version to an alpha version, adding an
480 underscore in an appropriate place.
486 Like bump, but increments the minor segment of the version. This will treat
487 numeric versions as x.yyyzzz format, incrementing the yyy segment.
491 Like bumpminor, but bumping the major segment.
495 Updates Distar and re-runs C<perl Makefile.PL>
499 IRC: #web-simple on irc.perl.org
501 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
503 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
507 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
511 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
513 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
515 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
517 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
521 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
526 This library is free software and may be distributed under the same terms
527 as perl itself. See L<http://dev.perl.org/licenses/>.