package Perl::Dist::Inno::Script;
use 5.006;
use strict;
use warnings;
use Carp qw{ croak };
use File::Spec ();
use File::Temp ();
use IPC::Run3 ();
use Params::Util qw{ _STRING _IDENTIFIER };
use Perl::Dist::Inno::File ();
use Perl::Dist::Inno::Icon ();
use Perl::Dist::Inno::Registry ();
use Perl::Dist::Inno::System ();
use vars qw{$VERSION};
BEGIN {
$VERSION = '1.16';
}
use Object::Tiny qw{
app_id
app_name
app_publisher
app_publisher_url
default_group_name
default_dir_name
output_dir
source_dir
bin_compil32
};
sub new {
my $self = shift->SUPER::new(@_);
# Apply defaults
unless ( defined $self->output_dir ) {
$self->{output_dir} = File::Spec->rel2abs(
File::Spec->curdir,
);
}
unless ( defined $self->default_group_name ) {
$self->{default_group_name} = $self->app_name;
}
# Check and default params
unless ( _IDENTIFIER($self->app_id) ) {
croak("Missing or invalid app_id param");
}
unless ( _STRING($self->app_name) ) {
croak("Missing or invalid app_name param");
}
unless ( _STRING($self->app_ver_name) ) {
croak("Missing or invalid app_ver_name param");
}
unless ( _STRING($self->app_publisher) ) {
croak("Missing or invalid app_publisher param");
}
unless ( _STRING($self->app_publisher_url) ) {
croak("Missing or invalid app_publisher_uri param");
}
unless ( _STRING($self->default_group_name) ) {
croak("Missing or invalid default_group_name param");
}
unless ( _STRING($self->default_dir_name) ) {
croak("Missing or invalid default_dir_name");
}
unless ( _STRING($self->output_dir) ) {
croak("Missing or invalid output_dir param");
}
unless ( -d $self->output_dir ) {
croak("The output_dir " . $self->output_dir . "directory does not exist");
}
unless ( -w $self->output_dir ) {
croak("The output_dir directory is not writable");
}
unless ( _STRING($self->output_base_filename) ) {
croak("Missing or invalid output_base_filename");
}
unless ( _STRING($self->source_dir) ) {
croak("Missing or invalid source_dir param");
}
unless ( -d $self->source_dir ) {
croak("The source_dir directory does not exist");
}
# Set ISS element collections
$self->{files} = [];
$self->{icons} = [];
$self->{registry} = [];
$self->{system} = [];
# Find the compil32 program
unless ( $ENV{PROGRAMFILES} and -d $ENV{PROGRAMFILES} ) {
die("Failed to find the Program Files directory\n");
}
my $innosetup_dir = File::Spec->catdir( $ENV{PROGRAMFILES}, "Inno Setup 5" );
my $innosetup_file = File::Spec->catfile( $innosetup_dir, 'Compil32.exe' );
unless ( -f $innosetup_file ) {
die("Failed to find the Inno Setup Compil32.exe program");
}
$self->{bin_compil32} = $innosetup_file;
return $self;
}
# Default the versioned name to an unversioned name
sub app_ver_name {
$_[0]->{app_ver_name} or
$_[0]->app_name;
}
# Default the output filename to the id plus the current date
sub output_base_filename {
$_[0]->{output_base_filename} or
$_[0]->app_id . '-' . $_[0]->output_date_string;
}
# Convenience method
sub output_date_string {
my @t = localtime;
return sprintf( "%04d%02d%02d", $t[5] + 1900, $t[4] + 1, $t[3] );
}
sub files {
return @{ $_[0]->{files} };
}
sub icons {
return @{ $_[0]->{icons} };
}
sub registry {
return @{ $_[0]->{registry} };
}
sub system {
return @{ $_[0]->{system} };
}
#####################################################################
# Main Methods
sub write_exe {
my $self = shift;
# Write out the .iss file
my $content = $self->as_string;
my ($fh, $filename) = File::Temp::tempfile();
$fh->print( $content );
$fh->close;
# Compile the .iss file
my $cmd = [
$self->bin_compil32,
'/cc',
$filename,
];
my $rv = IPC::Run3::run3( $cmd, \undef, \undef, \undef );
# Return the name of the exe file generated
my $output_exe = File::Spec->catfile(
$self->output_dir,
$self->output_base_filename . '.exe',
);
unless ( -f $output_exe ) {
croak("Failed to find $output_exe");
}
return $output_exe;
}
#####################################################################
# Manipulation Methods
sub add_file {
my $self = shift;
my $file = Perl::Dist::Inno::File->new(@_);
push @{$self->{files}}, $file;
return 1;
}
sub add_dir {
my $self = shift;
my $name = shift;
$self->add_file(
source => "$name\\*",
dest_dir => "{app}\\$name",
recurse_subdirs => 1,
create_all_subdirs => 1,
);
return 1;
}
sub add_icon {
my $self = shift;
my $icon = Perl::Dist::Inno::Icon->new(@_);
push @{$self->{icons}}, $icon;
return 1;
}
sub add_uninstall {
my $self = shift;
my $name = $self->app_name;
$self->add_icon(
name => "{cm:UninstallProgram,$name}",
filename => '{uninstallexe}',
);
return 1;
}
sub add_registry {
my $self = shift;
my $registry = Perl::Dist::Inno::Registry->new(@_);
push @{$self->{registry}}, $registry;
return 1;
}
sub add_env {
my $self = shift;
my $registry = Perl::Dist::Inno::Registry->env(@_);
push @{$self->{registry}}, $registry;
return 1;
}
sub add_system {
my $self = shift;
my $system = Perl::Dist::Inno::System->new(@_);
push @{$self->{system}}, $system;
return 1;
}
sub add_run {
my $self = shift;
my $system = Perl::Dist::Inno::System->run(@_);
push @{$self->{system}}, $system;
return 1;
}
sub add_uninstallrun {
my $self = shift;
my $system = Perl::Dist::Inno::System->uninstallrun(@_);
push @{$self->{system}}, $system;
return 1;
}
#####################################################################
# Serialization
sub as_string {
my $self = shift;
my @lines = (
'; Inno Setup Script for ' . $self->app_name,
'; Generated by ' . ref($self),
'',
);
# Add the setup area
push @lines, (
'[Setup]',
'; Distribution Identification',
'AppName=' . $self->app_name,
'AppVerName=' . $self->app_ver_name,
'AppPublisher=' . $self->app_publisher,
'AppPublisherURL=' . $self->app_publisher_url,
'AppId=' . $self->app_id,
'',
'; Start Menu Icons',
'DefaultGroupName=' . $self->default_group_name,
'AllowNoIcons=' . 'yes',
'',
'; Installation Path (This is always hard-coded)',
'DefaultDirName=' . $self->default_dir_name,
'DisableDirPage=' . 'yes',
'',
'; Where the output goes',
'OutputDir=' . $self->output_dir,
'OutputBaseFilename=' . $self->output_base_filename,
'UsePreviousAppDir=' . 'no',
'',
'; Source location',
'SourceDir=' . $self->source_dir,
'',
'; Win2K or newer required',
'MinVersion=' . '4.0.950,4.0.1381',
'',
'; Miscellaneous settings',
'Compression=' . 'lzma',
'SolidCompression=' . 'yes',
'ChangesEnvironment=' . 'yes',
'',
'; Delete old install',
'[InstallDelete]',
'Type: filesandordirs; Name: "' . $self->source_dir . '"',
'',
);
# Start with only English for now
push @lines, (
'[Languages]',
'Name: eng; MessagesFile: compiler:Default.isl',
'',
);
# Add the files to be installed
push @lines, '[Files]';
foreach my $file ( $self->files ) {
push @lines, $file->as_string;
}
push @lines, '';
# Add the icons to be installed
push @lines, '[Icons]';
foreach my $icon ( $self->icons ) {
push @lines, $icon->as_string;
}
push @lines, '';
# Add the registry entries to be added
push @lines, '[Registry]';
foreach my $registry ( $self->registry ) {
push @lines, $registry->as_string;
}
push @lines, '';
# Add any (optional) entries for [Run]
my @run = grep { $_->section eq 'Run' } $self->system;
if ( @run ) {
push @lines, '[Run]';
foreach my $system ( @run ) {
push @lines, $system->as_string;
}
push @lines, '';
}
# Add any (optional) entries for [UninstallRun]
my @uninstall = grep { $_->section eq 'UninstallRun' } $self->system;
if ( @uninstall ) {
push @lines, '[UninstallRun]';
foreach my $system ( @uninstall ) {
push @lines, $system->as_string;
}
push @lines, '';
}
# Combine it all
return join "\n", @lines;
}
1;