Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
# Copyright (C) 1998-2004 ERG Transit Systems, All rights reserved
2
#
3
# Module name   : installpkg.pl
4
# Module type   : Makefile system
5
# Environment(s): n/a
6
#											
7
# Description:    Install package definition file.
8
#		
9
#	This file is invoked during package installation
10
#
11
###############################################################################
12
#
13
#   The main purpose of this program is to take packages from dpkg_archive and
14
#   place them into the build's 'interface' directory in a form that can be used
15
#   by the rest of the build. This process is complicated by the number of
16
#   variants in package format. In the pre-JATS2 days the users were encourgaed
17
#   to dream up there own format for packages. The hard of of this script is
18
#   dealing with all the known variations. Under JATS2 the default package
19
#   layout is much easier to implemenet and users generally adhere to it.
20
#
21
#   The target 'interface' format is of the form:
22
#
23
#           interface/
24
#               include/
25
#                   PLATFORM/
26
#                   PRODUCT/
27
#                   TARGET/
28
#               lib/                                    - Should not be populated
29
#                   PLATFORM/                           - Ideal
30
#                   PRODUCT/                            - Not practical
31
#                   TARGET/
32
#               bin/                                    - Should not be populated
33
#                   PLATFORM[P|D]/                      - Ideal
34
#                   PRODUCT[P|D]/                       - Not practical
35
#                   TARGET[P|D]/
36
#
37
#               tools/
38
#                   bin/
39
#                       MACHTYPE/
40
#                   scrips/
41
#                       MACHTYPE/
42
#
43
#               pkg/
44
#
45
#               OTHERS
46
#
47
#
48
 
49
use strict;
50
use warnings;
51
 
52
use JatsError;
53
use DescPkg;
54
use JatsEnv;
55
 
56
use Cwd;
57
use File::Basename;
58
use File::Find;
59
use File::Path;
60
use File::Copy;
61
 
62
#
63
#   Global variables
64
#
65
our $GBE_VERBOSE;
66
our $GBE_MACHTYPE;
67
 
68
my %PLATFORMS = ();
69
my %dirs_processed = ();
70
my $symlinks;
71
 
72
#...
73
#
74
my $INTDIR;                                 # Interface directory (target)
75
my $BINDIR;                                 # Build directory (Not used)
76
my $PKG_ROOT=cwd();                         # Package source (CWD)
77
 
78
#
79
#   Global used for File::Find callback function
80
#
81
my $FF_SRC_DIR="";                          # Src subdir base
82
my $FF_DST_DIR="";                          # Dst subdir base
83
 
84
################################################################################
85
#
86
#
87
#
88
#   Init the error reporting package
89
#
90
ErrorConfig( 'name'    => 'installpkg' );
91
 
92
#
93
#   Ensure required environment variables are present
94
#
95
EnvImport ('GBE_MACHTYPE');
96
EnvImport ('GBE_VERBOSE');
97
 
98
ErrorConfig( 'verbose' => $GBE_VERBOSE );
99
 
100
#
101
#   Determine if symlinks are available
102
#   They may not be available at all, in which case we don't even try
103
#
104
$symlinks = eval { symlink("",""); 1 } || 0;
105
 
106
#
107
#   Report machine information
108
#
109
Verbose ("GBE_VERBOSE  : $GBE_VERBOSE" );
110
Verbose ("GBE_MACHTYPE : $GBE_MACHTYPE" );
111
Verbose ("SymLinks     : $symlinks" );
112
Verbose ("Cmd          : @ARGV");
113
 
114
################################################################################
115
#
116
#   Parse user arguments
117
#   Arguments
118
#       Arg0    - Interface directory
119
#       Arg1    - Build Directory ( Not Used )
120
#       Arg2..  - A list of Platform specifications
121
#                 One for each platform that needs to be processed
122
#                 Each plaform specification consists of:
123
#                   --Platform:PlatformName:PlatformParts:Options
124
#                   Where:
125
#                       --Platform      - is a leadin switch
126
#                       PlatformName    - The the target platform
127
#                       PlatformParts   - A colon seperated list of platform 'parts'
128
#                                         This consist of: Platform, Product, ... Target
129
#
130
$INTDIR = shift @ARGV;
131
Error("Interface directory not specified") unless( defined $INTDIR );
132
Error("Interface directory not found: $INTDIR") unless( -d $INTDIR );
133
 
134
$BINDIR = shift @ARGV;
135
Error("Program directory not specified")   unless( defined $BINDIR );
136
Error("Program directory not found: $BINDIR") unless( -d $BINDIR );
137
 
