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",
207
                     "include",             # Need the entire directory
208
                     "MergeModules",        # InstallShield Merge Modules
209
                     "deployfiles",         # Deployment internals
210
);
211
 
212
foreach my $i (@ModuleList)
213
{
214
    do_dir( $i, $i);
215
}
216
 
217
################################################################################
218
#
219
#   Process a "pkg" directory
220
#
221
#   There are two forms of pkg directory
222
#       1) pkg directory contains ONLY directories of the form pkg.$(GBE_MACHTYPE)
223
#          These are processed by coying:
224
#               pkg/pkg.GBE_MACHTYPE -> pkg
225
#
226
#       2) pkg without any pkg.* subdirs
227
#          Copy the entire subtree
228
#
229
#       3) Mixture
230
#          Cannot handle
231
#
232
#
233
my (@ModuleList2) =  ( "pkg" );
234
 
235
foreach my $i (@ModuleList2)
236
{
237
    #
238
    #   Determine the mode of operation
239
    #   Scan files in the directory for known format
240
    #
241
    my @dir_list = glob( "$i/*" );
242
    my $pkg_count = 0;
243
    my $other_count = 0;
244
 
245
    foreach ( @dir_list )
246
    {
247
        if ( m~/$i\.~ )
248
        {
249
            $pkg_count++;
250
        }
251
        else
252
        {
253
            $other_count++;
254
        }
255
    }
256
 
257
    if ( $pkg_count && $other_count )
258
    {
259
        Warning( "Cannot handle mixed \"${i}\" directory",
260
                 "Only machine directory will be copied" );
261
    }
262
 
263
    if ( $pkg_count )
264
    {
265
        #
266
        #   pkg/pkg.GBE_MACHTYPE -> pkg
267
        #
268
        do_dir("$i/$i\.$GBE_MACHTYPE", $i, );
269
    }
270
    else
271
    {
272
        #
273
        #   pkg -> pkg
274
        #
275
        do_dir($i, $i);
276
    }
277
}
278
 
279
 
280
################################################################################
281
#
282
#   Deal with the complex directories:
283
#           bin,
284
#           lib,
285
#           inc
286
#           include
287
#
288
#   Look for, and process the first of:
289
#
290
#   for each item in module list we shall process (if it exists) 
291
#   the following variants:
292
#
293
#       module.<platform>
294
#       module.<product>
295
#       module.<target>
296
#
297
#       module/<platform>
298
#       module/<product>
299
#       module/<target>
300
#
301
#   The platform, product and target are all passed on the command
302
#   line.  They are configured in the build.pl using the BuildProduct
303
#   directives.
304
#
305
#   For the bin dirs we need to consider the 'Debug' and 'Prod' 
306
#   build types as well as some cots packages that are both.
307
#
308
#   For the bin and lib dirs we also need to consider the format:
309
#       bin/bin.<platform>
310
#       lib/lib.<platform>
311
#
312
#
313
 
314
my %ModuleList3 =   (
315
                    "lib"           => 1,       # Copy root files
316
                    "inc"           => 1,       # Copy root files
317
                    "bin"           => 0,       # Should not be any root files
318
                    "include"       => 0,       # Root files already processed
319
                    );
320
 
