PAR-Packer

 view release on metacpan or  search on metacpan

script/tkpp  view on Meta::CPAN


#===============================================================================
# GUI Interface
#===============================================================================
my ( $output_command_widget, $output_stderr_widget, $command, $add_files_rep_listbox ) = ();

my $main = MainWindow->new( -title => $general_configuration{tk}{title} );
$main->withdraw();

# SplashScreen
my $splashscreen_widget = splashscreen_widget($main);

# Configuration option load/save
my $ref_options_pp = {};
my $opt = new Tk::Getopt( -opttable => \@pp_default_options, -options => $ref_options_pp, );
$opt->set_defaults;

#=======
# Menu
#=======
my $bar_menu = $main->Menu( -type => 'menubar', );
$main->configure( -menu => $bar_menu, );

# File Menu
my $file_menu = $bar_menu->cascade( -label => 'File', -tearoff => 0, );
$file_menu->command(
	-label   => '~Load configuration',
	-command => [ \&load_pp_configuration, $main, $opt, $ref_options_pp ],
);
$file_menu->command(
	-label   => '~Save configuration',
	-command => [ \&save_pp_configuration, $main, $opt, $ref_options_pp ],
);
$file_menu->separator;
$file_menu->command(
	-label   => 'Save ~command line',
	-command => sub {
		if ( my $file = save_file( $main, [ 'Batch Files', ['.bat'] ], $general_configuration{commandline_path} ) ) {
			open my $fh, '>', $file or die "Unable to write in $file\n";
			print {$fh} $output_command_widget->get( '1.0', 'end' );
			close $fh or die "Unable to close $file\n";
		}
	}
);
$file_menu->separator;
$file_menu->command( -label => '~Exit', -command => \&close_application, );

# Help Menu
my $help_menu = $bar_menu->cascade( -label => 'Help', -tearoff => 0, );
my $tkpp_pod_menu = $help_menu->command(
	-label   => '~Tkpp documentation',
	-command => [ \&open_pod_documentation, $main, 'tkpp' ],
);
my $pp_pod_menu = $help_menu->command(
	-label   => '~pp documentation',
	-command => [ \&open_pod_documentation, $main, 'pp' ],
);
$help_menu->separator;
$help_menu->command(
	-label   => 'About Tkpp',
	-command => sub { popup_information( $main, $general_configuration{tk}{about_message} ); },
);

$help_menu->command(
	-label   => 'About pp',
	-command => sub { popup_information( $main, $general_configuration{pp_version} ); },
);

#=======
# Header Frame
#=======
my $header_frame = $main->Frame( -background => 'white' );
$header_frame->Label(
	-text       => $general_configuration{tk}{name_application} . ' (v' . $VERSION . ')',
	-background => 'white',
	-font       => '{Arial} 10 {bold}',
)->pack(qw/ -side left -pady 10 -padx 20/);
$header_frame->Label(
	-text       => $general_configuration{tk}{header_title},
	-background => 'white',
	-font       => '{Arial} 12',
)->pack(qw/ -side left/);
$header_frame->Label(
	-image      => get_image_object( $header_frame, par_image(), 'gif' ),
	-background => 'white',
)->pack(qw/ -side right -padx 20 /);

#=======
# Notebook Frame
#=======
my $notebook = $main->NoteBook( -font => '{Arial} 10 bold', -backpagecolor => 'white', );
my $general_notebook = $notebook->add( 'General', -label => 'General Options' );

# DEPRECATED
#my $info_notebook    = $notebook->add( 'Information', -label => 'Information' );

my $size_notebook   = $notebook->add( 'Size',   -label => 'Size' );
my $option_notebook = $notebook->add( 'Option', -label => 'Other Options' );
my $output_notebook = $notebook->add( 'Output', -label => 'Output' );

display_general_notebook();

# DEPRECATED
#display_info_notebook();
display_size_notebook();
display_other_options_notebook();
display_output_notebook();

