Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1532 dpurdie 1
#! perl
2
########################################################################
3
# Copyright ( C ) 2005 ERG Limited, All rights reserved
4
#
5
# Module name   : jats.sh
6
# Module type   : Makefile system
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description   : Build an Install Shield project for deployment
11
#                 This script isolates the IS build from the rest of
12
#                 the deployment process.
13
#
14
#                 Assumes that:
15
#                       IS 11.5 Standalone builder has been installed
16
#                       Merge Modules have been installed / updated
17
#                       to subdirs with the SA installation of:
18
#                           Modules\i386
19
#                           Objects
20
#
21
#                 Note: IS SA builder can be copied and registered
22
#                       The installation is very simple.
23
#                       Registartion: regsvr32.exe
24
#
25
#                       Currently this script will register the required
26
#                       DLL anyway.
27
#
28
# Usage         : Refer to POD within this script
29
#
30
#......................................................................#
31
 
32
require 5.8.6;
33
use strict;
34
use warnings;
35
use JatsError;                              # Error reporting
1534 dpurdie 36
use JatsSystem;                             # System interface
1532 dpurdie 37
use Win32::OLE;                             # load the Win32::OLE module
38
use Pod::Usage;                             # required for help support
39
use Getopt::Long;                           # Parse input options
40
use Cwd;                                    # Where am I
41
use File::Copy;                             # Transfer files
42
use File::Path;
43
use File::Find;                             # Ony for kludge copy
44
use FileUtils;
45
 
46
my $VERSION = "1.0.0";                      # Update this
47
 
48
#
49
#   Globals
50
#
51
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
52
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
53
my $opt_help = 0;
54
my $opt_manual;
55
 
56
my $opt_read_only = 1;
57
my $opt_use_sa = 1;
58
my $opt_build = 1;
59
my $opt_project;
60
my $opt_new_codes;
61
my $opt_name;
62
my $opt_version;
63
my $opt_suffix;
64
my $opt_outpath;
65
my @opt_mergemodule;
66
my $opt_workdir;
1538 dpurdie 67
my $opt_name_version = 1;
1532 dpurdie 68
 
69
#
70
#   Kludgy values
71
#       May need to be configured
72
#       These are current IS 11.5 install locations
73
#
74
my $AutoBuilder = 'C:\Program Files\Macrovision\IS 11.5 StandaloneBuild';
75
my $result_code = 0;
76
 
77
#-------------------------------------------------------------------------------
78
# Function        : Mainline Entry Point
79
#
80
# Description     :
81
#
82
# Inputs          :
83
#
84
my $result = GetOptions (
85
                "help+"         => \$opt_help,              # flag, multiple use allowed
86
                "manual"        => \$opt_manual,            # flag
87
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
88
                "readonly!"     => \$opt_read_only,         # [no]flag
89
                "standalone!"   => \$opt_use_sa,            # [no]flag
90
                "build!"        => \$opt_build,             # [no]flag
91
                "project=s"     => \$opt_project,           # string
92
                "codes!"        => \$opt_new_codes,         # [no]flag
93
                "version=s"     => \$opt_version,           # string
94
                "out=s"         => \$opt_outpath,           # string
95
                "mergemodule=s" => \@opt_mergemodule,       # string
96
                "workdir=s"     => \$opt_workdir,           # string
1538 dpurdie 97
                "nameversion!"  => \$opt_name_version,      # [no]flag
1532 dpurdie 98
                );
99
 
100
                #
101
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
102
                #
103
 
104
#
105
#   Process help and manual options
106
#
107
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
108
pod2usage(-verbose => 1) if ($opt_help == 2 );
109
pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));
110
#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV < 0 );
111
 
112
#
113
#   Configure the error reporting process now that we have the user options
114
#
115
ErrorConfig( 'name'    =>'ISBUILD',
116
             'verbose' => $opt_verbose,
117
            );
118
 
