Subversion Repositories DevTools

Rev

Rev 6547 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6242 dpurdie 1
########################################################################
2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
3
#
4
# Module name   : DebianPackager.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : This program is invoked by the MakeDebianPackage and MakeRpmPackage
10
#                 directive that is a part of this package
11
#
12
#                 The program will use a user-provided script in order
13
#                 to create the output Package.
14
#
15
#                 The user script may call a number of directives in order to
16
#                 construct an image of the package being installed.
17
#
18
#                 The script specifies Debian/RPM configuration scripts that
19
#                 will be embedded in the package.
20
#
21
#                 This program will:
22
#                   Construct a filesystem image under control of the directives
23
#                   within the user script
24
#
25
#                   Debian:
26
#                       Massage the Debian control file
27
#                       Create a Debian Package
28
#                       Transfer it to the users 'BIN' directory, where it is available to be packaged.
29
#                       
30
#                   RedHat Package:    
31
#                       Generate rpmBuilder control files
32
#                       Create the RPM image
33
#                       Transfer it to the users 'BIN' directory, where it is available to be packaged.
34
#                   
35
#                   TarFile:
36
#                       Tar Gzip the image
37
#                       Transfer it to the users 'BIN' directory, where it is available to be packaged.
38
#
39
#                 Summary of directives available to the user-script:
40
#                       Message                 - Display progress text
41
#                       Verbose                 - Display progress text
42
#                       AddInitScript           - Add an init script
43
#                       CatFile                 - Append to a file
44
#                       ConvertFile             - Convert file(s) to Unix or Dos Text
45
#                       CopyDir                 - Copy directory tree
46
#                       CopyFile                - Copy a file
47
#                       CopyBinFile             - Copy an executable file
48
#                       CopyLibFile             - Copy a library file
49
#                       CopyDebPackage          - Copy a Debian Package
50
#                       CreateDir               - Create a directory
51
#                       AllFiles                - Specify control and script files 
52
#                       DebianFiles             - Specify control and script files (Debian Only)
53
#                       RpmFiles                - Specify control and script files (RPM Only)
54
#                       AllControlFile          - Specify control and script files
55
#                       DebianControlFile       - Specify control and script files (Debian Only)
56
#                       RpmControlFile          - Specify control and script files (RPM Only)
57
#                       AllDepends              - Add Depends entry to control file
58
#                       DebianDepends           - Add Depends entry to control file (Debian Only)
59
#                       RpmDepends              - Add Depends entry to control file (RPM Only)
60
#                       EchoFile                - Place text into a file
61
#                       MakeSymLink             - Create a symbolic link
62
#                       PackageDescription      - Specify the package description
63
#                       ReplaceTags             - Replace Tags on target file
64
#                       SetFilePerms            - Set file permissions
65
#                       SetVerbose              - Control progress display
66
#                       IsProduct               - Flow control
67
#                       IsPlatform              - Flow control
68
#                       IsTarget                - Flow control
69
#                       IsVariant               - Flow control
70
#                       IsAlias                 - Flow control
71
#                       RpmSetDefAttr           - Specify default file properties (RPM Only)
72
#                       RpmSetAttr              - Specify file properties (RPM Only)    
73
#                       SetBaseDir              - Sets base for installed files (RPM Hint for directory ownership)
74
#                       Section                 - Set current section
75
#                       PackageVersion          - Return the version of a named package
76
#                       ExtractTar              - Extract a tar file into the target
77
#
78
#                 Thoughts for expansion:
79
#                       SrcDir                  - Extend path for resolving local files
80
#
81
#                   Less used:
82
#                        ExpandLinkFiles        - Expand .LINK files
83
#
84
#                   Internal Use:
85
#                        FindFiles              - Find a file
86
#                        ResolveFile            - Resolve a 'local' source file
87
#                        chmodItem              - Set file or directory permissions
88
#                        
89
#......................................................................#
90
 
91
require 5.006_001;
92
use strict;
93
use warnings;
94
 
95
use Getopt::Long;
96
use File::Path;
97
use File::Copy;
98
use File::Find;
99
use JatsSystem;
100
use FileUtils;
101
use ArrayHashUtils;
102
use JatsError;
103
use JatsLocateFiles;
104
use ReadBuildConfig;
105
use JatsCopy ();                            # Don't import anything
106
use PackagerUtils;
107
 
108
#
109
#   Command line options
110
#
111
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
112
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
113
my $opt_vargs;                              # Verbose arg
114
my $opt_help = 0;
115
my $opt_manual = 0;
116
my $opt_clean = 0;
117
my $opt_interfacedir;
118
my $opt_package_script;
119
my $opt_interfaceincdir;
120
my $opt_interfacelibdir;
121
my $opt_interfacebindir;
122
my $opt_libdir;
123
my $opt_bindir;
124
my $opt_localincdir;
125
my $opt_locallibdir;
126
my $opt_localbindir;
127
my $opt_pkgdir;
128
my $opt_pkglibdir;
129
my $opt_pkgbindir;
130
my $opt_pkgpkgdir;
131
my $opt_noarch;
132
my $opt_tarFile;
133
my $opt_tarOnly;
134
my $opt_rpm = 0;
135
my $opt_debian = 0;
136
my $opt_output;
137
 
138
#
139
#   Options marked as 'our' so that they are visible within the users script
140
#   Don't give the user too much
141
#
142
our $opt_platform;
143
our $opt_type;
144
our $opt_buildname;
145
our $opt_buildversion;
146
our $opt_target;
147
our $opt_product;
148
our $opt_name;
149
our $opt_variant;
150
our $opt_pkgarch;
151
our $opt_rpmRelease = '';
152
 
153
#
154
#   Options derived from script directives
155
#
156
my $opt_description;
157
my $opt_specFile;
158
 
159
#
160
#   Globals
161
#
162
my $WorkDirBase;                            # Workspace
163
my $WorkDirInit;                            # Initial Dir to create file system image within
164
my $WorkDir;                                # Dir to create file system image within
165
my $WorkSubDir = '';                        # Diff between $WorkDirInit and $WorkDir
166
my @ResolveFileList;                        # Cached Package File List
167
my @ResolveBinFileList;                     # Cached PackageBin File List
168
my @ResolveDebFileList;                     # Cached PackageDeb File List
169
my @ResolveLibFileList;                     # Cached PackageLib File List
170
my %ControlFiles;                           # Control Files
171
my %ControlFileNames;                       # Control Files by name
172
my @DependencyList;                         # Package Dependencies
173
my @ConfigList;                             # Config Files
174
my %opt_aliases;                            # Cached Alias Names
175
my @RpmDefAttr = ('-','root','root','-');   # RPM: Default File Attributes
176
my @RpmAttrList;                            # RPM: File attributes
177
my %OwnedDirs;                              # RPM: Dirs marked as owned
178
my $ActiveSection = 1;                      # Indicates if the section is active
179
 
180
#-------------------------------------------------------------------------------
181
# Function        : Main Entry point
182
#
183
# Description     : This function will be called when the package is initialised
184
#                   Extract arguments from the users environment
185
#
186
#                   Done here to greatly simplify the user script
187
#                   There should be no junk in the user script - keep it simple
188
#
189
# Inputs          :
190
#
191
# Returns         : 
192
#
193
main();
194
sub main
195
{
196
    my $result = GetOptions (
197
                'verbose:s'         => \$opt_vargs,
198
                'clean'             => \$opt_clean,
199
                'Type=s'            => \$opt_type,
200
                'BuildName=s'       => \$opt_buildname,                     # Raw Jats Package Name (Do not use)
201
                'Name=s'            => \$opt_name,                          # Massaged Debian Package Name
202
                'BuildVersion=s'    => \$opt_buildversion,
203
                'Platform=s'        => \$opt_platform,
204
                'Target=s'          => \$opt_target,
205
                'Product=s'         => \$opt_product,
206
                'InterfaceDir=s'    => \$opt_interfacedir,
207
                'InterfaceIncDir=s' => \$opt_interfaceincdir,
208
                'InterfaceLibDir=s' => \$opt_interfacelibdir,
209
                'InterfaceBinDir=s' => \$opt_interfacebindir,
210
                'LibDir=s'          => \$opt_libdir,
211
                'BinDir=s'          => \$opt_bindir,
212
                'LocalIncDir=s'     => \$opt_localincdir,
213
                'LocalLibDir=s'     => \$opt_locallibdir,
214
                'LocalBinDir=s'     => \$opt_localbindir,
215
                'PackageDir=s'      => \$opt_pkgdir,
216
                'PackageLibDir=s'   => \$opt_pkglibdir,
217
                'PackageBinDir=s'   => \$opt_pkgbindir,
218
                'PackagePkgDir=s'   => \$opt_pkgpkgdir,
219
                'Variant:s'         => \$opt_variant,
220
                'PkgArch:s'         => \$opt_pkgarch,
221
                'NoArch'            => \$opt_noarch,
222
                'tarFile=s'         => \$opt_tarFile,
223
                'tarOnly'           => \$opt_tarOnly,
224
                'genRpm'            => \$opt_rpm,
225
                'genDeb'            => \$opt_debian,
226
                'output=s'          => \$opt_output,
227
                'script=s'          => \$opt_package_script,
228
                'rpmRelease=s'      => \$opt_rpmRelease,
229
    );
230
    $opt_verbose++ unless ( $opt_vargs eq '@' );
231
 
232
    ErrorConfig( 'name'    => 'PackagerUtils',
233
                 'verbose' => $opt_verbose,
234
                 'debug'   => $opt_debug );
235
 
236
    #
237
    #   Init the FileSystem Uiltity interface
238
    #
239
    InitFileUtils();
240
 
241
    #
242
    #   Ensure that we have all required options
243
    #
244
    Error ("Platform not set")                  unless ( $opt_platform );
245
    Error ("Type not set")                      unless ( $opt_type );
246
    Error ("BuildName not set")                 unless ( $opt_buildname );
247
    Error ("Package Name not set")              unless ( $opt_name );
248
    Error ("BuildVersion not set")              unless ( $opt_buildversion );
249
    Error ("InterfaceDir not set")              unless ( $opt_interfacedir );
250
    Error ("Target not set")                    unless ( $opt_target );
251
    Error ("Product not set")                   unless ( $opt_product );
252
    Error ("Packaging Script not set")          unless ( $opt_package_script );
253
 
254
    #
255
    #   Read in relevent config information
256
    #
257
    ReadBuildConfig ($opt_interfacedir, $opt_platform, '--NoTest' );
258
 
259
    #
260
    #   Build the package image in a directory based on the target being created
261
    #
262
    $WorkDirBase = uc("$opt_platform$opt_type.image");
263
    $WorkDirInit = "$WorkDirBase/$opt_name";
264
    $WorkDir = $WorkDirInit;
265
 
266
    #
267
    #   Configure the System command to fail on any error
268
    #
269
    SystemConfig ( ExitOnError => 1 );
270
 
271
    #
272
    #   Defaults
273
    #
274
    $opt_pkgarch = $opt_platform unless ( $opt_pkgarch );
275
 
276
    #
277
    #   Determine build operations
278
    #   
279
    my $genDebian = $opt_debian;
280
    my $genRpm = $opt_rpm;
281
    if ($opt_tarOnly) {
282
        $genDebian = $genRpm = 0; 
283
    }
284
 
285
 
286
    #
287
    #   Display variables used
288
    #
289
    Message    ("= Building Installer ================================================");
290
    Message    ("        Format: Debian") if ($genDebian);
291
    Message    ("        Format: RPM") if ($genRpm);
292
    Message    ("        Format: TGZ") if ($opt_tarFile);
293
    Message    ("          Name: $opt_name");
294
    Message    ("       Package: $opt_buildname");
295
    Message    ("       Variant: $opt_variant") if ($opt_variant);
296
    Message    ("       Version: $opt_buildversion");
297
    Message    ("  Building for: $opt_platform");
298
    Message    ("        Target: $opt_target") if ( $opt_platform ne $opt_target);
299
    Message    ("       Product: $opt_product") if ($opt_product ne $opt_platform);
300
    Message    ("          Type: $opt_type");
301
    Message    ("   RPM Release: $opt_rpmRelease") if ($opt_rpmRelease);
302
    Message    ("      Pkg Arch: $opt_pkgarch") if ($opt_pkgarch);
303
    Verbose    ("       Verbose: $opt_verbose");
304
    Verbose    ("  InterfaceDir: $opt_interfacedir");
305
    Message    ("        Output: " . StripDir($opt_output))  if ($genDebian || $genRpm);
306
    Message    ("        Output: " . StripDir($opt_tarFile)) if $opt_tarFile;
307
    Message    ("======================================================================");
308
 
309
    #
310
    #   Perform Clean up
311
    #   Invoked during "make clean" or "make clobber"
312
    #
313
    if ( $opt_clean )
314
    {
315
        Message ("Remove packaging directory: $WorkDirInit");
316
 
317
        #
318
        #   Remove the directory for this package
319
        #   Remove the general work dir - if all packages have been cleaned
320
        #
321
        rmtree( $WorkDirBase );
322
        rmtree ($opt_tarFile) if ( defined($opt_tarFile) && -f $opt_tarFile );
6535 dpurdie 323
        rmtree ($opt_output) if ( $opt_output && -f $opt_output );
6242 dpurdie 324
        exit;
325
    }
326
 
327
    #
328
    #   NoArch sanity test
329
    #       MUST only build no-arch for production
330
    #       User MUST do this in the build.pl file
331
    #
332
    if ($opt_noarch && $opt_type ne 'P')
333
    {
334
        Error ("Installer Packages marked as NoArch (all) must be built ONLY for production",
335
               "This must be configured in the build.pl" );
336
    }
337
 
338
    #
339
    #   Clean  out the WORK directory
340
    #   Always start with a clean slate
341
    #
342
    #   Ensure that the base of the directory tree does not have 'setgid'
343
    #       This will upset the debian packager
344
    #       This may be an artifact from the users directory and not expected
345
    #
346
    rmtree( $WorkDirInit );
347
    mkpath( $WorkDirInit );
348
 
349
    my $perm = (stat $WorkDirInit)[2] & 0777;
350
    chmod ( $perm & 0777, $WorkDirInit );
351
 
352
    #
353
    #   Invoke the user script to do the hard work
354
    #       Use abs path to avoid issues:
355
    #           * '.' not buing in search path
356
    #           * Script name = DebianPackager.pl
357
    $opt_package_script = AbsPath($opt_package_script);
358
    unless (my $return = do $opt_package_script) {
359
            Error ("Couldn't parse $opt_package_script: $@") if $@;
360
            Error ("Couldn't do $opt_package_script: $!") unless defined $return;
361
        };
362
    $ActiveSection = 1;
363
 
364
    #
365
    #   Now have an image of the directory that we wish to package
366
    #   Complete the building of the package
367
    #
368
    if ($opt_tarFile) {
369
        BuildTarFile();
370
        Message ("Created TGZ file");
371
    }
372
 
373
    #
374
    #   Create an RPM
375
    #
376
    if ($genRpm) {
377
        BuildRPM ();
378
        Message ("Created RPM");
379
    }
380
 
381
    #
382
    #   Create a Debian Package
383
    #
384
    if ($genDebian) {
385
        BuildDebianPackage ();
386
        Message ("Created Debian Package");
387
    }
388
}
389
 
390
#-------------------------------------------------------------------------------
391
# Function        : BuildRPM 
392
#
393
# Description     : This function will create the Debian Package
394
#                   and transfer it to the target directory
395
#
396
# Inputs          : None
397
#
398
# Returns         : Nothing
399
# 
400
sub BuildRPM
401
{
402
    #
403
    #   Sanity Checks
404
    #
405
    Error ("BuildRPM: Release")
406
        unless ( $opt_rpmRelease );
407
    Error ("BuildRPM: No Control File or Package Description")
408
        unless ( exists($ControlFiles{'control'}) || $opt_description );
409
 
410
    #
411
    #   Massage the 'control' file
412
    #   Generate or Massage
413
    #
414
    $opt_specFile = catfile($WorkDirBase, 'RPM.spec' );
415
    UpdateRedHatControlFile ($ControlFiles{'control'} );
416
 
417
    #   Generate a dummy rc file
418
    my $rcFile = catdir($WorkDirBase,'tmprc');
419
    TouchFile($rcFile);
420
 
421
    #
422
    #   Run the RPM builder
423
    #   Expect it to be installed on the build machine
424
    #
425
    my $prog = LocateProgInPath( 'rpmbuild', '--All');
426
    Error ("RPM Packager: The rpmbuild utility is not installed") unless $prog;
427
    System ($prog, '-bb', $opt_specFile, 
428
                   '--buildroot', AbsPath($WorkDirInit) ,
429
                   '--define', '_rpmdir ' . StripFileExt($opt_output),
430
                   '--define', '_rpmfilename ' .  StripDir($opt_output),
431
                   '--define', '_topdir ' . catfile($WorkDirBase, 'RPMBUILD' ),
432
                   '--noclean',
433
                   $opt_verbose ? '-v' : '--quiet',
434
                   #$opt_noarch ?  '--target=noarch' : undef,
435
                   '--rcfile', $rcFile ,
436
                   );
437
 
438
 
439
}
440
 
