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;
166 my $out = $self->SUPER::tarfile_target(@_);
167 my $verify = <<'END_FRAG';
168 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
170 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
177 my $distar_lib = File::Basename::dirname(__FILE__);
178 my $helpers = File::Spec->catdir($distar_lib, File::Spec->updir, 'helpers');
180 my $licenses = $self->{LICENSE} || $self->{META_ADD}{license} || $self->{META_MERGE}{license};
181 my $authors = $self->{AUTHOR};
182 $_ = ref $_ ? $_ : [$_ || ()]
183 for $licenses, $authors;
186 DISTAR_LIB => $self->quote_literal($distar_lib),
187 HELPERS => $self->quote_literal($helpers),
188 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR_LIB)', '-MDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
189 BRANCH => $self->{BRANCH} ||= 'master',
190 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
191 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
192 DISTTEST_MAKEFILE_PARAMS => '',
193 AUTHORS => $self->quote_literal(join(', ', @$authors)),
194 LICENSES => join(' ', map $self->quote_literal($_), @$licenses),
195 GET_CHANGELOG => '$(ABSPERLRUN) $(HELPERS)/get-changelog $(VERSION) $(CHANGELOG)',
197 -e File::Spec->catdir($distar_lib, File::Spec->updir, '.git')
198 ? 'git -C $(DISTAR_LIB) pull'
199 : '$(ECHO) "Distar code is not in a git repo, unable to update!"'
203 my $dist_test = $self->SUPER::dist_test(@_);
204 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
207 if (open my $fh, '<', 'maint/Makefile.include') {
208 $include = do { local $/; <$fh> };
209 $include =~ s/\n?\z/\n/;
215 preflight: check-version check-manifest check-cpan-upload
216 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
218 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
220 $(ABSPERLRUN) $(HELPERS)/check-manifest
222 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
224 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
225 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(ECHO) "Failed to generate $(DISTVNAME)/LICENSE!" >&2
226 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE
229 $(GET_CHANGELOG) -p"Release commit for $(VERSION)" | git commit -a -F -
230 $(GET_CHANGELOG) -p"release v$(VERSION)" | git tag -a -F - "v$(VERSION)"
231 $(RM_RF) $(DISTVNAME)
232 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
233 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
236 pushrelease$(FAKE_RELEASE) ::
237 cpan-upload $(DISTVNAME).tar$(SUFFIX)
238 git push origin v$(VERSION) HEAD
239 distdir: readmefile licensefile
240 readmefile: create_distdir
241 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
242 $(DISTVNAME)/README: $(VERSION_FROM)
243 $(NOECHO) $(MKPATH) $(DISTVNAME)
244 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
245 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
246 distsignature: readmefile licensefile
247 licensefile: create_distdir
248 $(NOECHO) $(TEST_F) $(DISTVNAME)/LICENSE || $(MAKE) $(DISTVNAME)/LICENSE || $(TRUE)
249 $(DISTVNAME)/LICENSE: Makefile.PL
250 $(NOECHO) $(MKPATH) $(DISTVNAME)
251 $(ABSPERLRUN) $(HELPERS)/generate-license -o $(DISTVNAME)/LICENSE $(AUTHORS) $(LICENSES)
252 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) LICENSE
253 disttest: distmanicheck
254 distmanicheck: create_distdir
255 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
257 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
260 $(RM_F) $(FIRST_MAKEFILE)
264 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
266 for my $target (@bump_targets) {
267 push @out, sprintf <<'END', "bump$target", ($target || '$(V)');
269 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
270 $(RM_F) $(FIRST_MAKEFILE)
277 "\n\n# --- Distar section:\n\n",
278 (map "$_ = $vars{$_}\n", sort keys %vars),
283 "# --- Makefile.include:\n",
298 Distar - Additions to ExtUtils::MakeMaker for dist authors
304 use ExtUtils::MakeMaker;
305 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
309 F<maint/Makefile.PL.include>:
311 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
312 use lib 'Distar/lib';
315 author 'A. U. Thor <author@cpan.org>';
317 manifest_include t => 'test-helper.pl';
318 manifest_include corpus => '.txt';
323 $ make bump # bump version
324 $ make bump V=2.000000 # bump to specific version
325 $ make bumpminor # bump minor version component
326 $ make bumpmajor # bump major version component
327 $ make nextrelease # add version heading to Changes file
328 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
329 $ make preflight # check that repo and file state is release ready
330 $ make release # check releasetest and preflight, commits and tags,
331 # builds and uploads to CPAN, and pushes commits and
333 $ make release FAKE_RELEASE=1
334 # builds a release INCLUDING committing and tagging,
335 # but does not upload to cpan or push anything to git
339 L<ExtUtils::MakeMaker> works well enough as development tool for
340 builting and testing, but using it to release is annoying and error prone.
341 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
342 author tool. This includes extra commands for releasing and safety checks, and
343 automatic generation of some files. It doesn't require any non-core modules and
344 is compatible with old versions of perl.
348 =head2 author( $author )
350 Set the author to include in generated META files. Can be a single entry, or
353 =head2 manifest_include( $dir, $pattern )
355 Add a pattern to include files in the MANIFEST file, and thus in the generated
358 The pattern can be either a regex, or a path suffix. It will be applied to the
359 full path past the directory specified.
361 The default files that are always included are: F<.pm> and F<.pod> files in
362 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
363 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
364 the dist root, and all files in F<maint>.
366 =head1 AUTOGENERATED FILES
370 =item F<MANIFEST.SKIP>
372 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
373 explicitly allowed via C<manifest_include> or the included defaults. It will be
374 created (or updated) at C<perl Makefile.PL> time.
378 The F<README> file will be generated at dist generation time, inside the built
379 dist. It will be generated using C<pod2text> on the main module.
381 If a F<README> file exists in the repo, it will be used directly instead of
386 =head1 MAKE COMMMANDS
390 test will be adjusted to include F<xt/> tests by default. This will only apply
391 for authors, not users installing from CPAN.
395 Releases the dist. Before releasing, checks will be done on the dist using the
396 C<preflight> and C<releasetest> commands.
398 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
399 It will also create a git tag for the release, and push the tag and branch.
403 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
404 pushing to git. A release commit will still be created and tagged locally.
408 Performs a number of checks on the files and repository, ensuring it is in a
409 sane state to do a release. The checks are:
413 =item * All version numbers match
415 =item * The F<MANIFEST> file is up to date
417 =item * The branch is correct
419 =item * There is no existing tag for the version
421 =item * There are no unmerged upstream changes
423 =item * There are no outstanding local changes
425 =item * There is an appropriate staged Changes heading
427 =item * cpan-upload is available
433 Test the dist preparing for a release. This generates a dist dir and runs the
434 tests from inside it. This ensures all appropriate files are included inside
435 the dist. C<RELEASE_TESTING> will be set in the environment.
439 Adds an appropriate changelog heading for the release, and prompts to stage the
444 Bumps the version number. This will try to preserve the length and format of
445 the version number. The least significant digit will be incremented. Versions
446 with underscores will preserve the underscore in the same position.
448 Optionally accepts a C<V> option to set the version to a specific value.
450 The version changes will automatically be committed. Unstaged modifications to
451 the files will be left untouched.
455 The V option will be passed along to the version bumping script. It can accept
456 a space separated list of options, including an explicit version number.
464 Updates version numbers even if they do not match the current expected version
469 Attempts to convert the updated version to a stable version, removing any
474 Attempts to convert the updated version to an alpha version, adding an
475 underscore in an appropriate place.
481 Like bump, but increments the minor segment of the version. This will treat
482 numeric versions as x.yyyzzz format, incrementing the yyy segment.
486 Like bumpminor, but bumping the major segment.
490 Updates Distar and re-runs C<perl Makefile.PL>
494 IRC: #web-simple on irc.perl.org
496 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
498 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
502 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
506 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
508 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
510 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
512 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
516 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
521 This library is free software and may be distributed under the same terms
522 as perl itself. See L<http://dev.perl.org/licenses/>.