#=======
# Status Frame
#=======
my $status_frame = $main->Frame( -relief => 'groove', );
$status_frame->Label(
	-textvariable => \$status,
	-font         => '{Arial} 8 {bold}',
)->pack(qw/ -side left -pady 5 -padx 20/);
my $build_button = $status_frame->ColoredButton(
	-text    => 'Build',
	-autofit => 1,
	-font    => '{Arial} 12 bold',
	-tooltip => 'Start building',
	-command => [ \&build_pp, $main, \%options_pp ],
)->pack(qw/-side right -padx 5/);
my $display_commandline_button = $status_frame->ColoredButton(
	-text    => 'Display command line',
	-autofit => 1,

script/tkpp  view on Meta::CPAN

	if ( $nbr_file > 0 ) {
		$current_dir = $files[0];
		open my $fh_write, '>', $last_filedir or die "Unable to write $last_filedir\n";
		print {$fh_write} $current_dir;
		close $fh_write or die "Unable to colse $last_filedir\n";
	}

	return ( $nbr_file == 1 ) ? File::Spec->catfile( $files[0] ) : undef;
}

sub get_label_widget {
	my ( $widget, $ref_info ) = @_;

	my $label = $widget->Label(
		-text    => $ref_info->{text},
		-font    => '{Arial} 10',
		-justify => 'left',
	);
	return $label;
}

sub get_entry_widget {
	my ( $widget, $ref_info ) = @_;

	my $entry = $widget->Entry(
		-textvariable => $ref_info->{textvariable},
		-background   => 'white',
	);
	return $entry;
}

sub get_button_widget {
	my ( $widget, $ref_info ) = @_;

	my $button = $widget->ColoredButton(
		-text    => $ref_info->{text},
		-autofit => 1,
		-font    => '{Arial} 8 bold',
		-tooltip => $ref_info->{tooltip},
		-command => $ref_info->{command},
	);
	return $button;
}

sub get_checkbutton_widget {
	my ( $widget, $ref_info ) = @_;

	my $button = $widget->Checkbutton( -variable => $ref_info->{variable}, );
	return $button;
}

