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 $dn = File::Spec->devnull;
142 my $tar = $self->{TAR};
145 my $version = `$tar --version 2>$dn`;
146 if ($version =~ /GNU tar/) {
149 elsif (!$pre_tar && `gtar --version 2>$dn`) {
153 my $tarflags = $self->{TARFLAGS};
154 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
155 if ($flags =~ s/c// && $flags =~ s/f//) {
156 $tarflags = '--format=ustar -c'.$flags.'f';
158 $tarflags = '--owner=0 --group=0 '.$tarflags;
170 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
173 warn "$warn too large! Max is ".(2**21-1).".\n"
174 ."Dist creation will likely fail. Install GNU tar to work around.\n";
179 $self->{TARFLAGS} = $tarflags;
186 my $out = $self->SUPER::tarfile_target(@_);
187 my $verify = <<'END_FRAG';
188 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
190 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
198 if (open my $fh, '<', 'maint/Makefile.include') {
199 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
200 $include =~ s/\n?\z/\n/;
204 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
206 my $distar_lib = File::Basename::dirname(__FILE__);
207 my $helpers = File::Spec->catdir($distar_lib, File::Spec->updir, 'helpers');
209 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
210 my $authors = $self->{AUTHOR};
211 $_ = ref $_ ? $_ : [$_ || ()]
212 for $licenses, $authors;
215 DISTAR_LIB => $self->quote_literal($distar_lib),
216 HELPERS => $self->quote_literal($helpers),
217 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR_LIB)', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
218 BRANCH => $self->{BRANCH} ||= 'master',
219 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
220 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
221 DISTTEST_MAKEFILE_PARAMS => '',
222 AUTHORS => $self->quote_literal(join(', ', @$authors)),
223 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
224 GET_CHANGELOG => '$(ABSPERLRUN) $(HELPERS)/get-changelog $(VERSION) $(CHANGELOG)',
226 -e File::Spec->catdir($distar_lib, File::Spec->updir, '.git')
227 ? 'git -C $(DISTAR_LIB) pull'
228 : '$(ECHO) "Distar code is not in a git repo, unable to update!"'
232 my $dist_test = $self->SUPER::dist_test(@_);
233 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
237 "\n\n# --- Distar section:\n\n",
238 (map "$_ = $vars{$_}\n", sort keys %vars),
241 preflight: check-version check-manifest check-cpan-upload
242 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
244 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
246 $(ABSPERLRUN) $(HELPERS)/check-manifest
248 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
250 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
251 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(ECHO) "Failed to generate $(DISTVNAME)/LICENSE!" >&2
252 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE
255 $(GET_CHANGELOG) -p"Release commit for $(VERSION)" | git commit -a -F -
256 $(GET_CHANGELOG) -p"release v$(VERSION)" | git tag -a -F - "v$(VERSION)"
257 $(RM_RF) $(DISTVNAME)
258 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
259 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
262 pushrelease$(FAKE_RELEASE) ::
263 cpan-upload $(DISTVNAME).tar$(SUFFIX)
264 git push origin v$(VERSION) HEAD
265 distdir: readmefile licensefile
266 readmefile: create_distdir
267 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
268 $(DISTVNAME)/README: $(VERSION_FROM)
269 $(NOECHO) $(MKPATH) $(DISTVNAME)
270 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
271 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
272 distsignature: readmefile licensefile
273 licensefile: create_distdir
274 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE || $(TRUE)
275 $(DISTVNAME)/LICENSE: Makefile.PL
276 $(NOECHO) $(MKPATH) $(DISTVNAME)
277 $(ABSPERLRUN) $(HELPERS)/generate-license -o $(DISTVNAME)/LICENSE $(AUTHORS) $(LICENSES)
278 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE
279 disttest: distmanicheck
280 distmanicheck: create_distdir
281 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
283 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
286 $(RM_F) $(FIRST_MAKEFILE)
289 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
291 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
292 $(RM_F) $(FIRST_MAKEFILE)
306 Distar - Additions to ExtUtils::MakeMaker for dist authors
312 use ExtUtils::MakeMaker;
313 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
317 F<maint/Makefile.PL.include>:
319 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
320 use lib 'Distar/lib';
323 author 'A. U. Thor <author@cpan.org>';
325 manifest_include t => 'test-helper.pl';
326 manifest_include corpus => '.txt';
331 $ make bump # bump version
332 $ make bump V=2.000000 # bump to specific version
333 $ make bumpminor # bump minor version component
334 $ make bumpmajor # bump major version component
335 $ make nextrelease # add version heading to Changes file
336 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
337 $ make preflight # check that repo and file state is release ready
338 $ make release # check releasetest and preflight, commits and tags,
339 # builds and uploads to CPAN, and pushes commits and
341 $ make release FAKE_RELEASE=1
342 # builds a release INCLUDING committing and tagging,
343 # but does not upload to cpan or push anything to git
347 L<ExtUtils::MakeMaker> works well enough as development tool for
348 builting and testing, but using it to release is annoying and error prone.
349 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
350 author tool. This includes extra commands for releasing and safety checks, and
351 automatic generation of some files. It doesn't require any non-core modules and
352 is compatible with old versions of perl.
356 =head2 author( $author )
358 Set the author to include in generated META files. Can be a single entry, or
361 =head2 manifest_include( $dir, $pattern )
363 Add a pattern to include files in the MANIFEST file, and thus in the generated
366 The pattern can be either a regex, or a path suffix. It will be applied to the
367 full path past the directory specified.
369 The default files that are always included are: F<.pm> and F<.pod> files in
370 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
371 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
372 the dist root, and all files in F<maint>.
374 =head1 AUTOGENERATED FILES
378 =item F<MANIFEST.SKIP>
380 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
381 explicitly allowed via C<manifest_include> or the included defaults. It will be
382 created (or updated) at C<perl Makefile.PL> time.
386 The F<README> file will be generated at dist generation time, inside the built
387 dist. It will be generated using C<pod2text> on the main module.
389 If a F<README> file exists in the repo, it will be used directly instead of
394 =head1 MAKE COMMMANDS
398 test will be adjusted to include F<xt/> tests by default. This will only apply
399 for authors, not users installing from CPAN.
403 Releases the dist. Before releasing, checks will be done on the dist using the
404 C<preflight> and C<releasetest> commands.
406 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
407 It will also create a git tag for the release, and push the tag and branch.
411 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
412 pushing to git. A release commit will still be created and tagged locally.
416 Performs a number of checks on the files and repository, ensuring it is in a
417 sane state to do a release. The checks are:
421 =item * All version numbers match
423 =item * The F<MANIFEST> file is up to date
425 =item * The branch is correct
427 =item * There is no existing tag for the version
429 =item * There are no unmerged upstream changes
431 =item * There are no outstanding local changes
433 =item * There is an appropriate staged Changes heading
435 =item * cpan-upload is available
441 Test the dist preparing for a release. This generates a dist dir and runs the
442 tests from inside it. This ensures all appropriate files are included inside
443 the dist. C<RELEASE_TESTING> will be set in the environment.
447 Adds an appropriate changelog heading for the release, and prompts to stage the
452 Bumps the version number. This will try to preserve the length and format of
453 the version number. The least significant digit will be incremented. Versions
454 with underscores will preserve the underscore in the same position.
456 Optionally accepts a C<V> option to set the version to a specific value.
458 The version changes will automatically be committed. Unstaged modifications to
459 the files will be left untouched.
463 The V option will be passed along to the version bumping script. It can accept
464 a space separated list of options, including an explicit version number.
472 Updates version numbers even if they do not match the current expected version
477 Attempts to convert the updated version to a stable version, removing any
482 Attempts to convert the updated version to an alpha version, adding an
483 underscore in an appropriate place.
489 Like bump, but increments the minor segment of the version. This will treat
490 numeric versions as x.yyyzzz format, incrementing the yyy segment.
494 Like bumpminor, but bumping the major segment.
498 Updates Distar and re-runs C<perl Makefile.PL>
502 IRC: #web-simple on irc.perl.org
504 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
506 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
510 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
514 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
516 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
518 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
520 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
524 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
529 This library is free software and may be distributed under the same terms
530 as perl itself. See L<http://dev.perl.org/licenses/>.