138
foreach ( @ARGV )
139
{
140
    if ( /^--Platform/ ) {
141
        Verbose2 ("ARGV = <$_>");
142
        my ($tmpVar, @platforms) = split /:/, $_;
143
 
144
        my $platform = $platforms[0];
145
        $PLATFORMS{$platform}{'PARTS'} = \@platforms;
146
 
147
    } elsif ( /^--NoSymlinks/i ) {
148
        $symlinks = 0;
149
 
150
    } else {
151
        Warning("Unknown argument(ignored): $_");
152
 
153
    }
154
}
155
 
156
#
157
# lets review what we have read in
158
#
159
foreach my $i ( sort keys %PLATFORMS )
160
{
161
    Verbose( "PLATFORMS{$i} = ", join( ',', @{$PLATFORMS{$i}{'PARTS'}} ) );
162
}
163
 
164
################################################################################
165
#   Read in the Packages descpkg file
166
#   The contents are not used. More a sanity test than anything else
167
#
168
my $rec = ReadDescpkg ( "descpkg" );
169
if ( $rec )
170
{
171
    Verbose ("Installing the package $rec->{NAME} $rec->{VERSION} $rec->{PROJ}");
172
}
173
else
174
{
175
    Message ("Installing the package ($PKG_ROOT)");
176
}
177
 
178
 
179
################################################################################
180
#
181
#   Lets deal with the top level flat dirs include dir(s)
182
#
183
#   For each directory listed in the ModuleList simply duplicate the entire
184
#   directory to the target location
185
#
186
my (@ModuleList) = ( "etc",
187
                     "swsfiles", 
188
                     "classes", 
189
                     "jar",
190
                     "sar",
191
                     "sql", 
192
                     "war", 
193
                     "scripts", 
194
                     "infofiles", 
195
                     "jsp", 
196
                     "thx", 
197
                     "rox", 
198
                     "rpt", 
199
                     "java", 
200
                     "achtml", 
201
                     "epedia", 
202
                     "doc", 
203
                     "docs",
204
                     "devcd",
205
                     "dat",
206
                     "mug",
261 dpurdie 207
                     "wsdl",                # Store wsdls
227 dpurdie 208
                     "include",             # Need the entire directory
209
                     "MergeModules",        # InstallShield Merge Modules
210
                     "deployfiles",         # Deployment internals
211
);
212
 
213
foreach my $i (@ModuleList)
214
{
215
    do_dir( $i, $i);
216
}
217
 
218
################################################################################
219
#
220
#   Process a "pkg" directory
221
#
222
#   There are two forms of pkg directory
223
#       1) pkg directory contains ONLY directories of the form pkg.$(GBE_MACHTYPE)
224
#          These are processed by coying:
225
#               pkg/pkg.GBE_MACHTYPE -> pkg
226
#
227
#       2) pkg without any pkg.* subdirs
228
#          Copy the entire subtree
229
#
230
#       3) Mixture
231
#          Cannot handle
232
#
233
#
234
my (@ModuleList2) =  ( "pkg" );
235
 
236
foreach my $i (@ModuleList2)
237
{
238
    #
239
    #   Determine the mode of operation
240
    #   Scan files in the directory for known format
241
    #
242
    my @dir_list = glob( "$i/*" );
243
    my $pkg_count = 0;
244
    my $other_count = 0;
245
 
246
    foreach ( @dir_list )
247
    {
248
        if ( m~/$i\.~ )
249
        {
250
            $pkg_count++;
251
        }
252
        else
253
        {
254
            $other_count++;
255
        }
256
    }
257
 
258
    if ( $pkg_count && $other_count )
259
    {
260
        Warning( "Cannot handle mixed \"${i}\" directory",
261
                 "Only machine directory will be copied" );
262
    }
263
 
264
    if ( $pkg_count )
265
    {
266
        #
267
        #   pkg/pkg.GBE_MACHTYPE -> pkg
268
        #
269
        do_dir("$i/$i\.$GBE_MACHTYPE", $i, );
270
    }
271
    else
272
    {
273
        #
274
        #   pkg -> pkg
275
        #
276
        do_dir($i, $i);
277
    }
278
}
279
 
280
 