321
foreach my $i (sort keys %ModuleList3)
322
{
323
    my $mDstDir;
324
    my $bType;
325
    my $mPart;
326
    my $mode =  $ModuleList3{$i};
327
 
328
    Verbose ("Processing: [Mode:$mode] $i");
329
 
330
    foreach my $j ( sort keys %PLATFORMS )
331
    {
332
        foreach $bType ( 'D', 'P', '' )
333
        {
334
            foreach $mPart ( sort @{$PLATFORMS{$j}{'PARTS'}} )
335
            {
336
                $mDstDir = "$i/$mPart$bType";
337
 
338
                #
339
                #   Try various combinations of directories to catter for
340
                #   all the crazy legacy combinations
341
                #
342
                do_dir("$i.$mPart$bType"    ,$mDstDir);
343
                do_dir("$i/$mPart$bType"    ,$mDstDir);
344
                do_dir("$i/$i.$mPart$bType" ,$mDstDir);
345
            }
346
        }
347
    }
348
 
349
    #
350
    # Transfer files in the root directory if required
351
    #
352
    # Now lets us deal with the simple case
353
    # here we are only interested in the top level files
354
    # sub-dirs are handles separately.
355
    #
356
    if ( ($mode & 1) && -d $i)
357
    {
358
        Verbose ("Processing: $i - Copy root directory files");
359
        do_FilesOnly ( $i );
360
    }
361
}
362
 
363
################################################################################
364
#   Deal with toolset extensions
365
#   These are JATS extensions that are platform specific and not a function of
366
#   the target. ie: If we are building on a 'win32' piece of hardware then we
367
#   need the win32 tools, independant of the target platforms
368
#
369
#   Use GBE_MACHTYPE to determine correct subdirs
370
#
371
my %ModuleList4 =   (
372
                    "tools/bin"             => 3,       # Copy GBE_MACHTYPE + root files
373
                    "tools/scripts"         => 4,       # Copy Subdir
374
                    "gbe"                   => 4,       # JATS General Build Environment
375
                    );
376
foreach my $i (sort keys %ModuleList4)
377
{
378
    my $mode = $ModuleList4{$i};
379
    Verbose ("Processing: $i, Machine Type: $GBE_MACHTYPE, Mode: $mode");
380
 
381
    #
382
    #   Transfer a machine specfic subdir
383
    #
384
    if ( $mode & 1 )
385
    {
386
        do_dir("$i.$GBE_MACHTYPE", "$i/$GBE_MACHTYPE") ;
387
        do_dir("$i/$GBE_MACHTYPE", "$i/$GBE_MACHTYPE") ;
388
    }
389
 
390
    #
391
    # Transfer files in the root directory if required
392
    #
393
    # Now lets us deal with the simple case
394
    # here we are only interested in the top level files
395
    # sub-dirs are handles separately.
396
    #
397
    if ( ($mode & 2) && -d $i)
398
    {
399
        Verbose ("Processing: $i - Copy root directory files");
400
        do_FilesOnly ( $i );
401
    }
402
 
403
    #
404
    #   Copy the entire subtree
405
    #   Used for non-machine specifc directories
406
    #
407
    if ( ($mode & 4) && -d $i)
408
    {
409
        Verbose ("Processing: $i - Copy directory tree");
410
        do_dir($i, $i) ;
411
    }
412
 
413
}
414
 
415
 
416
 
417
# done
418
exit 0;
419
 
420
 
421
#------------------------------------------------------------------------------
422
#------------------------------------------------------------------------------
423
#------------------------------------------------------------------------------
424
# subroutines
425
#------------------------------------------------------------------------------
426
#------------------------------------------------------------------------------
427
#------------------------------------------------------------------------------
428
 
