Perl::Dist::WiX::Mixin::Checkpoint - Checkpoint support for Perl::Dist::WiX


Perl-Dist-WiX documentation Contained in the Perl-Dist-WiX distribution.

Index


Code Index:

NAME

Top

Perl::Dist::WiX::Mixin::Checkpoint - Checkpoint support for Perl::Dist::WiX

VERSION

Top

This document describes Perl::Dist::WiX::Mixin::Checkpoint version 1.500002.

SYNOPSIS

Top

	# This module is not to be used independently.
	# It provides methods to be called on a Perl::Dist::WiX object.

	$dist = Perl::Dist::WiX->new(
		# ...
		checkpoint_before => 5,
		checkpoint_after => [8, 9],
		checkpoint_stop => 9,
		# ...
	);

DESCRIPTION

Top

This module provides the routines that Perl::Dist::WiX uses in order to support checkpointing.

INTERFACE

Top

There are 2 portions to the interface to this module - the parameters to new() (documented in that module), and the object methods that Perl::Dist::WiX uses to coordinate checkpointing, as described below.

These routines are not meant to be called from external classes. Perl::Dist::WiX calls these routines as required.

checkpoint_task

checkpoint_task executes a portion of creating an installer.

The first parameter is the name of the subroutine to be executed.

The second parameter is the task number that goes with that subroutine.

Returns true (technically, the object that called it), or throws an exception.

This routine is called for each task (a task is a method on Perl::Dist::WiX or a subclass of it) defined in the tasklist parameter to Perl::Dist::WiX-new()>.

checkpoint_file

Returns the file that the Perl::Dist::WiX object is stored in when checkpoint_save is called.

checkpoint_self

Currently unimplemented, and throws an exception saying so.

checkpoint_save

Saves a checkpoint within the checkpoint subdirectory of Perl::Dist::WiX->temp_dir()

checkpoint_load

Restores a checkpoint saved to the checkpoint subdirectory of Perl::Dist::WiX->temp_dir() with checkpoint_save.

DIAGNOSTICS

Top

See Perl::Dist::WiX::Diagnostics (Perl::Dist::WiX::Diagnostics) for a list of exceptions that this module can throw.

BUGS AND LIMITATIONS (SUPPORT)

Top

WARNING: The checkpointing facility in this module is NOT stable. It is currently implemented using Storable with the $Storable::Deparse variable set to 1 (localized, of course). This probably WILL change in the future, as when checkpoints are reloaded, hash entries are appearing that weren't intended to be there. I am also not sure that references that were weakened are weakened when reloaded.

Restored checkpoints currently crash with "Free in wrong pool" errors in global destruction - if an exception occurs, they're reported there instead.

Do NOT use this in production. Debugging a distribution using the facilities provided here is fine.

Bugs should be reported via:

1) The CPAN bug tracker at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Perl-Dist-WiX if you have an account there.

2) Email to <bug-Perl-Dist-WiX@rt.cpan.org> if you do not.

For other issues, contact the topmost author.

AUTHORS

Top

Curtis Jewell <csjewell@cpan.org>

Adam Kennedy <adamk@cpan.org>

SEE ALSO

Top

Perl::Dist, Perl::Dist::WiX, http://ali.as/, http://csjewell.comyr.com/perl/

COPYRIGHT AND LICENSE

Top


Perl-Dist-WiX documentation Contained in the Perl-Dist-WiX distribution.
package Perl::Dist::WiX::Mixin::Checkpoint;

#<<<
use 5.010;
use Moose;
use English                qw( -no_match_vars );
use List::Util             qw( first );
use File::Spec::Functions  qw( catdir catfile );
use Storable               qw();
use Clone                  qw(clone);
#>>>

our $VERSION = '1.500002';

sub checkpoint_task {
	my $self = shift;
	my $task = shift;
	my $step = shift;

	# Are we loading at this step?
	if ( $self->checkpoint_before() == $step ) {
		$self->checkpoint_load();
	}

	# Skip if we are loading later on
	if ( $self->checkpoint_before() > $step ) {
		$self->trace_line( 0, "Skipping $task (step $step.)\n" );
	} else {
		my $t = time;

		if ( not $self->can($task) ) {
			PDWiX::NotTask->throw(
				class => ref $self,
				task  => $task,
				step  => $step
			);
		}

		$self->$task();
		$self->trace_line( 0,
			    "Completed $task (step $step) in "
			  . ( time - $t )
			  . " seconds\n" );
	} ## end else [ if ( $self->checkpoint_before...)]

	# Are we saving at this step?
	if ( defined first { $step == $_ } @{ $self->checkpoint_after() } ) {
		$self->checkpoint_save();
	}

	# Are we stopping at this step?
	if ( $self->checkpoint_stop() == $step ) {
		return 0;
	}

	return $self;
} ## end sub checkpoint_task

