Subversion Repositories DevTools

Rev

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

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