429
#-------------------------------------------------------------------------------
430
# Function        : do_FilesOnly
431
#
432
# Description     : Copy all files in the current directory to the target
433
#                   directory. Assume that the target directory will be called
434
#                   the same as the source directory
435
#
436
#                   Do not process sub directories. These may be handled elsewhere
437
#
438
# Inputs          : $dir        - Src and Dst subdir name
439
#
440
# Returns         : Nothing
441
#
442
sub do_FilesOnly
443
{
444
    my ($dir) = @_;
445
    Verbose2 ("do_FilesOnly: dir=[$dir]");
446
 
447
    # define the type of dir we are working on
448
 
449
    my ($srcDir) = "$PKG_ROOT/$dir";
450
    my ($dstDir) = "$INTDIR/$dir";
451
 
452
    Verbose2("do_FilesOnly: INTDIR=[$INTDIR]");
453
    Verbose2("do_FilesOnly: dstDir=[$dstDir]");
454
    Verbose2("do_FilesOnly: srcDir=[$srcDir]");
455
 
456
    #
457
    # Create the interface dir if it does not exists
458
    #
459
    mkpath ( $dstDir, $GBE_VERBOSE, 0775) unless ( -d $dstDir );
460
 
461
 
462
    # Have a valid dst value we now need to get a hold of all the
463
    # lib scripts files.
464
    #
465
    local *DIR;
466
    opendir ( DIR, $srcDir ) or  Error ("Failed to open dir [$srcDir]");
467
 
468
    #
469
    # Process all directory entries
470
    #
471
    while (defined(my $_item = readdir(DIR)))
472
    {
473
        next if ( $_item eq '.' );
474
        next if ( $_item eq '..' );
475
 
476
        my $srcFile = "$srcDir/$_item";
477
        if ( -d $srcFile )
478
        {
479
            Verbose2 ("NOT processing dir item [$srcFile]");
480
        }
481
        else
482
        {
483
            FileLinkCopy ($srcFile, "$dstDir/$_item" );
484
        }
485
    }
486
    close DIR;
487
 
488
 
489
    # done
490
    return 1;
491
}
492
#-------------------------------------------------------------------------------
493
# Function        : do_dir
494
#
495
# Description     : Transfer an entire subdirectory tree
496
#                   Can detect that the tree has already been processed
497
#
498
# Inputs          : $src            - Source subdir (within PKG_ROOT)
499
#                   $dst            - Target path (within INTDIR)
500
#
501
# Returns         : Nothing
502
#
503
sub do_dir
504
{
505
    my ($src, $dst) = @_;
506
    Verbose2 ("do_dir: src=[$src], dst=[$dst]");
507
 
508
    #
509
    #   Prevent processing of the same source directory by multiple
510
    #   operations. Need only do them once
511
    #
512
    if ( $dirs_processed{$src} )
513
    {
514
        Verbose2 ("do_dir: Already processed");
515
        return 1;
516
    }
517
 
518
    $dirs_processed{$src} = 1;
519
 
520
    #
521
    #   Only if it exists
522
    #   Do the test in this function to simplify processing
523
    #
524
    unless ( -d $src )
525
    {
526
        Verbose2 ("do_dir: Directory not found");
527
        return 0;
528
    }
529
 
530
    #
531
    #   Setup values for the File::Find callback
532
    #   These need to be global due to the way that File::Find works
533
    #
534
    $FF_SRC_DIR = "$PKG_ROOT/$src";
535
    $FF_DST_DIR = "$INTDIR/$dst";
536
 
537
    Verbose2("do_dir: FF_SRC_DIR=[$FF_SRC_DIR]");
538
    Verbose2("do_dir: FF_DST_DIR=[$FF_DST_DIR]");
539
 
540
    #
541
    #   Handle directories that are really symbolic links
542
    #   This will only occur on system that handle symlinks
543
    #   May not always want to use symlinks.
544
    #
545
    if ( $symlinks && -l $FF_SRC_DIR )
546
    {
547
        Verbose2("do_dir: symlink $FF_SRC_DIR,$FF_DST_DIR");
548
        unless (symlink $FF_SRC_DIR, $FF_DST_DIR  )
549
        {
550
            Error("Failed to create symlink",
551
                  "Src: $FF_SRC_DIR",
552
                  "Dst: $FF_DST_DIR");
553
        }
554
        return 1;
555
    }
556
 
557
    #
558
    # Create the interface dir if it does not exists
559
    #
560
    mkpath ( $FF_DST_DIR, $GBE_VERBOSE, 0775)
561
        unless ( -d $FF_DST_DIR );
562
 
563
    File::Find::find( \&pkgFind2, $FF_SRC_DIR);
564
 
565
    # done
566
    return 1;
567
}
568
 
