Subversion Repositories DevTools

Rev

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