441
#-------------------------------------------------------------------------------
442
# Function        : BuildDebianPackage
443
#
444
# Description     : This function will create the Debian Package
445
#                   and transfer it to the target directory
446
#
447
# Inputs          : None
448
#
449
# Returns         : Nothing
450
#
451
sub BuildDebianPackage
452
{
453
    Error ("BuildDebianPackage: No Control File or Package Description")
454
        unless ( exists($ControlFiles{'control'}) || $opt_description );
455
 
456
    #
457
    #   Convert the FileSystem Image into a Debian Package
458
    #       Insert Debian control files
459
    #
460
    Verbose ("Copy in the Debian Control Files");
461
    mkdir ( "$WorkDirInit/DEBIAN" );
462
 
463
    #
464
    #   Copy in all the named Debian Control files
465
    #       Ignore any control file. It will be done next
466
    #
467
    foreach my $key ( keys %ControlFiles )
468
    {
469
        next if ($key eq 'control');
470
        CopyFile ( $ControlFiles{$key}, '/DEBIAN', $key  );
471
    }
472
 
473
    #
474
    #   Create 'conffiles'
475
    #       Append to any user provided file
476
    if ( @ConfigList )
477
    {
478
        my $conffiles = "$WorkDirInit/DEBIAN/conffiles";
479
        Warning("Appending user specified entries to conffiles") if ( -f $conffiles);
480
        FileAppend( $conffiles, @ConfigList );
481
    }
482
 
483
    #
484
    #   Massage the 'control' file
485
    #
486
    UpdateDebianControlFile ($ControlFiles{'control'} );
487
 
488
    #
489
    #   Mark all files in the debian folder as read-execute
490
    #
491
    System ( 'chmod', '-R', 'a+rx', "$WorkDirInit/DEBIAN" );
492
    System ( 'build_dpkg.sh', '-b', $WorkDirInit);
493
    System ( 'mv', '-f', "$WorkDirInit.deb", $opt_output );
494
 
495
    System ("build_dpkg.sh", '-I', $opt_output) if (IsVerbose(1));
496
 
497
}
498
 
499
#-------------------------------------------------------------------------------
500
# Function        : BuildTarFile 
501
#
502
# Description     : This function will create a TGZ file of the constructed package
503
#                   Not often used 
504
#
505
# Inputs          : None
506
#
507
# Returns         : Nothing
508
#
509
sub BuildTarFile
510
{
511
    Verbose ("Create TGZ file containing body of the package");
512
    System ('tar', 
513
            '--create',
514
            '--auto-compress',
515
            '--owner=0' ,
516
            '--group=0' ,
517
            '--one-file-system' ,
518
            '--exclude=./DEBIAN' ,
519
            '-C', $WorkDirInit,  
520
            '--file', $opt_tarFile,
521
            '.'
522
            );
523
}
524
 
525
#-------------------------------------------------------------------------------
526
# Function        : Section 
527
#
528
# Description     : Allows the Package file to be split into section
529
#                   This direcive is always active.
530
#
531
# Inputs          : Selector
532
#                       ALL     - Active
533
#                       RPM     - Active section when building an RPM
534
#                       DEBIAN  - Active section if build a Debian package
535
#                       TAR     - Active section if building a TAR
536
#
537
# Returns         : Nothing
538
#                   Will fkag to indicate if directives are active. 
539
#
540
sub Section
541
{
542
    my $newActiveSection;
543
    my $flip = sub {
544
        my ($val, $mode) = @_;
545
        if ( defined $mode) {
546
            return $val ? 0 : 1;
547
        }
548
        return $val;
549
    };
550
 
551
    $newActiveSection = 1 unless (@_);
552
    foreach my $arg ( @_)
553
    {
554
        if ($arg =~ m/^(!)*DEBIAN/i) {
555
            $newActiveSection = 1 if  $flip->($opt_debian, $1);
556
 
557
        } elsif ($arg =~ m/^(!)*RPM/i) {
558
            $newActiveSection = 1 if  $flip->($opt_rpm, $1);
559
 
560
        } elsif ($arg =~ m/^(!)*TAR/i) {
561
            $newActiveSection = 1 if $flip->($opt_tarFile, $1);
562
 
563
        } elsif (uc($arg) eq 'ALL') {
564
            $newActiveSection = 1;
565
 
566
        } elsif ( $arg eq 1  ) {
567
                $newActiveSection = 1;
568
 
569
        } elsif ( $arg eq 0  ) {
570
 
571
        } else {
572
            Warning ("Section: Unknown argument $arg");
573
        }
574
    }
575
 
576
    $ActiveSection = $newActiveSection ? 1: 0;
577
    Verbose ("Section State: $ActiveSection");
578
 
579
}
580
 
581
#-------------------------------------------------------------------------------
582
# Function        : UpdateDebianControlFile
583
#
584
# Description     : Update the Debian 'control' file to fix up various fields
585
#                   within the file.
586
#
587
#                   If the files has not been specified, then a basic control
588
#                   file will be provided.
589
#
590
#                   This routine knows where the control file will be placed
591
#                   within the output work space.
592
#
593
# Inputs          : $src            - Path to source file
594
#                   Uses global variables
595
#
596
# Returns         : Nothing
597
#
598
sub UpdateDebianControlFile
599
{
600
    my($src) = @_;
601
    return 1 unless ($ActiveSection);
602
    my $dst = "$WorkDirInit/DEBIAN/control";
603
 
604
    unless ( $src )
605
    {
606
        CreateDebianControlFile();
607
        return;
608
    }
609
 
610
    #
611
    #   User has provided a control file
612
    #       Tweak the internals
613
    #
614
    Verbose ("UpdateDebianControlFile: $dst" );
615
    $src = ResolveFile( 0, $src );
616
 
617
    #   Calc depends line
618
    my $depData = join (', ', @DependencyList );
619
 
620
    open (SF, '<', $src) || Error ("UpdateDebianControlFile: Cannot open:$src, $!");
621
    open (DF, '>', $dst) || Error ("UpdateDebianControlFile: Cannot create:$dst, $!");
622
    while ( <SF> )
623
    {
624
        s~\s*$~~;
625
        if ( m~^Package:~ ) {
626
            $_ = "Package: $opt_name";
627
 
628
        } elsif ( m~^Version:~ ) {
629
            $_ = "Version: $opt_buildversion";
630
 
631
        } elsif ( m~^Architecture:~ ) {
632
            $_ = "Architecture: $opt_pkgarch";
633
 
634
        } elsif ( $opt_description && m~^Description:~ ) {
635
            $_ = "Description: $opt_description";
636
 
637
        } elsif ( m~^Depends:~ ) {
638
            $_ = "Depends: $depData";
639
            $depData = '';
640
        }
641
        print DF $_ , "\n";
642
    }
643
 
644
    close (SF);
645
    close (DF);
646
 
647
    #
648
    #   Warn if Depends section is needed
649
    #
650
    Error ("No Depends section seen in user control file") 
651
        if ($depData);
652
}
653
 
654
#-------------------------------------------------------------------------------
655
# Function        : CreateDebianControlFile
656
#
657
# Description     : Create a basic debian control file
658
#
659
# Inputs          : Uses global variables
660
#
661
# Returns         : 
662
#
663
sub CreateDebianControlFile
664
{
665
    return 1 unless ($ActiveSection);
666
    my $dst = "$WorkDirInit/DEBIAN/control";
667
 
668
    Verbose ("CreateDebianControlFile: $dst" );
669
 
670
    my $depData = join (', ', @DependencyList );
671
 
672
    open (DF, '>', $dst) || Error ("CreateDebianControlFile: Cannot create:$dst");
673
    print DF "Package: $opt_name\n";
674
    print DF "Version: $opt_buildversion\n";
675
    print DF "Section: main\n";
676
    print DF "Priority: standard\n";
677
    print DF "Architecture: $opt_pkgarch\n";
678
    print DF "Essential: No\n";
679
    print DF "Maintainer: Vix Technology\n";
680
    print DF "Description: $opt_description\n";
681
    print DF "Depends: $depData\n" if ($depData);
682
 
683
    close (DF);
684
}
685
 
686
#-------------------------------------------------------------------------------
687
# Function        : UpdateRedHatControlFile 
688
#
689
# Description     : Update the Redhat 'control' file to fix up various fields
690
#                   within the file.
691
#
692
#                   If the files has not been specified, then a basic control
693
#                   (spec) file will be provided.
694
#                   Various tags will be replaced
695
#                       tag_name
696
#                       tag_version
697
#                       tag_buildarch
698
#                       tag_release
699
#                       tag_description
700
#                       tag_requires
701
#                       tag_filelist
702
#
703
# Inputs          : $src            - Path to source file
704
#                   Uses global variables
705
#
706
# Returns         : Nothing
707
#
708
sub UpdateRedHatControlFile
709
{
710
    my($src) = @_;
711
    return 1 unless ($ActiveSection);
712
    my $dst = $opt_specFile;
713
    unless ( $src )
714
    {
715
        CreateRedHatControlFile();
716
        return;
717
    }
718
 
719
    #
720
    #   User has provided a control file
721
    #       Tweak the internals
722
    #
723
    Verbose ("UpdateRedHatControlFile: $dst" );
724
    $src = ResolveFile( 0, $src );
725
 
726
    my @depList = @DependencyList;
727
    my $cleanSeen;
728
 
729
    open (my $sf, '<', $src) || Error ("UpdateRedHatControlFile: Cannot open:$src, $!");
730
    open (my $df, '>', $dst) || Error ("UpdateRedHatControlFile: Cannot create:$dst, $!");
731
    while ( <$sf> )
732
    {
733
        s~\s*$~~;
734
        if ( m~^tag_Name~i ) {
735
            $_ = "Name: $opt_name";
736
 
737
        } elsif ( m~^tag_Version~i ) {
738
            $_ = "Version: $opt_buildversion";
739
 
740
        } elsif ( m~^tag_BuildArch~i ) {
741
            $_ = "BuildArch: $opt_pkgarch";
742
 
743
        } elsif ( m~^tag_Release~i ) {
744
            $_ = "Release: $opt_rpmRelease";
745
 
746
        } elsif ( $opt_description && m~^tag_Description~i ) {
747
            print $df "%description\n";
748
            print $df "$opt_description\n";
749
            $_ = undef;
750
 
751
        } elsif ( m~^tag_Requires~i ) {
752
            foreach my $item (@depList) {
753
                print $df "Requires:       $item\n";
754
            }
755
            $_ = undef;
756
            @depList = ();
757
 
758
        } elsif ( m~^tag_filelist~i ) {
759
            GenerateRedHatFileList ($df);
760
            $_ = undef;
761
 
762
        } elsif ( m~^%clean~i ) {
763
            $cleanSeen  = 1;
764
        }
765
        print $df ($_ , "\n") if defined ($_);
766
    }
767
 
768
    close ($sf);
769
    close ($df);
770
 
771
    #
772
    #   Warn if Depends section is needed
773
    #
774
    Error ("No %clean section seen in user control file") unless $cleanSeen; 
775
    Error ("No Requires tag seen in user control file") if (@depList);
776
}
777
 
778
#-------------------------------------------------------------------------------
779
# Function        : CreateRedHatControlFile
780
#
781
# Description     : Create a binary RedHat spec file
782
#
783
# Inputs          : Uses global variables
784
#
785
# Returns         : 
786
#
787
sub CreateRedHatControlFile
788
{
789
    #
790
    #   Generate the RPM spec file
791
    #
792
    open (my $sf, '>', $opt_specFile) || Error ("RPM Spec File: Cannot create: $opt_specFile, $!");
793
 
794
    # Standard tags
795
    print $sf ("# Standard SPEC Tags\n");
796
    print $sf "Summary:        Installer for the $opt_name Package\n";
797
    print $sf "Name:           $opt_name\n";
798
    print $sf "Version:        $opt_buildversion\n";
799
    print $sf "Release:        $opt_rpmRelease\n";
800
    print $sf "License:        COPYRIGHT - VIX IP PTY LTD (\"VIX\"). ALL RIGHTS RESERVED.\n";
801
    print $sf "Source:         None\n";
802
    print $sf "BuildArch:      $opt_pkgarch\n";
803
    print $sf "Group:          VIX/System\n";
804
    print $sf "Vendor:         Vix Technology\n";
805
    print $sf "Autoreq:        No\n";
806
    #
807
    #   Requires tags
808
    #
809
    print $sf "\n# Dependencies\n" if @DependencyList;
810
    foreach my $item (@DependencyList) {
811
        print $sf "Requires:       $item\n";
812
    }
813
 
814
    print $sf "\n";
815
    print $sf "%description\n";
816
    print $sf "$opt_description\n";
817
 
818
    print $sf "\n";
819
    print $sf "%clean\n";
820
 
821
    #
822
    #   Insert various scripts
823
    #
824
    my $insertRpmControlFile = sub {
825
        my ($sname, $cname) = @_;
826
        if ( my $src = $ControlFiles{$cname} ) {
827
            print $sf "\n";
828
            print $sf '%' . $sname . "\n";
829
            open ( my $cf, '<', $src ) || Error ("BuildRPM: Cannot open:$src, $!");
830
            while ( <$cf> ) {
831
                $_ =~ s~\%~%%~g;
832
                print $sf $_;
833
            }
834
            close ($cf);
835
            print $sf "\n";
836
        }
837
    };
838
 
839
    #   Run the PreInstall script as %pretrans
840
    #       %pretrans is the only script that can terminate the RPM installation
841
    &$insertRpmControlFile ('pretrans', 'preinst');
842
    &$insertRpmControlFile ('post',     'postinst');
843
    &$insertRpmControlFile ('preun',    'prerm');
844
    &$insertRpmControlFile ('postun',   'postrm');
845
 
846
    #
847
    #   Insert the list of files to be processed
848
    #       Can't use /* as this will mess with permissions of the root directory. 
849
    #       Can list Top Level directories and then use *
850
    #
851
    print $sf "\n%files\n";
852
    print $sf "%defattr(",join (',', @RpmDefAttr),")\n";
853
    GenerateRedHatFileList ($sf);
854
    print $sf "\n";
855
    close ($sf);
856
}
857
 
858
#-------------------------------------------------------------------------------
859
# Function        : GenerateRedHatFileList 
860
#
861
# Description     : Internal function
862
#                   Generate a file list to be inserted into an RPM spec file
863
#
864
# Inputs          : $fd     - File descriptor.
865
#                             Function will write directly to the output
866
#
867
# Returns         : Nothing 
868
#
869
sub GenerateRedHatFileList
870
{
871
    my ($fd) = @_;
872
 
873
    #
874
    #   Sanity Test
875
    #
876
    Warning ("No directories has been marked as 'Owned'",
877
             "Under RedHat a directory must be 'owned' by a package so that it can be removed.",
878
             "This ownership may be in that package or a 'Required' package.",
879
             "This ownership may be shared or exclusive.",
880
             ) unless scalar keys %OwnedDirs;
881
 
882
    #
883
    #   Flag files and directories with attributes
884
    #
885
    my %Attrs;
886
    my %Dirs;
887
    foreach my $item ( @RpmAttrList ) {
888
        my $file =  $item->[0]; 
889
        my $full_path = $WorkDirInit . $file;
890
        $Attrs{$file} =  '%attr(' . join(',',@{$item}[1..3] ) . ')';
891
        $Dirs{$file} = '%dir' if (-d $full_path);
892
    }
893
 
894
    #
895
    #   Flag configuration files ( ConfFile )
896
    #
897
    my %Configs;
898
    foreach my $item (@ConfigList) {
899
        $Configs{$item} = '%config';
900
    }
901
 
902
    #
903
    #   Internal subroutine to pretty-print a file/dirname with attributes
904
    #       $path   - path element
905
    #       $isDir  - True if a directory
906
    #   
907
    my $printer = sub {
908
        my ($path, $isDir) = @_;
909
        my $attrText =  delete $Attrs{$path};
910
        my $confText =  delete $Configs{$path};
911
        my $dirText  =  delete $Dirs{$path};
912
        $dirText = '%dir' if $isDir;
913
 
914
        my $txt;
915
        my $joiner = '';
916
        $path = '"' . $path . '"';
917
        foreach ($attrText,$dirText,$confText, $path) {
918
            next unless $_;
919
            $txt .= $joiner . $_;
920
            $joiner = ' ';
921
        }
922
        print $fd ("$txt\n");
923
    };
924
 
925
    #
926
    #   List all files in the tree
927
    #       If we use wildcards we get interpackage dependency issues
928
    #       Process files and directories
929
    #
930
    my $search =  JatsLocateFiles->new( '--Recurse', '--NoFullPath', '--DirsToo' );
931
    my @flist = $search->search($WorkDirInit);
932
    foreach (@flist) {
933
        my $file = '/' . $_;
934
        my $full_path = $WorkDirInit . $file;
935
        my $isDir = (-d $full_path) || 0;
936
 
937
        #
938
        #   Determine if the element is within a known RootDir
939
        #
940
        my $inRoot = 0;
941
        my $isOwner = 0;
942
        foreach (keys %OwnedDirs) {
943
            if ($file =~ m~^$_~) {
944
                $inRoot = 1;
945
                $isOwner = $OwnedDirs {$_};
946
                last;
947
            }
948
        }
949
 
950
        #
951
        #   Ignore directories that are not within a RootDir
952
        #   
953
        unless ($inRoot) {
954
            next if $isDir;
955
        }
956
 
957
        #
958
        #   Ignore directories that are not within an 'owned' directory
959
        #
960
        if ( !$isOwner && $isDir ) {
961
            next;
962
        }
963
 
964
        &$printer($file, $isDir);
965
    }
966
 
967
    #
968
    #   Sanity tests
969
    #   We should have process all the Configs and Attributes
970
    #
971
    if ( (keys %Configs) || ( keys %Attrs))
972
    {
973
        Error ("Internal Error. Unprocessed Config or Attributes.",
974
               keys %Configs, keys %Attrs );
975
    }
976
 
977
}
978
 