569
#-------------------------------------------------------------------------------
570
sub pkgFind2
571
#
572
# Description     : Callback function: Process a directory
573
#                   Target name is NOT the same as the source name
574
#
575
#                   The function is called for each file to be processed
576
#                   The name of the file is extracted from $File::Find::name
577
#
578
#                   Processes
579
#                       Directory: Create same directory in the target
580
#                       File     : Link/Copy file to the target
581
#
582
# Inputs          : None passed
583
#                   Globals are used
584
#
585
# Returns         :
586
#
587
#------------------------------------------------------------------------------
588
{
589
    Verbose2("pkgFind2:");
590
 
241 dpurdie 591
    my $item = "$File::Find::name";                     # Full source path
592
    my $dest_path = $FF_DST_DIR . substr ( $item, length ($FF_SRC_DIR) ); # Full destination path
227 dpurdie 593
 
594
    Verbose2 ("---- Src = [$item]");
595
    Verbose2 ("---- Dst = [$dest_path]");
596
    if ( -d $item )
597
    {
598
        #
599
        #   Create a directory
600
        #
601
        mkpath ( $dest_path, $GBE_VERBOSE, 0775) unless( -d $dest_path );
602
 
603
        #
604
        #   Flag the subdir as being processed
605
        #   Prevent multiple copy operations (and warnings)
606
        #
241 dpurdie 607
        my $subdir = substr ( $item, 1 + length ($PKG_ROOT) );
227 dpurdie 608
        $dirs_processed{$subdir} = 1;
609
 
610
    }
611
    else
612
    {
613
        #
614
        #   Copy/Link the file
615
        #
616
        FileLinkCopy ( $item, $dest_path);
617
    }
618
    return 1;
619
}
620
 
621
#-------------------------------------------------------------------------------
622
# Function        : FileLinkCopy
623
#
624
# Description     : Copy a file to a destination
625
#                   If possible create a symlink (Not always be possible)
626
#                   If the file is copied, then chmod it.
627
#
628
# Inputs          : $srcFile                 - Source path (Full)
629
#                   $dstFile                 - Destination path (Full)
630
#
631
#
632
# Globals         : symlinks                - Set if Symlinks are available
633
#                                             Will be cleared if the operation
634
#                                             failed, forcing copy
635
#
636
# Returns         : Nothing
637
#                   Will terminate, with a message, on error
638
#
639
sub FileLinkCopy
640
{
641
    my ($srcFile, $dstFile ) = @_;
642
    my $done;
643
    (my $file = $srcFile) =~ s~.*/~~;       # Filename. Just to be pretty
644
 
645
    #
646
    #   Delete target file. If it exists
647
    #
648
    if ( -f $dstFile )
649
    {
650
        unlink ($dstFile );
651
        Message("overwriting existing dpkg_archive item [$file] --> [$dstFile]\n");
652
    }
653
 
654
    #
655
    #   Try a symlink first
656
    #
657
    if ( $symlinks )
658
    {
659
        Verbose("linking file [$file] --> [$dstFile]...ok");
660
        unless (symlink ($srcFile, $dstFile)  )
661
        {
662
            #
663
            #   Symlink has failed
664
            #   Flag: Don't symlink anymore
665
            #
666
            $symlinks = 0;
667
            Verbose ("Failed to create symlink from: [$file] --> [$dstFile]");
668
        }
669
        else
670
        {
671
            $done = 1;
672
        }
673
    }
674
 
675
    #
676
    #   Try a copy
677
    #
678
    unless ( $done )
679
    {
680
        if(File::Copy::copy($srcFile, $dstFile))
681
        {
682
            Verbose("copying file [$file] --> [$dstFile]...ok");
683
            CORE::chmod oct("0755"), $dstFile;
684
        }
685
        else
686
        {
687
            Error("copying file [$file] --> [$dstFile]: $!");
688
        }
689
    }
690
}
691
 
692
############ EOF ###############################################################
693