Rev 1538 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#! perl######################################################################### Copyright ( C ) 2005 ERG Limited, All rights reserved## Module name : jats.sh# Module type : Makefile system# Compiler(s) : n/a# Environment(s): jats## Description : Build an Install Shield project for deployment# This script isolates the IS build from the rest of# the deployment process.## Assumes that:# IS 11.5 Standalone builder has been installed# Merge Modules have been installed / updated# to subdirs with the SA installation of:# Modules\i386# Objects## Note: IS SA builder can be copied and registered# The installation is very simple.# Registartion: regsvr32.exe## Currently this script will register the required# DLL anyway.## Usage : Refer to POD within this script##......................................................................#require 5.8.6;use strict;use warnings;use JatsError; # Error reportinguse JatsSystem; # System interfaceuse Win32::OLE; # load the Win32::OLE moduleuse Pod::Usage; # required for help supportuse Getopt::Long; # Parse input optionsuse Cwd; # Where am Iuse File::Copy; # Transfer filesuse File::Path;use File::Find; # Ony for kludge copyuse FileUtils;my $VERSION = "1.0.0"; # Update this## Globals#my $opt_debug = $ENV{'GBE_DEBUG'}; # Allow global debugmy $opt_verbose = $ENV{'GBE_VERBOSE'}; # Allow global verbosemy $opt_help = 0;my $opt_manual;my $opt_read_only = 1;my $opt_use_sa = 1;my $opt_build = 1;my $opt_project;my $opt_new_codes;my $opt_name;my $opt_version;my $opt_suffix;my $opt_outpath;my @opt_mergemodule;my $opt_workdir;my $opt_name_version = 1;## Kludgy values# May need to be configured# These are current IS 11.5 install locations#my $AutoBuilder = 'C:\Program Files\Macrovision\IS 11.5 StandaloneBuild';my $result_code = 0;#-------------------------------------------------------------------------------# Function : Mainline Entry Point## Description :## Inputs :#my $result = GetOptions ("help+" => \$opt_help, # flag, multiple use allowed"manual" => \$opt_manual, # flag"verbose+" => \$opt_verbose, # flag, multiple use allowed"readonly!" => \$opt_read_only, # [no]flag"standalone!" => \$opt_use_sa, # [no]flag"build!" => \$opt_build, # [no]flag"project=s" => \$opt_project, # string"codes!" => \$opt_new_codes, # [no]flag"version=s" => \$opt_version, # string"out=s" => \$opt_outpath, # string"mergemodule=s" => \@opt_mergemodule, # string"workdir=s" => \$opt_workdir, # string"nameversion!" => \$opt_name_version, # [no]flag);## UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!### Process help and manual options#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);pod2usage(-verbose => 1) if ($opt_help == 2 );pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV < 0 );## Configure the error reporting process now that we have the user options#ErrorConfig( 'name' =>'ISBUILD','verbose' => $opt_verbose,);## User must specify a project or we will attempt to locate one#Verbose ("Current directory: " . getcwd );unless ( $opt_project ){my @projects = glob ('*.ism' );Error ("No InstallShield projects found in current directory") unless ( $#projects >= 0 );Error ( "Multiple Install Shield projects located. Use -project option") if ( $#projects > 0 );$opt_project = $projects[0];}else{Error ("Project file not found: $opt_project") unless ( -f $opt_project );}## Determine project name from the project file name# - remove any path information# - remove .ism extension#$opt_name = $opt_project;$opt_name =~ s~\\~/~g;$opt_name =~ s~.*/~~;$opt_name =~ s~\.ism$~~i;## User must specify a version# This will be processed and used within the build#Error ("Version must be specified") unless ( $opt_version );Error ("Bad format for version: $opt_version") unless ( $opt_version =~ m~(\d+\.\d+\.\d+)\.(\w+)$~ );$opt_version = $1;$opt_suffix = $2;Error ("Project suffix not found in version") unless ( $opt_suffix );Message( "Package: $opt_name, Version: $opt_version, Project: $opt_suffix");## Output path must exist#if ( $opt_outpath ){Error("Output path does not exist: $opt_outpath") unless ( -e $opt_outpath );Error("Output path is not a directory: $opt_outpath") unless ( -d $opt_outpath );}## Workdir path must exist#$opt_workdir = getcwd unless( $opt_workdir );Error("Workdir path does not exist: $opt_outpath") unless ( -e $opt_workdir );Error("Workdir path is not a directory: $opt_outpath") unless ( -d $opt_workdir );## Process Merge Module paths#if ( @opt_mergemodule ){## User may have entered a comma seperated list# Convert into a full array#@opt_mergemodule = split(/,/,join(',',@opt_mergemodule));## Ensure that each path exists# Clean up paths#foreach my $path ( @opt_mergemodule ){Warning ("MergeModule path not found: $path" ) unless ( -d $path );$path =~ s~/~\\~g;}}## Instantiate the Developer Automation interface# Use the StandAlone interface if it can be found#my $dev;if ( $opt_use_sa ){Message "Using StandAlone OLE";## Ensure the interface is registered# This allows a simple 'copy' of the SA build environment to a build# machine.#my $regdll = $AutoBuilder . '\SAAuto1150.dll' ;Error ("Cannot find SA OLE DLL: $regdll") unless ( -f $regdll );my $rv = System( 'regsvr32.exe', '/s', $regdll);Error ("Failed to register $regdll: $rv" ) if ( $rv );$dev = Win32::OLE->new("SAAuto1150.ISWiProject");} else {Message "Using InstallShield OLE";$dev = Win32::OLE->new("IswiAuto1150.ISWiProject");}Error( "Cannot open Automation interface") unless ( $dev );## Open a project as read-write# The second argument ( if true ) will open as read only#Verbose ("Opening project: $opt_project, ReadOnly: $opt_read_only" );$dev->OpenProject( $opt_project, $opt_read_only );my $estring = Win32::OLE->LastError();Error( $estring ) if ( $estring );Verbose ("Project Open");#DebugDumpData("Dev", $dev );## Massage the ProductName [ if required ]# Should contain a comma<space><version>#if ( $opt_name_version ){Verbose( "Update ProductName" );Verbose( "Originial ProductName :" . $dev->ProductName);my $product_name = $dev->ProductName;if ( $product_name =~ m/^(.*),/ ){$product_name = $1;}$product_name .= ', ' . $opt_version . '.' . $opt_suffix;$dev->SetProperty('ProductName', $product_name );}Message( "ProductName :" . $dev->ProductName);## Massage the ProjectVersion# This will not have the project suffix on it#Verbose( "Update ProductVersion" );Verbose( "Original ProductVersion:" . $dev->ProductVersion);$dev->SetProperty('ProductVersion', $opt_version );Message ("ProductVersion:" . $dev->ProductVersion);## If we need to generate new codes#if ( $opt_new_codes ){Message ("Update GUIDs");$dev->SetProperty('PackageCode', $dev->GenerateGUID() );$dev->SetProperty('ProductCode', $dev->GenerateGUID() );$dev->SetProperty('UpgradeCode', $dev->GenerateGUID() );}Message ("PackageCode :" . $dev->PackageCode );Message ("ProductCode :" . $dev->ProductCode );Message ("UpgradeCode :" . $dev->UpgradeCode );## Examine all components and display the files within each# The files are a collection and need to be processed in a special manner#if ( $opt_verbose ){Verbose ("InstallShield Components");my $mycomps = $dev->ISWiComponents;foreach my $comp (in $mycomps){Verbose ("Component: " . $comp->Name, ": ", $comp->Destination );my $files = $comp->ISWiFiles;my $fileCount = $files->Count;Verbose ("Number of Files: $fileCount");foreach my $index ( 1 .. $fileCount ){Verbose (" Name: " . $files->Item($index)->Name );Verbose (" DisplayName: " . $files->Item($index)->DisplayName );Verbose (" FullPath: " . $files->Item($index)->FullPath );}}}## Examine all the Features#if ( $opt_verbose ){Verbose ("InstallShield Features");my $myfeature = $dev->ISWiFeatures;foreach my $feat (in $myfeature){Verbose ("Feature: " . $feat->Name, ": ", $feat->Description );}}## Display Releases# These are found within the product config# We need to locate the Release in order to build it#Verbose ("InstallShield Products");my $products = $dev->ISWiProductConfigs;foreach my $index ( 1 .. $products->Count ){my $product = $products->Item($index);Verbose ("Product Index : " . $index );Verbose (" Product Name : " . $product->Name );Verbose (" SetupFileName: " . $product->SetupFileName );my $releases = $product->ISWiReleases;foreach my $index ( 1 .. $releases->Count ){my $release = $releases->Item($index);Verbose ("Release Index : " . $index );Verbose (" Name : " . $release->Name );Verbose (" BuildLocation : " . $release->BuildLocation );Verbose (" SingleEXEFileName: " . ( $release->SingleEXEFileName || 'None Specified' ) );## Build the Project# Not working at the moment !!!!#if ( $opt_build ){Message ("Building...");## Set build location#my $location = $opt_workdir . '/Media';$location =~ s~/~\\~g;$release->SetProperty('BuildLocation', $location );Message ("BuildLocation: " . $release->BuildLocation );## If building with the Standalone interface will need to set# up the merge module paths#if ( $opt_use_sa ){foreach my $dir ( @opt_mergemodule ){Error ("MergeModule Directory not found: $dir") unless ( -d $dir );Verbose( "Merge Module Search Path:", $dir );}$dev->SetProperty('MergeModuleSearchPath', join (',', @opt_mergemodule));Verbose2 ( "MergeModulePath: " . $dev->MergeModuleSearchPath );## See comments in this function#kludge_merge_module_stuff(@opt_mergemodule);}## Set thename of the setup file# This contains the build name and number#Verbose ("Setting Setup Filename");Verbose2 ( "Initial SetupFileName: " . $product->SetupFileName );my $setup_name = $opt_name. '-'. $dev->ProductVersion. '.'. $opt_suffix. '-WIN32';$product->SetProperty('SetupFileName', $setup_name );Message( "SetupFileName: " . $product->SetupFileName );## Perform the build and report errors and warnings#$release->Build;$result_code = $release->BuildErrorCount;Message ("Build Error Count : " . $release->BuildErrorCount );Message ("Build Warning Count: " . $release->BuildWarningCount );## Transfer the result file to the user#if ( $result_code == 0 && $opt_outpath ){Message("Transfer output file: $opt_outpath");my$ofile = $location . "/ishield package/Release/DiskImages/DISK1/" . $setup_name . '.exe';Error ("Build output file not found", "Expected: $ofile" ) unless ( -f $ofile );File::Copy::copy( $ofile, $opt_outpath) ||Error ("Did not transfer InstallShield output file", $ofile, $opt_outpath);}}}}## Save and Close the project# Release the OLE data#$dev->SaveProject( ) unless ($opt_read_only);$dev->CloseProject( );undef $dev;## Return build result to the user#exit $result_code;#-------------------------------------------------------------------------------# Function : kludge_merge_module_stuff## Description : Handle BUG in the SA builder## The current version of InstallShield StandAlone Builder has a bug associated# with the processing of Merge Modules## It would appear that the search path is not fully used# There is a interaction between the ObjectGallery directory and# the processing of Merge modules.## The problem (that I see) is solved by deleting the ObjectGallery# but InstallShield do not recomment this solution.## They recommend that the Object and Modules be copied into the# 'C:\Program Files\Macrovision\IS 11.5 StandaloneBuild' directory# There are a few bug reports out for this one.# With luck this problem will be solved and this code can be removed## The solution that I have taken is to transfer the Object and# Modules directories as suggseted. This is UGLY:# Makes the build single user# Modifies the build environment# Time consuming#### Inputs : List of Merge Module paths## Returns : Nothing#my $kludge_copy_dir_len;my $kludge_copy_dir;sub kludge_merge_module_stuff{my (@mergemodules) = @_;foreach my $dir ( @mergemodules ){next if ( $dir =~ m/Merge Modules$/ );Message("KLUDGE copy: [$dir] to [$AutoBuilder]");$kludge_copy_dir = $dir;$kludge_copy_dir =~ s~\\+~/~g;$kludge_copy_dir =~ s~/$~~;$kludge_copy_dir =~ s~/[^/]*$~~;$kludge_copy_dir_len = length($kludge_copy_dir);File::Find::find( \&kludge_copy, $dir);}}sub kludge_copy{my $item = $File::Find::name;my $base = $_;my $tpath = $AutoBuilder . substr( $item, $kludge_copy_dir_len );if ( -d $item ){unless ( -d $tpath ){Verbose( "Create Directory: $tpath");mkpath("$tpath", 1, 0775) || Error ("Cannot mkdir: $tpath");}}else{if ( FileIsNewer( $item, $tpath ) ){Verbose ("Copy File: tpath");File::Copy::copy($item, $tpath) || Error("Copying: $tpath");}}}#-------------------------------------------------------------------------------# Documentation#=pod=head1 NAMEisbuild - Build an Install Shield Project=head1 SYNOPSISjats eprog isbuild.pl [options]Options:-help - brief help message-help -help - Detailed help message-man - Full documentation-version=version - Specify build version-project=name - Specifies the project to process-out=path - Output directory (optional)-mergemodule=path - Path to one or more merge modules-workdir=path - Path to working directory base-[no]readonly - Open project in readonly mode-[no]standalone - Use SA or IS automation interface-[no]build - Build project-[no]codes - Modify GUID codes in release-[no]nameversion - Add Version info to ProductName (default)=head1 OPTIONS=over 8=item B<-help>Print a brief help message and exits.=item B<-help -help>Print a detailed help message with an explanation for each option.=item B<-man>Prints the manual page and exits.=item B<-version=version>This option is essential. It is used to specify the output package version.The version information will be inserted in the InstallShield project beforeit is compiled.=item B<-project=name>This option specifies the InstallShield project to be processed. If not projectname is specified then this script will locate an '.ism' file in the currentdirectory and use it. Multiple '.ism' files are not supported.=item B<-out=path>Specifies the output path. If specified the InstallShield project will bymoved to this directory, if it is build successfully.The path must exist and it must be a directory.=item B<-mergemodule=path>This option specifies one or more merge module paths to be used by the InstallShield compiler. Multiple paths may be specified with multiple directives oras a comma seperated list.=item B<-workdir=path>This option specifies the path of a directory in which this program will createits working directory. If not specified then the current directory will beused.=item B<-readony>Open the project in readonly mode. This is the defaultChanges to the project are not written back.=item B<-standalone>Invoke the StandAlone Install Shield builder. This is the default.If B<-nostandalone> is specified then the InstallShield IDE Automation interfaceis used. This may not be the same as that on the build machine.=item B<-build>Build the project. This is the default mode of operation.If B<-nobuild> is specified then the project will not be built. All otheroperations will be performed.=item B<-codes>If specified then the following GUID elements are rolled:=over 8=item * PackageCode=item * ProductCode=item * UpgradeCode=backThe default operation is to NOT roll the specified GUID elements.=item B<-nameversion>This option Add Version information to the Product Name.The default operation will add Version Information. Use -nonameversion to disablethis operation.=back=head1 DESCRIPTIONThis program is used within the ERG deployment process to build up an InstallShield project.=head1 EXAMPLE=cut