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);
129 $resources->{bugtracker} ||= do {
130 (my $queue = $meta->{name} || $self->{NAME}) =~ s/::/-/g;
131 my $rt_link = 'https://rt.cpan.org/Dist/Display.html?Name='.$queue;
132 $spec_ver < 2 ? $rt_link : {
134 mailto => "bug-$queue\@rt.cpan.org",
139 my $license = $meta->{license} = [
140 map { $_ eq 'perl' ? 'perl_5' : $_ }
141 map { ref ? @$_ : $_ }
142 ( $meta->{license} || $self->{LICENSE} || 'perl_5' )
145 $resources->{license} ||= [ 'http://dev.perl.org/licenses/' ]
146 if @$license == 1 && $license->[0] eq 'perl_5';
154 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
155 my $maniskip_tracked = !$?;
157 Distar::write_manifest_skip($self)
158 unless $maniskip_tracked;
160 my @results = @{$self->{RESULT}};
162 utf8::encode($_) for @results;
164 local $self->{RESULT} = \@results;
165 $self->SUPER::flush(@_);
168 sub special_targets {
170 my $targets = $self->SUPER::special_targets(@_);
171 my $phony_targets = join ' ', qw(
186 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
192 my $pre_tar = $self->{TAR};
193 my $out = $self->SUPER::init_dist(@_);
195 my $tar = $self->{TAR};
198 my $version = `$tar --version`;
199 if ($version =~ /GNU tar/) {
202 elsif (!$pre_tar && `gtar --version`) {
206 my $tarflags = $self->{TARFLAGS};
207 if (my ($flags) = $tarflags =~ /^-?([cvhlLf]+)$/) {
208 if ($flags =~ s/c// && $flags =~ s/f//) {
209 $tarflags = '--format=ustar -c'.$flags.'f';
211 $tarflags = '--owner=0 --group=0 '.$tarflags;
223 $warn .= ($warn ? ' and ' : '').'gid('.(0+$)).')';
226 warn "$warn too large! Max is ".(2**21-1).".\n"
227 ."Dist creation will likely fail. Install GNU tar to work around.\n";
232 $self->{TARFLAGS} = $tarflags;
239 my $out = $self->SUPER::tarfile_target(@_);
240 my $verify = <<'END_FRAG';
241 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
243 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
251 if (open my $fh, '<', 'maint/Makefile.include') {
252 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
253 $include =~ s/\n?\z/\n/;
257 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
259 my $distar = File::Spec->catdir(
260 File::Spec->catpath((File::Spec->splitpath(__FILE__))[0,1], ''),
263 my $helpers = File::Spec->catdir($distar, 'helpers');
266 DISTAR => $self->quote_literal($distar),
267 HELPERS => $self->quote_literal($helpers),
268 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR)/lib', '-mDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
269 BRANCH => $self->{BRANCH} ||= 'master',
270 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
271 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
272 DISTTEST_MAKEFILE_PARAMS => '',
275 my $dist_test = $self->SUPER::dist_test(@_);
276 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
280 "\n\n# --- Distar section:\n\n",
281 (map "$_ = $vars{$_}\n", sort keys %vars),
284 preflight: check-version check-manifest check-cpan-upload
285 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
287 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
289 $(ABSPERLRUN) $(HELPERS)/check-manifest
291 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
293 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
296 git commit -a -m "Release commit for $(VERSION)"
297 git tag v$(VERSION) -m "release v$(VERSION)"
298 $(RM_RF) $(DISTVNAME)
299 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
300 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
303 pushrelease$(FAKE_RELEASE) ::
304 cpan-upload $(DISTVNAME).tar$(SUFFIX)
305 git push origin v$(VERSION) HEAD
307 readmefile: create_distdir
308 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
309 $(DISTVNAME)/README: $(VERSION_FROM)
310 $(NOECHO) $(MKPATH) $(DISTVNAME)
311 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
312 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
313 distsignature: readmefile
314 disttest: distmanicheck
315 distmanicheck: create_distdir
316 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
318 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
320 cd $(DISTAR) && git pull || $(TRUE)
321 $(RM_F) $(FIRST_MAKEFILE)
324 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
326 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
327 $(RM_F) $(FIRST_MAKEFILE)
341 Distar - Additions to ExtUtils::MakeMaker for dist authors
347 use ExtUtils::MakeMaker;
348 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
352 F<maint/Makefile.PL.include>:
354 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
355 use lib 'Distar/lib';
358 author 'A. U. Thor <author@cpan.org>';
360 manifest_include t => 'test-helper.pl';
361 manifest_include corpus => '.txt';
366 $ make bump # bump version
367 $ make bump V=2.000000 # bump to specific version
368 $ make bumpminor # bump minor version component
369 $ make bumpmajor # bump major version component
370 $ make nextrelease # add version heading to Changes file
371 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
372 $ make preflight # check that repo and file state is release ready
373 $ make release # check releasetest and preflight, commits and tags,
374 # builds and uploads to CPAN, and pushes commits and
376 $ make release FAKE_RELEASE=1
377 # builds a release INCLUDING committing and tagging,
378 # but does not upload to cpan or push anything to git
382 L<ExtUtils::MakeMaker> works well enough as development tool for
383 builting and testing, but using it to release is annoying and error prone.
384 Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
385 author tool. This includes extra commands for releasing and safety checks, and
386 automatic generation of some files. It doesn't require any non-core modules and
387 is compatible with old versions of perl.
391 =head2 author( $author )
393 Set the author to include in generated META files. Can be a single entry, or
396 =head2 manifest_include( $dir, $pattern )
398 Add a pattern to include files in the MANIFEST file, and thus in the generated
401 The pattern can be either a regex, or a path suffix. It will be applied to the
402 full path past the directory specified.
404 The default files that are always included are: F<.pm> and F<.pod> files in
405 F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
406 F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
407 the dist root, and all files in F<maint>.
409 =head1 AUTOGENERATED FILES
413 =item F<MANIFEST.SKIP>
415 The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
416 explicitly allowed via C<manifest_include> or the included defaults. It will be
417 created (or updated) at C<perl Makefile.PL> time.
421 The F<README> file will be generated at dist generation time, inside the built
422 dist. It will be generated using C<pod2text> on the main module.
424 If a F<README> file exists in the repo, it will be used directly instead of
429 =head1 MAKE COMMMANDS
433 test will be adjusted to include F<xt/> tests by default. This will only apply
434 for authors, not users installing from CPAN.
438 Releases the dist. Before releasing, checks will be done on the dist using the
439 C<preflight> and C<releasetest> commands.
441 Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
442 It will also create a git tag for the release, and push the tag and branch.
446 If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
447 pushing to git. A release commit will still be created and tagged locally.
451 Performs a number of checks on the files and repository, ensuring it is in a
452 sane state to do a release. The checks are:
456 =item * All version numbers match
458 =item * The F<MANIFEST> file is up to date
460 =item * The branch is correct
462 =item * There is no existing tag for the version
464 =item * There are no unmerged upstream changes
466 =item * There are no outstanding local changes
468 =item * There is an appropriate staged Changes heading
470 =item * cpan-upload is available
476 Test the dist preparing for a release. This generates a dist dir and runs the
477 tests from inside it. This ensures all appropriate files are included inside
478 the dist. C<RELEASE_TESTING> will be set in the environment.
482 Adds an appropriate changelog heading for the release, and prompts to stage the
487 Bumps the version number. This will try to preserve the length and format of
488 the version number. The least significant digit will be incremented. Versions
489 with underscores will preserve the underscore in the same position.
491 Optionally accepts a C<V> option to set the version to a specific value.
493 The version changes will automatically be committed. Unstaged modifications to
494 the files will be left untouched.
498 The V option will be passed along to the version bumping script. It can accept
499 a space separated list of options, including an explicit version number.
507 Updates version numbers even if they do not match the current expected version
512 Attempts to convert the updated version to a stable version, removing any
517 Attempts to convert the updated version to an alpha version, adding an
518 underscore in an appropriate place.
524 Like bump, but increments the minor segment of the version. This will treat
525 numeric versions as x.yyyzzz format, incrementing the yyy segment.
529 Like bumpminor, but bumping the major segment.
533 Updates Distar and re-runs C<perl Makefile.PL>
537 IRC: #web-simple on irc.perl.org
539 Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
541 Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
545 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
549 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
551 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
553 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
555 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
559 Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
564 This library is free software and may be distributed under the same terms
565 as perl itself. See L<http://dev.perl.org/licenses/>.