Subversion Repositories DevTools

Rev

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

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