281
################################################################################
282
#
283
#   Deal with the complex directories:
284
#           bin,
285
#           lib,
286
#           inc
287
#           include
288
#
289
#   Look for, and process the first of:
290
#
291
#   for each item in module list we shall process (if it exists) 
292
#   the following variants:
293
#
294
#       module.<platform>
295
#       module.<product>
296
#       module.<target>
297
#
298
#       module/<platform>
299
#       module/<product>
300
#       module/<target>
301
#
302
#   The platform, product and target are all passed on the command
303
#   line.  They are configured in the build.pl using the BuildProduct
304
#   directives.
305
#
306
#   For the bin dirs we need to consider the 'Debug' and 'Prod' 
307
#   build types as well as some cots packages that are both.
308
#
309
#   For the bin and lib dirs we also need to consider the format:
310
#       bin/bin.<platform>
311
#       lib/lib.<platform>
312
#
313
#
314
 
315
my %ModuleList3 =   (
316
                    "lib"           => 1,       # Copy root files
317
                    "inc"           => 1,       # Copy root files
318
                    "bin"           => 0,       # Should not be any root files
319
                    "include"       => 0,       # Root files already processed
320
                    );
321
 
322
foreach my $i (sort keys %ModuleList3)
323
{
324
    my $mDstDir;
325
    my $bType;
326
    my $mPart;
327
    my $mode =  $ModuleList3{$i};
328
 
329
    Verbose ("Processing: [Mode:$mode] $i");
330
 
331
    foreach my $j ( sort keys %PLATFORMS )
332
    {
333
        foreach $bType ( 'D', 'P', '' )
334
        {
335
            foreach $mPart ( sort @{$PLATFORMS{$j}{'PARTS'}} )
336
            {
337
                $mDstDir = "$i/$mPart$bType";
338
 
339
                #
340
                #   Try various combinations of directories to catter for
341
                #   all the crazy legacy combinations
342
                #
343
                do_dir("$i.$mPart$bType"    ,$mDstDir);
344
                do_dir("$i/$mPart$bType"    ,$mDstDir);
345
                do_dir("$i/$i.$mPart$bType" ,$mDstDir);
346
            }
347
        }
348
    }
349
 
350
    #
351
    # Transfer files in the root directory if required
352
    #
353
    # Now lets us deal with the simple case
354
    # here we are only interested in the top level files
355
    # sub-dirs are handles separately.
356
    #
357
    if ( ($mode & 1) && -d $i)
358
    {
359
        Verbose ("Processing: $i - Copy root directory files");
360
        do_FilesOnly ( $i );
361
    }
362
}
363
 
364
################################################################################
365
#   Deal with toolset extensions
366
#   These are JATS extensions that are platform specific and not a function of
367
#   the target. ie: If we are building on a 'win32' piece of hardware then we
368
#   need the win32 tools, independant of the target platforms
369
#
370
#   Use GBE_MACHTYPE to determine correct subdirs
371
#
372
my %ModuleList4 =   (
373
                    "tools/bin"             => 3,       # Copy GBE_MACHTYPE + root files
374
                    "tools/scripts"         => 4,       # Copy Subdir
375
                    "gbe"                   => 4,       # JATS General Build Environment
376
                    );
377
foreach my $i (sort keys %ModuleList4)
378
{
379
    my $mode = $ModuleList4{$i};
380
    Verbose ("Processing: $i, Machine Type: $GBE_MACHTYPE, Mode: $mode");
381
 
382
    #
383
    #   Transfer a machine specfic subdir
384
    #
385
    if ( $mode & 1 )
386
    {
387
        do_dir("$i.$GBE_MACHTYPE", "$i/$GBE_MACHTYPE") ;
388
        do_dir("$i/$GBE_MACHTYPE", "$i/$GBE_MACHTYPE") ;
389
    }
390
 
391
    #
392
    # Transfer files in the root directory if required
393
    #
394
    # Now lets us deal with the simple case
395
    # here we are only interested in the top level files
396
    # sub-dirs are handles separately.
397
    #
398
    if ( ($mode & 2) && -d $i)
399
    {
400
        Verbose ("Processing: $i - Copy root directory files");
401
        do_FilesOnly ( $i );
402
    }
403
 
404
    #
405
    #   Copy the entire subtree
406
    #   Used for non-machine specifc directories
407
    #
408
    if ( ($mode & 4) && -d $i)
409
    {
410
        Verbose ("Processing: $i - Copy directory tree");
411
        do_dir($i, $i) ;
412
    }
413
 
414
}
415
 
416
 
417
 
418
# done
419
exit 0;
420
 
421
 
