The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Perl::Dist::WiX::Asset::Perl;

=pod

=head1 NAME

Perl::Dist::WiX::Asset::Perl - "Perl core" asset for a Win32 Perl

=head1 VERSION

This document describes Perl::Dist::WiX::Asset::Perl version 1.500002.

=head1 SYNOPSIS

  my $distribution = Perl::Dist::WiX::Asset::Perl->new(
    parent => $dist, # A Perl::Dist::WiX object.
    url    => 'http://strawberryperl.com/package/perl-5.10.1.tar.gz',
    patch  => [ qw{
        lib/CPAN/Config.pm
        win32/config.gc
        win32/config_sh.PL
        win32/config_H.gc
        }
    ],
    license => {
        'perl-5.10.1/Readme'   => 'perl/Readme',
        'perl-5.10.1/Artistic' => 'perl/Artistic',
        'perl-5.10.1/Copying'  => 'perl/Copying',
	},
  );

  $distribution->install();
  
=head1 DESCRIPTION

This asset downloads the Perl source code for a given version of Perl
and patches and installs it into a specified directory

=cut

#<<<
use 5.010;
use Moose;
use MooseX::Types::Moose   qw( Str HashRef ArrayRef Bool Maybe );
use File::Spec::Functions  qw( catdir splitpath rel2abs catfile );
use File::Basename         qw();
#>>>

our $VERSION = '1.500002';

with 'Perl::Dist::WiX::Role::Asset';

=head1 METHODS

This class is a L<Perl::Dist::WiX::Role::Asset|Perl::Dist::WiX::Role::Asset>
and shares its API.

=head2 new

The C<new> constructor takes a series of parameters, validates then
and returns a new C<Perl::Dist::WiX::Asset::Perl> object.

It inherits all the parameters described in the 
L<< Perl::Dist::WiX::Role::Asset->new()|Perl::Dist::WiX::Role::Asset/new >> 
method documentation, and adds the additional parameters described below.

=head3 name

The C<name> parameter is the name of the package for the purposes of 
identification in messages.

This defauls to 'perl'.

=cut



has name => (
	is      => 'bare',
	isa     => Str,
	reader  => '_get_name',
	default => 'perl',
);




=head3 license

The required C<license> parameter allows you to specify which files get 
copied to the license directory of the distribution.

The keys are the files to copy, as relative filenames from the subdirectory
named in C<unpack_to>. (Git checkouts are copied to a directory named 
C<'perl-git'>, and that directory needs to be specified in the keys.)

The values are the locations to copy them to, relative to the license 
directory of the distribution.

=cut



has license => (
	is       => 'bare',
	isa      => HashRef,
	reader   => '_get_license',
	required => 1,
);



=head3 patch

The required C<patch> parameter allows you to specify which files get 
patched before the distribution is built.

These files will be passed to the routine C<_find_perl_file>, which will 
check the share directory of each plugin module(s) that was/were loaded
for the named file, and return the correct location. 

VERSION is 'git' for git checkouts.

The patch files can either have the names of original files (in which case 
the files are copied) or can have an additional extension of C<.tt> (in 
which case the files are processed through Template Toolkit, with the 
parameters described in 
L<< Perl::Dist::WiX->patch_file()|Perl::Dist::WiX::Mixin::Patching/patch_file >>.)

The makefile.mk is automatically patched and is not mentioned here.

=cut



has patch => (
	is       => 'bare',
	isa      => ArrayRef,
	reader   => '_get_patch',
	required => 1,
);



=head3 unpack_to

The optional C<unpack_to> parameter allows you to specify in which 
subdirectory of the build directory the tarball gets unpacked to or the
checkout gets copied to.

This defaults to 'perl'.

=cut



has unpack_to => (
	is      => 'bare',
	isa     => Str,
	reader  => '_get_unpack_to',
	default => 'perl',
);



=head3 install_to

The optional C<install_to> parameter allows you to specify in which 
subdirectory of the image directory the Perl distribution gets
installed to.

This defaults to 'perl'.

=cut



has install_to => (
	is      => 'ro',
	isa     => Str,
	reader  => '_get_install_to',
	default => 'perl',
);



=head3 force