sub build_pp {
	my ( $widget, $ref_options, $display_commandline ) = @_;

	clean_report();
	$command = $EMPTY;

	# perl.exe not found
	if ( !-e $ref_options->{'--perlfile'}{-value} ) {
		my $error = 'The path to ' . basename($EXECUTABLE_NAME) . ' has not been set or invalid.';
		popup_information_warning( $widget, $error );
		$options_pp{'--perlfile'}{-widget}->focus;
		$notebook->raise('General');
		print_error($error);
		return;
	}

	# pp not found
	if ( !-e $ref_options->{'--ppfile'}{-value} ) {
		my $error = 'The path to ' . basename( $general_configuration{pp_path} ) . ' has not been set or invalid.';
		popup_information_warning( $widget, $error );
		$options_pp{'--ppfile'}{-widget}->focus;
		$notebook->raise('General');
		print_error($error);
		return;
	}
	$command .= ' "' . $ref_options->{'--ppfile'}{-value} . $DOUBLE_QUOTE;

	# output not found
	my $output = $ref_options->{'--output'}{-value};
	if ( $output eq $EMPTY ) {
		my $error = 'You must specify an output file to write.';
		popup_information_warning( $widget, $error );
		$options_pp{'--output'}{-widget}->focus;
		$notebook->raise('General');
		print_error($error);
		return;
	}

	# Overwrite output or not
	if ( -e $output ) {
		my $warning = 'The output ' . basename($output) . ' already exists.' . "\n" . 'Do you want overwrite it ?';
		if ( !popup_confirmation( $widget, $warning ) ) {
			$options_pp{'--output'}{-widget}->focus;
			$notebook->raise('General');
			return;
		}

		unlink $output or print_ok("Unable to delete $output"), return;
		print_ok("$output deleted");
	}
	$command .= ' --output="' . $ref_options->{'--output'}{-value} . $DOUBLE_QUOTE;
	print_ok( 'Start building ' . basename($output) );

	# PAR, perlscript check extension
	if ( $ref_options->{'--output'}{-value} =~ m{\.par$}msxi ) {
		$command .= ' --par';
	}
	elsif ( $ref_options->{'--output'}{-value} =~ m{\.pl$}msxi ) {
		$command .= ' --perlscript';
	}
	elsif ( $ref_options->{'--output'}{-value} !~ m{\Q$Config{_exe}\E$}msxi ) {
		my $error = 'You are trying to write your output file as an invalid file format.'
		  . "It must be either a $Config{_exe} or .par file.";
		popup_information_warning( $widget, $error );
		$options_pp{'--output'}{-widget}->focus;
		$notebook->raise('General');
		print_error($error);
		return;
	}

	# Check iconfile
	# if ( my $icon = $ref_options->{'--icon'}{-value} ) {
	#   my $error
	#     = ( !-e $ref_options->{'--icon'}{-value} ) ? 'You have to set an existing icon file'
	#     : ( $icon !~ m{\.(?:dll|ico|exe)$}msxi ) ? 'You are trying to use an icon with bad extension ('
	#     . basename($icon) . ').'
	#     . "\nExtension must be .dll, .exe or .ico."
	#     : undef;
	#
	#   if ( defined $error ) {
	#     popup_information_warning( $widget, $error );
	#     $options_pp{'--icon'}{-widget}->focus;
	#     $notebook->raise('General');
	#     print_error($error);
	#     return;
	#   }
	#   else {
	#     $command .= ' --icon="' . $ref_options->{'--icon'}{-value} . $DOUBLE_QUOTE;
	#   }
	# }

	# GUI
	if ( $ref_options->{'--gui'}{-value} == 1 ) { $command .= ' --gui'; }

	# Log
	if ( my $logfile = $ref_options->{'--log'}{-value} ) {
		$command .= " --log=\"$logfile\"";
		if ( -e $logfile ) { unlink $logfile or die "Unable to delete $logfile\n"; }
	}

	# verbose
	if ( $ref_options->{'--verbose'}{-value} ne 'none' ) {

		# Need to select logfile
		unless ( my $logfile = $ref_options->{'--log'}{-value} ) {
			my $error = 'You have to select a log file if you want to see verbose message.';
			popup_information_warning( $widget, $error );
			$options_pp{'--log'}{-widget}->focus;
			$notebook->raise('General');
			print_error($error);
			return;
		}

		$command .= ' --verbose=' . $ref_options->{'--verbose'}{-value};
	}

	# scandependencies
	if ( $options_pp{'--scandependencies'}{-value} ) {
		$command .= $SPACE . $options_pp{'--scandependencies'}{-value};
	}

	# Log
	if ( my $cachedeps_file = $ref_options->{'--cachedeps'}{-value} ) {
		$command .= " --cachedeps=\"$cachedeps_file\"";
	}

	# Product Informations
	# DEPRECATED
	#foreach my $type ( sort keys %{ $options_pp{'--information'} } ) {
	#  foreach my $key ( sort keys %{ $options_pp{'--information'}{$type} } ) {
	#    if ( my $value = $options_pp{'--information'}{$type}{$key}{-value} ) {
	#      $value =~ s{$DOUBLE_QUOTE}{}g;
	#      $command .= $SPACE . "--info $key=$DOUBLE_QUOTE$value$DOUBLE_QUOTE";
	#    }
	#  }
	#}

	# Exclude Perl
	if ( $options_pp{'--dependent'}{-value} == 1 ) {
		$command .= ' --dependent';
	}

	# Compression
	$command .= ' --compress ' . $options_pp{'--compress'}{-value};

	# Add modules
	if ( my $widget_modules = $options_pp{'--module'}{-widget} ) {
		my $modules = $widget_modules->get || $EMPTY;
		foreach my $module ( split( /;/, $modules ) ) {
			$command .= ' --module="' . $module . $DOUBLE_QUOTE;
		}
	}

	# Exclude modules
	if ( my $widget_modules = $options_pp{'--exclude'}{-widget} ) {
		my $modules = $widget_modules->get || $EMPTY;
		foreach my $module ( split( /;/, $modules ) ) {
			$command .= ' --exclude="' . $module . $DOUBLE_QUOTE;
		}
	}

	# Add files, dir and shared libraries
	foreach my $file_rep ( $add_files_rep_listbox->get( '0', 'end' ) ) {
		chomp $file_rep;
		my ( $type, $file_and_rep ) = $file_rep =~ m{^(f|d|l|s|p):\s*(.+)}msx;
		if ( defined $type ) {
			$command .=
			    ( $type eq 'f' or $type eq 'd' ) ? ' --addfile="' . $file_and_rep . $DOUBLE_QUOTE
			  : ( $type eq 'l' ) ? ' --link="' . $file_and_rep . $DOUBLE_QUOTE
			  : ( $type eq 's' ) ? ' --addlist="' . $file_and_rep . $DOUBLE_QUOTE
			  :                    ' --lib="' . $file_and_rep . $DOUBLE_QUOTE;
		}
	}

	# Other options
	my @yes_not_options =
	  ( '--bundle', '--clean', '--run', '--reusable', '--save', '--sign', '--tempcache', '--multiarch' );
	foreach my $option (@yes_not_options) {
		if ( $options_pp{$option}{-value} == 1 ) {
			$command .= $SPACE . $option;
		}
	}

	# PodStrip
	if ( $options_pp{'--podstrip'}{-value} == 1 ) {
		$ENV{PAR_VERBATIM} = 1;
	}

	# --filter
	if ( my $filter = $options_pp{'--filter'}{-value} and $options_pp{'--filter'}{-value} ne 'None' ) {
		if ( exists $FILTERS_MODULES{$filter} ) {
			eval "use $FILTERS_MODULES{$filter}";
			if ( $EVAL_ERROR !~ /^\s*$/msx ) {
				my $error = "You have to install $FILTERS_MODULES{$filter} to use '$filter' filter";
				popup_information_warning( $widget, $error );
				$options_pp{'--filter'}{-widget}->focus;
				$notebook->raise('Option');
				print_error($error);
				return;
			}
		}
		$command .= ' --filter="' . $filter . $DOUBLE_QUOTE;
	}

	# --modfilter
	if ( my $modfilter = $options_pp{'--modfilter'}{-value} ) {
		foreach my $filter ( split( /;/, $modfilter ) ) {
			$command .= ' --modfilter="' . $filter . $DOUBLE_QUOTE;
		}
	}

	# --eval
	if ( $options_pp{'--eval'}{-value} ) {
		$command .= ' --eval="' . $options_pp{'--eval'}{-value} . $DOUBLE_QUOTE;
	}

	# --evalfeature
	elsif ( $options_pp{'--evalfeature'}{-value} ) {
		$command .= ' --evalfeature="' . $options_pp{'--evalfeature'}{-value} . $DOUBLE_QUOTE;
	}
	elsif ( -e $options_pp{'--sourcefile'}{-value} ) {

		# add source file in command
		$command .= ' "' . $ref_options->{'--sourcefile'}{-value} . $DOUBLE_QUOTE;
	}

	# sourcefile not found
	elsif ( !-e $ref_options->{'--sourcefile'}{-value} ) {
		my $error = 'You must specify a source file to build.';
		popup_information_warning( $widget, $error );
		$options_pp{'--sourcefile'}{-widget}->focus;
		$notebook->raise('General');
		print_error($error);
		return;
	}

	# tkpp is execute in temp directory (read/write). if -M is used, tkpp have to check the module
	# in current source file directory. We will add it in the @INC
	# Perl will execute with -I option to change @INC
	$command = ' -I ' . dirname( $ref_options->{'--sourcefile'}{-value} ) . $command;

	# Display and execute command
	display_command("$EXECUTABLE_NAME $command");

	# Dispay output notebook
	$notebook->raise('Output');

	# Just display command line
	if ( defined $display_commandline ) {
		return;
	}
	execute_command( $EXECUTABLE_NAME, $command, $ref_options->{'--output'}{-value} );

	return;
}

