summaryrefslogtreecommitdiff
path: root/inc
diff options
context:
space:
mode:
Diffstat (limited to 'inc')
-rw-r--r--inc/CheckAuthorDeps.pm52
-rw-r--r--inc/CheckDelta.pm18
-rw-r--r--inc/CheckReleaseType.pm37
-rw-r--r--inc/Clean.pm50
-rw-r--r--inc/ExtractInlineTests.pm58
-rw-r--r--inc/GenerateDocs.pm57
-rw-r--r--inc/GitUpToDate.pm52
-rw-r--r--inc/MMHelper.pm79
-rw-r--r--inc/MakeMaker.pm96
-rw-r--r--inc/MyInline.pm98
-rw-r--r--inc/SimpleAuthority.pm13
-rw-r--r--inc/SimpleProvides.pm34
-rw-r--r--inc/TestRelease.pm17
13 files changed, 661 insertions, 0 deletions
diff --git a/inc/CheckAuthorDeps.pm b/inc/CheckAuthorDeps.pm
new file mode 100644
index 0000000..69f2dde
--- /dev/null
+++ b/inc/CheckAuthorDeps.pm
@@ -0,0 +1,52 @@
+use strict;
+use warnings;
+package inc::CheckAuthorDeps;
+
+# our goal is to verify that the declared authordeps already reflect
+# everything in configure + runtime prerequisites -- otherwise, we won't be
+# able to bootstrap our built Moose for the purposes of running
+# author/docGenerator.pl
+
+use Moose;
+with 'Dist::Zilla::Role::AfterBuild';
+
+sub after_build
+{
+ my $self = shift;
+
+ # get our authordeps
+ require Dist::Zilla::Util::AuthorDeps;
+ Dist::Zilla::Util::AuthorDeps->VERSION(5.021);
+
+ require CPAN::Meta::Requirements;
+ my $authordeps = CPAN::Meta::Requirements->new;
+ $authordeps->add_string_requirement(%$_)
+ foreach @{ Dist::Zilla::Util::AuthorDeps::extract_author_deps('.') };
+
+ # get our prereqs
+ my $prereqs = $self->zilla->prereqs;
+
+ # merge prereqs into authordeps
+ my $merged_prereqs = CPAN::Meta::Requirements->new;
+ $merged_prereqs->add_requirements($authordeps);
+ $merged_prereqs->add_requirements($prereqs->requirements_for('configure', 'requires'));
+ $merged_prereqs->add_requirements($prereqs->requirements_for('runtime', 'requires'));
+
+ # remove some false positives we know we already have fulfilled
+ $merged_prereqs->clear_requirement('ExtUtils::MakeMaker');
+ $merged_prereqs->clear_requirement('Dist::CheckConflicts');
+
+ # the merged set should not be different than the original authordeps.
+ require Test::Deep;
+ my ($ok, $stack) = Test::Deep::cmp_details(
+ $authordeps->as_string_hash,
+ Test::Deep::superhashof($merged_prereqs->as_string_hash),
+ );
+
+ return if $ok;
+
+ $self->log_fatal('authordeps does not have all prereqs found in configure, runtime prereqs: '
+ . Test::Deep::deep_diag($stack));
+}
+
+1;
diff --git a/inc/CheckDelta.pm b/inc/CheckDelta.pm
new file mode 100644
index 0000000..d4ef142
--- /dev/null
+++ b/inc/CheckDelta.pm
@@ -0,0 +1,18 @@
+package inc::CheckDelta;
+use Moose;
+
+with 'Dist::Zilla::Role::AfterBuild';
+
+sub after_build {
+ my $self = shift;
+
+ return unless $ENV{DZIL_RELEASING};
+
+ my ($delta) = grep { $_->name eq 'lib/Moose/Manual/Delta.pod' }
+ @{ $self->zilla->files };
+
+ die "Moose::Manual::Delta still contains \$NEXT"
+ if $delta->content =~ /\$NEXT/;
+}
+
+1;
diff --git a/inc/CheckReleaseType.pm b/inc/CheckReleaseType.pm
new file mode 100644
index 0000000..6e79958
--- /dev/null
+++ b/inc/CheckReleaseType.pm
@@ -0,0 +1,37 @@
+package inc::CheckReleaseType;
+use Moose;
+with 'Dist::Zilla::Role::BeforeRelease';
+
+# this is so I don't accidentally release 2.x<odd>xx without the --trial
+# option, which has very nearly happened a few times.
+
+sub before_release
+{
+ my $self = shift;
+ my $version = $self->zilla->version;
+
+ $version =~ m/^\d\.\d{4}$/
+ or $self->log_fatal("version $version doesn't seem to conform to the normal specification!");
+
+ my $digit = substr($version, 3, 1);
+ if ($self->zilla->is_trial)
+ {
+ $digit % 2 == 1
+ or $self->log_fatal('-TRIAL releases must be numbered 2.x{ODD}xx!');
+ }
+ else
+ {
+ $digit % 2 == 0
+ or $self->log_fatal('stable releases must be numbered 2.x{EVEN}xx!');
+
+ # Moose::Manual::Support says:
+ # 2.x{EVEN}00 must be January, April, July, October only.
+ if (substr($version, -2, 2) eq '00')
+ {
+ # month is 0..11
+ my $month = (gmtime(time))[4];
+ $month % 3 == 0
+ or $self->log_fatal('2.x{EVEN}00 releases can only occur in January, April, July or October!');
+ }
+ }
+}
diff --git a/inc/Clean.pm b/inc/Clean.pm
new file mode 100644
index 0000000..a2a5563
--- /dev/null
+++ b/inc/Clean.pm
@@ -0,0 +1,50 @@
+package inc::Clean;
+use Moose;
+
+with 'Dist::Zilla::Role::BeforeBuild',
+ 'Dist::Zilla::Role::AfterBuild';
+use Path::Tiny;
+use File::pushd 'pushd';
+use Config;
+
+sub before_build { shift->_clean('.') }
+
+sub after_build {
+ my ($self, $opts) = @_;
+
+ $self->_clean($opts->{build_root});
+
+ my $iter = path($opts->{build_root})->iterator({ recurse => 1 });
+ my %found_files;
+ while (my $found_file = $iter->()) {
+ next if -d $found_file;
+ ++$found_files{ $found_file->relative($opts->{build_root}) };
+ }
+ delete $found_files{$_->name} foreach @{ $self->zilla->files };
+
+ $self->log(join("\n",
+ "WARNING: Files were left behind in $opts->{build_root} that were not explicitly added:",
+ sort keys %found_files,
+ )) if keys %found_files;
+}
+
+sub _clean {
+ my ($self, $build_dir) = @_;
+
+ my $cwd = pushd $build_dir;
+ if (-e 'Makefile') {
+
+ my $make = $Config{make} || 'make';
+
+ $self->log("Running $make distclean in $build_dir to clear out build cruft");
+ my $pid = fork;
+ unless ($pid) {
+ close(STDIN);
+ close(STDOUT);
+ close(STDERR);
+ { exec("$^X Makefile.PL && $make distclean") }
+ die "couldn't exec: $!";
+ }
+ waitpid($pid, 0) if $pid;
+ }
+}
diff --git a/inc/ExtractInlineTests.pm b/inc/ExtractInlineTests.pm
new file mode 100644
index 0000000..e2cda0a
--- /dev/null
+++ b/inc/ExtractInlineTests.pm
@@ -0,0 +1,58 @@
+package inc::ExtractInlineTests;
+
+use Moose;
+
+with 'Dist::Zilla::Role::FileGatherer';
+
+use File::Find::Rule;
+use inc::MyInline;
+use Test::Inline;
+
+sub gather_files {
+ my $self = shift;
+ my $arg = shift;
+
+ my $inline = Test::Inline->new(
+ verbose => 0,
+ ExtractHandler => 'My::Extract',
+ ContentHandler => 'My::Content',
+ OutputHandler => My::Output->new($self),
+ );
+
+ for my $pod (
+ File::Find::Rule->file->name(qr/\.pod$/)->in('lib/Moose/Cookbook') ) {
+ $inline->add($pod);
+ }
+
+ $inline->save;
+}
+
+{
+ package My::Output;
+
+ sub new {
+ my $class = shift;
+ my $dzil = shift;
+
+ return bless { dzil => $dzil }, $class;
+ }
+
+ sub write {
+ my $self = shift;
+ my $name = shift;
+ my $content = shift;
+
+ $name =~ s/^moose_cookbook_//;
+
+ $self->{dzil}->add_file(
+ Dist::Zilla::File::InMemory->new(
+ name => "t/recipes/$name",
+ content => $content,
+ )
+ );
+
+ return 1;
+ }
+}
+
+1;
diff --git a/inc/GenerateDocs.pm b/inc/GenerateDocs.pm
new file mode 100644
index 0000000..27d4cf4
--- /dev/null
+++ b/inc/GenerateDocs.pm
@@ -0,0 +1,57 @@
+package inc::GenerateDocs;
+
+use Moose;
+with 'Dist::Zilla::Role::FileGatherer',
+ 'Dist::Zilla::Role::AfterBuild',
+ 'Dist::Zilla::Role::FileInjector';
+use IPC::System::Simple qw(capturex);
+use File::pushd;
+use Path::Tiny;
+use List::Util 'first';
+
+my $filename = path(qw(lib Moose Manual Exceptions Manifest.pod));
+
+sub gather_files {
+ my ($self, $arg) = @_;
+
+ $self->add_file(Dist::Zilla::File::InMemory->new(
+ name => $filename->stringify,
+ # more to fill in later
+ content => <<'END_POD',
+# PODNAME: Moose::Manual::Exceptions::Manifest
+# ABSTRACT: Moose's Exception Types
+
+__END__
+
+=for comment insert generated content here
+END_POD
+ ));
+}
+
+sub after_build {
+ my ($self, $opts) = @_;
+ my $build_dir = $opts->{build_root};
+
+ my $wd = File::pushd::pushd($build_dir);
+ unless ( -d 'blib' ) {
+ my @builders = @{ $self->zilla->plugins_with( -BuildRunner ) };
+ die "no BuildRunner plugins specified" unless @builders;
+ $_->build for @builders;
+ die "no blib; failed to build properly?" unless -d 'blib';
+ }
+
+ # this must be run as a separate process because we need to use the new
+ # Moose we just generated, in order to introspect all the exception classes
+ $self->log('running author/docGenerator.pl...');
+ my $text = capturex($^X, "author/docGenerator.pl");
+
+ my $file_obj = first { $_->name eq $filename } @{$self->zilla->files};
+
+ my $content = $file_obj->content;
+ my $pos = index($content, "\n\n=for comment insert generated content here");
+ $file_obj->content(substr($content, 0, $pos) . "\n\n" . $text . substr($content, $pos, -1));
+
+ $filename->spew_raw($file_obj->encoded_content);
+}
+
+1;
diff --git a/inc/GitUpToDate.pm b/inc/GitUpToDate.pm
new file mode 100644
index 0000000..b688d8a
--- /dev/null
+++ b/inc/GitUpToDate.pm
@@ -0,0 +1,52 @@
+package inc::GitUpToDate;
+use Moose;
+
+with 'Dist::Zilla::Role::BeforeBuild';
+
+sub git {
+ if (wantarray) {
+ chomp(my @ret = qx{git $_[0]});
+ return @ret;
+ }
+ else {
+ chomp(my $ret = qx{git $_[0]});
+ return $ret;
+ }
+}
+
+sub before_build {
+ my $self = shift;
+
+ return unless $ENV{DZIL_RELEASING};
+
+ my $branch = git "symbolic-ref HEAD";
+ die "Could not get the current branch"
+ unless $branch;
+
+ $branch =~ s{refs/heads/}{};
+
+ $self->log("Ensuring branch $branch is up to date");
+
+ git "fetch origin";
+ my $origin = git "rev-parse origin/$branch";
+ my $head = git "rev-parse HEAD";
+
+ die "Branch $branch is not up to date (origin: $origin, HEAD: $head)"
+ if $origin ne $head;
+
+
+ # now also check that HEAD is current with the release branch
+ # that is, that the release branch is an ancestor commit of HEAD.
+ my $release_branch = ($self->zilla->plugin_named('Git::CheckFor::CorrectBranch')->release_branch)[0];
+ foreach my $remote ('origin/', '')
+ {
+ my $release_commit = git "rev-parse ${remote}$release_branch";
+ my $common_ancestor = git "merge-base $head $release_commit";
+
+ die "Branch $branch does not contain all commits from the current release branch ",
+ "(common ancestor for ${remote}$release_branch: $common_ancestor)"
+ if $common_ancestor ne $release_commit;
+ }
+}
+
+1;
diff --git a/inc/MMHelper.pm b/inc/MMHelper.pm
new file mode 100644
index 0000000..7e340b9
--- /dev/null
+++ b/inc/MMHelper.pm
@@ -0,0 +1,79 @@
+package MMHelper;
+
+use strict;
+use warnings;
+
+use Config;
+
+sub ccflags_dyn {
+ my $is_dev = shift;
+
+ my $ccflags = q<( $Config::Config{ccflags} || '' ) . ' -I.'>;
+ if ($is_dev and ($Config{cc} !~ /^cl\b/i)) {
+ $ccflags .= q< . ' -Wall -Wdeclaration-after-statement'>;
+ }
+
+ return $ccflags;
+}
+
+sub ccflags_static {
+ my $is_dev = shift;
+
+ return eval(ccflags_dyn($is_dev));
+}
+
+sub mm_args {
+ my ( @object, %xs );
+
+ for my $xs ( glob "xs/*.xs" ) {
+ ( my $c = $xs ) =~ s/\.xs$/.c/i;
+ ( my $o = $xs ) =~ s/\.xs$/\$(OBJ_EXT)/i;
+
+ $xs{$xs} = $c;
+ push @object, $o;
+ }
+
+ for my $c ( glob "*.c" ) {
+ ( my $o = $c ) =~ s/\.c$/\$(OBJ_EXT)/i;
+ push @object, $o;
+ }
+
+ return (
+ clean => { FILES => join( q{ }, @object ) },
+ OBJECT => join( q{ }, @object ),
+ XS => \%xs,
+ );
+}
+
+sub my_package_subs {
+ return <<'EOP';
+{
+package MY;
+
+use Config;
+
+sub const_cccmd {
+ my $ret = shift->SUPER::const_cccmd(@_);
+ return q{} unless $ret;
+
+ if ($Config{cc} =~ /^cl\b/i) {
+ warn 'you are using MSVC... we may not have gotten some options quite right.';
+ $ret .= ' /Fo$@';
+ }
+ else {
+ $ret .= ' -o $@';
+ }
+
+ return $ret;
+}
+
+sub postamble {
+ return <<'EOF';
+$(OBJECT) : mop.h
+EOF
+}
+}
+EOP
+}
+
+1;
diff --git a/inc/MakeMaker.pm b/inc/MakeMaker.pm
new file mode 100644
index 0000000..cd034ff
--- /dev/null
+++ b/inc/MakeMaker.pm
@@ -0,0 +1,96 @@
+package inc::MakeMaker;
+
+use Moose;
+
+use lib 'inc';
+
+use MMHelper;
+
+extends 'Dist::Zilla::Plugin::MakeMaker::Awesome';
+
+override _build_MakeFile_PL_template => sub {
+ my $self = shift;
+
+ my $tmpl = super();
+ my $assert_compiler = <<'ASSERT_COMPILER';
+# Secondary compile testing via ExtUtils::CBuilder
+sub can_xs {
+ # Do we have the configure_requires checker?
+ unless (eval 'require ExtUtils::CBuilder; ExtUtils::CBuilder->VERSION(0.27); 1') {
+ # They don't obey configure_requires, so it is
+ # someone old and delicate. Try to avoid hurting
+ # them by falling back to an older simpler test.
+ return can_cc();
+ }
+
+ return ExtUtils::CBuilder->new( quiet => 1 )->have_compiler;
+}
+
+# can we locate a (the) C compiler
+sub can_cc {
+ my @chunks = split(/ /, $Config::Config{cc}) or return;
+
+ # $Config{cc} may contain args; try to find out the program part
+ while (@chunks) {
+ return can_run("@chunks") || (pop(@chunks), next);
+ }
+
+ return;
+}
+
+# check if we can run some command
+sub can_run {
+ my ($cmd) = @_;
+
+ return $cmd if -x $cmd;
+ if (my $found_cmd = MM->maybe_command($cmd)) {
+ return $found_cmd;
+ }
+
+ for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') {
+ next if $dir eq '';
+ my $abs = File::Spec->catfile($dir, $cmd);
+ return $abs if (-x $abs or $abs = MM->maybe_command($abs));
+ }
+
+ return;
+}
+
+die 'This distribution requires a working compiler' unless can_xs();
+
+ASSERT_COMPILER
+
+ # splice in our stuff after the preamble bits
+ # TODO - MMA ought to make this easier.
+ $tmpl =~ m/use warnings;\n\n/g;
+ $tmpl = substr($tmpl, 0, pos($tmpl)) . $assert_compiler . substr($tmpl, pos($tmpl));
+
+
+ # TODO: splice this in using 'around _build_WriteMakefile_args'
+ my $ccflags = MMHelper::ccflags_dyn();
+ $tmpl =~ s/^(WriteMakefile\()/\$WriteMakefileArgs{CCFLAGS} = $ccflags;\n\n$1/m;
+
+ return $tmpl . "\n\n" . MMHelper::my_package_subs();
+};
+
+override _build_WriteMakefile_args => sub {
+ my $self = shift;
+
+ my $args = super();
+
+ return {
+ %{$args},
+ MMHelper::mm_args(),
+ };
+};
+
+override test => sub {
+ my $self = shift;
+
+ local $ENV{PERL5LIB} = join ':',
+ grep {defined} @ENV{ 'PERL5LIB', 'DZIL_TEST_INC' };
+
+ super();
+};
+
+1;
diff --git a/inc/MyInline.pm b/inc/MyInline.pm
new file mode 100644
index 0000000..e0697a6
--- /dev/null
+++ b/inc/MyInline.pm
@@ -0,0 +1,98 @@
+package MyInline;
+
+use strict;
+use warnings;
+
+{
+ package My::Extract;
+
+ use parent 'Test::Inline::Extract';
+
+ use List::Util qw( first );
+
+ # This extracts the SYNOPSIS in addition to code specifically
+ # marked for testing
+ my $search = qr/
+ (?:^|\n) # After the beginning of the string, or a newline
+ ( # ... start capturing
+ # EITHER
+ package\s+ # A package
+ [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
+ \s*; # And a statement terminator
+ | # OR
+ \#\s*PODNAME:\s+ # A PODNAME comment
+ [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
+ (?:\s+|$) # And a name terminator
+ |
+ =head1[ \t]+SYNOPSIS\n
+ .*?
+ (?=\n=)
+ | # OR
+ =for[ \t]+example[ \t]+begin\n # ... when we find a =for example begin
+ .*? # ... and keep capturing
+ \n=for[ \t]+example[ \t]+end\s*? # ... until the =for example end
+ (?:\n|$) # ... at the end of file or a newline
+ | # OR
+ =begin[ \t]+(?:test|testing)(?:-SETUP)? # ... when we find a =begin test or testing
+ .*? # ... and keep capturing
+ \n=end[ \t]+(?:test|testing)(?:-SETUP)? # ... until an =end tag
+ .*?
+ (?:\n|$) # ... at the end of file or a newline
+ ) # ... and stop capturing
+ /isx;
+
+ sub _elements {
+ my $self = shift;
+ my @elements = ();
+ while ( $self->{source} =~ m/$search/go ) {
+ my $elt = $1;
+
+ # A hack to turn the SYNOPSIS into something Test::Inline
+ # doesn't barf on
+ if ( $elt =~ s/=head1[ \t]+SYNOPSIS/=begin testing-SETUP\n\n{/ ) {
+ $elt .= "}\n\n=end testing-SETUP";
+ }
+
+ # It seems like search.cpan doesn't like a name with
+ # spaces after =begin. bleah, what a mess.
+ $elt =~ s/testing-SETUP/testing SETUP/g;
+
+ push @elements, $elt;
+ }
+
+ # If we have just one element it's a SYNOPSIS, so there's no
+ # tests.
+ return unless @elements > 2;
+
+ if ( @elements && $self->{source} =~ /# PODNAME: (Moose::Cookbook\S+)(?:\s|$)/ ) {
+ foreach my $element (@elements)
+ {
+ $element = "package $1;" if $element =~ /# PODNAME: (Moose::Cookbook\S+)(?:\s+|$)/;
+ }
+ }
+
+ if ( @elements && $self->{source} =~ /=head1 NAME\n\n(Moose::Cookbook\S+)/ ) {
+ unshift @elements, 'package ' . $1 . ';';
+ }
+
+ ( first {/^=/} @elements ) ? \@elements : '';
+ }
+}
+
+{
+ package My::Content;
+
+ use parent 'Test::Inline::Content::Default';
+
+ sub process {
+ my $self = shift;
+
+ my $base = $self->SUPER::process(@_);
+
+ $base =~ s/(\$\| = 1;)/use Test::Fatal;\n$1/;
+
+ return $base;
+ }
+}
+
+1;
diff --git a/inc/SimpleAuthority.pm b/inc/SimpleAuthority.pm
new file mode 100644
index 0000000..839571a
--- /dev/null
+++ b/inc/SimpleAuthority.pm
@@ -0,0 +1,13 @@
+use strict;
+use warnings;
+package inc::SimpleAuthority;
+
+use Moose;
+with 'Dist::Zilla::Role::MetaProvider';
+
+sub metadata
+{
+ return +{ x_authority => 'cpan:STEVAN' };
+}
+
+1;
diff --git a/inc/SimpleProvides.pm b/inc/SimpleProvides.pm
new file mode 100644
index 0000000..3d768b1
--- /dev/null
+++ b/inc/SimpleProvides.pm
@@ -0,0 +1,34 @@
+use strict;
+use warnings;
+package inc::SimpleProvides;
+
+use Moose;
+with 'Dist::Zilla::Role::MetaProvider',
+ 'Dist::Zilla::Role::FileFinderUser' => {
+ default_finders => [ ':InstallModules' ], # this is overridden in dist.ini!
+ },
+;
+
+sub metadata
+{
+ my $self = shift;
+
+ my $version = $self->zilla->version;
+
+ return +{
+ provides => {
+ map {
+ # this is an awful hack and assumes ascii package names:
+ # please do not cargo-cult this code elsewhere. The proper
+ # thing to do is to crack open the file and read the pod name.
+ my $filename = $_->name;
+ (my $package = $filename) =~ s{[/\\]}{::}g;
+ $package =~ s/^lib:://;
+ $package =~ s/\.pod$//;
+ $package => { file => $filename, version => $version }
+ } @{$self->found_files},
+ }
+ };
+}
+
+__PACKAGE__->meta->make_immutable;
diff --git a/inc/TestRelease.pm b/inc/TestRelease.pm
new file mode 100644
index 0000000..9d30a76
--- /dev/null
+++ b/inc/TestRelease.pm
@@ -0,0 +1,17 @@
+package inc::TestRelease;
+
+use Moose;
+
+extends 'Dist::Zilla::Plugin::TestRelease';
+
+around before_release => sub {
+ my $orig = shift;
+ my $self = shift;
+
+ local $ENV{MOOSE_TEST_MD} = 1 if not $self->zilla->is_trial;
+ local $ENV{AUTHOR_TESTING} = 1 if not $self->zilla->is_trial;
+
+ $self->$orig(@_);
+};
+
+1;