package Dist::Zilla::Dist::Builder 6.006;
# ABSTRACT: dist zilla subclass for building dists
use Moose 0.92; # role composition fixes
extends 'Dist::Zilla';
use MooseX::Types::Moose qw(HashRef);
use Dist::Zilla::Types qw(Path);
use File::pushd ();
use Dist::Zilla::Path; # because more Path::* is better, eh?
use Try::Tiny;
use List::Util 1.45 'uniq';
use namespace::autoclean;
#pod =method from_config
#pod
#pod my $zilla = Dist::Zilla->from_config(\%arg);
#pod
#pod This routine returns a new Zilla from the configuration in the current working
#pod directory.
#pod
#pod This method should not be relied upon, yet. Its semantics are B<certain> to
#pod change.
#pod
#pod Valid arguments are:
#pod
#pod config_class - the class to use to read the config
#pod default: Dist::Zilla::MVP::Reader::Finder
#pod
#pod =cut
sub from_config {
my ($class, $arg) = @_;
$arg ||= {};
my $root = path($arg->{dist_root} || '.');
my $sequence = $class->_load_config({
root => $root,
chrome => $arg->{chrome},
config_class => $arg->{config_class},
_global_stashes => $arg->{_global_stashes},
});
my $self = $sequence->section_named('_')->zilla;
$self->_setup_default_plugins;
return $self;
}
sub _setup_default_plugins {
my ($self) = @_;
unless ($self->plugin_named(':InstallModules')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':InstallModules',
zilla => $self,
style => 'grep',
code => sub {
my ($file, $self) = @_;
local $_ = $file->name;
return 1 if m{\Alib/} and m{\.(pm|pod)$};
return;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':IncModules')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':IncModules',
zilla => $self,
style => 'grep',
code => sub {
my ($file, $self) = @_;
local $_ = $file->name;
return 1 if m{\Ainc/} and m{\.pm$};
return;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':TestFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':TestFiles',
zilla => $self,
style => 'grep',
code => sub { local $_ = $_->name; m{\At/} },
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':ExtraTestFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':ExtraTestFiles',
zilla => $self,
style => 'grep',
code => sub { local $_ = $_->name; m{\Axt/} },
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':ExecFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':ExecFiles',
zilla => $self,
style => 'list',
code => sub {
my $plugins = $_[0]->zilla->plugins_with(-ExecFiles);
my @files = uniq map {; @{ $_->find_files } } @$plugins;
return \@files;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':PerlExecFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':PerlExecFiles',
zilla => $self,
style => 'list',
code => sub {
my $parent_plugin = $self->plugin_named(':ExecFiles');
my @files = grep {
$_->name =~ m{\.pl$}
or $_->content =~ m{^\s*\#\!.*perl\b};
} @{ $parent_plugin->find_files };
return \@files;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':ShareFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':ShareFiles',
zilla => $self,
style => 'list',
code => sub {
my $self = shift;
my $map = $self->zilla->_share_dir_map;
my @files;
if ( $map->{dist} ) {
push @files, grep {; $_->name =~ m{\A\Q$map->{dist}\E/} }
@{ $self->zilla->files };
}
if ( my $mod_map = $map->{module} ) {
for my $mod ( keys %$mod_map ) {
push @files, grep { $_->name =~ m{\A\Q$mod_map->{$mod}\E/} }
@{ $self->zilla->files };
}
}
return \@files;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':MainModule')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':MainModule',
zilla => $self,
style => 'grep',
code => sub {
my ($file, $self) = @_;
local $_ = $file->name;
return 1 if $_ eq $self->zilla->main_module->name;
return;
},
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':AllFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':AllFiles',
zilla => $self,
style => 'grep',
code => sub { return 1 },
});
push @{ $self->plugins }, $plugin;
}
unless ($self->plugin_named(':NoFiles')) {
require Dist::Zilla::Plugin::FinderCode;
my $plugin = Dist::Zilla::Plugin::FinderCode->new({
plugin_name => ':NoFiles',
zilla => $self,
style => 'list',
code => sub { return },
});
push @{ $self->plugins }, $plugin;
}
}
has _share_dir_map => (
is => 'ro',
isa => HashRef,
init_arg => undef,
lazy => 1,
builder => '_build_share_dir_map',
);
sub _build_share_dir_map {
my ($self) = @_;
my $share_dir_map = {};
for my $plugin (@{ $self->plugins_with(-ShareDir) }) {
next unless my $sub_map = $plugin->share_dir_map;
if ( $sub_map->{dist} ) {
$self->log_fatal("can't install more than one distribution ShareDir")
if $share_dir_map->{dist};
$share_dir_map->{dist} = $sub_map->{dist};
}
if ( my $mod_map = $sub_map->{module} ) {
for my $mod ( keys %$mod_map ) {
$self->log_fatal("can't install more than one ShareDir for $mod")
if $share_dir_map->{module}{$mod};
$share_dir_map->{module}{$mod} = $mod_map->{$mod};
}
}
}
return $share_dir_map;
}
sub _load_config {
my ($class, $arg) = @_;
$arg ||= {};
my $config_class =
$arg->{config_class} ||= 'Dist::Zilla::MVP::Reader::Finder';
Class::Load::load_class($config_class);
$arg->{chrome}->logger->log_debug(
{ prefix => '[DZ] ' },
"reading configuration using $config_class"
);
my $root = $arg->{root};
require Dist::Zilla::MVP::Assembler::Zilla;
require Dist::Zilla::MVP::Section;
my $assembler = Dist::Zilla::MVP::Assembler::Zilla->new({
chrome => $arg->{chrome},
zilla_class => $class,
section_class => 'Dist::Zilla::MVP::Section', # make this DZMA default
});
for ($assembler->sequence->section_named('_')) {
$_->add_value(chrome => $arg->{chrome});
$_->add_value(root => $arg->{root});
$_->add_value(_global_stashes => $arg->{_global_stashes})
if $arg->{_global_stashes};
}
my $seq;
try {
$seq = $config_class->read_config(
$root->child('dist'),
{
assembler => $assembler
},
);
} catch {
die $_ unless try {
$_->isa('Config::MVP::Error')
and $_->ident eq 'package not installed'
};
my $package = $_->package;
my $bundle = $_->section_name =~ m{^@(?!.*/)} ? ' bundle' : '';
die <<"END_DIE";
Required plugin$bundle $package isn't installed.
Run 'dzil authordeps' to see a list of all required plugins.
You can pipe the list to your CPAN client to install or update them:
dzil authordeps --missing | cpanm
END_DIE
};
return $seq;
}
#pod =method build_in
#pod
#pod $zilla->build_in($root);
#pod
#pod This method builds the distribution in the given directory. If no directory
#pod name is given, it defaults to DistName-Version. If the distribution has
#pod already been built, an exception will be thrown.
#pod
#pod =method build
#pod
#pod This method just calls C<build_in> with no arguments. It gets you the default
#pod behavior without the weird-looking formulation of C<build_in> with no object
#pod for the preposition!
#pod
#pod =cut
sub build { $_[0]->build_in }
sub build_in {
my ($self, $root) = @_;
$self->log_fatal("tried to build with a minter")
if $self->isa('Dist::Zilla::Dist::Minter');
$self->log_fatal("attempted to build " . $self->name . " a second time")
if $self->built_in;
$_->before_build for @{ $self->plugins_with(-BeforeBuild) };
$self->log("beginning to build " . $self->name);
$_->gather_files for @{ $self->plugins_with(-FileGatherer) };
$_->set_file_encodings for @{ $self->plugins_with(-EncodingProvider) };
$_->prune_files for @{ $self->plugins_with(-FilePruner) };
$self->version; # instantiate this lazy attribute now that files are gathered
$_->munge_files for @{ $self->plugins_with(-FileMunger) };
$_->register_prereqs for @{ $self->plugins_with(-PrereqSource) };
$self->prereqs->finalize;
# Barf if someone has already set up a prereqs entry? -- rjbs, 2010-04-13
$self->distmeta->{prereqs} = $self->prereqs->as_string_hash;
$_->setup_installer for @{ $self->plugins_with(-InstallTool) };
$self->_check_dupe_files;
my $build_root = $self->_prep_build_root($root);
$self->log("writing " . $self->name . " in $build_root");
for my $file (@{ $self->files }) {
$self->_write_out_file($file, $build_root);
}
$_->after_build({ build_root => $build_root })
for @{ $self->plugins_with(-AfterBuild) };
$self->built_in($build_root);
}
#pod =attr built_in
#pod
#pod This is the L<Path::Tiny>, if any, in which the dist has been built.
#pod
#pod =cut
has built_in => (
is => 'rw',
isa => Path,
init_arg => undef,
coerce => 1,
);
#pod =method ensure_built_in
#pod
#pod $zilla->ensure_built_in($root);
#pod
#pod This method behaves like C<L</build_in>>, but if the dist is already built in
#pod C<$root> (or the default root, if no root is given), no exception is raised.
#pod
#pod =method ensure_built
#pod
#pod This method just calls C<ensure_built_in> with no arguments. It gets you the
#pod default behavior without the weird-looking formulation of C<ensure_built_in>
#pod with no object for the preposition!
#pod
#pod =cut
sub ensure_built {
$_[0]->ensure_built_in;
}
sub ensure_built_in {
my ($self, $root) = @_;
# $root ||= $self->name . q{-} . $self->version;
return $self->built_in if $self->built_in and
(!$root or ($self->built_in eq $root));
Carp::croak("dist is already built, but not in $root") if $self->built_in;
$self->build_in($root);
}
#pod =method dist_basename
#pod
#pod my $basename = $zilla->dist_basename;
#pod
#pod This method will return the dist's basename (e.g. C<Dist-Name-1.01>.
#pod The basename is used as the top-level directory in the tarball. It
#pod does not include C<-TRIAL>, even if building a trial dist.
#pod
#pod =cut
sub dist_basename {
my ($self) = @_;
return join(q{},
$self->name,
'-',
$self->version,
);
}
#pod =method archive_filename
#pod
#pod my $tarball = $zilla->archive_filename;
#pod
#pod This method will return the filename (e.g. C<Dist-Name-1.01.tar.gz>)
#pod of the tarball of this distribution. It will include C<-TRIAL> if building a
#pod trial distribution, unless the version contains an underscore. The tarball
#pod might not exist.
#pod
#pod =cut
sub archive_filename {
my ($self) = @_;
return join(q{},
$self->dist_basename,
( $self->is_trial && $self->version !~ /_/ ? '-TRIAL' : '' ),
'.tar.gz'
);
}
#pod =method build_archive
#pod
#pod $zilla->build_archive;
#pod
#pod This method will ensure that the dist has been built, and will then build a
#pod tarball of the build directory in the current directory.
#pod
#pod =cut
sub build_archive {
my ($self) = @_;
my $built_in = $self->ensure_built;
my $basename = $self->dist_basename;
my $basedir = path($basename);
$_->before_archive for @{ $self->plugins_with(-BeforeArchive) };
my $method = Class::Load::load_optional_class('Archive::Tar::Wrapper',
{ -version => 0.15 })
? '_build_archive_with_wrapper'
: '_build_archive';
my $archive = $self->$method($built_in, $basename, $basedir);
my $file = path($self->archive_filename);
$self->log("writing archive to $file");
$archive->write("$file", 9);
return $file;
}
sub _build_archive {
my ($self, $built_in, $basename, $basedir) = @_;
$self->log("building archive with Archive::Tar; install Archive::Tar::Wrapper 0.15 or newer for improved speed");
require Archive::Tar;
my $archive = Archive::Tar->new;
my %seen_dir;
for my $distfile (
sort { length($a->name) <=> length($b->name) } @{ $self->files }
) {
my $in = path($distfile->name)->parent;
unless ($seen_dir{ $in }++) {
$archive->add_data(
$basedir->child($in),
'',
{ type => Archive::Tar::Constant::DIR(), mode => 0755 },
)
}
my $filename = $built_in->child( $distfile->name );
$archive->add_data(
$basedir->child( $distfile->name ),
path($filename)->slurp_raw,
{ mode => (stat $filename)[2] & ~022 },
);
}
return $archive;
}
sub _build_archive_with_wrapper {
my ($self, $built_in, $basename, $basedir) = @_;
$self->log("building archive with Archive::Tar::Wrapper");
my $archive = Archive::Tar::Wrapper->new;
for my $distfile (
sort { length($a->name) <=> length($b->name) } @{ $self->files }
) {
my $in = path($distfile->name)->parent;
my $filename = $built_in->child( $distfile->name );
$archive->add(
$basedir->child( $distfile->name )->stringify,
$filename->stringify,
{ perm => (stat $filename)[2] & ~022 },
);
}
return $archive;
}
sub _prep_build_root {
my ($self, $build_root) = @_;
$build_root = path($build_root || $self->dist_basename);
$build_root->mkpath unless -d $build_root;
my $dist_root = $self->root;
return $build_root if !-d $build_root;
my $ok = eval { $build_root->remove_tree({ safe => 0 }); 1 };
die "unable to delete '$build_root' in preparation of build: $@" unless $ok;
# the following is done only on windows, and only if the deletion failed,
# yet rmtree reported success, because currently rmdir is non-blocking as per:
# https://rt.perl.org/Ticket/Display.html?id=123958
if ( $^O eq 'MSWin32' and -d $build_root ) {
$self->log("spinning for at least one second to allow other processes to release locks on $build_root");
my $timeout = time + 2;
while(time != $timeout and -d $build_root) { }
die "unable to delete '$build_root' in preparation of build because some process has a lock on it"
if -d $build_root;
}
return $build_root;
}
#pod =method release
#pod
#pod $zilla->release;
#pod
#pod This method releases the distribution, probably by uploading it to the CPAN.
#pod The actual effects of this method (as with most of the methods) is determined
#pod by the loaded plugins.
#pod
#pod =cut
sub release {
my $self = shift;
Carp::croak("you can't release without any Releaser plugins")
unless my @releasers = @{ $self->plugins_with(-Releaser) };
$ENV{DZIL_RELEASING} = 1;
my $tgz = $self->build_archive;
# call all plugins implementing BeforeRelease role
$_->before_release($tgz) for @{ $self->plugins_with(-BeforeRelease) };
# do the actual release
$_->release($tgz) for @releasers;
# call all plugins implementing AfterRelease role
$_->after_release($tgz) for @{ $self->plugins_with(-AfterRelease) };
}
#pod =method clean
#pod
#pod This method removes temporary files and directories suspected to have been
#pod produced by the Dist::Zilla build process. Specifically, it deletes the
#pod F<.build> directory and any entity that starts with the dist name and a hyphen,
#pod like matching the glob C<Your-Dist-*>.
#pod
#pod =cut
sub clean {
my ($self, $dry_run) = @_;
require File::Path;
for my $x (grep { -e } '.build', glob($self->name . '-*')) {
if ($dry_run) {
$self->log("clean: would remove $x");
} else {
$self->log("clean: removing $x");
File::Path::rmtree($x);
}
};
}
#pod =method ensure_built_in_tmpdir
#pod
#pod $zilla->ensure_built_in_tmpdir;
#pod
#pod This method will consistently build the distribution in a temporary
#pod subdirectory. It will return the path for the temporary build location.
#pod
#pod =cut
sub ensure_built_in_tmpdir {
my $self = shift;
require File::Temp;
my $build_root = path('.build');
$build_root->mkpath unless -d $build_root;
my $target = path( File::Temp::tempdir(DIR => $build_root) );
$self->log("building distribution under $target for installation");
my $os_has_symlinks = eval { symlink("",""); 1 };
my $previous;
my $latest;
if( $os_has_symlinks ) {
$previous = path( $build_root, 'previous' );
$latest = path( $build_root, 'latest' );
if( -l $previous ) {
$previous->remove
or $self->log("cannot remove old .build/previous link");
}
if( -l $latest ) {
rename $latest, $previous
or $self->log("cannot move .build/latest link to .build/previous");
}
symlink $target->basename, $latest
or $self->log('cannot create link .build/latest');
}
$self->ensure_built_in($target);
return ($target, $latest, $previous);
}
#pod =method install
#pod
#pod $zilla->install( \%arg );
#pod
#pod This method installs the distribution locally. The distribution will be built
#pod in a temporary subdirectory, then the process will change directory to that
#pod subdir and an installer will be run.
#pod
#pod Valid arguments are:
#pod
#pod keep_build_dir - if true, don't rmtree the build dir, even if everything
#pod seemed to work
#pod install_command - the command to run in the subdir to install the dist
#pod default (roughly): $^X -MCPAN -einstall .
#pod
#pod this argument should be an arrayref
#pod
#pod =cut
sub install {
my ($self, $arg) = @_;
$arg ||= {};
my ($target, $latest) = $self->ensure_built_in_tmpdir;
my $ok = eval {
## no critic Punctuation
my $wd = File::pushd::pushd($target);
my @cmd = $arg->{install_command}
? @{ $arg->{install_command} }
: (cpanm => ".");
$self->log_debug([ 'installing via %s', \@cmd ]);
system(@cmd) && $self->log_fatal([ "error running %s", \@cmd ]);
1;
};
unless ($ok) {
my $error = $@ || '(exception clobered)';
$self->log("install failed, left failed dist in place at $target");
die $error;
}
if ($arg->{keep_build_dir}) {
$self->log("all's well; left dist in place at $target");
} else {
$self->log("all's well; removing $target");
$target->remove_tree({ safe => 0 });
$latest->remove if $latest;
}
return;
}
#pod =method test
#pod
#pod $zilla->test(\%arg);
#pod
#pod This method builds a new copy of the distribution and tests it using
#pod C<L</run_tests_in>>.
#pod
#pod C<\%arg> may be omitted. Otherwise, valid arguments are:
#pod
#pod keep_build_dir - if true, don't rmtree the build dir, even if everything
#pod seemed to work
#pod
#pod =cut
sub test {
my ($self, $arg) = @_;
Carp::croak("you can't test without any TestRunner plugins")
unless my @testers = @{ $self->plugins_with(-TestRunner) };
my ($target, $latest) = $self->ensure_built_in_tmpdir;
my $error = $self->run_tests_in($target, $arg);
if ($arg and $arg->{keep_build_dir}) {
$self->log("all's well; left dist in place at $target");
return;
}
$self->log("all's well; removing $target");
$target->remove_tree({ safe => 0 });
$latest->remove if $latest;
}
#pod =method run_tests_in
#pod
#pod my $error = $zilla->run_tests_in($directory, $arg);
#pod
#pod This method runs the tests in $directory (a Path::Tiny), which must contain an
#pod already-built copy of the distribution. It will throw an exception if there
#pod are test failures.
#pod
#pod It does I<not> set any of the C<*_TESTING> environment variables, nor
#pod does it clean up C<$directory> afterwards.
#pod
#pod =cut
sub run_tests_in {
my ($self, $target, $arg) = @_;
Carp::croak("you can't test without any TestRunner plugins")
unless my @testers = @{ $self->plugins_with(-TestRunner) };
for my $tester (@testers) {
my $wd = File::pushd::pushd($target);
$tester->test( $target, $arg );
}
}
#pod =method run_in_build
#pod
#pod $zilla->run_in_build( \@cmd );
#pod
#pod This method makes a temporary directory, builds the distribution there,
#pod executes all the dist's L<BuildRunner|Dist::Zilla::Role::BuildRunner>s
#pod (unless directed not to, via C<< $arg->{build} = 0 >>), and
#pod then runs the given command in the build directory. If the command exits
#pod non-zero, the directory will be left in place.
#pod
#pod =cut
sub run_in_build {
my ($self, $cmd, $arg) = @_;
$self->log_fatal("you can't build without any BuildRunner plugins")
unless ($arg and exists $arg->{build} and ! $arg->{build})
or @{ $self->plugins_with(-BuildRunner) };
require "Config.pm"; # skip autoprereq
my ($target, $latest) = $self->ensure_built_in_tmpdir;
my $abstarget = $target->absolute;
# building the dist for real
my $ok = eval {
my $wd = File::pushd::pushd($target);
if ($arg and exists $arg->{build} and ! $arg->{build}) {
system(@$cmd) and die "error while running: @$cmd";
return 1;
}
$self->_ensure_blib;
local $ENV{PERL5LIB} = join $Config::Config{path_sep},
(map { $abstarget->child('blib', $_) } qw(arch lib)),
(defined $ENV{PERL5LIB} ? $ENV{PERL5LIB} : ());
local $ENV{PATH} = join $Config::Config{path_sep},
(map { $abstarget->child('blib', $_) } qw(bin script)),
(defined $ENV{PATH} ? $ENV{PATH} : ());
system(@$cmd) and die "error while running: @$cmd";
1;
};
if ($ok) {
$self->log("all's well; removing $target");
$target->remove_tree({ safe => 0 });
$latest->remove if $latest;
} else {
my $error = $@ || '(unknown error)';
$self->log($error);
$self->log_fatal("left failed dist in place at $target");
}
}
# Ensures that a F<blib> directory exists in the build, by invoking all
# C<-BuildRunner> plugins to generate it. Useful for commands that operate on
# F<blib>, such as C<test> or C<run>.
sub _ensure_blib {
my ($self) = @_;
unless ( -d 'blib' ) {
my @builders = @{ $self->plugins_with( -BuildRunner ) };
$self->log_fatal("no BuildRunner plugins specified") unless @builders;
$_->build for @builders;
$self->log_fatal("no blib; failed to build properly?") unless -d 'blib';
}
}
__PACKAGE__->meta->make_immutable;
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Dist::Zilla::Dist::Builder - dist zilla subclass for building dists
=head1 VERSION
version 6.006
=head1 ATTRIBUTES
=head2 built_in
This is the L<Path::Tiny>, if any, in which the dist has been built.
=head1 METHODS
=head2 from_config
my $zilla = Dist::Zilla->from_config(\%arg);
This routine returns a new Zilla from the configuration in the current working
directory.
This method should not be relied upon, yet. Its semantics are B<certain> to
change.
Valid arguments are:
config_class - the class to use to read the config
default: Dist::Zilla::MVP::Reader::Finder
=head2 build_in
$zilla->build_in($root);
This method builds the distribution in the given directory. If no directory
name is given, it defaults to DistName-Version. If the distribution has
already been built, an exception will be thrown.
=head2 build
This method just calls C<build_in> with no arguments. It gets you the default
behavior without the weird-looking formulation of C<build_in> with no object
for the preposition!
=head2 ensure_built_in
$zilla->ensure_built_in($root);
This method behaves like C<L</build_in>>, but if the dist is already built in
C<$root> (or the default root, if no root is given), no exception is raised.
=head2 ensure_built
This method just calls C<ensure_built_in> with no arguments. It gets you the
default behavior without the weird-looking formulation of C<ensure_built_in>
with no object for the preposition!
=head2 dist_basename
my $basename = $zilla->dist_basename;
This method will return the dist's basename (e.g. C<Dist-Name-1.01>.
The basename is used as the top-level directory in the tarball. It
does not include C<-TRIAL>, even if building a trial dist.
=head2 archive_filename
my $tarball = $zilla->archive_filename;
This method will return the filename (e.g. C<Dist-Name-1.01.tar.gz>)
of the tarball of this distribution. It will include C<-TRIAL> if building a
trial distribution, unless the version contains an underscore. The tarball
might not exist.
=head2 build_archive
$zilla->build_archive;
This method will ensure that the dist has been built, and will then build a
tarball of the build directory in the current directory.
=head2 release
$zilla->release;
This method releases the distribution, probably by uploading it to the CPAN.
The actual effects of this method (as with most of the methods) is determined
by the loaded plugins.
=head2 clean
This method removes temporary files and directories suspected to have been
produced by the Dist::Zilla build process. Specifically, it deletes the
F<.build> directory and any entity that starts with the dist name and a hyphen,
like matching the glob C<Your-Dist-*>.
=head2 ensure_built_in_tmpdir
$zilla->ensure_built_in_tmpdir;
This method will consistently build the distribution in a temporary
subdirectory. It will return the path for the temporary build location.
=head2 install
$zilla->install( \%arg );
This method installs the distribution locally. The distribution will be built
in a temporary subdirectory, then the process will change directory to that
subdir and an installer will be run.
Valid arguments are:
keep_build_dir - if true, don't rmtree the build dir, even if everything
seemed to work
install_command - the command to run in the subdir to install the dist
default (roughly): $^X -MCPAN -einstall .
this argument should be an arrayref
=head2 test
$zilla->test(\%arg);
This method builds a new copy of the distribution and tests it using
C<L</run_tests_in>>.
C<\%arg> may be omitted. Otherwise, valid arguments are:
keep_build_dir - if true, don't rmtree the build dir, even if everything
seemed to work
=head2 run_tests_in
my $error = $zilla->run_tests_in($directory, $arg);
This method runs the tests in $directory (a Path::Tiny), which must contain an
already-built copy of the distribution. It will throw an exception if there
are test failures.
It does I<not> set any of the C<*_TESTING> environment variables, nor
does it clean up C<$directory> afterwards.
=head2 run_in_build
$zilla->run_in_build( \@cmd );
This method makes a temporary directory, builds the distribution there,
executes all the dist's L<BuildRunner|Dist::Zilla::Role::BuildRunner>s
(unless directed not to, via C<< $arg->{build} = 0 >>), and
then runs the given command in the build directory. If the command exits
non-zero, the directory will be left in place.
=head1 AUTHOR
Ricardo SIGNES 😏 <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by Ricardo SIGNES.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut