3 use warnings FATAL => 'all';
5 use ExtUtils::MakeMaker ();
10 our $VERSION = '0.003000';
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 $out = $self->SUPER::init_dist(@_);
140 my $dn = File::Spec->devnull;
141 my $tar = $self->{TAR};
143 my $tarflags = $self->{TARFLAGS};
144 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
145 if ($flags =~ s/c// && $flags =~ s/f//) {
146 $tarflags = '--format=ustar -c'.$flags.'f';
148 for my $options ('--owner=0 --group=0', '--uid=0 --gid=0') {
149 my $try = `$tar -c $options "$me" 2>$dn`;
151 $tarflags = "$options $tarflags";
159 $self->{TARFLAGS} = $tarflags;
168 # default setup for Distar involves checking it out as a subdirectory at
169 # the top of the dist. Without NORECURS, EUMM would try to include
170 # Distar's Makefile.PL. Prevent EUMM from looking inside.
172 if $path eq 'Distar';
174 $self->SUPER::libscan(@_);
179 my $out = $self->SUPER::tarfile_target(@_);
180 my $verify = <<'END_FRAG';
181 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
183 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
190 my $distar_lib = File::Basename::dirname(__FILE__);
191 my $helpers = File::Spec->catdir($distar_lib, 'Distar', 'helpers');
193 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
194 my $authors = $self->{AUTHOR};
195 $_ = ref $_ ? $_ : [$_ || ()]
196 for $licenses, $authors;
199 DISTAR_LIB => $self->quote_literal($distar_lib),
200 HELPERS => $self->quote_literal($helpers),
201 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR_LIB)', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
202 BRANCH => $self->{BRANCH} ||= 'master',
203 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
204 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
205 DISTTEST_MAKEFILE_PARAMS => '',
206 AUTHORS => $self->quote_literal(join(', ', @$authors)),
207 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
208 GET_CHANGELOG => '$(ABSPERLRUN) $(HELPERS)/get-changelog $(VERSION) $(CHANGELOG)',
210 -e File::Spec->catdir($distar_lib, File::Spec->updir, '.git')
211 ? 'git -C $(DISTAR_LIB) pull'
212 : '$(ECHO) "Distar code is not in a git repo, unable to update!"'
216 my $dist_test = $self->SUPER::dist_test(@_);
217 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
220 if (open my $fh, '<', 'maint/Makefile.include') {
221 $include = do { local $/; <$fh> };
222 $include =~ s/\n?\z/\n/;
228 'preflight: check-version check-manifest check-cpan-upload' => [
229 '$(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)',
231 'check-version:' => [
232 '$(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)',
234 'check-manifest:' => [
235 '$(ABSPERLRUN) $(HELPERS)/check-manifest',
237 'check-cpan-upload:' => [
238 '$(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)',
241 '$(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""',
242 '$(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(ECHO) "Failed to generate $(DISTVNAME)/LICENSE!" >&2',
243 '$(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE',
245 'release: preflight' => [
246 '$(MAKE) releasetest',
247 '$(GET_CHANGELOG) -p"Release commit for $(VERSION)" | git commit -a -F -',
248 '$(GET_CHANGELOG) -p"release v$(VERSION)" | git tag -a -F - "v$(VERSION)"',
249 '$(RM_RF) $(DISTVNAME)',
250 '$(MAKE) $(DISTVNAME).tar$(SUFFIX)',
251 '$(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)',
253 'pushrelease ::' => [
256 'pushrelease$(FAKE_RELEASE) ::' => [
257 'cpan-upload $(DISTVNAME).tar$(SUFFIX)',
258 'git push origin v$(VERSION) HEAD',
260 'distdir: readmefile licensefile',
261 'readmefile: create_distdir' => [
262 '$(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',
269 'distsignature: readmefile licensefile',
270 'licensefile: create_distdir' => [
271 '$(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE || $(TRUE)',
273 '$(DISTVNAME)/LICENSE: Makefile.PL' => [
274 '$(NOECHO) $(MKPATH) $(DISTVNAME)',
275 '$(ABSPERLRUN) $(HELPERS)/generate-license -o $(DISTVNAME)/LICENSE $(AUTHORS) $(LICENSES)',
276 '$(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE',
278 'disttest: distmanicheck',
279 'distmanicheck: create_distdir' => [
280 $self->cd('$(DISTVNAME)',
281 '$(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"',
285 '$(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)',
289 '$(RM_F) $(FIRST_MAKEFILE)',
295 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
299 '$(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) '.($_ || '$(V)'),
300 '$(RM_F) $(FIRST_MAKEFILE)',
307 "\n\n# --- Distar section:\n\n",
308 (map "$_ = $vars{$_}\n", sort keys %vars),
314 s/^\t?/\t/mg for @lines;
319 s/\n?\z/\n/ for @lines;
324 "# --- Makefile.include:\n",
339 Distar - Additions to ExtUtils::MakeMaker for dist authors
345 use ExtUtils::MakeMaker;
346 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
350 F<maint/Makefile.PL.include>:
352 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
353 use lib 'Distar/lib';
356 author 'A. U. Thor <author@cpan.org>';
358 manifest_include t => 'test-helper.pl';
359 manifest_include corpus => '.txt';
364 $ make bump # bump version
365 $ make bump V=2.000000 # bump to specific version
366 $ make bumpminor # bump minor version component
367 $ make bumpmajor # bump major version component
368 $ make nextrelease # add version heading to Changes file
369 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
370 $ make preflight # check that repo and file state is release ready
371 $ make release # check releasetest and preflight, commits and tags,
372 # builds and uploads to CPAN, and pushes commits and
374 $ make release FAKE_RELEASE=1
375 # builds a release INCLUDING committing and tagging,
376 # but does not upload to cpan or push anything to git
380 L<ExtUtils::MakeMaker> works well enough as development tool for
381 builting and testing, but using it to release is annoying and error prone.
382 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
383 author tool. This includes extra commands for releasing and safety checks, and
384 automatic generation of some files. It doesn't require any non-core modules and
385 is compatible with old versions of perl.
389 =head2 author( $author )
391 Set the author to include in generated META files. Can be a single entry, or
394 =head2 manifest_include( $dir, $pattern )
396 Add a pattern to include files in the MANIFEST file, and thus in the generated
399 The pattern can be either a regex, or a path suffix. It will be applied to the
400 full path past the directory specified.
402 The default files that are always included are: F<.pm> and F<.pod> files in
403 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
404 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
405 the dist root, and all files in F<maint>.
407 =head1 AUTOGENERATED FILES
411 =item F<MANIFEST.SKIP>
413 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
414 explicitly allowed via C<manifest_include> or the included defaults. It will be
415 created (or updated) at C<perl Makefile.PL> time.
419 The F<README> file will be generated at dist generation time, inside the built
420 dist. It will be generated using C<pod2text> on the main module.
422 If a F<README> file exists in the repo, it will be used directly instead of
427 =head1 MAKE COMMMANDS
431 test will be adjusted to include F<xt/> tests by default. This will only apply
432 for authors, not users installing from CPAN.
436 Releases the dist. Before releasing, checks will be done on the dist using the
437 C<preflight> and C<releasetest> commands.
439 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
440 It will also create a git tag for the release, and push the tag and branch.
444 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
445 pushing to git. A release commit will still be created and tagged locally.
449 Performs a number of checks on the files and repository, ensuring it is in a
450 sane state to do a release. The checks are:
454 =item * All version numbers match
456 =item * The F<MANIFEST> file is up to date
458 =item * The branch is correct
460 =item * There is no existing tag for the version
462 =item * There are no unmerged upstream changes
464 =item * There are no outstanding local changes
466 =item * There is an appropriate staged Changes heading
468 =item * cpan-upload is available
474 Test the dist preparing for a release. This generates a dist dir and runs the
475 tests from inside it. This ensures all appropriate files are included inside
476 the dist. C<RELEASE_TESTING> will be set in the environment.
480 Adds an appropriate changelog heading for the release, and prompts to stage the
485 Bumps the version number. This will try to preserve the length and format of
486 the version number. The least significant digit will be incremented. Versions
487 with underscores will preserve the underscore in the same position.
489 Optionally accepts a C<V> option to set the version to a specific value.
491 The version changes will automatically be committed. Unstaged modifications to
492 the files will be left untouched.
496 The V option will be passed along to the version bumping script. It can accept
497 a space separated list of options, including an explicit version number.
505 Updates version numbers even if they do not match the current expected version
510 Attempts to convert the updated version to a stable version, removing any
515 Attempts to convert the updated version to an alpha version, adding an
516 underscore in an appropriate place.
522 Like bump, but increments the minor segment of the version. This will treat
523 numeric versions as x.yyyzzz format, incrementing the yyy segment.
527 Like bumpminor, but bumping the major segment.
531 Updates Distar and re-runs C<perl Makefile.PL>
535 IRC: #web-simple on irc.perl.org
537 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
539 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
543 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
547 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
549 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
551 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
553 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
557 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
562 This library is free software and may be distributed under the same terms
563 as perl itself. See L<http://dev.perl.org/licenses/>.