422
#------------------------------------------------------------------------------
423
#------------------------------------------------------------------------------
424
#------------------------------------------------------------------------------
425
# subroutines
426
#------------------------------------------------------------------------------
427
#------------------------------------------------------------------------------
428
#------------------------------------------------------------------------------
429
 
430
#-------------------------------------------------------------------------------
431
# Function        : do_FilesOnly
432
#
433
# Description     : Copy all files in the current directory to the target
434
#                   directory. Assume that the target directory will be called
435
#                   the same as the source directory
436
#
437
#                   Do not process sub directories. These may be handled elsewhere
438
#
439
# Inputs          : $dir        - Src and Dst subdir name
440
#
441
# Returns         : Nothing
442
#
443
sub do_FilesOnly
444
{
445
    my ($dir) = @_;
446
    Verbose2 ("do_FilesOnly: dir=[$dir]");
447
 
448
    # define the type of dir we are working on
449
 
450
    my ($srcDir) = "$PKG_ROOT/$dir";
451
    my ($dstDir) = "$INTDIR/$dir";
452
 
453
    Verbose2("do_FilesOnly: INTDIR=[$INTDIR]");
454
    Verbose2("do_FilesOnly: dstDir=[$dstDir]");
455
    Verbose2("do_FilesOnly: srcDir=[$srcDir]");
456
 
457
    #
458
    # Create the interface dir if it does not exists
459
    #
460
    mkpath ( $dstDir, $GBE_VERBOSE, 0775) unless ( -d $dstDir );
461
 
462
 
463
    # Have a valid dst value we now need to get a hold of all the
464
    # lib scripts files.
465
    #
466
    local *DIR;
467
    opendir ( DIR, $srcDir ) or  Error ("Failed to open dir [$srcDir]");
468
 
469
    #
470
    # Process all directory entries
471
    #
472
    while (defined(my $_item = readdir(DIR)))
473
    {
474
        next if ( $_item eq '.' );
475
        next if ( $_item eq '..' );
476
 
477
        my $srcFile = "$srcDir/$_item";
478
        if ( -d $srcFile )
479
        {
480
            Verbose2 ("NOT processing dir item [$srcFile]");
481
        }
482
        else
483
        {
484
            FileLinkCopy ($srcFile, "$dstDir/$_item" );
485
        }
486
    }
285 dpurdie 487
    closedir DIR;
227 dpurdie 488
 
489
 
490
    # done
491
    return 1;
492
}
493
#-------------------------------------------------------------------------------
494
# Function        : do_dir
495
#
496
# Description     : Transfer an entire subdirectory tree
497
#                   Can detect that the tree has already been processed
498
#
499
# Inputs          : $src            - Source subdir (within PKG_ROOT)
500
#                   $dst            - Target path (within INTDIR)
501
#
502
# Returns         : Nothing
503
#
504
sub do_dir
505
{
506
    my ($src, $dst) = @_;
507
    Verbose2 ("do_dir: src=[$src], dst=[$dst]");
508
 
509
    #
510
    #   Prevent processing of the same source directory by multiple
511
    #   operations. Need only do them once
512
    #
513
    if ( $dirs_processed{$src} )
514
    {
515
        Verbose2 ("do_dir: Already processed");
516
        return 1;
517
    }
518
 
519
    $dirs_processed{$src} = 1;
520
 
521
    #
522
    #   Only if it exists
523
    #   Do the test in this function to simplify processing
524
    #
525
    unless ( -d $src )
526
    {
527
        Verbose2 ("do_dir: Directory not found");
528
        return 0;
529
    }
530
 
531
    #
532
    #   Setup values for the File::Find callback
533
    #   These need to be global due to the way that File::Find works
534
    #
535
    $FF_SRC_DIR = "$PKG_ROOT/$src";
536
    $FF_DST_DIR = "$INTDIR/$dst";
537
 
538
    Verbose2("do_dir: FF_SRC_DIR=[$FF_SRC_DIR]");
539
    Verbose2("do_dir: FF_DST_DIR=[$FF_DST_DIR]");
540
 
541
    #
542
    #   Handle directories that are really symbolic links
543
    #   This will only occur on system that handle symlinks
544
    #   May not always want to use symlinks.
545
    #
546
    if ( $symlinks && -l $FF_SRC_DIR )
547
    {
548
        Verbose2("do_dir: symlink $FF_SRC_DIR,$FF_DST_DIR");
549
        unless (symlink $FF_SRC_DIR, $FF_DST_DIR  )
550
        {
551
            Error("Failed to create symlink",
552
                  "Src: $FF_SRC_DIR",
553
                  "Dst: $FF_DST_DIR");
554
        }
555
        return 1;
556
    }
557
 
558
    #
559
    # Create the interface dir if it does not exists
560
    #
561
    mkpath ( $FF_DST_DIR, $GBE_VERBOSE, 0775)
562
        unless ( -d $FF_DST_DIR );
563
 
564
    File::Find::find( \&pkgFind2, $FF_SRC_DIR);
565
 
566
    # done
567
    return 1;
568
}
569
 