sub execute_command {
	my ( $executable, $arguments, $outputfile_exe ) = @_;

	# Now, we can complet the command line
	$status = $ALL_STATUS{building};

	# Use Win32 Process
	if ( $OSNAME eq 'MSWin32' ) {
		require Win32::Process;
		require Win32;
		import Win32::Process qw(CREATE_NO_WINDOW STILL_ACTIVE );

		my $logfile         = $options_pp{'--log'}{-value};
		my $octet_size_read = 0;
		my $flags           = CREATE_NO_WINDOW();

		Win32::Process::Create( $win32_process_buiding, $executable, $arguments, 0, $flags, '.' )
		  or print_error( 'Erreur [' . Win32::GetLastError() . '] : ' . Win32::FormatMessage( Win32::GetLastError() ) );

		$build_button->configure( -state => 'disabled' );
		$build_button->redraw_button;

		# Check process id running and enabled Build button
		$main->after( $REPEAT_FILE_TIME, [ \&check_process_id, $logfile, \$octet_size_read, $outputfile_exe ] );

	}
	else {
		$main->Busy( -recurse => 1 );
		system( $executable, $arguments ) == 0 or print_error("Command line failed : $?");
		$main->Unbusy();
		$status = $ALL_STATUS{finished};
	}

	return;
}