The optional boolean C<force> param allows you to specify that the tests
should be skipped and Perl installed without validating it.

This defaults to true if either the force() or forceperl() attributes of 
the C<Perl::Dist::WiX> parent object are true.  Otherwise, it defaults to
false.

=cut



has force => (
	is      => 'bare',
	isa     => Bool,
	reader  => '_get_force',
	lazy    => 1,
	default => sub {
		$_[0]->_force() ? 1 : $_[0]->_forceperl() ? 1 : 0;
	},
);



=head3 git

The optional C<git> param specifies, if defined, that:

1) Perl is being built from a checkout directory, as opposed to a tarball, 
and

2) The "git describe" output is as specified in this parameter.

This defaults to undef, and needs to be specified for building a git 
checkout.

=cut



has git => (
	is      => 'bare',
	isa     => Maybe [Str],
	reader  => '_get_git',
	default => undef,
);



=head2 install

The install method installs the Perl distribution described by the
B<Perl::Dist::WiX::Asset::Perl> object and returns true or throws
an exception.

The C<install> method takes care of the detailed process
of building the Perl binary and installing it into the
distribution.

A short summary of the process would be that it downloads or otherwise
fetches the package that was named when the object is created, unpacks it, 
copies out any license files from the source code, then tweaks the Win32 
makefile to point to the specific build directory, and then runs 
make/make test/make install. 

Returns true (after 20 minutes or so) or throws an exception on
error.



=cut