570
#-------------------------------------------------------------------------------
571
sub pkgFind2
572
#
573
# Description     : Callback function: Process a directory
574
#                   Target name is NOT the same as the source name
575
#
576
#                   The function is called for each file to be processed
577
#                   The name of the file is extracted from $File::Find::name
578
#
579
#                   Processes
580
#                       Directory: Create same directory in the target
581
#                       File     : Link/Copy file to the target
582
#
583
# Inputs          : None passed
584
#                   Globals are used
585
#
586
# Returns         :
587
#
588
#------------------------------------------------------------------------------
589
{
590
    Verbose2("pkgFind2:");
591
 
241 dpurdie 592
    my $item = "$File::Find::name";                     # Full source path
593
    my $dest_path = $FF_DST_DIR . substr ( $item, length ($FF_SRC_DIR) ); # Full destination path
227 dpurdie 594
 
595
    Verbose2 ("---- Src = [$item]");
596
    Verbose2 ("---- Dst = [$dest_path]");
597
    if ( -d $item )
598
    {
599
        #
600
        #   Create a directory
601
        #
602
        mkpath ( $dest_path, $GBE_VERBOSE, 0775) unless( -d $dest_path );
603
 
604
        #
605
        #   Flag the subdir as being processed
606
        #   Prevent multiple copy operations (and warnings)
607
        #
241 dpurdie 608
        my $subdir = substr ( $item, 1 + length ($PKG_ROOT) );
227 dpurdie 609
        $dirs_processed{$subdir} = 1;
610
 
611
    }
612
    else
613
    {
614
        #
615
        #   Copy/Link the file
616
        #
617
        FileLinkCopy ( $item, $dest_path);
618
    }
619
    return 1;
620
}
621
 
622
#-------------------------------------------------------------------------------
623
# Function        : FileLinkCopy
624
#
625
# Description     : Copy a file to a destination
626
#                   If possible create a symlink (Not always be possible)
627
#                   If the file is copied, then chmod it.
628
#
629
# Inputs          : $srcFile                 - Source path (Full)
630
#                   $dstFile                 - Destination path (Full)
631
#
632
#
633
# Globals         : symlinks                - Set if Symlinks are available
634
#                                             Will be cleared if the operation
635
#                                             failed, forcing copy
636
#
637
# Returns         : Nothing
638
#                   Will terminate, with a message, on error
639
#
640
sub FileLinkCopy
641
{
642
    my ($srcFile, $dstFile ) = @_;
643
    my $done;
644
    (my $file = $srcFile) =~ s~.*/~~;       # Filename. Just to be pretty
645
 
646
    #
647
    #   Delete target file. If it exists
648
    #
649
    if ( -f $dstFile )
650
    {
651
        unlink ($dstFile );
652
        Message("overwriting existing dpkg_archive item [$file] --> [$dstFile]\n");
653
    }
654
 
655
    #
656
    #   Try a symlink first
657
    #
658
    if ( $symlinks )
659
    {
660
        Verbose("linking file [$file] --> [$dstFile]...ok");
661
        unless (symlink ($srcFile, $dstFile)  )
662
        {
663
            #
664
            #   Symlink has failed
665
            #   Flag: Don't symlink anymore
666
            #
667
            $symlinks = 0;
668
            Verbose ("Failed to create symlink from: [$file] --> [$dstFile]");
669
        }
670
        else
671
        {
672
            $done = 1;
673
        }
674
    }
675
 
676
    #
677
    #   Try a copy
678
    #
679
    unless ( $done )
680
    {
681
        if(File::Copy::copy($srcFile, $dstFile))
682
        {
683
            Verbose("copying file [$file] --> [$dstFile]...ok");
684
            CORE::chmod oct("0755"), $dstFile;
685
        }
686
        else
687
        {
688
            Error("copying file [$file] --> [$dstFile]: $!");
689
        }
690
    }
691
}
692
 
693
############ EOF ###############################################################
694