979
#-------------------------------------------------------------------------------
980
# Function        : SetVerbose
981
#
982
# Description     : Set the level of verbosity
983
#                   Display activity
984
#
985
# Inputs          : Verbosity level
986
#                       0 - Use makefile verbosity (Default)
987
#                       1..2
988
#
989
# Returns         : 
990
#
991
sub SetVerbose
992
{
993
    return 1 unless ($ActiveSection);
994
    my ($level) = @_;
995
 
996
    $level = $opt_verbose unless ( $level );
997
    $opt_verbose = $level;
998
    ErrorConfig( 'verbose' => $level);
999
}
1000
 
1001
#-------------------------------------------------------------------------------
1002
# Function        : SetBaseDir 
1003
#
1004
# Description     : Sets the root directory for all directories
1005
#                   Used to simplify scripts
1006
#                   
1007
# Inputs          : $path           - Absolute path. Now within the RootDir
1008
#                   @options        - As for CreateDir
1009
#
1010
# Returns         : Nothing 
1011
#                   Sets $WorkDir
1012
#
1013
sub SetBaseDir
1014
{
1015
    my ($path, @opts) = @_;
1016
    return 1 unless ($ActiveSection);
1017
 
1018
    my $rootdir = $path || '/';
1019
    $rootdir = '/' . $rootdir;
1020
    $rootdir =~ s~/+~/~g; 
1021
    Verbose ("Setting RootDir: $rootdir");
1022
 
1023
    #
1024
    #   Create the directory
1025
    #
1026
    $WorkDir = $WorkDirInit;
1027
    CreateDir ($rootdir, @opts);
1028
    $WorkSubDir = $rootdir;
1029
    $WorkDir = $WorkDirInit . $rootdir;
1030
}
1031
 
1032
#-------------------------------------------------------------------------------
1033
# Function        : DebianFiles
1034
#                   RpmFiles
1035
#                   AllFiles
1036
#
1037
# Description     : Name Debian and RPM builder control files
1038
#                   May be called multiple times
1039
#
1040
# Inputs          :   $fName    - Name under which the function is being called
1041
#                     Options
1042
#                       --Control=file
1043
#                       --PreRm=file
1044
#                       --PostRm=file
1045
#                       --PreInst=file
1046
#                       --PostInst=file
1047
#                       --SimpleSharedLibs
1048
#                         
1049
#
1050
# Returns         : Nothing
1051
#
1052
sub MULTI_Files
1053
{
1054
    my $fName = shift;
1055
    return 1 unless ($ActiveSection);
1056
    Verbose ("Specify Installer Control Files and Scripts");
1057
    foreach  ( @_ )
1058
    {
1059
        if ( m/^--Control=(.+)/i ) {
1060
            MULTI_ControlFile($fName, 'control',$1)
1061
 
1062
        } elsif ( m/^--PreRm=(.+)/i ) {
1063
            MULTI_ControlFile($fName, 'prerm',$1)
1064
 
1065
        } elsif ( m/^--PostRm=(.+)/i ) {
1066
            MULTI_ControlFile($fName, 'postrm',$1)
1067
 
1068
        } elsif ( m/^--PreInst=(.+)/i ) {
1069
            MULTI_ControlFile($fName, 'preinst',$1)
1070
 
1071
        } elsif ( m/^--PostInst=(.+)/i ) {
1072
            MULTI_ControlFile($fName, 'postinst',$1)
1073
 
1074
        } elsif ( m/^--SimpleSharedLibs/i ) {
1075
 
1076
            my $file = catfile($WorkDirBase, 'ldconfig.sh' );
1077
 
1078
            open (my $df, '>', $file) || Error ("$fName: Cannot create:$file");
1079
            print $df "#!/bin/sh\n";
1080
            print $df "/sbin/ldconfig\n";
1081
            print $df "exit 0\n";
1082
            close $df;
1083
 
1084
            MULTI_ControlFile($fName, 'postinst',$file);
1085
            MULTI_ControlFile($fName, 'postrm',$file);
1086
 
1087
        } else {
1088
            Error ("$fName: Unknown option: $_");
1089
        }
1090
    }
1091
}
1092
 
1093
#-------------------------------------------------------------------------------
1094
# Function        : DebianControlFile
1095
#                   RpmControlFile 
1096
#                   AllControlFile
1097
#
1098
# Description     : Add special control files to the Debian/RedHat Installer 
1099
#                   Not useful for embedded installers
1100
#
1101
#                   More general than DebianFiles() or RpmFiles
1102
#
1103
# Inputs          : name            - Target Name
1104
#                                     If the name starts with 'package.' then it will be replaced
1105
#                                     with the name of the current package
1106
#                                     Ideally: prerm, postrm, preinst, postinst
1107
#                   file            - Source File Name
1108
#                   options         - Options include
1109
#                                       --FromPackage
1110
#
1111
# Returns         : 
1112
#
1113
sub MULTI_ControlFile
1114
{
1115
    my ($fName, $name, $file, @options) = @_;
1116
    return 1 unless ($ActiveSection);
1117
    my $fromPackage = 0;
1118
 
1119
    #
1120
    #   Process options
1121
    foreach ( @options)
1122
    {
1123
        if (m~^--FromPackage~) {
1124
            $fromPackage = 1;
1125
        }
1126
        else  {
1127
            ReportError(("$fName: Unknown argument: $_"));
1128
        }
1129
    }
1130
    ErrorDoExit();
1131
 
1132
    #
1133
    #   Some control files need to have the package name prepended
1134
    #
1135
    $name =~ s~^package\.~$opt_name.~;
1136
 
1137
    #
1138
    #   Only allow one file of each type
1139
    #       Try to protect the user by testing for names by lowercase
1140
    #
1141
    my $simpleName = lc($name);
1142
    Error("$fName: Multiple definitions for '$name' not allowed")
1143
        if (exists $ControlFileNames{$simpleName});
1144
 
1145
    my $filePath = ResolveFile($fromPackage, $file);
1146
 
1147
    #
1148
    #   Add info to data structures
1149
    #
1150
    $ControlFiles{$name} = $filePath;
1151
    $ControlFileNames{$simpleName} = $name;
1152
}
1153
 
1154
#-------------------------------------------------------------------------------
1155
# Function        : DebianDepends 
1156
#                   RpmDepends
1157
#                   AllDepends
1158
#
1159
# Description     : This directive allows simple dependency information to be  
1160
#                   inserted into the control file
1161
#                   
1162
#                   Names will be massaged into conforming names.
1163
#
1164
#                   Not useful in embedded system
1165
#
1166
# Inputs          : Entry             - A dependency entry
1167
#                   ...               - More entries
1168
#                   Options
1169
#                       --Raw          - Prevent name modification
1170
#                       --NoRaw        - Enable name modification
1171
#                   
1172
#
1173
# Returns         : Nothing
1174
#
1175
sub MULTI_Depends
1176
{
1177
    return 1 unless ($ActiveSection);
1178
    shift;
1179
    my $raw = 0;
1180
 
1181
    #
1182
    #   Convert the provided name into a canonical name
1183
    #   Simplifies use when using both RPM and Debian
1184
    foreach ( @_)
1185
    {
1186
        if (m~^--(No)?Raw~i) {
1187
            $raw = ! defined($1);
1188
            next;
1189
        }
1190
        my $name = $_;
1191
        $name = canonicalName($_, $opt_rpm ? 'RPM' : 'DEBIAN' , 1) unless $raw;
1192
        push @DependencyList, $name;
1193
    }
1194
 
1195
}
1196
 
1197
#-------------------------------------------------------------------------------
1198
# Function        : PackageDescription
1199
#
1200
# Description     : Specify the Package Description
1201
#                   Keep it short
1202
#
1203
# Inputs          : $description
1204
#
1205
# Returns         : 
1206
#
1207
sub PackageDescription
1208
{
1209
    return 1 unless ($ActiveSection);
1210
    ($opt_description) = @_;
1211
}
1212
 
1213
#-------------------------------------------------------------------------------
1214
# Function        : MakeSymLink
1215
#
1216
# Description     : Create a symlink - with error detection
1217
#
1218
# Inputs          : old_file    - Link Target
1219
#                                 Path to the link target
1220
#                                 If an ABS path is provided, the routine will
1221
#                                 attempt to create a relative link.
1222
#                   new_file    - Relative to the output work space
1223
#                                 Path to where the 'link' file will be created
1224
#                   Options     - Must be last
1225
#                                 --NoClean         - Don't play with links
1226
#                                 --NoDotDot        - Don't create symlinks with ..
1227
#
1228
# Returns         : Nothing
1229
#
1230
sub MakeSymLink
1231
{
1232
    my $no_clean;
1233
    my $no_dot;
1234
    my @args;
1235
    return 1 unless ($ActiveSection);
1236
 
1237
    #
1238
    #   Extract options
1239
    #
1240
    foreach ( @_ )
1241
    {
1242
        if ( m/^--NoClean/i ) {
1243
            $no_clean = 1;
1244
 
1245
        } elsif ( m/^--NoDotDot/i ) {
1246
            $no_dot = 1;
1247
 
1248
        } elsif ( m/^--/ ) {
1249
            Error ("MakeSymLink: Unknown option: $_");
1250
 
1251
        } else {
1252
            push @args, $_;
1253
        }
1254
    }
1255
 
1256
    my ($old_file, $new_file) = @args;
1257
 
1258
    my $tfile = $WorkDir . '/' . $new_file;
1259
    $tfile =~ s~//~/~;
1260
    Verbose ("Symlink $old_file -> $new_file" );
1261
 
1262
    #
1263
    #   Create the directory in which the link will be placed
1264
    #   Remove any existing file of the same name
1265
    #
1266
    my $dir = StripFileExt( $tfile );
1267
    mkpath( $dir) unless -d $dir;
1268
    unlink $tfile;
1269
 
1270
    #
1271
    #   Determine a good name of the link
1272
    #   Convert to a relative link in an attempt to prune them
1273
    #
1274
    my $sfile = $old_file;
1275
    unless ( $no_clean )
1276
    {
1277
        $sfile = CalcRelPath( StripFileExt( $new_file ), $old_file );
1278
        $sfile = $old_file if ( $no_dot && $sfile =~ m~^../~ );
1279
    }
1280
 
1281
    my $result = symlink $sfile, $tfile;
1282
    Error ("Cannot create symlink. $old_file -> $new_file") unless ( $result );
1283
}
1284
 
1285
#-------------------------------------------------------------------------------
1286
# Function        : CopyFile
1287
#
1288
# Description     : Copy a file to a target dir
1289
#                   Used for text files, or files with fixed names
1290
#
1291
# Inputs          : $src
1292
#                   $dst_dir    - Within the output workspace
1293
#                   $dst_name   - Output Name [Optional]
1294
#                   Options     - Common Copy Options
1295
#
1296
# Returns         : Full path to destination file
1297
#
1298
sub CopyFile
1299
{
1300
    return 1 unless ($ActiveSection);
1301
    CopyFileCommon( \&ResolveFile, @_ );
1302
}
1303
 
1304
#-------------------------------------------------------------------------------
1305
# Function        : CopyBinFile
1306
#
1307
# Description     : Copy a file to a target dir
1308
#                   Used for executable programs. Will look in places where
1309
#                   programs are stored.
1310
#
1311
# Inputs          : $src
1312
#                   $dst_dir    - Within the output workspace
1313
#                   $dst_name   - Output Name [Optional]
1314
#
1315
#                   Options:
1316
#                       --FromPackage
1317
#                       --SoftLink=xxxx
1318
#                       --LinkFile=xxxx
1319
#
1320
# Returns         : Full path to destination file
1321
#
1322
sub CopyBinFile
1323
{
1324
    return 1 unless ($ActiveSection);
1325
    CopyFileCommon( \&ResolveBinFile, @_ );
1326
}
1327
 
1328
#-------------------------------------------------------------------------------
1329
# Function        : CopyLibFile
1330
#
1331
# Description     : Copy a file to a target dir
1332
#                   Used for shared programs. Will look in places where
1333
#                   shared libraries are stored.
1334
#
1335
# Inputs          : $src        - Base for 'realname' (no lib, no extension)
1336
#                   $dst_dir    - Within the output workspace
1337
#                   $dst_name   - Output Name [Optional, but not suggested]
1338
#
1339
# Returns         : Full path to destination file
1340
#
1341
# Notes           : Copying 'lib' files
1342
#                   These are 'shared libaries. There is no provision for copying
1343
#                   static libraries.
1344
#
1345
#                   The tool will attempt to copy a well-formed 'realname' library
1346
#                   The soname of the library should be constructed on the target
1347
#                   platform using ldconfig.
1348
#                   There is no provision to copy the 'linker' name
1349
#
1350
#                   Given a request to copy a library called 'fred', then the
1351
#                   well formed 'realname' will be:
1352
#                           libfred[P|D|]].so.nnnnn
1353
#                   where:
1354
#                           nnnn is the library version
1355
#                           [P|D|] indicates Production, Debug or None
1356
#
1357
#                   The 'soname' is held within the realname form of the library
1358
#                   and will be created by lsconfig.
1359
#
1360
#                   The 'linkername' would be libfred[P|D|].so. This is only
1361
#                   needed when linking against the library.
1362
#
1363
#
1364
#                   The routine will also recognize Windows DLLs
1365
#                   These are of the form fred[P|D|].nnnnn.dll
1366
#
1367
sub CopyLibFile
1368
{
1369
    return 1 unless ($ActiveSection);
1370
    CopyFileCommon( \&ResolveLibFile, @_ );
1371
}
1372
 
1373
#-------------------------------------------------------------------------------
1374
# Function        : CopyDebianPackage
1375
#
1376
# Description     : Copy a Debian Package to a target dir
1377
#                   Will look in places where Debian Packages are stored.
1378
#
1379
# Inputs          : $src        - BaseName for 'Debian Package' (no version, no extension)
1380
#                   $dst_dir    - Within the output workspace
1381
#                   Optional arguments embedded into the BaseName
1382
#                   --Arch=XXXX         - Architecture - if not current
1383
#                   --Product=XXXX      - Product - if required
1384
#                   --Debug             - If not the current type
1385
#                   --Prod              - If not the current type
1386
#
1387
# Returns         : Full path to destination file
1388
#
1389
# Notes           : Copying Debian Packages from external packages
1390
#
1391
#                   The tool will attempt to copy a well-formed debian packages
1392
#                   These are:
1393
#                   
1394
#                       "BaseName_VersionString[_Product]_Arch${PkgType}.deb";
1395
#                   
1396
#                   Where 'Product' is optional (and rare)
1397
#                   Where 'PkgType' is P or D or nothing
1398
#                   Where 'Arch' may be 'all'
1399
#                   
1400
#                   The routine will locate Debian packages in
1401
#                       - The root of the package
1402
#                       - bin/TARGET[P|D/]
1403
#                       - bin/Arch[P|D]
1404
#
1405
#
1406
sub CopyDebianPackage
1407
{
1408
    return 1 unless ($ActiveSection);
1409
    CopyFileCommon( \&ResolveDebPackage, '--FromPackage', @_ );
1410
}
1411
 