119
#
120
#   User must specify a project or we will attempt to locate one
121
#
122
Verbose ("Current directory: " . getcwd );
123
unless ( $opt_project )
124
{
125
    my @projects = glob ('*.ism' );
126
    Error ("No InstallShield projects found in current directory") unless ( $#projects >= 0 );
127
    Error ( "Multiple Install Shield projects located. Use -project option") if ( $#projects > 0 );
128
    $opt_project = $projects[0];
129
}
130
else
131
{
132
    Error ("Project file not found: $opt_project") unless ( -f $opt_project );
133
}
134
#
135
#   Determine project name from the project file name
136
#       - remove any path information
137
#       - remove .ism extension
138
#
139
$opt_name = $opt_project;
140
$opt_name =~ s~\\~/~g;
141
$opt_name =~ s~.*/~~;
142
$opt_name =~ s~\.ism$~~i;
143
 
144
#
145
#   User must specify a version
146
#   This will be processed and used within the build
147
#
148
Error ("Version must be specified") unless ( $opt_version );
149
Error ("Bad format for version: $opt_version") unless ( $opt_version =~ m~(\d+\.\d+\.\d+)\.(\w+)$~ );
150
$opt_version = $1;
151
$opt_suffix = $2;
152
Error ("Project suffix not found in version") unless ( $opt_suffix );
153
Message( "Package: $opt_name, Version: $opt_version, Project: $opt_suffix");
154
 
155
#
156
#   Output path must exist
157
#
158
if ( $opt_outpath )
159
{
160
    Error("Output path does not exist: $opt_outpath") unless ( -e $opt_outpath );
161
    Error("Output path is not a directory: $opt_outpath") unless ( -d $opt_outpath );
162
}
163
 
164
#
165
#   Workdir path must exist
166
#
167
$opt_workdir = getcwd unless( $opt_workdir );
168
Error("Workdir path does not exist: $opt_outpath") unless ( -e $opt_workdir );
169
Error("Workdir path is not a directory: $opt_outpath") unless ( -d $opt_workdir );
170
 
171
#
172
#   Process Merge Module paths
173
#
174
if ( @opt_mergemodule )
175
{
176
    #
177
    #   User may have entered a comma seperated list
178
    #   Convert into a full array
179
    #
180
    @opt_mergemodule = split(/,/,join(',',@opt_mergemodule));
181
 
182
    #
183
    #   Ensure that each path exists
184
    #   Clean up paths
185
    #
186
    foreach my $path ( @opt_mergemodule )
187
    {
188
        Warning ("MergeModule path not found: $path" ) unless ( -d $path );
189
        $path =~ s~/~\\~g;
190
    }
191
}
192
 
193
 
194
#
195
#   Instantiate the Developer Automation interface
196
#   Use the StandAlone interface if it can be found
197
#
198
my $dev;
199
if ( $opt_use_sa )
200
{
201
    Message "Using StandAlone OLE";
202
 
203
    #
204
    #   Ensure the interface is registered
205
    #   This allows a simple 'copy' of the SA build environment to a build
206
    #   machine.
207
    #
208
    my $regdll = $AutoBuilder . '\SAAuto1150.dll' ;
209
    Error ("Cannot find SA OLE DLL: $regdll") unless ( -f $regdll );
210
 
211
    my $rv = System( 'regsvr32.exe', '/s', $regdll);
212
    Error ("Failed to register $regdll: $rv" ) if ( $rv  );
213
 
214
    $dev = Win32::OLE->new("SAAuto1150.ISWiProject");
215
 
216
} else {
217
    Message "Using InstallShield OLE";
218
    $dev = Win32::OLE->new("IswiAuto1150.ISWiProject");
219
 
220
}
221
Error( "Cannot open Automation interface") unless ( $dev );
222
 
223
#
224
#   Open a project as read-write
225
#   The second argument ( if true ) will open as read only
226
#
227
Verbose ("Opening project: $opt_project, ReadOnly: $opt_read_only" );
228
$dev->OpenProject( $opt_project, $opt_read_only );
229
my $estring = Win32::OLE->LastError();
230
Error( $estring ) if ( $estring );
231
Verbose ("Project Open");
232
 
233
#DebugDumpData("Dev", $dev );
234
 
235
#
1538 dpurdie 236
#   Massage the ProductName [ if required ]
1532 dpurdie 237
#   Should contain a comma<space><version>
238
#
1538 dpurdie 239
if ( $opt_name_version )
1532 dpurdie 240
{
1538 dpurdie 241
    Verbose( "Update ProductName" );
242
    Verbose( "Originial ProductName   :" . $dev->ProductName);
243
    my $product_name = $dev->ProductName;
244
    if ( $product_name =~ m/^(.*),/ )
245
    {
246
        $product_name = $1;
247
    }
248
    $product_name .= ', ' . $opt_version . '.' . $opt_suffix;
249
    $dev->SetProperty('ProductName', $product_name );
1532 dpurdie 250
}
251
Message( "ProductName   :" . $dev->ProductName);
252
 
253
#
254
#   Massage the ProjectVersion
255
#   This will not have the project suffix on it
256
#
257
Verbose( "Update ProductVersion" );
258
Verbose( "Original ProductVersion:" . $dev->ProductVersion);
259
$dev->SetProperty('ProductVersion', $opt_version );
260
Message ("ProductVersion:" . $dev->ProductVersion);
261
 
262
#
263
#   If we need to generate new codes
264
#
265
if ( $opt_new_codes )
266
{
267
    Message ("Update GUIDs");
268
    $dev->SetProperty('PackageCode', $dev->GenerateGUID() );
269
    $dev->SetProperty('ProductCode', $dev->GenerateGUID() );
270
    $dev->SetProperty('UpgradeCode', $dev->GenerateGUID() );
271
}
272
Message ("PackageCode   :" . $dev->PackageCode );
273
Message ("ProductCode   :" . $dev->ProductCode );
274
Message ("UpgradeCode   :" . $dev->UpgradeCode );
275
 
276
#
277
#   Examine all components and display the files within each
278
#   The files are a collection and need to be processed in a special manner
279
#
280
if ( $opt_verbose )
281
{
282
    Verbose ("InstallShield Components");
283
    my $mycomps = $dev->ISWiComponents;
284
    foreach my $comp (in $mycomps)
285
    {
286
        Verbose ("Component: " . $comp->Name, ": ", $comp->Destination );
287
 
288
        my $files = $comp->ISWiFiles;
289
        my $fileCount = $files->Count;
290
        Verbose ("Number of Files: $fileCount");
291
 
292
        foreach my $index ( 1 .. $fileCount )
293
        {
294
            Verbose ("           Name: " . $files->Item($index)->Name );
295
            Verbose ("    DisplayName: " . $files->Item($index)->DisplayName );
296
            Verbose ("       FullPath: " .  $files->Item($index)->FullPath );
297
        }
298
    }
299
}
300
 
301
#
302
#   Examine all the Features
303
#
304
if ( $opt_verbose  )
305
{
306
    Verbose ("InstallShield Features");
307
    my $myfeature = $dev->ISWiFeatures;
308
    foreach my $feat (in $myfeature)
309
    {
310
        Verbose ("Feature: " . $feat->Name, ": ", $feat->Description );
311
    }
312
}
313
 
314
#
315
#   Display Releases
316
#   These are found within the product config
317
#   We need to locate the Release in order to build it
318
#
319
Verbose ("InstallShield Products");
320
my $products = $dev->ISWiProductConfigs;
321
foreach my $index ( 1 .. $products->Count )
322
{
323
    my $product = $products->Item($index);
324
 
325
    Verbose ("Product Index  : " . $index );
326
    Verbose ("  Product Name : " . $product->Name );
327
    Verbose ("  SetupFileName: " . $product->SetupFileName );
328
 
329
    my $releases = $product->ISWiReleases;
330
    foreach my $index ( 1 .. $releases->Count )
331
    {
332
        my $release = $releases->Item($index);
333
 
334
        Verbose ("Release Index      : " . $index );
335
        Verbose ("  Name             : " . $release->Name );
336
        Verbose ("  BuildLocation    : " . $release->BuildLocation );
337
        Verbose ("  SingleEXEFileName: " . ( $release->SingleEXEFileName || 'None Specified' ) );
338
 
339
 
340
        #
341
        #   Build the Project
342
        #   Not working at the moment !!!!
343
        #
344
        if ( $opt_build )
345
        {
346
            Message ("Building...");
347
 
348
            #
349
            #   Set build location
350
            #
351
            my $location = $opt_workdir . '/Media';
352
            $location =~ s~/~\\~g;
353
            $release->SetProperty('BuildLocation', $location );
354
            Message ("BuildLocation: " . $release->BuildLocation );
355
 
356
 
357
            #
358
            #   If building with the Standalone interface will need to set
359
            #   up the merge module paths
360
            #
361
            if ( $opt_use_sa )
362
            {
363
                foreach my $dir ( @opt_mergemodule )
364
                {
365
                    Error ("MergeModule Directory not found: $dir") unless ( -d $dir );
366
                    Verbose( "Merge Module Search Path:", $dir );
367
                }
368
                $dev->SetProperty('MergeModuleSearchPath', join (',', @opt_mergemodule));
369
                Verbose2 ( "MergeModulePath: " . $dev->MergeModuleSearchPath );
370
 
371
                #
372
                #   See comments in this function
373
                #
374
                kludge_merge_module_stuff(@opt_mergemodule);
375
            }
376
 
377
            #
378
            #   Set thename of the setup file
379
            #   This contains the build name and number
380
            #
381
            Verbose ("Setting Setup Filename");
382
            Verbose2 ( "Initial SetupFileName: " . $product->SetupFileName );
383
            my $setup_name = $opt_name
384
                           . '-'
385
                           . $dev->ProductVersion
386
                           . '.'
387
                           . $opt_suffix
388
                           . '-WIN32';
389
 
390
            $product->SetProperty('SetupFileName', $setup_name );
391
            Message( "SetupFileName: " . $product->SetupFileName );
392
 
393
            #
394
            #   Perform the build and report errors and warnings
395
            #
396
            $release->Build;
397
            $result_code = $release->BuildErrorCount;
398
            Message ("Build Error Count  : " . $release->BuildErrorCount );
399
            Message ("Build Warning Count: " . $release->BuildWarningCount );
400
 
401
            #
402
            #   Transfer the result file to the user
403
            #
404
            if ( $result_code == 0 && $opt_outpath )
405
            {
406
                Message("Transfer output file: $opt_outpath");
407
                my$ofile = $location . "/ishield package/Release/DiskImages/DISK1/" . $setup_name . '.exe';
408
                Error ("Build output file not found", "Expected: $ofile" ) unless ( -f $ofile );
409
 
410
                File::Copy::copy( $ofile, $opt_outpath) ||
411
                    Error ("Did not transfer InstallShield output file", $ofile, $opt_outpath);
412
            }
413
        }
414
    }
415
}
416
 
417
#
418
#   Save and Close the project
419
#   Release the OLE data
420
#
421
$dev->SaveProject( ) unless ($opt_read_only);
422
$dev->CloseProject( );
423
undef $dev;
424
 
425
#
426
#   Return build result to the user
427
#
428
exit $result_code;
429
 
430
#-------------------------------------------------------------------------------
431
# Function        : kludge_merge_module_stuff
432
#
433
# Description     : Handle BUG in the SA builder
434
#
435
#   The current version of InstallShield StandAlone Builder has a bug associated
436
#   with the processing of Merge Modules
437
#
438
#   It would appear that the search path is not fully used
439
#   There is a interaction between the ObjectGallery directory and
440
#   the processing of Merge modules.
441
#
442
#   The problem (that I see) is solved by deleting the ObjectGallery
443
#   but InstallShield do not recomment this solution.
444
#
445
#   They recommend that the Object and Modules be copied into the
446
#   'C:\Program Files\Macrovision\IS 11.5 StandaloneBuild' directory
447
#   There are a few bug reports out for this one.
448
#   With luck this problem will be solved and this code can be removed
449
#
450
#   The solution that I have taken is to transfer the Object and
451
#   Modules directories as suggseted. This is UGLY:
452
#       Makes the build single user
453
#       Modifies the build environment
454
#       Time consuming
455
#
456
#
457
#
458
# Inputs          : List of Merge Module paths
459
#
460
# Returns         : Nothing
461
#
462
my $kludge_copy_dir_len;
463
my $kludge_copy_dir;
464
 
465
sub kludge_merge_module_stuff
466
{
467
    my (@mergemodules) = @_;
468
    foreach my $dir ( @mergemodules )
469
    {
470
        next if ( $dir =~ m/Merge Modules$/ );
471
        Message("KLUDGE copy: [$dir] to [$AutoBuilder]");
472
        $kludge_copy_dir = $dir;
473
        $kludge_copy_dir =~ s~\\+~/~g;
474
        $kludge_copy_dir =~ s~/$~~;
475
        $kludge_copy_dir =~ s~/[^/]*$~~;
476
        $kludge_copy_dir_len = length($kludge_copy_dir);
477
 
478
        File::Find::find( \&kludge_copy, $dir);
479
    }
480
}
481
 
482
sub kludge_copy
483
{
484
    my $item = $File::Find::name;
485
    my $base = $_;
486
    my $tpath =  $AutoBuilder . substr( $item, $kludge_copy_dir_len );
487
 
488
    if ( -d $item )
489
    {
490
        unless ( -d $tpath )
491
        {
492
            Verbose( "Create Directory: $tpath");
493
            mkpath("$tpath", 1, 0775) || Error ("Cannot mkdir: $tpath");
494
        }
495
    }
496
    else
497
    {
498
        if ( FileIsNewer( $item, $tpath ) )
499
        {
500
            Verbose ("Copy File: tpath");
501
            File::Copy::copy($item, $tpath) || Error("Copying: $tpath");
502
        }
503
    }
504
}
505
 
506
#-------------------------------------------------------------------------------
507
#   Documentation
508
#
509
 
510
=pod
511
 
512
=head1 NAME
513
 
514
isbuild - Build an Install Shield Project
515
 
516
=head1 SYNOPSIS
517
 
518
jats eprog isbuild.pl [options]
519
 
520
 Options:
521
    -help              - brief help message
522
    -help -help        - Detailed help message
523
    -man               - Full documentation
524
    -version=version   - Specify build version
525
    -project=name      - Specifies the project to process
526
    -out=path          - Output directory (optional)
527
    -mergemodule=path  - Path to one or more merge modules
528
    -workdir=path      - Path to working directory base
529
    -[no]readonly      - Open project in readonly mode
530
    -[no]standalone    - Use SA or IS automation interface
531
    -[no]build         - Build project
532
    -[no]codes         - Modify GUID codes in release
1538 dpurdie 533
    -[no]nameversion   - Add Version info to ProductName (default)
1532 dpurdie 534
 
535
=head1 OPTIONS
536
 
537
=over 8
538
 
539
=item B<-help>
540
 
541
Print a brief help message and exits.
542
 
543
=item B<-help -help>
544
 
545
Print a detailed help message with an explanation for each option.
546
 
547
=item B<-man>
548
 
549
Prints the manual page and exits.
550
 
551
=item B<-version=version>
552
 
553
This option is essential. It is used to specify the output package version.
554
The version information will be inserted in the InstallShield project before
555
it is compiled.
556
 
557
=item B<-project=name>
558
 
559
This option specifies the InstallShield project to be processed. If not project
560
name is specified then this script will locate an '.ism' file in the current
561
directory and use it. Multiple '.ism' files are not supported.
562
 
563
=item B<-out=path>
564
 
565
Specifies the output path. If specified the InstallShield project will by
566
moved to this directory, if it is build successfully.
567
 
568
The path must exist and it must be a directory.
569
 
570
=item B<-mergemodule=path>
571
 
572
This option specifies one or more merge module paths to be used by the Install
573
Shield compiler. Multiple paths may be specified with multiple directives or
574
as a comma seperated list.
575
 
576
=item B<-workdir=path>
577
 
578
This option specifies the path of a directory in which this program will create
579
its working directory. If not specified then the current directory will be
580
used.
581
 
582
=item B<-readony>
583
 
584
Open the project in readonly mode. This is the default
585
Changes to the project are not written back.
586
 
587
=item B<-standalone>
588
 
589
Invoke the StandAlone Install Shield builder. This is the default.
590
 
591
If B<-nostandalone> is specified then the InstallShield IDE Automation interface
592
is used. This may not be the same as that on the build machine.
593
 
594
=item B<-build>
595
 
596
Build the project. This is the default mode of operation.
597
 
598
If B<-nobuild> is specified then the project will not be built. All other
599
operations will be performed.
600
 
601
 
602
=item B<-codes>
603
 
604
If specified then the following GUID elements are rolled:
605
 
606
=over 8
607
 
608
=item * PackageCode
609
 
610
=item * ProductCode
611
 
612
=item * UpgradeCode
613
 
614
=back
615
 
616
The default operation is to NOT roll the specified GUID elements.
617
 
1538 dpurdie 618
=item B<-nameversion>
619
 
620
This option Add Version information to the Product Name.
621
 
622
The default operation will add Version Information. Use -nonameversion to disable
623
this operation.
624
 
1532 dpurdie 625
=back
626
 
627
=head1 DESCRIPTION
628
 
629
This program is used within the ERG deployment process to build up an Install
630
Shield project.
631
 
632
=head1 EXAMPLE
633
 
634
 
635
=cut
636