sub checkpoint_file {
	my $self = shift;
	return catfile( $self->checkpoint_dir(), 'self.dat' );
}

sub checkpoint_self {
	return WiX3::Exception::Unimplemented->throw();
}

sub checkpoint_save {
	my $self = shift;
	if ( not $self->temp_dir() ) {
		PDWiX->throw('Checkpoints require a temp_dir to be set');
	}

	# Clear out any existing checkpoint.
	$self->trace_line( 1, "Removing old checkpoint\n" );
	$self->remake_path( $self->checkpoint_dir() );

	# Copy the paths into the checkpoint directory.
	$self->trace_line( 1, "Copying checkpoint directories...\n" );
	foreach my $dir (qw{ build_dir download_dir image_dir output_dir }) {
		my $from = $self->$dir();
		my $to = catdir( $self->checkpoint_dir(), $dir );
		$self->copy_file( $from => $to );
	}

	# Blank the checkpoint values to prevent load/save loops, and remove
	# things we can recreate later.
	my $copy = clone($self);
	$copy->_clear_patch_template();
	$copy->_clear_guidgen();
	$copy->_clear_user_agent();
	$copy->_clear_trace_object();
	$copy->_set_checkpoint_before(0);
	$copy->_set_checkpoint_after( [0] );
	$copy->_set_checkpoint_stop(0);

	# Store the main object.
	local $Storable::Deparse = 1;
	eval { Storable::nstore( $copy, $self->checkpoint_file() ); 1; }
	  or PDWiX::Caught::Storable->throw(
		message => $EVAL_ERROR,
		object  => $copy
	  );

	return 1;
} ## end sub checkpoint_save

sub checkpoint_load {
	## no critic(ProtectPrivateSubs)
	my $self  = shift;
	my $class = ref $self;

	# Does the checkpoint exist?
	if ( not -d $self->checkpoint_dir() ) {
		PDWiX::Directory->throw(
			message => 'Checkpoint directory does not exist',
			dir     => $self->checkpoint_dir() );
	}
	if ( not -f $self->checkpoint_file() ) {
		PDWiX::File->throw(
			message => 'Checkpoint file does not exist',
			file    => $self->checkpoint_file() );
	}

	$self->trace_line( 1, "Preparing to restore checkpoint\n" );

	# If we want a future checkpoint, save it.
	my $checkpoint_after = $self->checkpoint_after() || 0;
	my $checkpoint_stop  = $self->checkpoint_stop()  || 0;

	# Save off the user agent for later restoration.
	my $user_agent = $self->user_agent();

	# Clear the directory tree.
	$self->_clear_directory_tree();
	Perl::Dist::WiX::DirectoryTree->_clear_instance();

	# Load the stored hash over our object
	local $Storable::Eval = 1;
	my $stored = Storable::retrieve( $self->checkpoint_file() );
	%{$self} = %{$stored};

	# Restore any possible future checkpoint.
	$self->_set_checkpoint_after($checkpoint_after);
	$self->_set_checkpoint_stop($checkpoint_stop);

	# Grab the directory tree stuff before we clear it.
	my $directory_tree_root = $self->{_directories}->{_root};
	my $app_name            = $self->{_directories}->{app_name};
	my $app_dir             = $self->{_directories}->{app_dir};

	# Clear the directory tree instance again, then
	# recreate it with the saved stuff.
	$self->_clear_directory_tree();
	Perl::Dist::WiX::DirectoryTree->_clear_instance();
	$self->_set_directories(
		Perl::Dist::WiX::DirectoryTree->new(
			app_dir  => $app_dir,
			app_name => $app_name,
			_root    => $directory_tree_root,
		) );

	# Reload the misc object.
	$self->_clear_trace_object();
	WiX3::Trace::Object->_clear_instance();
	WiX3::Traceable->_clear_instance();
	$self->_set_trace_object(
		WiX3::Traceable->new( tracelevel => $self->trace() ) );

	# Reload GUID generator.
	$self->_clear_guidgen();
	WiX3::XML::GeneratesGUID::Object->_clear_instance();
	$self->_set_guidgen(
		WiX3::XML::GeneratesGUID::Object->new(
			_sitename => $self->sitename() ) );

	# Reload LWP user agent.
	$self->_clear_user_agent();
	$self->_set_user_agent($user_agent);

	# Clear other objects for reloading.
	$self->_clear_patch_template();

	# Pull all the directories out of the storage.
	$self->trace_line( 0, "Restoring checkpoint directories...\n" );
	foreach my $dir (qw{ build_dir download_dir image_dir output_dir }) {
		my $from = File::Spec->catdir( $self->checkpoint_dir(), $dir );
		my $to = $self->$dir();
		$self->remove_path($to);
		$self->copy_file( $from => $to );
	}

	return 1;
} ## end sub checkpoint_load

no Moose;
__PACKAGE__->meta()->make_immutable();

1;

__END__