1412
#-------------------------------------------------------------------------------
1413
# Function        : CopyFileCommon
1414
#
1415
# Description     : Common ( internal File Copy )
1416
#
1417
# Inputs          : $resolver           - Ref to function to resolve source file
1418
#                   $src                - Source File Name
1419
#                   $dst_dir            - Target Dir
1420
#                   $dst_name           - Target Name (optional)
1421
#                   Options
1422
#                   Options:
1423
#                       --FromPackage
1424
#                       --FromBuild
1425
#                       --SoftLink=xxxx
1426
#                       --LinkFile=xxxx
1427
#                       --ConfFile
1428
#                       --Platform=xxxx[,yyyyy]
1429
#
1430
# Returns         : 
1431
#
1432
sub CopyFileCommon
1433
{
1434
    my $from_package = 0;
1435
    my $isa_linkfile = 0;
1436
    my $isa_configFile = 0;
1437
    my @llist;
1438
    my @args;
1439
    my @platforms;
1440
 
1441
    #
1442
    #   Parse options
1443
    #
1444
    foreach ( @_ )
1445
    {
1446
        if ( m/^--FromPackage/ ) {
1447
            $from_package = 1;
1448
 
1449
        } elsif ( m/^--FromBuild/ ) {
1450
            $from_package = 0;
1451
 
1452
        } elsif ( m/^--LinkFile/ ) {
1453
            $isa_linkfile = 1;
1454
 
1455
        } elsif ( m/^--ConfFile/i ) {
1456
            $isa_configFile = 1;
1457
 
1458
        } elsif ( m/^--SoftLink=(.+)/ ) {
1459
            push @llist, $1;
1460
 
1461
        } elsif ( m/^--Platform=(.+)/ ) {
1462
            push @platforms, split(',', $1 );
1463
 
1464
        } elsif ( m/^--/ ) {
1465
            Error ("FileCopy: Unknown option: $_");
1466
 
1467
        } else {
1468
            push @args, $_;
1469
        }
1470
    }
1471
 
1472
    #
1473
    #   Extract non-options.
1474
    #   These are the bits that are left over
1475
    #
1476
    my ($resolver, $src, $dst_dir, $dst_name ) = @args;
1477
 
1478
    #
1479
    #   Clean up dest_dir. Must start with a / and not end with one
1480
    #
1481
    $dst_dir = "/$dst_dir/";
1482
    $dst_dir =~ s~/+~/~g;
1483
    $dst_dir =~ s~/$~~;
1484
 
1485
    Verbose ("CopyFile: $src, $dst_dir, " . ($dst_name || ''));
1486
    foreach $src ( &$resolver( $from_package, $src, \@platforms ) )
1487
    {
1488
        my $dst_fname = $dst_name ? $dst_name : StripDir($src);
1489
        my $dst_file = "$dst_dir/$dst_fname";
1490
        Verbose ("CopyFile: Copy $src, $dst_file" );
1491
 
1492
 
1493
        #
1494
        #   LinkFiles are special
1495
        #   They get concatenated to any existing LINKS File
1496
        #
1497
        if ( $isa_linkfile )
1498
        {
1499
            CatFile ( $src, "$dst_dir/.LINKS" );
1500
        }
1501
        else
1502
        {
1503
            mkpath( "$WorkDir$dst_dir", 0, 0775);
1504
            unlink ("$WorkDir$dst_file");
1505
            System ('cp','-f', $src, "$WorkDir$dst_file" );
1506
 
1507
            foreach my $lname ( @llist )
1508
            {
1509
                $lname = $dst_dir . '/' . $lname unless ( $lname =~ m ~^/~ );
1510
                MakeSymLink( $dst_file ,$lname);
1511
            }
1512
        }
1513
 
1514
        #
1515
        #   ConfigFiles are marked so that they can be handled by the debain installer
1516
        #
1517
        if ($isa_configFile)
1518
        {
1519
            push @ConfigList, $WorkSubDir . $dst_file;
1520
        }
1521
    }
1522
}
1523
 