sub install {
	my $self = shift;

	# Get the initial directory contents to compare against later.
	$self->_trace_line( 0, 'Preparing ' . $self->_get_name() . "\n" );
	my $fl2 = File::List::Object->new->readdir(
		catdir( $self->_get_image_dir, 'perl' ) );

	# Are we building from a git snapshot?
	my $git = $self->_get_git();

	# Download the perl tarball if needed.
	my $tgz;
	if ( not defined $git ) {

		# Download the file
		$tgz =
		  $self->_mirror( $self->_get_url(), $self->_get_download_dir(), );
	}

	# Prepare for building.
	my $unpack_to =
	  catdir( $self->_get_build_dir(), $self->_get_unpack_to() );
	if ( -d $unpack_to ) {
		$self->_trace_line( 2, "Removing previous $unpack_to\n" );
		File::Remove::remove( \1, $unpack_to );
	}

	my $perlsrc;
	if ( defined $git ) {

		# Copy to the build directory.
		$self->_copy(
			URI->new( $self->_get_url() )->file(),
			catdir( $unpack_to, 'perl-git' ) );
		$perlsrc = 'perl-git';
	} else {

		# Unpack to the build directory
		my @files = $self->_extract( $tgz, $unpack_to );

		# Get the versioned name of the directory
		( $perlsrc = $tgz ) =~
s{[.] tar[.] gz\z | [.] tgz\z | [.] tar[.] bz2\z | [.] tbz\z}{}msx;
		$perlsrc = File::Basename::basename($perlsrc);
	}

	# Pre-copy updated files over the top of the source
	my $patch   = $self->_get_patch();
	my $version = $self->_get_pv_human();
	if ($patch) {

		# Overwrite the appropriate files
		foreach my $file ( @{$patch} ) {
			$self->_patch_perl_file( $file => "$unpack_to\\$perlsrc" );
		}
	}

	# Copy in licenses
	if ( ref $self->_get_license() eq 'HASH' ) {
		my $licenses = $self->_get_license();
		my $license_dir = catdir( $self->_get_image_dir(), 'licenses' );
		if ( defined $git ) {
			foreach my $key ( keys %{$licenses} ) {
				$self->_copy( catfile( $unpack_to, $key ),
					catfile( $license_dir, $licenses->{$key} ) );
			}
		} else {
			$self->_extract_filemap( $tgz, $self->_get_license(),
				$license_dir, 1 );
		}
	} ## end if ( ref $self->_get_license...)

	# Build win32 perl
  SCOPE: {

		# Prepare to patch
		my $image_dir = $self->_get_image_dir();
		my $INST_TOP = catdir( $image_dir, $self->_get_install_to() );
		my ($INST_DRV) = splitpath( $INST_TOP, 1 );

		my $wd = $self->_pushd( $unpack_to, $perlsrc, 'win32' );

		# Patch the makefile.
		$self->_trace_line( 2, "Patching makefile.mk\n" );
		$self->_patch_perl_file(
			'win32/makefile.mk' => "$unpack_to\\$perlsrc",
			{   dist     => $self->_get_parent(),
				INST_DRV => $INST_DRV,
				INST_TOP => $INST_TOP,
			} );

		# Compile perl.
		$self->_trace_line( 1, "Building perl $version...\n" );
		$self->_make();

		# Get information required for testing and installing perl.
		my $force = $self->_get_force();
		my $long_build =
		  Win32::GetLongPathName( rel2abs( $self->_get_build_dir() ) );

		# Warn about problem with testing perl 5.10.0
		if (   ( not $force )
			&& ( $long_build =~ /\s/ms )
			&& ( $self->_get_pv_human() eq '5.10.0' ) )
		{
			$force = 1;
			$self->_trace_line( 0, <<"EOF");
***********************************************************
* Perl 5.10.0 cannot be tested at this point.
* Because the build directory
* $long_build
* contains spaces when it becomes a long name,
* testing the CPANPLUS module fails in 
* lib/CPANPLUS/t/15_CPANPLUS-Shell.t
* 
* You may wish to build perl within a directory
* that does not contain spaces by setting the build_dir
* (or temp_dir, which sets the build_dir indirectly if
* build_dir is not specified) parameter to new to a 
* directory that does not contain spaces.
*
* -- csjewell\@cpan.org
***********************************************************
EOF
		} ## end if ( ( not $force ) &&...)

		# Testing perl if requested.
		if ( not $force ) {
			local $ENV{PERL_SKIP_TTY_TEST} = 1;
			$self->_trace_line( 1, "Testing perl...\n" );
			$self->_make('test');
		}

		# Installing perl.
		$self->_trace_line( 1, "Installing perl...\n" );
		$self->_make(qw/install UNINST=1/);
	} ## end SCOPE:

	# If using gcc4, copy the helper dll into perl's bin directory.
	if ( 4 == $self->_gcc_version() ) {
		$self->_copy(
			catfile(
				$self->_get_image_dir(), 'c',
				'bin',                   'libgcc_s_sjlj-1.dll'
			),
			catfile(
				$self->_get_image_dir(), 'perl',
				'bin',                   'libgcc_s_sjlj-1.dll'
			),
		);
	} ## end if ( 4 == $self->_gcc_version...)

	# Delete a2p.exe if relocatable (Can't relocate a binary).
	if ( $self->_relocatable() ) {
		unlink catfile( $self->_get_image_dir(), 'perl', 'bin', 'a2p.exe' )
		  or PDWiX->throw("Could not delete a2p.exe\n");
	}

	# Create the perl_licenses fragment.
	my $fl_lic = File::List::Object->new()
	  ->readdir( catdir( $self->_get_image_dir(), 'licenses', 'perl' ) );
	$self->_insert_fragment( 'perl_licenses', $fl_lic );

	# Now create the perl fragment.
	my $fl = File::List::Object->new()
	  ->readdir( catdir( $self->_get_image_dir(), 'perl' ) );
	$fl->subtract($fl2)->filter( $self->_filters );
	$self->_insert_fragment( 'perl', $fl, 1 );

	return 1;
} ## end sub install

no Moose;
__PACKAGE__->meta->make_immutable;

1;

__END__

=head1 SUPPORT

Bugs should be reported via the CPAN bug tracker at

L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Perl-Dist-WiX>

For other issues, contact the author.

=head1 AUTHOR

Curtis Jewell E<lt>csjewell@cpan.orgE<gt>

Adam Kennedy E<lt>adamk@cpan.orgE<gt>

=head1 SEE ALSO

L<Perl::Dist::WiX|Perl::Dist::WiX>, 
L<Perl::Dist::WiX::Role::Asset|Perl::Dist::WiX::Role::Asset>

=head1 COPYRIGHT

Copyright 2009 - 2010 Curtis Jewell.

Copyright 2007 - 2009 Adam Kennedy.

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.

=cut