#================================================
# check process working
#================================================
sub check_process_id {
	my ( $logfile, $ref_octet_size_read, $outputfile_exe ) = @_;
	my $pid = $win32_process_buiding->GetProcessID();
	my $exitcode;
	my $still_active = $win32_process_buiding->GetExitCode($exitcode);

	# Read file
	if ( defined $logfile and -e $logfile ) {
		my ( $buffer, $buffer_size ) = ( undef, 1000 );
		open my $fh, '<', $logfile or die "Unable to read $logfile";
		seek $fh, ${$ref_octet_size_read}, 0;

		while ( read( $fh, $buffer, $buffer_size ) != 0 ) {
			print_ok( $buffer, 1 );
			${$ref_octet_size_read} += $buffer_size;
		}
		close $fh or die "Unable to close $logfile\n";

		#${$ref_octet_size_read} = ( stat($log_file) )[7];
	}

	# Check if process is active
	if ( $exitcode == STILL_ACTIVE() ) {
		$main->after( $REPEAT_FILE_TIME, [ \&check_process_id, $logfile, $ref_octet_size_read, $outputfile_exe ] );
		return;
	}

	$build_button->configure( -state => 'normal' );
	$build_button->redraw_button;
	$win32_process_buiding = undef;

	if ( -e $outputfile_exe ) {
		$status = $ALL_STATUS{finished};
		print_ok("\n ==> $status");
	}
	else {
		$status = $ALL_STATUS{error};
		my $error = Win32::GetLastError();
		print_error("Building $outputfile_exe failed :");
		print_error( Win32::FormatMessage($error) );
		print_error("Active verbose to see more details (General Options)");
		print_ok("\n ==> $status");
	}

	return;
}

#================================================
# popup_information_warning($widget, $message);
#================================================
sub popup_information_warning {
	my ( $widget, $message ) = @_;
	$widget->bell;
	$widget->messageBox(
		-icon    => 'warning',
		-title   => 'Warning',
		-type    => 'OK',
		-message => $message,
	);

	return;
}

#================================================
# popup_information($widget, $message);
#================================================
sub popup_information {
	my ( $widget, $message ) = @_;

	$widget->bell;
	$widget->messageBox(
		-icon    => 'info',
		-title   => 'Information',
		-type    => 'OK',
		-message => $message,
	);

	return;
}

#================================================
# popup_confirmation($widget, $message);
#================================================
sub popup_confirmation {
	my ( $widget, $message ) = @_;

	$widget->bell;
	my $response = $widget->messageBox(
		-icon    => 'info',
		-title   => 'Information',
		-type    => 'OKCANCEL',
		-message => $message,
	);

	$response = uc $response;
	return ( $response eq 'OK' ) ? 1 : undef;
}

#================================================
# Center a widget
#================================================
sub center_widget {
	my ($widget) = @_;

	# Height and width of the screen
	my $width_screen  = $widget->screenwidth();
	my $height_screen = $widget->screenheight();

	# update le widget pour récupérer les vraies dimensions
	$widget->update;
	my $width_widget  = $widget->width;
	my $height_widget = $widget->height;

	# On centre le widget en fonction de la taille de l'écran
	my $new_width  = int( ( $width_screen - $width_widget ) / 2 );
	my $new_height = int( ( $height_screen - $height_widget ) / 2 );
	$widget->geometry( $width_widget . 'x' . $height_widget . "+$new_width+$new_height" );

	$widget->update;

	return;
}

#================================================
# Close Tkpp application
#================================================
sub close_application {

	if ( ( $OSNAME eq 'MSWin32' ) and ( defined $win32_process_buiding ) ) {
		$win32_process_buiding->Kill(0);
	}
	close STDOUT or die "Unable to close STDOUT\n";
	close STDERR or die "Unable to close STDERR\n";

	# Allow to delete temp directory
	chdir $homedir;
	exit;
}

sub open_pod_documentation {
	my ( $widget, $module ) = @_;

	eval { my $pod_widget = $widget->Pod( -file => $module, )->pack(qw/ -fill both -expand 1 /); };



( run in 1.143 second using v1.01-cache-2.11-cpan-364913b4093 )