1524
#-------------------------------------------------------------------------------
1525
# Function        : ExtractTar 
1526
#
1527
# Description     : Extract a tar file into a target directory
1528
#                   Useful for massive structures and those with embedded symlinks
1529
#                   Performs an implicit merge
1530
#                   Will create output root if it does not exist
1531
#
1532
# Inputs          : $srcTar      - Source Tar file
1533
#                   $dst_dir     - Within the output workspace
1534
#                   Options
1535
#                       --Source=Name           - Source via Symbolic Name
1536
#                       --FromPackage           - Source via package roots
1537
#                       --Strip=nn              - Strip nn path elements from the dir
1538
#
1539
# Returns         : 
1540
#
1541
sub ExtractTar
1542
{
1543
    my ($srcTar, $dst_dir, @opts) = @_;
1544
    my $userSrcTar = $srcTar;
1545
    my $opt_source;
1546
    my $opt_package;
1547
    my $opt_strip;
1548
    my $opt_base;
1549
    my $from_interface;
1550
    my $dname = StripDir($userSrcTar);
1551
    my $errConfig = ErrorReConfig( prefix => "ExtractTar($dname): ");
1552
    #
1553
    #   Setup the basic options
1554
    #       May be altered as we parse user options
1555
    #
1556
    $dst_dir = $WorkDir . '/' . $dst_dir;
1557
    $dst_dir =~ s~//~/~;
1558
 
1559
    #
1560
    #   Scan and collect user options
1561
    #
1562
    foreach  ( @opts )
1563
    {
1564
        Verbose2 ("$_");
1565
        if ( m/^--Source=(.+)/ ) {
1566
            Error ("Source directory can only be specified once")
1567
                if ( defined $opt_source );
1568
            $opt_source = $1;
1569
 
1570
        } elsif ( m/^--FromPackage/ ) {
1571
            Error ("FromPackage can only be specified once")
1572
                if ( defined $opt_package );
1573
            $opt_package = 1;
1574
 
1575
        } elsif ( m/^--Strip=(\d+)$/i ) {
1576
            Error ("Strip can only be specified once")
1577
                if ( defined $opt_package );
1578
            $opt_strip = $1;
1579
 
1580
        } else {
1581
            Error ("Unknown option: $_" );
1582
        }
1583
    }
1584
 
1585
    #
1586
    #   All options have been gathered. Now process some of them
1587
    #
1588
    Error ("Cannot use both --Source and --FromPackage: $srcTar") if ($opt_source && $opt_package);
1589
 
1590
    #
1591
    #   Convert a symbolic path into a physical path
1592
    #
1593
    if ($opt_source)
1594
    {
1595
        Verbose2 ("Determine Source: $opt_source");
1596
 
1597
        $opt_source = lc($opt_source);
1598
        my %ExtractTarSymbolic = (
1599
            'interfaceincdir'   => $opt_interfaceincdir,
1600
            'interfacelibdir'   => $opt_interfacelibdir,
1601
            'interfacebindir'   => $opt_interfacebindir,
1602
            'libdir'            => $opt_libdir,
1603
            'bindir'            => $opt_bindir,
1604
            'localincdir'       => $opt_localincdir,
1605
            'locallibdir'       => $opt_locallibdir,
1606
            'localbindir'       => $opt_localbindir,
1607
            'packagebindir'     => $opt_pkgbindir,
1608
            'packagelibdir'     => $opt_pkglibdir,
1609
            'packagepkgdir'     => $opt_pkgpkgdir,
1610
            'packagedir'        => $opt_pkgdir,
1611
        );
1612
 
1613
        if ( exists $ExtractTarSymbolic{$opt_source} )
1614
        {
1615
            $opt_base = $ExtractTarSymbolic{$opt_source};
1616
 
1617
            #
1618
            #   If sourceing from interface, then follow
1619
            #   symlinks in the copy. All files will be links anyway
1620
            #
1621
            $from_interface = 1
1622
                if ( $opt_source =~ m~^interface~ );
1623
        }
1624
        else
1625
        {
1626
            DebugDumpData ("ExtractTarSymbolic", \%ExtractTarSymbolic);
1627
            Error ("Unknown Source Name: $opt_source" );
1628
        }
1629
    }
1630
 
1631
    #
1632
    #   Locate the path within an external package
1633
    #
1634
    if ($opt_package)
1635
    {
1636
        Verbose2 ("FromPackage: $srcTar");
1637
 
1638
        my @path;
1639
        my @scanned;
1640
        foreach my $entry ( getPackageList() )
1641
        {
1642
            my $base = $entry->getBase(3);
1643
            next unless ( defined $base );
1644
            push @scanned, $base;
1645
            if ( -f $base . '/' . $srcTar )
1646
            {
1647
                push @path, $base;
1648
                $from_interface = 1
1649
                    if ( $entry->{'TYPE'} eq 'interface' );
1650
            }
1651
        }
1652
 
1653
        if ( $#path < 0 )
1654
        {
1655
            Error ("Cannot find source dir in any package: $userSrcTar", @scanned);
1656
        }
1657
 
1658
        Error ("Requested path found in mutiple packages: $userSrcTar",
1659
                @path ) if ( $#path > 0 );
1660
        $opt_base = pop @path;
1661
 
1662
        #
1663
        #   If sourceing from interface, then follow symlinks in the copy.
1664
        #   All files will be links anyway
1665
        #
1666
        #   This is a very ugly test for 'interface'
1667
        #
1668
        $from_interface = 1
1669
            if ( $opt_base =~ m~/interface/~ );
1670
    }
1671
 
1672
    #
1673
    #   Create the full source path
1674
    #   May be: from a package, from a known directory, from a local directory
1675
    #
1676
    $srcTar = $opt_base . '/' . $srcTar if ( $opt_base );
1677
    $srcTar =~ s~//~/~g;
1678
 
1679
    Verbose ("$srcTar, $dst_dir");
1680
    Error ("Tar File not found: $userSrcTar") unless ( -f $srcTar );
1681
 
1682
    #
1683
    #   Create the output path if it does not exist
1684
    #
1685
    mkpath( $dst_dir ) unless -d $dst_dir;
1686
 
1687
    #
1688
    #   Generate and execute the tar command
1689
    #   
1690
    my @cmd = qw (tar -x --keep-old-files);
1691
    push @cmd, '-f', $srcTar;
1692
    push (@cmd, qw(-v --show-transformed-names)) if ($opt_verbose > 2);
1693
    push (@cmd, "--strip=$opt_strip") if (defined $opt_strip);
1694
    push @cmd, '-C', $dst_dir;
1695
    System (@cmd);
1696
}
1697
 
1698
 
1699
#-------------------------------------------------------------------------------
1700
# Function        : CopyDir
1701
#
1702
# Description     : Copy a directory to a target dir
1703
#
1704
# Inputs          : $src_dir    - Local to the user
1705
#                                 Symbolic Name
1706
#                   $dst_dir    - Within the output workspace
1707
#                   Options
1708
#                       --Merge                 - Don't delete first
1709
#                       --Source=Name           - Source via Symbolic Name
1710
#                       --FromPackage           - Source via package roots
6535 dpurdie 1711
#                       --FromPackage:Name      - Source via specified package roots
6242 dpurdie 1712
#                       --NoIgnoreDbgFiles      - Do not ignore .dbg and .debug files in dir copy
1713
#                       --IfPresent             - Not an error if the path cannot be found
1714
#                       --ConfFile              - Mark transferred files as config files
1715
#                       --Flatten               - Copy all to one directory
1716
#                       --FilterOut=xxx         - Ignore files. DOS Wildcard
1717
#                       --FilterOutRe=xxx       - Ignore files. Regular expression name
1718
#                       --FilterOutDir=xxx      - Ignore directories. DOS Wilcard
1719
#                       --FilterOutDirRe=xxx    - Ignore directories. Regular expression name
1720
#                       --SkipTLF               - Ignore files in the Top Level Directory
1721
#                       --NoRecurse             - Only process files in the Top Level Directory
1722
#                       --FilterIn=xxx          - Include files. DOS Wildcard
1723
#                       --FilterInRe=xxx        - Include files. Regular expression name
1724
#                       --FilterInDir=xxx       - Include directories. DOS Wilcard
1725
#                       --FilterInDirRe=xxx     - Include directories. Regular expression name
1726
#
1727
# Returns         :
1728
#
1729
sub CopyDir
1730
{
1731
    my ($src_dir, $dst_dir, @opts) = @_;
1732
    my $opt_base;
1733
    my $from_interface = 0;
1734
    my $ignoreDbg = 1;
1735
    my $ignoreNoDir;
1736
    my $user_src_dir = $src_dir;
1737
    my $opt_source;
1738
    my $opt_package;
6535 dpurdie 1739
    my $opt_package_name;
6242 dpurdie 1740
    my @fileList;
1741
    my $isFiltered;
1742
    return 1 unless ($ActiveSection);
1743
 
1744
    #
1745
    #   Setup the basic copy options
1746
    #       May be altered as we parse user options
1747
    #
1748
    my %copyOpts;
1749
    $copyOpts{'IgnoreDirs'} = ['.svn', '.git', '.cvs', '.hg'];
1750
    $copyOpts{'Ignore'} = ['.gbedir', '_gbedir'];
1751
    $copyOpts{'Log'} = 1 if ( $opt_verbose > 1 );
1752
    $copyOpts{'DeleteFirst'} = 1;
1753
 
1754
    $dst_dir = $WorkDir . '/' . $dst_dir;
1755
    $dst_dir =~ s~//~/~;
1756
 
1757
    #
1758
    #   Scan and collect user options
1759
    #
1760
    foreach  ( @opts )
1761
    {
1762
        Verbose2 ("CopyDir: $_");
1763
        if ( m/^--Merge/ ) {
1764
            $copyOpts{'DeleteFirst'} = 0;
1765
 
1766
        } elsif ( m/^--Source=(.+)/ ) {
1767
            Error ("Source directory can only be specified once")
1768
                if ( defined $opt_source );
1769
            $opt_source = $1;
1770
 
6535 dpurdie 1771
        } elsif ( m/^--FromPackage:(.+)/ ) {
1772
            Error ("FromPackage can only be specified once")
1773
                if ( defined $opt_package );
1774
            $opt_package = 1;
1775
            $opt_package_name = $1;
1776
 
6242 dpurdie 1777
        } elsif ( m/^--FromPackage/ ) {
1778
            Error ("FromPackage can only be specified once")
1779
                if ( defined $opt_package );
1780
            $opt_package = 1;
1781
 
1782
        } elsif ( m/^--NoIgnoreDbgFiles/ ) {
1783
            $ignoreDbg = 0;
1784
 
1785
        } elsif ( m/^--IfPresent/ ) {
1786
            $ignoreNoDir = 1;
1787
 
1788
        } elsif ( m/^--ConfFile/i ) {
1789
            $copyOpts{'FileList'} = \@fileList;
1790
 
1791
        } elsif ( m/^--Flatten/i ) {
1792
            $copyOpts{'Flatten'} = 1;
1793
 
1794
        } elsif ( m/^--FilterOut=(.+)/i ) {
1795
            push (@{$copyOpts{'Ignore'}}, $1);
1796
            $isFiltered = 1;
1797
 
1798
        } elsif ( m/^--FilterOutRe=(.+)/i ) {
1799
            push (@{$copyOpts{'IgnoreRE'}}, $1);
1800
            $isFiltered = 1;
1801
 
1802
        } elsif ( m/^--FilterOutDir=(.+)/i ) {
1803
            push (@{$copyOpts{'IgnoreDirs'}}, $1);
1804
            $isFiltered = 1;
1805
 
1806
        } elsif ( m/^--FilterOutDirRe=(.+)/i ) {
1807
            push (@{$copyOpts{'IgnoreDirsRE'}}, $1);
1808
            $isFiltered = 1;
1809
 
1810
        } elsif ( m/^--FilterIn=(.+)/i ) {
1811
            push (@{$copyOpts{'Match'}}, $1);
1812
            $isFiltered = 1;
1813
 
1814
        } elsif ( m/^--FilterInRe=(.+)/i ) {
1815
            push (@{$copyOpts{'MatchRE'}}, $1);
1816
            $isFiltered = 1;
1817
 
1818
        } elsif ( m/^--FilterInDir=(.+)/i ) {
1819
            push (@{$copyOpts{'MatchDirs'}}, $1);
1820
            $isFiltered = 1;
1821
 
1822
        } elsif ( m/^--FilterInDirRe=(.+)/i ) {
1823
            push (@{$copyOpts{'MatchDirsRE'}}, $1);
1824
            $isFiltered = 1;
1825
 
1826
        } elsif ( m/^--SkipTLF$/i ) {
1827
            $copyOpts{'SkipTLF'} = 1;
1828
 
1829
        } elsif ( m/^--NoRecurse$/i ) {
1830
            $copyOpts{'NoSubDirs'} = 1;
1831
 
1832
        } else {
1833
            Error ("CopyDir: Unknown option: $_" );
1834
        }
1835
    }
1836
 
1837
    #
1838
    #   All options have been gathered. Now process some of them
1839
    #
1840
    Error ("CopyDir: Cannot use both --Source and --FromPackage: $src_dir") if ($opt_source && $opt_package);
1841
 
1842
    #
1843
    #   Convert a symbolic path into a physical path
1844
    #
1845
    if ($opt_source)
1846
    {
1847
        Verbose2 ("CopyDir: Determine Source: $opt_source");
1848
 
1849
        $opt_source = lc($opt_source);
1850
        my %CopyDirSymbolic = (
1851
            'interfaceincdir'   => $opt_interfaceincdir,
1852
            'interfacelibdir'   => $opt_interfacelibdir,
1853
            'interfacebindir'   => $opt_interfacebindir,
1854
            'libdir'            => $opt_libdir,
1855
            'bindir'            => $opt_bindir,
1856
            'localincdir'       => $opt_localincdir,
1857
            'locallibdir'       => $opt_locallibdir,
1858
            'localbindir'       => $opt_localbindir,
1859
            'packagebindir'     => $opt_pkgbindir,
1860
            'packagelibdir'     => $opt_pkglibdir,
1861
            'packagepkgdir'     => $opt_pkgpkgdir,
1862
            'packagedir'        => $opt_pkgdir,
1863
        );
1864
 
1865
        if ( exists $CopyDirSymbolic{$opt_source} )
1866
        {
1867
            $opt_base = $CopyDirSymbolic{$opt_source};
1868
 
1869
            #
1870
            #   If sourceing from interface, then follow
1871
            #   symlinks in the copy. All files will be links anyway
1872
            #
1873
            $from_interface = 1
1874
                if ( $opt_source =~ m~^interface~ );
1875
        }
1876
        else
1877
        {
1878
            DebugDumpData ("CopyDirSymbolic", \%CopyDirSymbolic);
1879
            Error ("CopyDir: Unknown Source Name: $opt_source" );
1880
        }
1881
    }
1882
 
1883
    #
1884
    #   Locate the path within an external package
1885
    #
1886
    if ($opt_package)
1887
    {
1888
        Verbose2 ("CopyDir: FromPackage: $src_dir");
1889
 
1890
        my @path;
1891
        foreach my $entry ( getPackageList() )
1892
        {
6535 dpurdie 1893
            #
1894
            #   Locate the named package if specified
1895
            #
1896
            if (defined $opt_package_name) {
1897
                next unless ($opt_package_name eq $entry->getName() || uc($opt_package_name) eq $entry->getUnifiedName() );
1898
            }
1899
 
6242 dpurdie 1900
            my $base = $entry->getBase(3);
1901
            next unless ( defined $base );
6535 dpurdie 1902
            if ( folderHasFiles( $base . '/' . $src_dir) )
6242 dpurdie 1903
            {
1904
                push @path, $base;
1905
                $from_interface = 1
1906
                    if ( $entry->{'TYPE'} eq 'interface' );
1907
            }
1908
        }
1909
 
1910
        if ( $#path < 0 )
1911
        {
1912
            Error ("CopyDir: Cannot find source dir in any package: $user_src_dir") unless ($ignoreNoDir);
1913
            Message ("CopyDir: Optional path not found: $user_src_dir");
1914
            return;
1915
        }
1916
 
1917
        Error ("CopyDir: Requested path found in mutiple packages: $user_src_dir",
1918
                @path ) if ( $#path > 0 );
1919
        $opt_base = pop @path;
1920
 
1921
        #
1922
        #   If sourceing from interface, then follow symlinks in the copy.
1923
        #   All files will be links anyway
1924
        #
1925
        #   This is a very ugly test for 'interface'
1926
        #
1927
        $from_interface = 1
1928
            if ( $opt_base =~ m~/interface/~ );
1929
 
1930
    }
1931
 
1932
    #
1933
    #   Create the full source path
1934
    #   May be: from a package, from a known directory, from a local directory
1935
    #
1936
 
1937
    $src_dir = $opt_base . '/' . $src_dir if ( $opt_base );
1938
    $src_dir =~ s~//~/~g;
1939
    $src_dir =~ s~/$~~;
1940
 
1941
    Verbose ("CopyDir: $src_dir, $dst_dir");
1942
    unless ( -d $src_dir )
1943
    {
1944
        Error ("CopyDir: Directory not found: $user_src_dir") unless ($ignoreNoDir);
1945
        Message ("CopyDir: Optional path not found: $user_src_dir");
1946
        return;
1947
    }
1948
 
1949
    #
1950
    #   Continue to configure the copy options
1951
    #
1952
    push (@{$copyOpts{'Ignore'}}, '*.debug', '*.dbg') if $ignoreDbg;
1953
    $copyOpts{'DuplicateLinks'} = 1 unless ( $from_interface );
1954
    $copyOpts{'EmptyDirs'} = 1 unless ($isFiltered);
1955
 
1956
    #
1957
    #   Transfer the directory
1958
    #
1959
    JatsCopy::CopyDir ( $src_dir, $dst_dir, \%copyOpts );
1960
 
1961
    #
1962
    #   If requested, mark files as config files
1963
    #   Must remove the DebianWorkDir prefix
1964
    #
1965
    if(@fileList)
1966
    {
1967
        Verbose ("Mark all transfered files as ConfFiles");
1968
        my $removePrefix = length ($WorkDir);
1969
        foreach my $file (@fileList)
1970
        {
1971
            push @ConfigList, substr($file, $removePrefix);
1972
        }
1973
    }
1974
 
1975
    #
1976
    #   Expand link files that may have been copied in
1977
    #
1978
    Verbose ("Locate LINKFILES in $WorkDir");
1979
    ExpandLinkFiles();
1980
}
1981
 
1982
#-------------------------------------------------------------------------------
1983
# Function        : AddInitScript
1984
#
1985
# Description     : Add an Init Script to the target
1986
#                   Optionally create start and stop links
1987
#
1988
# Inputs          : $script     - Name of the init script
1989
#                   $start      - Start Number
1990
#                   $stop       - Stop Number
1991
#                   Options:
1992
#                       --NoCopy        - Don't copy the script, just add links
1993
#                       --Afc           - Place in AFC init area
1994
#                       --FromPackage   - Source is in a package
6535 dpurdie 1995
#                       --Hibernate     - Add hibernate symlink
1996
#                       --Resume        - Add resume symlink
6547 dpurdie 1997
#                       --Sk100Mode     - Force SK100 Mode
6242 dpurdie 1998
#
1999
# Returns         : 
2000
#
2001
sub AddInitScript
2002
{
2003
    my $no_copy;
2004
    my $basedir = "";
2005
    my @args;
2006
    my $from_package = 0;
6535 dpurdie 2007
    my $hibernate = 0;
2008
    my $resume = 0;
6547 dpurdie 2009
    my $sk100 = ($opt_platform eq 'SK100');
2010
    my $afcMode;
2011
 
6242 dpurdie 2012
    return 1 unless ($ActiveSection);
2013
 
2014
    # This directive is only available on the VIX platforms
2015
    #   Kludgey test - at the moment
2016
    #
6547 dpurdie 2017
    if ($opt_pkgarch =~ m~i386~) {
6242 dpurdie 2018
        Error ("AddInitScript is not supported on this platform"); 
2019
    }
2020
 
2021
    #
2022
    #   Process and Remove options
2023
    #
2024
    foreach  ( @_ )
2025
    {
2026
        if ( m/^--NoCopy/ ) {
2027
            $no_copy = 1;
2028
 
2029
        } elsif ( m/^--Afc/ ) {
2030
            $basedir = "/afc";
6547 dpurdie 2031
            $afcMode = 1;
6242 dpurdie 2032
 
2033
        } elsif ( m/^--FromPackage/ ) {
2034
            $from_package = 1;
2035
 
6535 dpurdie 2036
        } elsif ( m/^--Hibernate=(.*)/ ) {
2037
            $hibernate = $1;
2038
 
2039
        } elsif ( m/^--Resume=(.*)/ ) {
2040
            $resume = $1;
2041
 
6547 dpurdie 2042
        } elsif ( m/^--SK100/i ) {
2043
            $sk100 = 1;
2044
 
2045
        } elsif ( m/^--NoSK100/i ) {
2046
            $sk100 = 0;
2047
 
6242 dpurdie 2048
        } elsif ( m/^--/ ) {
2049
            Error ("AddInitScript: Unknown option: $_");
2050
 
2051
        } else {
2052
            push @args, $_;
2053
 
2054
        }
2055
    }
2056
 
2057
    my( $script, $start, $stop ) = @args;
2058
    Error ("No script file specified") unless ( $script );
2059
    Warning("AddInitScript: No start or stop index specified") unless ( $start || $stop );
2060
    Verbose ("AddInitScript: $script, " . ($start || 'No Start') . ", " . ($stop || 'No Stop'));
6547 dpurdie 2061
    Error ("Resume script not supported") if ($resume && !$sk100);
2062
    Error ("Hibernate script not supported") if ($hibernate && !$sk100);
2063
    Error ("AFC mode not supported on SK100 (@args)") if ( $sk100 && $afcMode );
6242 dpurdie 2064
    $script = ResolveFile($from_package, $script );
6547 dpurdie 2065
 
2066
    my $tdir = $sk100 ?  "/etc/init.d/init.vix.d" : "/etc/init.d/init.d";
2067
    $tdir = catdir($basedir, $tdir);
6242 dpurdie 2068
    my $base = StripDir($script);
2069
    CopyFile( $script, $tdir ) unless $no_copy;
2070
 
2071
    my $link;
6547 dpurdie 2072
    my $linkPath = $sk100 ? "/etc/init.d/init.vix.d/" : "/etc/init.d/";
2073
    $linkPath = catdir($basedir, $linkPath) . '/';
2074
    Verbose("InitScript: ", $base, $tdir, $linkPath);
2075
 
6535 dpurdie 2076
    if ( $start ) {
2077
        $link = sprintf ("${linkPath}S%2.2d%s", $start, $base );
6242 dpurdie 2078
        MakeSymLink( "$tdir/$base", $link);
2079
    }
2080
 
6535 dpurdie 2081
    if ( $stop ) {
2082
        $link = sprintf ("${linkPath}K%2.2d%s", $stop, $base );
6242 dpurdie 2083
        MakeSymLink( "$tdir/$base", $link);
2084
    }
6535 dpurdie 2085
 
2086
    if ( $hibernate ) {
2087
        $link = sprintf ("${linkPath}H%2.2d%s", $hibernate, $base );
2088
        MakeSymLink( "$tdir/$base", $link);
2089
    }
2090
 
2091
    if ( $resume ) {
2092
        $link = sprintf ("${linkPath}R%2.2d%s", $resume, $base );
2093
        MakeSymLink( "$tdir/$base", $link);
2094
    }
2095
 
6547 dpurdie 2096
    # In SK100 mode
2097
    #   init script must be placed in rc.local.d and must be sources and 
2098
    #   a start stop resume or suspend function must be implemented.
6535 dpurdie 2099
    # For VIX these functions will call existing initscripts already package in
2100
    # a vix folder. 
6547 dpurdie 2101
    if ( $sk100 ) {
2102
 
2103
        my $rcLocal =  "/etc/init.d/rc.local.d";
2104
        my $rcLocalFile = catfile( $rcLocal, $base);
2105
        my $rcWorkFile = catfile($WorkDir, $rcLocalFile );
2106
        my $fh;
2107
        CreateDir($rcLocal);
2108
 
2109
        Message ("creating service file: $rcLocalFile");
2110
        unless (open $fh,'>', $rcWorkFile) {
2111
            Error ("Failed to create Service file in $rcLocal, $!");
6535 dpurdie 2112
        }
6547 dpurdie 2113
        print $fh "#!/bin/sh\n# $base service file\n\n";
2114
        print $fh "start() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base start\n}\n";
2115
        print $fh "stop() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base stop\n}\n";
2116
        print $fh "restart() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base restart\n}\n";
2117
        print $fh "suspend() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base suspend\n}\n";
2118
        print $fh "resume() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base resume\n}\n";
2119
        close $fh;
6535 dpurdie 2120
        SetFilePerms('a+rx', "/etc/init.d/rc.local.d/$base");
2121
    }
6547 dpurdie 2122
 
2123
    return 1;
6242 dpurdie 2124
}
2125
 
2126
#-------------------------------------------------------------------------------
2127
# Function        : CatFile
2128
#
2129
# Description     : Copy a file to the end of a file
2130
#
2131
# Inputs          : $src
2132
#                   $dst    - Within the output workspace
2133
#
2134
# Returns         :
2135
#
2136
sub CatFile
2137
{
2138
    my ($src, $dst) = @_;
2139
    return 1 unless ($ActiveSection);
2140
 
2141
    $dst = $WorkDir . '/' . $dst;
2142
    $dst =~ s~//~/~;
2143
    Verbose ("CatFile: $src, $dst");
2144
    $src = ResolveFile(0, $src );
2145
 
2146
    open (SF, '<', $src)  || Error ("CatFile: Cannot open $src");
2147
    open (DF, '>>', $dst) || Error ("CatFile: Cannot create:$dst");
2148
    while ( <SF> )
2149
    {
2150
        print DF $_;
2151
    }
2152
    close (SF);
2153
    close (DF);
2154
}
2155
 
2156
#-------------------------------------------------------------------------------
2157
# Function        : EchoFile
2158
#
2159
# Description     : Echo simple text to a file
2160
#
2161
# Inputs          : $file   - Within the output workspace
2162
#                   $text
2163
#
2164
# Returns         : 
2165
#
2166
sub EchoFile
2167
{
2168
    my ($file, $text) = @_;
2169
    return 1 unless ($ActiveSection);
2170
    Verbose ("EchoFile: $file");
2171
 
2172
    $file = $WorkDir . '/' . $file;
2173
    $file =~ s~//~/~;
2174
 
2175
    unlink $file;
2176
    open (DT, ">", $file ) || Error ("Cannot create $file");
2177
    print DT  $text || Error ("Cannot print to $file");
2178
    close DT;
2179
}
2180
 
2181
#-------------------------------------------------------------------------------
2182
# Function        : ConvertFiles
2183
#
2184
# Description     : This sub-routine is used to remove all carrage return\line
2185
#                   feeds from a line and replace them with the platform
2186
#                   specific equivalent chars.
2187
#
2188
#                   We let PERL determine what characters are written to the
2189
#                   file base on the  platform you are running on.
2190
#
2191
#                   i.e. LF    for unix
2192
#                        CR\LF for win32
2193
#
2194
# Inputs          : outPath                 - Output directory
2195
#                   flist                   - List of files in that directory
2196
#                   or
2197
#                   SearchOptions           - Search options to find files
2198
#                                           --Recurse
2199
#                                           --NoRecurse
2200
#                                           --FilterIn=xxx
2201
#                                           --FilterInRe=xxx
2202
#                                           --FilterOut=xxx
2203
#                                           --FilterOutRe=xxx
2204
#                   Common options
2205
#                                           --Dos
2206
#                                           --Unix
2207
#
2208
#
2209
# Returns         : 1
2210
#
2211
sub ConvertFiles
2212
{
2213
    my @uargs;
2214
    return 1 unless ($ActiveSection);
2215
    my $lineEnding = "\n";
2216
    my ($dosSet, $unixSet);
2217
    my $search =  JatsLocateFiles->new( '--NoRecurse' );
2218
 
2219
    #
2220
    #   Process user arguments extracting options
2221
    #
2222
    foreach  ( @_ )
2223
    {
2224
        if ( m~^--Recurse~ ) {
2225
            $search->recurse(1);
2226
 
2227
        } elsif ( m~^--NoRecurse~) {
2228
            $search->recurse(0);
2229
 
2230
        } elsif ( /^--FilterOut=(.*)/ ) {
2231
            $search->filter_out($1);
2232
 
2233
        } elsif ( /^--FilterOutRe=(.*)/ ) {
2234
            $search->filter_out_re($1);
2235
 
2236
        } elsif ( /^--FilterIn=(.*)/ ) {
2237
            $search->filter_in($1);
2238
 
2239
        } elsif ( /^--FilterInRe=(.*)/ ) {
2240
            $search->filter_in_re($1);
2241
 
2242
        } elsif ( m~^--Dos~) {
2243
            $lineEnding = "\r\n";
2244
            $dosSet = 1;
2245
 
2246
        } elsif ( m~^--Unix~) {
2247
            $lineEnding = "\n";
2248
            $unixSet = 1;
2249
 
2250
        } elsif ( m~^--~) {
2251
            Error ("ConvertFiles: Unknown option: $_");
2252
 
2253
        } else {
2254
            push @uargs, $_;
2255
        }
2256
    }
2257
 
2258
    #
2259
    #   Process non-option arguments
2260
    #       - Base dir
2261
    #       - List of files
2262
    #
2263
    my ($outPath, @flist) = @uargs;
2264
    Error ("ConvertFiles: Target Dir must be specified" ) unless ( $outPath );
2265
 
2266
    #
2267
    #   Sanity Tests
2268
    #
2269
    Error ("ConvertFiles: --Dos and --Unix are mutually exclusive" ) if ( $dosSet && $unixSet );
2270
 
2271
 
2272
    #
2273
    # Convert output path to physical path
2274
    #
2275
    my $topDir = catdir($WorkDir, $outPath);
2276
    Verbose("ConvertFiles: topDir: $topDir");
2277
    Error ("ConvertFiles: Path does not exist", $topDir) unless ( -e $topDir );
2278
    Error ("ConvertFiles: Path is not a directory", $topDir) unless ( -d $topDir );
2279
 
2280
    #
2281
    #   Need to determine if we are searching or simply using a file list
2282
    #   There are two forms of the functions. If any of the search options have
2283
    #   been used then we assume that we are searchine
2284
    #
2285
    if ( $search->has_filter() )
2286
    {
2287
        Error ("ConvertFiles: Cannot mix search options with named files") if ( @flist );
2288
        @flist = $search->search($topDir);
2289
    }
2290
    Error ("ConvertFiles: No files specified") unless ( @flist );
2291
 
2292
    #
2293
    #   Process all named files
2294
    #
2295
    foreach my $file ( @flist )
2296
    {
2297
 
2298
        # this is our file that we want to clean.
2299
        my ($ifileLoc) = "$topDir/$file";
2300
        my ($tfileLoc) = "$topDir/$file\.tmp";
2301
        Verbose("ConvertFiles: $file");
2302
 
2303
        # we will check to see if the file exists.
2304
        #
2305
        my $ifile;
2306
        my $tfile;
2307
        if ( -f "$ifileLoc" )
2308
        {
2309
            open ($ifile, "< $ifileLoc" ) or
2310
                Error("Failed to open file [$ifileLoc] : $!");
2311
 
2312
            open ($tfile, "> $tfileLoc" ) or
2313
                Error("Failed to open file [$tfileLoc] : $!");
2314
            binmode $tfile;
2315
 
2316
            while ( <$ifile> ) 
2317
            {
2318
                s~[\n\r]+$~~;               # Chomp
2319
                print $tfile "$_" . $lineEnding;
2320
            }
2321
        }
2322
        else
2323
        {
2324
            Error("ConvertFiles [$ifileLoc] does not exist.");
2325
        }
2326
 
2327
        close $ifile;
2328
        close $tfile;
2329
 
2330
 
2331
        # lets replace our original file with the new one
2332
        #
2333
        if(File::Copy::move("$tfileLoc", "$ifileLoc"))
2334
        {
2335
            Verbose2("ConvertFiles: Renamed [$tfileLoc] to [$ifileLoc] ...");
2336
        }
2337
        else
2338
        {
2339
            Error("ConvertFiles: Failed to rename file [$tfileLoc] to [$ifileLoc]: $!");
2340
        }
2341
    }
2342
 
2343
    return 1;
2344
}
2345
 
2346
#----------------------------------------------------------------------------
2347
# Function        : ReplaceTags
2348
#
2349
# Description     : This sub-routine is used to replace Tags in one or more files
2350
#
2351
# Inputs          : outPath                 - Output directory
2352
#                   flist                   - List of files in that directory
2353
#                   or
2354
#                   SearchOptions           - Search options to find files
2355
#                                           --Recurse
2356
#                                           --NoRecurse
2357
#                                           --FilterIn=xxx
2358
#                                           --FilterInRe=xxx
2359
#                                           --FilterOut=xxx
2360
#                                           --FilterOutRe=xxx
2361
#                   Common options
2362
#                                           --Tag=Tag,Replace
2363
#                                           
2364
#
2365
# Returns         : 1
2366
#
2367
sub ReplaceTags
2368
{
2369
    return 1 unless ($ActiveSection);
2370
    my @uargs;
2371
    my $search =  JatsLocateFiles->new( '--NoRecurse' );
2372
    my @tagsList;
2373
    my $tagSep = ',';
2374
    my @tagOrder;
2375
    my %tagData;
2376
 
2377
    #
2378
    #   Process user arguments extracting options
2379
    #
2380
    foreach  ( @_ )
2381
    {
2382
        if ( m~^--Recurse~ ) {
2383
            $search->recurse(1);
2384
 
2385
        } elsif ( m~^--NoRecurse~) {
2386
            $search->recurse(0);
2387
 
2388
        } elsif ( /^--FilterOut=(.*)/ ) {
2389
            $search->filter_out($1);
2390
 
2391
        } elsif ( /^--FilterOutRe=(.*)/ ) {
2392
            $search->filter_out_re($1);
2393
 
2394
        } elsif ( /^--FilterIn=(.*)/ ) {
2395
            $search->filter_in($1);
2396
 
2397
        } elsif ( /^--FilterInRe=(.*)/ ) {
2398
            $search->filter_in_re($1);
2399
 
2400
        } elsif ( m~^--Tag=(.*)~) {
2401
            push @tagsList, $1;
2402
 
2403
        } elsif ( m~^--~) {
2404
            Error ("ReplaceTags: Unknown option: $_");
2405
 
2406
        } else {
2407
            push @uargs, $_;
2408
        }
2409
    }
2410
 
2411
    #
2412
    #   Process non-option arguments
2413
    #       - Base dir
2414
    #       - List of files
2415
    #
2416
    my ($outPath, @flist) = @uargs;
2417
    Error ("ReplaceTags: Target Dir must be specified" ) unless ( $outPath );
2418
 
2419
    #
2420
    #   Sanity Tests
2421
    #
2422
    Error ("ReplaceTags: No tags specified" ) unless ( @tagsList );
2423
 
2424
    #
2425
    # Convert output path to physical path
2426
    #
2427
    my $topDir = catdir($WorkDir, $outPath);
2428
    Verbose("ReplaceTags: topDir: $topDir");
2429
    Error ("ReplaceTags: Path does not exist", $topDir) unless ( -e $topDir );
2430
    Error ("ReplaceTags: Path is not a directory", $topDir) unless ( -d $topDir );
2431
 
2432
    #
2433
    #   Convert Tags into pairs for latter use
2434
    #
2435
    my $sep = quotemeta ($tagSep );
2436
    foreach my $tag ( @tagsList )
2437
    {
2438
        my ($tname,$tvalue) = split ( $sep, $tag, 2 );
2439
        Error ("No tag value in: $tag" ) unless ( defined $tvalue );
2440
        Error ("Duplicate Tag: $tname" ) if ( exists $tagData{$tname} );
2441
        Verbose ("Tag: $tname :: $tvalue");
2442
        push @tagOrder, $tname;
2443
        $tagData{$tname} = $tvalue;
2444
    }
2445
 
2446
    #
2447
    #   Need to determine if we are searching or simply using a file list
2448
    #   There are two forms of the functions. If any of the search options have
2449
    #   been used then we assume that we are searchine
2450
    #
2451
    if ( $search->has_filter() )
2452
    {
2453
        Error ("ReplaceTags: Cannot mix search options with named files") if ( @flist );
2454
        @flist = $search->search($topDir);
2455
    }
2456
    Error ("ReplaceTags: No files specified") unless ( @flist );
2457
 
2458
    #
2459
    #   Process all named files
2460
    #
2461
    foreach my $file ( @flist )
2462
    {
2463
 
2464
        # this is our file that we want to clean.
2465
        my ($ifileLoc) = "$topDir/$file";
2466
        my ($tfileLoc) = "$topDir/$file\.tmp";
2467
        Verbose("ReplaceTags: $file");
2468
 
2469
        # we will check to see if the file exists.
2470
        #
2471
        my $ifile;
2472
        my $tfile;
2473
        if ( -f "$ifileLoc" )
2474
        {
2475
            open ($ifile, "< $ifileLoc" ) or
2476
                Error("Failed to open file [$ifileLoc] : $!");
2477
 
2478
            open ($tfile, "> $tfileLoc" ) or
2479
                Error("Failed to open file [$tfileLoc] : $!");
2480
 
2481
            while ( <$ifile> ) 
2482
            {
2483
                s~[\n\r]+$~~;               # Chomp
2484
 
2485
                #
2486
                #   Perform tag replacement
2487
                #
2488
                foreach my $tag ( @tagOrder )
2489
                {
2490
                    my $value = $tagData{$tag};
2491
                    if ( s~$tag~$value~g )
2492
                    {
2493
                        Verbose2("Replaced: $tag with $value");
2494
                    }
2495
                }
2496
 
2497
                print $tfile "$_\n";
2498
            }
2499
        }
2500
        else
2501
        {
2502
            Error("ReplaceTags [$ifileLoc] does not exist.");
2503
        }
2504
 
2505
        close $ifile;
2506
        close $tfile;
2507
 
2508
 
2509
        # lets replace our original file with the new one
2510
        #
2511
        if(File::Copy::move("$tfileLoc", "$ifileLoc"))
2512
        {
2513
            Verbose2("ReplaceTags: Renamed [$tfileLoc] to [$ifileLoc] ...");
2514
        }
2515
        else
2516
        {
2517
            Error("ReplaceTags: Failed to rename file [$tfileLoc] to [$ifileLoc]: $!");
2518
        }
2519
    }
2520
 
2521
    return 1;
2522
}
2523
 
2524
#-------------------------------------------------------------------------------
2525
# Function        : SetFilePerms
2526
#
2527
# Description     : Set file permissions on one or more files or directories
2528
#                   Use SetPermissions
2529
#
2530
# Inputs          : $perm           - Perm Mask
2531
#                   @paths          - List of paths/files to process
2532
#                   Options
2533
#                       --Recurse   - Recurse subdirs
2534
#
2535
# Returns         : 
2536
#
2537
sub SetFilePerms
2538
{
2539
 
2540
    return 1 unless ($ActiveSection);
2541
    my @args;
2542
    my $perms;
2543
    my $recurse = 0;
2544
 
2545
    #
2546
    #   Process and Remove options
2547
    #
2548
    foreach  ( @_ )
2549
    {
2550
        if ( m/^--Recurse/ ) {
2551
            $recurse = 1;
2552
 
2553
        } elsif ( m/^--/ ) {
2554
            Error ("SetFilePerms: Unknown option: $_");
2555
 
2556
        } else {
2557
            push @args, $_;
2558
 
2559
        }
2560
    }
2561
 
2562
    $perms = shift @args;
2563
    Error ("SetFilePerms: No Permissions" ) unless ( $perms );
2564
 
2565
    foreach my $path ( @args )
2566
    {
2567
        Verbose ("Set permissions; $perms, $path");
2568
        my $full_path = $WorkDir . '/' . $path;
2569
        if ( -f $full_path )
2570
        {
2571
            System ('chmod', $perms, $full_path );
2572
        }
2573
        elsif ( -d $full_path )
2574
        {
2575
            System ('chmod', '-R', $perms, $full_path ) if ($recurse);
2576
            System ('chmod', $perms, $full_path ) unless ($recurse);
2577
        }
2578
        else
2579
        {
2580
            Warning("SetFilePerms: Path not found: $path");
2581
        }
2582
    }
2583
    return 1;
2584
}
2585
 
2586
#-------------------------------------------------------------------------------
2587
# Function        : SetPermissions 
2588
#
2589
# Description     : Called to set permissions of files/dirs in a directory structure.
2590
#                   With no options sets DirTag and all files/dirs in it to perms
2591
#   
2592
# Inputs          : path        - The directory tag to start setting permissions on
2593
#                   Options     - See below
2594
#       
2595
#   Required Options:
2596
#       One or both of
2597
#               --FilePerms=    Sets the permissions of files to this permission.
2598
#                               If not supplied then no files have their permissions changed
2599
#               --DirPerms=     Sets the permissions of directories to this permission
2600
#                               If not supplied then no directories have their permissions changed
2601
#       OR
2602
#               --Perms=        Sets the permissions of both files and directories to this permissions
2603
#                               Equivalent to supplying both --FilePerms=X && --DirPerms=X
2604
#               
2605
#   Options:                    
2606
#               --RootOnly      Only sets the permissions on the 'path' directory/file, 
2607
#                               all other options ignored
2608
#               --SkipRoot      Does not set permissions on the 'path' directory/file, 
2609
#                               obviously mutually exlusive with --RootOnly
2610
#   
2611
#       Any option supported by JatsLocateFiles. 
2612
#       Some of these include:
2613
#               
2614
#               --Recurse       Recurse the directory tree.  Does a depth first recurse so that all 
2615
#                               dir entries are processed before the dir itself (default)
2616
#               --NoRecurse     Dont recurse
2617
#               --FilterIn=     Apply permissions to files/directories that matches this value.
2618
#               --FilterInRe=   Perl RE's can be used (Not Shell wildcards) and this option
2619
#                               can be supplied mulitple times
2620
#               --FilterOut=    Dont apply permissions to any files/directories matching this value
2621
#               --FilterOutRe=  Perl RE's can be used (Not Shell wildcards) and this option
2622
#                               can be supplied mulitple times
2623
#               
2624
#                               FilterIn is applied before FilterOut.  If Recurse is specified 
2625
#                               the directory will be recursed regardless of these filters, however
2626
#                               the filter will be applied when it comes time to chmod the dir 
2627
#
2628
#------------------------------------------------------------------------------
2629
sub SetPermissions
2630
{
2631
    return 1 unless ($ActiveSection);
2632
    my ( $path, $filePerms, $dirPerms, $someDone );
2633
    my ( $rootOnly, $skipRoot ) = ( 0, 0 );
2634
 
2635
    my $search =  JatsLocateFiles->new( '--Recurse', '--DirsToo' );
2636
 
2637
    foreach ( @_ )
2638
    {
2639
        if ( m/^--Perms=(.*)/ ) {
2640
            $filePerms = $1;
2641
            $dirPerms = $1;
2642
 
2643
        } elsif (m/^--FilePerms=(.*)/ )  {
2644
            $filePerms = $1;
2645
 
2646
        } elsif ( m/^--DirPerms=(.*)/ )  {
2647
            $dirPerms = $1;
2648
 
2649
        }  elsif ( m/^--RootOnly/ ) {
2650
            $rootOnly = 1;
2651
 
2652
        } elsif ( m/^--SkipRoot/ )  {
2653
            $skipRoot = 1;
2654
 
2655
        } elsif ( m/^--Filter/ && $search->option( $_ ) ) {
2656
            Verbose2 ("Search Option: $_" );
2657
 
2658
        } elsif ( m/^--Recurse|--NoRecurse/ && $search->option( $_ ) ) {
2659
            Verbose2 ("Search Option: $_" );
2660
 
2661
        } elsif (m/^--/ ) {
2662
            Error ("SetPermissions: Unknown option: $_");
2663
 
2664
        } else  {
2665
            Error("SetPermissions 'path' already set", "Path: $_") if ( $path );
2666
            $path = $_;
2667
        }
2668
    }
2669
 
2670
    #
2671
    #   Sanity test
2672
    #
2673
    Error("SetPermissions called with out a 'path' parameter") if ( !defined($path) );
2674
    Error("SetPermissions called with out any Permissions specified") if ( !defined($filePerms) && !defined($dirPerms) );
2675
    Error("SetPermissions: Options --RootOnly & --SkipRoot are mutually exclusive" ) if ( $rootOnly && $skipRoot );
2676
 
2677
 
2678
    #   Convert the target directory name into a physical path
2679
    #   User specifies '/' as the root of the image
2680
    #   User specifies 'name' as relateve to the root of the image
2681
    #
2682
    my $topDir = $WorkDir . '/' . $path;
2683
    $topDir =~ s~/+$~~;
2684
 
2685
    Verbose("SetPermissions: Called with options " . join(", ", @_));
2686
 
2687
    #
2688
    #   Only set perms on the root directory
2689
    #       This is a trivial operation
2690
    #
2691
    if ( $rootOnly )
2692
    {
2693
        $someDone += chmodItem( $topDir, $filePerms, $dirPerms );
2694
    }
2695
    else
2696
    {
2697
        #
2698
        #   Create a list of files/dirs to process
2699
        #
2700
        my @elements = $search->search( $topDir );
2701
 
2702
        foreach my $dirEntry ( @elements )
2703
        {
2704
            my $fullPath = "$topDir/$dirEntry";
2705
 
2706
            # A dir and we dont have dirperms, so skip
2707
            if ( -d $fullPath && !defined($dirPerms) )
2708
            {
2709
                Verbose2("SetPermissions: Skipping dir $fullPath as we have no dir permissions");
2710
                next;
2711
            }
2712
 
2713
            # A file and we dont have fileperms, so skip
2714
            if ( -f $fullPath && !defined($filePerms) )
2715
            {
2716
                Verbose2("SetPermissions: Skipping file $fullPath as we have no file permissions");
2717
                next;
2718
            }
2719
 
2720
            # a file or a dir and have the right permissions and we are not recursing
2721
            if ( -f $fullPath || -d $fullPath )
2722
            {
2723
                $someDone += chmodItem( $fullPath, $filePerms, $dirPerms );
2724
            }
2725
            else
2726
            {
2727
                Warning("SetPermissions: Skipping $fullPath as its not a file or directory");
2728
            }
2729
        }
2730
 
2731
        #
2732
        #   Process the topDir
2733
        #   May not be modified if --SkipRoot has been requested
2734
        #
2735
        if ( !$skipRoot && -e $topDir )
2736
        {
2737
            $someDone += chmodItem( $topDir, $filePerms, $dirPerms );
2738
        }
2739
    }
2740
 
2741
    #   Final warning
2742
    #
2743
    Warning ("SetPermissions: No files located", "Args: @_") unless ( $someDone );
2744
}
2745
 
2746
#************ INTERNAL USE ONLY  **********************************************
2747
# Function        : chmodItem 
2748
#
2749
# Description     : Internal
2750
#                   chmod a file or a folder
2751
#
2752
# Inputs          : item                        - Item to mod
2753
#                   filePerms                   - File perms
2754
#                   dirPerms                    - dire perms
2755
#
2756
# Returns         : 1   - Item modified
2757
#                   0   - Item not modified
2758
#
2759
#************ INTERNAL USE ONLY  **********************************************
2760
sub chmodItem
2761
{
2762
    my ($item, $filePerms, $dirPerms) = @_;
2763
 
2764
    if ( -d $item && defined $dirPerms)
2765
    {
2766
        Verbose("SetPermissions: $dirPerms : $item");
2767
        System ('chmod', $dirPerms, $item );
2768
        return 1;
2769
    }
2770
 
2771
    if ( -f $item  && defined $filePerms)
2772
    {
2773
        Verbose("SetPermissions: $filePerms : $item");
2774
        System ('chmod', $filePerms, $item );
2775
        return 1;
2776
    }
2777
 
2778
    return 0;
2779
}
2780
 
2781
 
2782
#-------------------------------------------------------------------------------
2783
# Function        : CreateDir
2784
#
2785
# Description     : Create a directory within the target workspace
2786
#
2787
# Inputs          : $path           - Name of the target directory
2788
#                   @opts           - Options
2789
#                     --Owner       - Tells RPM Builder that this package. Owns this directory
2790
#
2791
# Returns         : Nothing
2792
#
2793
sub CreateDir
2794
{
2795
    my ($path, @opts) = @_;
2796
    return 1 unless ($ActiveSection);
2797
    Verbose ("Create Dir: $path");
2798
    my $owner  = 0;
2799
    foreach ( @opts) {
2800
        if (m~^--Owner~i ) {
2801
            $owner = 1;
2802
        } else {
2803
            ReportError ("SetBaseDir: Unknown option: $_");
2804
        }
2805
    }
2806
    ErrorDoExit();
2807
 
2808
    $path =~ s~^/+~~;
2809
    $path = '/' . $path;
2810
    $OwnedDirs{$path} = $owner if $owner;
2811
    mkpath( $WorkDir . $path );
2812
}
2813
 
2814
#-------------------------------------------------------------------------------
2815
# Function        : RpmSetDefAttr 
2816
#
2817
# Description     : RPM only: Set the defAttr values 
2818
#
2819
# Inputs          : Expect 4 or less argument
2820
#                       The default permissions, or "mode" for files.
2821
#                       The default user id.
2822
#                       The default group id.
2823
#                       The default permissions, or "mode" for directories.
2824
#                   
2825
sub RpmSetDefAttr
2826
{
2827
    return 1 unless ($ActiveSection);
2828
    return 1 unless $opt_rpm;
2829
    my @args = @_;
2830
    Error ("RpmSetDefAttr: Expecting 4 arguments") if (scalar @args ne 4);
2831
    @RpmDefAttr = @_;
2832
    return 1;
2833
}
2834
 
2835
#-------------------------------------------------------------------------------
2836
# Function        : RpmSetAttr 
2837
#
2838
# Description     : RPM Only : Specify specific file attributes
2839
#
2840
# Inputs          : $file - file to target
2841
#                   $mode - File mode to place on the file (optional)
2842
#                   $user - user name to place on the file  (optional)
2843
#                   $group  - group name to place eon the file (optional)
2844
#
2845
sub RpmSetAttr
2846
{
2847
    return 1 unless ($ActiveSection);
2848
    return 1 unless $opt_rpm;
2849
    my ($file, $mode, $user, $group, @extra) = @_;
2850
    Error ("RpmSetAttr: Too many arguments") if @extra;
2851
 
2852
    #
2853
    #   Validate the file
2854
    #
2855
    $file = '/' . $file;
2856
    $file =~ s~//~/~g;
2857
    my $full_path = $WorkDir . $file;
2858
    Error ("RpmSetAttr: File not found: $WorkSubDir$file") unless (-x $full_path );
2859
 
2860
    my @data;
2861
    $data[0] = $WorkSubDir . $file;
2862
    $data[1] = $mode || '-';
2863
    $data[2] = $user || '-';
2864
    $data[3] = $group ||'-';
2865
    push @RpmAttrList, \@data;
2866
    return 1;
2867
}
2868
 
2869
 
2870
#-------------------------------------------------------------------------------
2871
# Function        : IsProduct
2872
#                   IsPlatform
2873
#                   IsTarget
2874
#                   IsVariant
2875
#                   IsAlias
2876
#                   IsDebian
2877
#                   IsRpm
2878
#                   IsTar
2879
#
2880
# Description     : This function allows some level of control in the
2881
#                   packaging scripts. It will return true if the current
2882
#                   product is listed.
2883
#
2884
#                   Ugly after thought
2885
#
2886
#                   Intended use:
2887
#                       Xxxxxx(...) if (IsProduct( 'aaa',bbb' );
2888
#
2889
# Inputs          : products    - a list of products to compare against
2890
#
2891
# Returns         : True if the current build is for one of the listed products
2892
#
2893
sub IsProduct
2894
{
2895
    foreach ( @_ )
2896
    {
2897
        return 1 if ( $opt_product eq $_ );
2898
    }
2899
    return 0;
2900
}
2901
 
2902
sub IsPlatform
2903
{
2904
    foreach ( @_ )
2905
    {
2906
        return 1 if ( $opt_platform eq $_ );
2907
    }
2908
    return 0;
2909
}
2910
 
2911
sub IsTarget
2912
{
2913
    foreach ( @_ )
2914
    {
2915
        return 1 if ( $opt_target eq $_ );
2916
    }
2917
    return 0;
2918
}
2919
 
2920
sub IsVariant
2921
{
2922
    foreach ( @_ )
2923
    {
2924
        return 1 if ( $opt_variant eq $_ );
2925
    }
2926
    return 0;
2927
}
2928
 
2929
sub IsAlias
2930
{
2931
 
2932
    #
2933
    #   Get the aliases from the build info
2934
    #   This function was introduced late so its not always available
2935
    #
2936
    Error("IsAlias not supported in this version of JATS")
2937
        unless (defined &ReadBuildConfig::getAliases);
2938
    #
2939
    #   Create an hash of aliases to simplify testing
2940
    #   Do it once and cache the results
2941
    #
2942
    unless (%opt_aliases) {
2943
        %opt_aliases = map { $_ => 1 } getAliases();
2944
    }
2945
 
2946
    foreach ( @_ )
2947
    {
2948
        return 1 if ( exists $opt_aliases{$_} );
2949
    }
2950
    return 0;
2951
}
2952
 
2953
sub IsDebian()
2954
{
2955
    return $opt_debian ? 1 : 0;
2956
}
2957
 
2958
sub IsRpm()
2959
{
2960
    return $opt_rpm ? 1 : 0;
2961
}
2962
 
2963
sub IsTar()
2964
{
2965
    return $opt_tarFile ? 1 : 0;
2966
}
2967
 
2968
#-------------------------------------------------------------------------------
2969
# Function        : PackageVersion 
2970
#
2971
# Description     : Return the version of the named package 
2972
#
2973
# Inputs          : pkgName - Name of the package 
2974
#                   Options
2975
#                       --format=SomeString. The text replacements
2976
#                           {VERSION}
2977
#                           {VERSIONNUMVER}
2978
#                           {PROJECT}
2979
#                           {NAME}
2980
#                           {TYPE}
2981
#                           {ARCH}
2982
#
2983
# Returns         : A string 
2984
#
2985
sub PackageVersion
2986
{
2987
    my ($pkgName, @args) = @_;
2988
    my ($version, $versionNumber, $project, $format);
2989
 
2990
    foreach ( @args)
2991
    {
2992
        if (m~^--format=(.+)~i) {
2993
            $format = $1
2994
        } else {
2995
            Error ("PackageVersion: Unknown option: $_")
2996
        }
2997
    }
2998
 
2999
    foreach my $entry ( getPackageList() )
3000
    {
3001
        if ($entry->getName() eq $pkgName ) {
3002
            $version = $entry->getVersion();
3003
            ($versionNumber = $version ) =~ s~\.[^.]+$~~;
3004
            ($project = $version ) =~ s~.*\.~~;
3005
            last;
3006
        }
3007
    }
3008
 
3009
    Error ("PackageVersion: $pkgName is not a dependent package") unless defined $version;
3010
 
3011
    #
3012
    #   Format the string
3013
    #
3014
    if ($format) {
3015
        $format =~ s~{NAME}~$pkgName~g;
3016
        $format =~ s~{VERSION}~$version~g;
3017
        $format =~ s~{VERSIONNUMBER}~$versionNumber~g;
3018
        $format =~ s~{PROJECT}~$project~g;
3019
        $format =~ s~{TYPE}~$opt_type~g;
3020
        $format =~ s~{ARCH}~$opt_pkgarch~g;
3021
 
3022
        $version = $format;
3023
    }
3024
 
3025
    return $version;
3026
}
3027
 
3028
 
3029
#************ INTERNAL USE ONLY  **********************************************
3030
# Function        : FindFiles
3031
#
3032
# Description     : Locate files within a given dir tree
3033
#
3034
# Inputs          : $root           - Base of the search
3035
#                   $match          - Re to match
3036
#
3037
# Returns         : A list of files that match
3038
#
3039
#************ INTERNAL USE ONLY  **********************************************
3040
my @FIND_LIST;
3041
my $FIND_NAME;
3042
 
3043
sub FindFiles
3044
{
3045
    my ($root, $match ) = @_;
3046
    Verbose2("FindFiles: Root: $root, Match: $match");
3047
 
3048
    #
3049
    #   Becareful of closure, Must use globals
3050
    #
3051
    @FIND_LIST = ();
3052
    $FIND_NAME = $match;
3053
    File::Find::find( \&find_files, $root);
3054
 
3055
    #
3056
    #   Find callback program
3057
    #
3058
    sub find_files
3059
    {
3060
        my $item =  $File::Find::name;
3061
 
3062
        return if ( -d $File::Find::name );
3063
        return unless ( $_ =~ m~$FIND_NAME~ );
3064
        push @FIND_LIST, $item;
3065
    }
3066
    return @FIND_LIST;
3067
}
3068
 
3069
#-------------------------------------------------------------------------------
3070
# Function        : CalcRelPath
3071
#
3072
# Description     : Return the relative path to the current working directory
3073
#                   as provided in $Cwd
3074
#
3075
# Inputs          : $Cwd - Base dir
3076
#                   $base - Path to convert
3077
#
3078
# Returns         : Relative path from the $Cwd
3079
#
3080
sub CalcRelPath
3081
{
3082
    my ($Cwd, $base) = @_;
3083
 
3084
    my @base = split ('/', $base );
3085
    my @here = split ('/', $Cwd );
3086
    my $result;
3087
 
3088
    Debug("RelPath: Source: $base");
3089
 
3090
    return $base unless ( $base =~ m~^/~ );
3091
 
3092
    #
3093
    #   Remove common bits from the head of both lists
3094
    #
3095
    while ( $#base >= 0 && $#here >= 0 && $base[0] eq $here[0] )
3096
    {
3097
        shift @base;
3098
        shift @here;
3099
    }
3100
 
3101
    #
3102
    #   Need to go up some directories from here and then down into base
3103
    #
3104
    $result = '../' x ($#here + 1);
3105
    $result .= join ( '/', @base);
3106
    $result = '.' unless ( $result );
3107
    $result =~ s~//~/~g;
3108
    $result =~ s~/$~~;
3109
 
3110
    Debug("RelPath: Result: $result");
3111
    return $result;
3112
}
3113
 
3114
#-------------------------------------------------------------------------------
6535 dpurdie 3115
# Function        : folderHasFiles  
3116
#
3117
# Description     : Detect empty folders
3118
#
3119
# Inputs          : dirname - Path to examine 
3120
#
3121
# Returns         : TRUE - Is a folder and it has files
3122
#
3123
 
3124
sub folderHasFiles {
3125
    my $dirname = shift;
3126
    my $rv = 0;
3127
 
3128
    opendir(my $dh, $dirname) or return 0;
3129
    while (readdir $dh)
3130
    {
3131
        next if ($_ eq "." || $_ eq "..");
3132
        $rv = 1;
3133
        last;
3134
    }
3135
    closedir $dh;
3136
    return $rv;
3137
}
3138
 
3139
#-------------------------------------------------------------------------------
6242 dpurdie 3140
# Function        : ExpandLinkFiles
3141
#
3142
# Description     : Look for .LINK files in the output image and expand
3143
#                   the links into softlinks
3144
#
3145
# Inputs          : None
3146
#                   The routine works on the $WorkDir directory tree
3147
#
3148
# Returns         : Nothing
3149
#                   Will remove .LINKS files that are processed
3150
#
3151
sub ExpandLinkFiles
3152
{
3153
    return 1 unless ($ActiveSection);
3154
    foreach my $linkfile ( FindFiles( $WorkDir, ".LINKS" ))
3155
    {
3156
        next if ( $linkfile =~ m~/\.svn/~ );
3157
        my $BASEDIR = StripFileExt( $linkfile );
3158
        $BASEDIR =~ s~^$WorkDir/~~;
3159
        Verbose "Expand links: $BASEDIR";
3160
 
3161
        open (LF, "<", $linkfile ) || Error ("Cannot open link file: $linkfile" );
3162
        while ( <LF> )
3163
        {
3164
            chomp;
3165
            next if ( m~^#~ );
3166
            next unless ( $_ );
3167
            my ($link, $file) = split;
3168
 
3169
            MakeSymLink($file ,"$BASEDIR/$link", '--NoDotDot' );
3170
        }
3171
        close (LF);
3172
        unlink $linkfile;
3173
    }
3174
}
3175
 
3176
#************ INTERNAL USE ONLY  **********************************************
3177
# Function        : ResolveFile
3178
#
3179
# Description     : Determine where the source for a file is
3180
#                   Will look in (default):
3181
#                       Local directory
3182
#                       Local Include
3183
#                   Or  (FromPackage)
3184
#                       Our Package directory
3185
#                       Interface directory (BuildPkgArchives)
3186
#                       Packages (LinkPkgArchive)
3187
#
3188
#                   Will scan 'parts' subdirs
3189
#
3190
# Inputs          : $from_package       - 0 - Local File
3191
#                   $file
3192
#                   $refPlatforms       - Not used
3193
#
3194
# Returns         : Path
3195
#
3196
#************ INTERNAL USE ONLY  **********************************************
3197
sub ResolveFile
3198
{
3199
    my ($from_package, $file,$refPlatforms) = @_;
3200
    my $wildcard = ($file =~ /[*?]/);
3201
    my @path;
3202
 
3203
    #
3204
    #   Determine the paths to search
3205
    #
3206
    if ( $from_package )
3207
    {
3208
        unless ( @ResolveFileList )
3209
        {
3210
            push @ResolveFileList, $opt_pkgdir;
3211
            foreach my $entry ( getPackageList() )
3212
            {
3213
                push @ResolveFileList, $entry->getBase(3);
3214
            }
3215
        }
3216
        @path = @ResolveFileList;
3217
    }
3218
    else
3219
    {
3220
        @path = ('.', $opt_localincdir);
3221
    }
3222
 
3223
    #   Determine a full list of 'parts' to search
3224
    #       Default: Provided within the build information
3225
    #       User   : Can provide a list
3226
    my @parts = getPlatformPartsList($refPlatforms);
3227
 
3228
    my @done;
3229
    foreach my $root (  @path )
3230
    {
3231
        foreach my $subdir ( @parts )
3232
        {
3233
            my $sfile;
3234
            $sfile = "$root/$subdir/$file";
3235
            $sfile =~ s~//~/~g;
3236
            $sfile =~ s~^./~~g;
3237
            Verbose2("LocateFile: $sfile, $root, $subdir");
3238
            if ( $wildcard )
3239
            {
3240
                push @done, glob ( $sfile );
3241
            }
3242
            else
3243
            {
3244
                push @done, $sfile if ( -f $sfile || -l $sfile )
3245
            }
3246
        }
3247
    }
3248
 
3249
    DisplaySearchPath('ResolveFile', $file, \@parts, undef, \@path) unless (@done) ;
3250
 
3251
    Warning ("ResolveFile: Multiple instances of file found. Only first is used", @done)
3252
        if ( $#done > 0 && ! $wildcard && !wantarray );
3253
 
3254
    return wantarray ? @done : $done[0];
3255
}
3256
 
3257
#-------------------------------------------------------------------------------
3258
# Function        : ResolveBinFile
3259
#
3260
# Description     : Determine where the source for a BIN file is
3261
#                   Will look in (default):
3262
#                       Local directory
3263
#                       Local Include
3264
#                   Or  (FromPackage)
3265
#                       Our Package directory
3266
#                       Interface directory (BuildPkgArchives)
3267
#                       Packages (LinkPkgArchive)
3268
#                   Will scan 'parts' subdirs (default)
3269
#                   May scan user-provided parts (cross platform packaging)
3270
#
3271
# Inputs          : $from_package       - 0 - Local File
3272
#                   $file
3273
#                   $refPlatforms       - (optional) Ref to an array of platforms to scan
3274
#
3275
# Returns         : Path
3276
#
3277
sub ResolveBinFile
3278
{
3279
    my ($from_package, $file, $refPlatforms) = @_;
3280
    my @path;
3281
    my @types;
3282
    my $wildcard = ($file =~ /[*?]/);
3283
 
3284
    #
3285
    #   Determine the paths to search
3286
    #
3287
    if ( $from_package )
3288
    {
3289
        unless ( @ResolveBinFileList )
3290
        {
3291
            push @ResolveBinFileList, $opt_pkgdir . '/bin';
3292
            foreach my $entry ( getPackageList() )
3293
            {
3294
                if ( my $path = $entry->getBase(3) )
3295
                {
3296
                    $path .= '/bin';
3297
                    push @ResolveBinFileList, $path if ( -d $path );
3298
                }
3299
            }
3300
        }
3301
        @path = @ResolveBinFileList;
3302
        @types = ($opt_type, '');
3303
    }
3304
    else
3305
    {
3306
        @path = ($opt_bindir, $opt_localbindir);
3307
        @types = '';
3308
    }
3309
 
3310
    #
3311
    #   Determine a full list of 'parts' to search
3312
    #       Default: Provided within the build information
3313
    #       User   : Can provide a list
3314
    #
3315
    my @parts = getPlatformPartsList($refPlatforms);
3316
 
3317
    my @done;
3318
    foreach my $root (  @path )
3319
    {
3320
        foreach my $subdir ( @parts )
3321
        {
3322
            foreach my $type ( @types )
3323
            {
3324
                my $sfile;
3325
                $sfile = "$root/$subdir$type/$file";
3326
                $sfile =~ s~//~/~g;
3327
                Verbose2("LocateBinFile: $sfile");
3328
                if ( $wildcard )
3329
                {
3330
                    foreach  ( glob ( $sfile ) )
3331
                    {
3332
                        # Ignore .dbg (vix) and .debug (qt) files.
3333
                        next if ( m~\.dbg$~ );
3334
                        next if ( m~\.debug$~ );
3335
                        push @done, $_;
3336
                    }
3337
                }
3338
                else
3339
                {
3340
                    push @done, $sfile if ( -f $sfile || -l $sfile )
3341
                }
3342
            }
3343
        }
3344
    }
3345
 
3346
    #
3347
    #   Pretty display the search path - on error
3348
    #       Will not return.
3349
    #
3350
    DisplaySearchPath('ResolveBinFile', $file, \@parts, \@types, \@path) unless (@done) ;
3351
 
3352
    if ( $#done > 0 && ! $wildcard )
3353
    {
3354
        Warning ("ResolveBinFile: Multiple instances of file found. Only first is used", @done);
3355
        splice (@done, 1);
3356
    }
3357
 
3358
    return wantarray ? @done : $done[0];
3359
}
3360
 
3361
#-------------------------------------------------------------------------------
3362
# Function        : ResolveLibFile
3363
#
3364
# Description     : Determine where the source for a LIB file is
3365
#                   Will look in (default):
3366
#                       Local directory
3367
#                       Local Include
3368
#                   Or  (FromPackage)
3369
#                       Our Package directory
3370
#                       Interface directory (BuildPkgArchives)
3371
#                       Packages (LinkPkgArchive)
3372
#                   Will scan 'parts' subdirs
3373
#
3374
# Inputs          : $from_package   - 0:Local File
3375
#                   $file           - Basename for a 'realname'
3376
#                                     Do not provide 'lib' or '.so' or version info
3377
#                                     May contain embedded options
3378
#                                       --Dll           - Use Windows style versioned DLL
3379
#                                       --VersionDll    - Use the versioned DLL
3380
#                                       --3rdParty      - Use exact name provided
3381
#                   $refPlatforms       - Ref to an array of platforms to scan
3382
#
3383
# Returns         : Path
3384
#
3385
sub ResolveLibFile
3386
{
3387
    my ($from_package, $file, $refPlatforms) = @_;
3388
    my $wildcard = ($file =~ /[*?]/);
3389
    my @options;
3390
    my $num_dll;
3391
    my @types;
3392
    my @path;
3393
    #
3394
    #   Extract options from file
3395
    #
3396
    $num_dll = 0;
3397
    ($file, @options) = split ( ',', $file);
3398
    foreach ( @options )
3399
    {
3400
        if ( m/^--Dll/ ) {
3401
            $num_dll = 1;
3402
        } elsif ( m/^--VersionDll/ ) {
3403
            $num_dll = 2;
3404
        } elsif ( m/^--3rdParty/ ) {
3405
            $num_dll = 3;
3406
        } else {
3407
            Error ("Unknown suboption to ResolveLibFile: $_" );
3408
        }
3409
    }
3410
 
3411
    #
3412
    #   Determine the paths to search
3413
    #
3414
    if ( $from_package )
3415
    {
3416
        unless ( @ResolveLibFileList )
3417
        {
3418
            push @ResolveLibFileList, $opt_pkgdir . '/lib';
3419
            foreach my $entry ( getPackageList() )
3420
            {
3421
                push @ResolveLibFileList, $entry->getLibDirs(3);
3422
            }
3423
        }
3424
        @path = @ResolveLibFileList;
3425
    }
3426
    else
3427
    {
3428
        @path = ($opt_libdir, $opt_locallibdir);
3429
    }
3430
 
3431
    #   Determine a full list of 'parts' to search
3432
    #       Default: Provided within the build information
3433
    #       User   : Can provide a list
3434
    my @parts = getPlatformPartsList($refPlatforms);
3435
 
3436
    @types = ( $opt_type, '');
3437
 
3438
    my @done;
3439
    foreach my $root (  @path )
3440
    {
3441
        foreach my $type ( @types )
3442
        {
3443
            foreach my $subdir ( @parts )
3444
            {
3445
                my $sfile;
3446
                my $exact;
3447
                if ( $num_dll == 2 ) {
3448
                    $sfile = $file . $type . '.*.dll' ;
3449
                } elsif ( $num_dll == 1 ) {
3450
                    $sfile = $file . $type . '.dll' ;
3451
                    $exact = 1;
3452
                } elsif ( $num_dll == 3 ) {
3453
                    $sfile = $file;
3454
                    $exact = 1;
3455
                } else {
3456
                    $sfile = "lib" . $file . $type . '.so.*';
3457
                }
3458
 
3459
                $sfile = "$root/$subdir/$sfile";
3460
                $sfile =~ s~//~/~g;
3461
                Verbose2("LocateLibFile: $sfile");
3462
                if ( $exact )
3463
                {
3464
                    push @done, $sfile if ( -f $sfile || -l $sfile );
3465
                }
3466
                elsif ($num_dll)
3467
                {
3468
                    push @done, glob ( $sfile );
3469
                }
3470
                else
3471
                {
3472
                    #
3473
                    #   Looking for .so files
3474
                    #   Filter out the soname so files
3475
                    #   Assume that the soname is shorter than the realname
3476
                    #       Ignore .dbg (vix) and .debug (qt) files.
3477
                    #
3478
                    my %sieve;
3479
                    foreach ( glob ( $sfile )  )
3480
                    {
3481
                        next if ( m~\.dbg$~ );
3482
                        next if ( m~\.debug$~ );
3483
                        m~(.*\.so\.)([\d\.]*\d)$~;
3484
                        if ( $1 )
3485
                        {
3486
                            my $file = $1;
3487
                            my $len = exists $sieve{$file} ? length($sieve{$file}) : 0;
3488
                            $sieve{$file} = $_
3489
                                if ( $len == 0 || length($_) > $len );
3490
                        }                                
3491
                    }
3492
 
3493
                    push @done, values %sieve;
3494
                }
3495
            }
3496
        }
3497
    }
3498
 
3499
    DisplaySearchPath('ResolveLibFile', $file, \@parts, \@types, \@path) unless (@done) ;
3500
 
3501
    if ( $#done > 0 && ! $wildcard )
3502
    {
3503
        Warning ("ResolveLibFile: Multiple instances of file found. Only first is used", @done);
3504
        splice (@done, 1);
3505
    }
3506
    return wantarray ? @done : $done[0];
3507
}
3508
 
3509
#-------------------------------------------------------------------------------
3510
# Function        : ResolveDebPackage
3511
#
3512
# Description     : Determine where the source for a Debian Package is
3513
#                   Will look in (default):
3514
#                       Local directory
3515
#                       Local Include
3516
#                   Or  (FromPackage)
3517
#                       Our Package directory
3518
#                       Interface directory (BuildPkgArchives)
3519
#                       Packages (LinkPkgArchive)
3520
#
3521
# Inputs          : $from_package   - 0:Local File
3522
#                   $baseName       - Basename for a 'DebianPackage'
3523
#                                     Do not provide version info, architecture or suffix
3524
#                                     May contain embedded options
3525
#                                       --Arch=XXX      - Specify alternate architcuture
3526
#                                       --Product=YYYY  - Specify product family
3527
#                                       --Debug         - Use alternate build type
3528
#                                       --Prod          - Use alternate build type
3529
#                   $refPlatforms       - Ref to an array of platforms to scan
3530
#
3531
# Returns         : Path
3532
#
3533
sub ResolveDebPackage
3534
{
3535
    my ($from_package, $file, $refPlatforms) = @_;
3536
    my @path;
3537
    my $arch;
3538
    my $product;
3539
    my $buildType;
3540
    my @types;
3541
    my $baseName;
3542
    my @options;
3543
 
3544
    #
3545
    #   Extract options from file
3546
    #
3547
    ($baseName, @options) = split ( ',', $file);
3548
    foreach ( @options )
3549
    {
3550
        if ( m/^--Arch=(.+)/ ) {
3551
            $arch=$1;
3552
        } elsif ( m/^--Product=(.+)/ ) {
3553
            $product = $1;
3554
        } elsif ( m/^--Debug/ ) {
3555
            Error ("ResolveDebPackage: Cannot specify --Prod and --Debug") if defined $buildType;
3556
            $buildType = 'D';
3557
        } elsif ( m/^--Prod/ ) {
3558
            Error ("ResolveDebPackage: Cannot specify --Prod and --Debug") if defined $buildType;
3559
            $buildType = 'P';
3560
        } else {
3561
            Error ("Unknown suboption to ResolveDebPackage: $_" );
3562
        }
3563
    }
3564
 
3565
    #
3566
    #   Insert defaults
3567
    #
3568
    $buildType = $opt_type unless ($buildType);
3569
    $arch = $opt_target unless ($arch);
3570
 
3571
    #
3572
    #   Determine the paths to search
3573
    #
3574
    if ( $from_package )
3575
    {
3576
        unless ( @ResolveDebFileList )
3577
        {
3578
            push @ResolveDebFileList,  $opt_pkgdir, $opt_pkgdir . '/bin';
3579
            foreach my $entry ( getPackageList() )
3580
            {
3581
                if ( my $path = $entry->getBase(3) )
3582
                {
3583
                    push @ResolveDebFileList, $path if ( -d $path );
3584
 
3585
                    $path .= '/bin';
3586
                    push @ResolveDebFileList, $path if ( -d $path );
3587
                }
3588
            }
3589
        }
3590
        @path = @ResolveDebFileList;
3591
        @types = ($buildType, '');
3592
    }
3593
    else
3594
    {
3595
        @path = ($opt_bindir, $opt_localbindir);
3596
        @types = ($buildType, '');
3597
    }
3598
 
3599
    #
3600
    #   The debian  package name is
3601
    #   In packages BIN dir
3602
    #       (BaseName)_VersionString(_Product)(_Arch).deb
3603
    #       
3604
    #   In root of package
3605
    #       (BaseName)_VersionString(_Product)(_Arch)(_Type).deb
3606
    #
3607
    #       
3608
    #   The package may be found in
3609
    #       Package Root
3610
    #       Package bin directory
3611
    #       
3612
    $file = $baseName . '_*';
3613
    if (defined $product) {
3614
        $file .= ( '_' . $product)
3615
        }
3616
    $file .= '_' . $arch;
3617
 
3618
    #   Determine a full list of 'parts' to search
3619
    #       Default: Provided within the build information
3620
    #       User   : Can provide a list
3621
    my @parts = getPlatformPartsList($refPlatforms);
3622
 
3623
    my @done;
3624
    foreach my $root (  @path )
3625
    {
3626
        foreach my $subdir ( @parts )
3627
        {
3628
            foreach my $type ( @types )
3629
            {
3630
                my $sfile;
3631
                $sfile = "$root/$subdir$type/$file";
3632
                $sfile =~ s~//~/~g;
3633
                foreach my $type2 ( @types )
3634
                {
3635
                    my $tfile = $sfile;
3636
                    $tfile .= '_' . $type2 if $type2;
3637
                    $tfile .= '.deb';
3638
                    Verbose2("ResolveDebPackage: $tfile");
3639
                    foreach  ( glob ( $tfile ) )
3640
                    {
3641
                        push @done, $_;
3642
                    }
3643
                }
3644
            }
3645
        }
3646
    }
3647
 
3648
    DisplaySearchPath('ResolveDebPackage', $file, \@parts, \@types, \@path) unless (@done) ;
3649
 
3650
    if ( $#done > 0 )
3651
    {
3652
        Error ("ResolveDebPackage: Multiple instances of Package found.", @done);
3653
    }
3654
    return wantarray ? @done : $done[0];
3655
}
3656
 
3657
#-------------------------------------------------------------------------------
3658
# Function        : prettyArray 
3659
#
3660
# Description     : Generate a quoted string from an array
3661
#
3662
# Inputs          : Array Ref
3663
#
3664
# Returns         : A string
3665
#
3666
sub prettyArray
3667
{
3668
    my ($arrayRef) = @_;
3669
    return join(',', map { qq!"$_"! }  @{$arrayRef})
3670
}
3671
 
3672
#-------------------------------------------------------------------------------
3673
# Function        : DisplaySearchPath 
3674
#
3675
# Description     : Pretty display of the search path
3676
#                   Error display
3677
#
3678
# Inputs          : $name   - Function Name
3679
#                   $file   - Base filename being searched
3680
#                   $parts  - Ref to array of parts searched
3681
#                   $types  - Ref to array of types searched - may be undef
3682
#                   $path   - Ref to array of paths searched
3683
#
3684
# Returns         : Will not return
3685
#
3686
sub DisplaySearchPath
3687
{
3688
    my ($name, $file, $parts, $types, $path) = @_;
3689
    my @text;
3690
 
3691
    push @text, $name . ': File not found: ' . $file;
3692
    push @text, 'Search Platforms: ' . prettyArray($parts);
3693
    push @text, 'Search Types: ' . prettyArray($types) if defined $types;
3694
    push @text, 'Search Path:', @$path;
3695
    Error (@text);
3696
}
3697
 
3698
#-------------------------------------------------------------------------------
3699
# Function        : getPlatformPartsList  
3700
#
3701
# Description     : Determine a full list of 'parts' to search
3702
#                       Default: Provided within the build information
3703
#                       User   : Can provide a list
3704
#
3705
# Inputs          : $refPlatforms - Ref to an array of user provided platforms
3706
#                                   If provided will override the internal list
3707
#
3708
# Returns         : An array 
3709
#
3710
sub getPlatformPartsList
3711
{
3712
    my ($refPlatforms) = @_;
3713
    my @parts;
3714
 
3715
    if ($refPlatforms && scalar @{$refPlatforms}) {
3716
        @parts = @{$refPlatforms};
3717
 
3718
    } else {
3719
        @parts = getPlatformParts ();
3720
    }
3721
    push @parts, '';
3722
    return @parts;
3723
}
3724
 
3725
#-------------------------------------------------------------------------------
3726
# Function        : AUTOLOAD
3727
#
3728
# Description     : Intercept unknown user directives and issue a nice error message
3729
#                   This is a simple routine to report unknown user directives
3730
#                   It does not attempt to distinguish between user errors and
3731
#                   programming errors. It assumes that the program has been
3732
#                   tested. The function simply report filename and line number
3733
#                   of the bad directive.
3734
#
3735
# Inputs          : Original function arguments ( not used )
3736
#
3737
# Returns         : This function does not return
3738
#
3739
our $AUTOLOAD;
3740
sub AUTOLOAD
3741
{
3742
    my $fname = $AUTOLOAD;
3743
    $fname =~ s~^main::~~;
3744
    my ($package, $filename, $line) = caller;
3745
    my $prefix;
3746
 
3747
    #
3748
    #   Some directives are applicable to Rpm and/or Debian only
3749
    #   If a directive starts with Rpm, Debian or All, then invoke
3750
    #   the underlying directive iff we are process a Debian/Rpm file
3751
    #   
3752
    #   The underlying directive will start with MULTI_
3753
    #   It will be called with the first argument being the name of the function
3754
    #   that it is being called as.
3755
    #
3756
    $fname =~ m~^(Rpm|Debian|All)(.*)~;
3757
    if (defined $1) {
3758
        my $type = $1;
3759
        my $tfname = 'MULTI_' . $2;
3760
        my $fRef = \&{$tfname}; 
3761
 
3762
        if (defined &{$tfname}) {
3763
            if ($type eq 'Rpm') {
3764
                $fRef->($fname, @_) if $opt_rpm;
3765
 
3766
            } elsif ($type eq 'Debian') {
3767
                $fRef->($fname, @_) if $opt_debian;
3768
 
3769
            } elsif ($type eq 'All') {
3770
                $fRef->($fname, @_);
3771
            }
3772
            return 1;
3773
        }
3774
    }
3775
 
3776
    Error ("Directive not known or not allowed in this context: $fname",
3777
           "Directive: $fname( @_ );",
3778
           "File: " . RelPath($filename) . ", Line: $line" );
3779
}
3780
 
3781
1;
3782