Subversion Repositories DevTools

Rev

Rev 6988 | Rev 7398 | 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
    #
7268 dpurdie 894
    #   On many packages the RPM "Checking for unpackaged file(s)" 
895
    #   can take a long while (minutes). It can't be disabled
896
    #   but it can be made faster by disabling compression of the RPM
897
    #   
898
    print $sf "\n%define _unpackaged_files_terminate_build 0\n";
899
    print $sf "\n%define _source_payload w0.gzdio\n";
900
    print $sf "\n%define _binary_payload w0.gzdio\n";
901
 
902
    #
6242 dpurdie 903
    #   Insert the list of files to be processed
904
    #       Can't use /* as this will mess with permissions of the root directory. 
905
    #       Can list Top Level directories and then use *
906
    #
907
    print $sf "\n%files\n";
908
    print $sf "%defattr(",join (',', @RpmDefAttr),")\n";
909
    GenerateRedHatFileList ($sf);
910
    print $sf "\n";
911
    close ($sf);
912
}
913
 
914
#-------------------------------------------------------------------------------
915
# Function        : GenerateRedHatFileList 
916
#
917
# Description     : Internal function
918
#                   Generate a file list to be inserted into an RPM spec file
919
#
920
# Inputs          : $fd     - File descriptor.
921
#                             Function will write directly to the output
922
#
923
# Returns         : Nothing 
924
#
925
sub GenerateRedHatFileList
926
{
927
    my ($fd) = @_;
928
 
929
    #
930
    #   Sanity Test
931
    #
932
    Warning ("No directories has been marked as 'Owned'",
933
             "Under RedHat a directory must be 'owned' by a package so that it can be removed.",
934
             "This ownership may be in that package or a 'Required' package.",
935
             "This ownership may be shared or exclusive.",
936
             ) unless scalar keys %OwnedDirs;
937
 
938
    #
939
    #   Flag files and directories with attributes
940
    #
941
    my %Attrs;
942
    my %Dirs;
943
    foreach my $item ( @RpmAttrList ) {
944
        my $file =  $item->[0]; 
945
        my $full_path = $WorkDirInit . $file;
946
        $Attrs{$file} =  '%attr(' . join(',',@{$item}[1..3] ) . ')';
947
        $Dirs{$file} = '%dir' if (-d $full_path);
948
    }
949
 
950
    #
951
    #   Flag configuration files ( ConfFile )
952
    #
953
    my %Configs;
954
    foreach my $item (@ConfigList) {
955
        $Configs{$item} = '%config';
956
    }
957
 
958
    #
959
    #   Internal subroutine to pretty-print a file/dirname with attributes
960
    #       $path   - path element
961
    #       $isDir  - True if a directory
962
    #   
963
    my $printer = sub {
964
        my ($path, $isDir) = @_;
965
        my $attrText =  delete $Attrs{$path};
966
        my $confText =  delete $Configs{$path};
967
        my $dirText  =  delete $Dirs{$path};
968
        $dirText = '%dir' if $isDir;
969
 
970
        my $txt;
971
        my $joiner = '';
972
        $path = '"' . $path . '"';
973
        foreach ($attrText,$dirText,$confText, $path) {
974
            next unless $_;
975
            $txt .= $joiner . $_;
976
            $joiner = ' ';
977
        }
978
        print $fd ("$txt\n");
979
    };
980
 
981
    #
982
    #   List all files in the tree
983
    #       If we use wildcards we get interpackage dependency issues
984
    #       Process files and directories
985
    #
986
    my $search =  JatsLocateFiles->new( '--Recurse', '--NoFullPath', '--DirsToo' );
987
    my @flist = $search->search($WorkDirInit);
988
    foreach (@flist) {
989
        my $file = '/' . $_;
990
        my $full_path = $WorkDirInit . $file;
991
        my $isDir = (-d $full_path) || 0;
992
 
993
        #
994
        #   Determine if the element is within a known RootDir
995
        #
996
        my $inRoot = 0;
997
        my $isOwner = 0;
998
        foreach (keys %OwnedDirs) {
999
            if ($file =~ m~^$_~) {
1000
                $inRoot = 1;
1001
                $isOwner = $OwnedDirs {$_};
1002
                last;
1003
            }
1004
        }
1005
 
1006
        #
1007
        #   Ignore directories that are not within a RootDir
1008
        #   
1009
        unless ($inRoot) {
1010
            next if $isDir;
1011
        }
1012
 
1013
        #
1014
        #   Ignore directories that are not within an 'owned' directory
1015
        #
1016
        if ( !$isOwner && $isDir ) {
1017
            next;
1018
        }
1019
 
1020
        &$printer($file, $isDir);
1021
    }
1022
 
1023
    #
1024
    #   Sanity tests
1025
    #   We should have process all the Configs and Attributes
1026
    #
1027
    if ( (keys %Configs) || ( keys %Attrs))
1028
    {
1029
        Error ("Internal Error. Unprocessed Config or Attributes.",
1030
               keys %Configs, keys %Attrs );
1031
    }
1032
 
1033
}
1034
 
1035
#-------------------------------------------------------------------------------
1036
# Function        : SetVerbose
1037
#
1038
# Description     : Set the level of verbosity
1039
#                   Display activity
1040
#
1041
# Inputs          : Verbosity level
1042
#                       0 - Use makefile verbosity (Default)
1043
#                       1..2
1044
#
1045
# Returns         : 
1046
#
1047
sub SetVerbose
1048
{
1049
    return 1 unless ($ActiveSection);
1050
    my ($level) = @_;
1051
 
1052
    $level = $opt_verbose unless ( $level );
1053
    $opt_verbose = $level;
1054
    ErrorConfig( 'verbose' => $level);
1055
}
1056
 
1057
#-------------------------------------------------------------------------------
1058
# Function        : SetBaseDir 
1059
#
1060
# Description     : Sets the root directory for all directories
1061
#                   Used to simplify scripts
1062
#                   
1063
# Inputs          : $path           - Absolute path. Now within the RootDir
1064
#                   @options        - As for CreateDir
1065
#
1066
# Returns         : Nothing 
1067
#                   Sets $WorkDir
1068
#
1069
sub SetBaseDir
1070
{
1071
    my ($path, @opts) = @_;
1072
    return 1 unless ($ActiveSection);
1073
 
1074
    my $rootdir = $path || '/';
1075
    $rootdir = '/' . $rootdir;
1076
    $rootdir =~ s~/+~/~g; 
1077
    Verbose ("Setting RootDir: $rootdir");
1078
 
1079
    #
1080
    #   Create the directory
1081
    #
1082
    $WorkDir = $WorkDirInit;
1083
    CreateDir ($rootdir, @opts);
1084
    $WorkSubDir = $rootdir;
1085
    $WorkDir = $WorkDirInit . $rootdir;
1086
}
1087
 
1088
#-------------------------------------------------------------------------------
1089
# Function        : DebianFiles
1090
#                   RpmFiles
1091
#                   AllFiles
1092
#
1093
# Description     : Name Debian and RPM builder control files
1094
#                   May be called multiple times
1095
#
1096
# Inputs          :   $fName    - Name under which the function is being called
1097
#                     Options
1098
#                       --Control=file
1099
#                       --PreRm=file
1100
#                       --PostRm=file
1101
#                       --PreInst=file
1102
#                       --PostInst=file
1103
#                       --SimpleSharedLibs
1104
#                         
1105
#
1106
# Returns         : Nothing
1107
#
1108
sub MULTI_Files
1109
{
1110
    my $fName = shift;
1111
    return 1 unless ($ActiveSection);
1112
    Verbose ("Specify Installer Control Files and Scripts");
1113
    foreach  ( @_ )
1114
    {
1115
        if ( m/^--Control=(.+)/i ) {
1116
            MULTI_ControlFile($fName, 'control',$1)
1117
 
1118
        } elsif ( m/^--PreRm=(.+)/i ) {
1119
            MULTI_ControlFile($fName, 'prerm',$1)
1120
 
1121
        } elsif ( m/^--PostRm=(.+)/i ) {
1122
            MULTI_ControlFile($fName, 'postrm',$1)
1123
 
1124
        } elsif ( m/^--PreInst=(.+)/i ) {
1125
            MULTI_ControlFile($fName, 'preinst',$1)
1126
 
1127
        } elsif ( m/^--PostInst=(.+)/i ) {
1128
            MULTI_ControlFile($fName, 'postinst',$1)
1129
 
1130
        } elsif ( m/^--SimpleSharedLibs/i ) {
1131
 
1132
            my $file = catfile($WorkDirBase, 'ldconfig.sh' );
1133
 
1134
            open (my $df, '>', $file) || Error ("$fName: Cannot create:$file");
1135
            print $df "#!/bin/sh\n";
1136
            print $df "/sbin/ldconfig\n";
1137
            print $df "exit 0\n";
1138
            close $df;
1139
 
1140
            MULTI_ControlFile($fName, 'postinst',$file);
1141
            MULTI_ControlFile($fName, 'postrm',$file);
1142
 
1143
        } else {
1144
            Error ("$fName: Unknown option: $_");
1145
        }
1146
    }
1147
}
1148
 
1149
#-------------------------------------------------------------------------------
1150
# Function        : DebianControlFile
1151
#                   RpmControlFile 
1152
#                   AllControlFile
1153
#
1154
# Description     : Add special control files to the Debian/RedHat Installer 
1155
#                   Not useful for embedded installers
1156
#
1157
#                   More general than DebianFiles() or RpmFiles
1158
#
1159
# Inputs          : name            - Target Name
1160
#                                     If the name starts with 'package.' then it will be replaced
1161
#                                     with the name of the current package
1162
#                                     Ideally: prerm, postrm, preinst, postinst
1163
#                   file            - Source File Name
1164
#                   options         - Options include
1165
#                                       --FromPackage
1166
#
1167
# Returns         : 
1168
#
1169
sub MULTI_ControlFile
1170
{
1171
    my ($fName, $name, $file, @options) = @_;
1172
    return 1 unless ($ActiveSection);
1173
    my $fromPackage = 0;
1174
 
1175
    #
1176
    #   Process options
1177
    foreach ( @options)
1178
    {
1179
        if (m~^--FromPackage~) {
1180
            $fromPackage = 1;
1181
        }
1182
        else  {
1183
            ReportError(("$fName: Unknown argument: $_"));
1184
        }
1185
    }
1186
    ErrorDoExit();
1187
 
1188
    #
1189
    #   Some control files need to have the package name prepended
1190
    #
1191
    $name =~ s~^package\.~$opt_name.~;
1192
 
1193
    #
1194
    #   Only allow one file of each type
1195
    #       Try to protect the user by testing for names by lowercase
1196
    #
1197
    my $simpleName = lc($name);
1198
    Error("$fName: Multiple definitions for '$name' not allowed")
1199
        if (exists $ControlFileNames{$simpleName});
1200
 
1201
    my $filePath = ResolveFile($fromPackage, $file);
1202
 
1203
    #
1204
    #   Add info to data structures
1205
    #
1206
    $ControlFiles{$name} = $filePath;
1207
    $ControlFileNames{$simpleName} = $name;
1208
}
1209
 
1210
#-------------------------------------------------------------------------------
1211
# Function        : DebianDepends 
1212
#                   RpmDepends
1213
#                   AllDepends
1214
#
1215
# Description     : This directive allows simple dependency information to be  
1216
#                   inserted into the control file
1217
#                   
1218
#                   Names will be massaged into conforming names.
1219
#
1220
#                   Not useful in embedded system
1221
#
1222
# Inputs          : Entry             - A dependency entry
1223
#                   ...               - More entries
1224
#                   Options
1225
#                       --Raw          - Prevent name modification
1226
#                       --NoRaw        - Enable name modification
1227
#                   
1228
#
1229
# Returns         : Nothing
1230
#
1231
sub MULTI_Depends
1232
{
1233
    return 1 unless ($ActiveSection);
1234
    shift;
1235
    my $raw = 0;
1236
 
1237
    #
1238
    #   Convert the provided name into a canonical name
1239
    #   Simplifies use when using both RPM and Debian
1240
    foreach ( @_)
1241
    {
1242
        if (m~^--(No)?Raw~i) {
1243
            $raw = ! defined($1);
1244
            next;
1245
        }
1246
        my $name = $_;
1247
        $name = canonicalName($_, $opt_rpm ? 'RPM' : 'DEBIAN' , 1) unless $raw;
1248
        push @DependencyList, $name;
1249
    }
1250
 
1251
}
1252
 
1253
#-------------------------------------------------------------------------------
1254
# Function        : PackageDescription
1255
#
1256
# Description     : Specify the Package Description
1257
#                   Keep it short
1258
#
1259
# Inputs          : $description
1260
#
1261
# Returns         : 
1262
#
1263
sub PackageDescription
1264
{
1265
    return 1 unless ($ActiveSection);
1266
    ($opt_description) = @_;
1267
}
1268
 
1269
#-------------------------------------------------------------------------------
1270
# Function        : MakeSymLink
1271
#
1272
# Description     : Create a symlink - with error detection
1273
#
1274
# Inputs          : old_file    - Link Target
1275
#                                 Path to the link target
1276
#                                 If an ABS path is provided, the routine will
1277
#                                 attempt to create a relative link.
1278
#                   new_file    - Relative to the output work space
1279
#                                 Path to where the 'link' file will be created
1280
#                   Options     - Must be last
1281
#                                 --NoClean         - Don't play with links
1282
#                                 --NoDotDot        - Don't create symlinks with ..
1283
#
1284
# Returns         : Nothing
1285
#
1286
sub MakeSymLink
1287
{
1288
    my $no_clean;
1289
    my $no_dot;
1290
    my @args;
1291
    return 1 unless ($ActiveSection);
1292
 
1293
    #
1294
    #   Extract options
1295
    #
1296
    foreach ( @_ )
1297
    {
1298
        if ( m/^--NoClean/i ) {
1299
            $no_clean = 1;
1300
 
1301
        } elsif ( m/^--NoDotDot/i ) {
1302
            $no_dot = 1;
1303
 
1304
        } elsif ( m/^--/ ) {
1305
            Error ("MakeSymLink: Unknown option: $_");
1306
 
1307
        } else {
1308
            push @args, $_;
1309
        }
1310
    }
1311
 
1312
    my ($old_file, $new_file) = @args;
1313
 
1314
    my $tfile = $WorkDir . '/' . $new_file;
1315
    $tfile =~ s~//~/~;
1316
    Verbose ("Symlink $old_file -> $new_file" );
1317
 
1318
    #
1319
    #   Create the directory in which the link will be placed
1320
    #   Remove any existing file of the same name
1321
    #
1322
    my $dir = StripFileExt( $tfile );
1323
    mkpath( $dir) unless -d $dir;
1324
    unlink $tfile;
1325
 
1326
    #
1327
    #   Determine a good name of the link
1328
    #   Convert to a relative link in an attempt to prune them
1329
    #
1330
    my $sfile = $old_file;
1331
    unless ( $no_clean )
1332
    {
1333
        $sfile = CalcRelPath( StripFileExt( $new_file ), $old_file );
1334
        $sfile = $old_file if ( $no_dot && $sfile =~ m~^../~ );
1335
    }
1336
 
1337
    my $result = symlink $sfile, $tfile;
1338
    Error ("Cannot create symlink. $old_file -> $new_file") unless ( $result );
1339
}
1340
 
1341
#-------------------------------------------------------------------------------
1342
# Function        : CopyFile
1343
#
1344
# Description     : Copy a file to a target dir
1345
#                   Used for text files, or files with fixed names
1346
#
1347
# Inputs          : $src
1348
#                   $dst_dir    - Within the output workspace
1349
#                   $dst_name   - Output Name [Optional]
1350
#                   Options     - Common Copy Options
1351
#
1352
# Returns         : Full path to destination file
1353
#
1354
sub CopyFile
1355
{
1356
    return 1 unless ($ActiveSection);
1357
    CopyFileCommon( \&ResolveFile, @_ );
1358
}
1359
 
1360
#-------------------------------------------------------------------------------
1361
# Function        : CopyBinFile
1362
#
1363
# Description     : Copy a file to a target dir
1364
#                   Used for executable programs. Will look in places where
1365
#                   programs are stored.
1366
#
1367
# Inputs          : $src
1368
#                   $dst_dir    - Within the output workspace
1369
#                   $dst_name   - Output Name [Optional]
1370
#
1371
#                   Options:
1372
#                       --FromPackage
1373
#                       --SoftLink=xxxx
1374
#                       --LinkFile=xxxx
1375
#
1376
# Returns         : Full path to destination file
1377
#
1378
sub CopyBinFile
1379
{
1380
    return 1 unless ($ActiveSection);
1381
    CopyFileCommon( \&ResolveBinFile, @_ );
1382
}
1383
 
1384
#-------------------------------------------------------------------------------
1385
# Function        : CopyLibFile
1386
#
1387
# Description     : Copy a file to a target dir
1388
#                   Used for shared programs. Will look in places where
1389
#                   shared libraries are stored.
1390
#
1391
# Inputs          : $src        - Base for 'realname' (no lib, no extension)
1392
#                   $dst_dir    - Within the output workspace
1393
#                   $dst_name   - Output Name [Optional, but not suggested]
1394
#
1395
# Returns         : Full path to destination file
1396
#
1397
# Notes           : Copying 'lib' files
1398
#                   These are 'shared libaries. There is no provision for copying
1399
#                   static libraries.
1400
#
1401
#                   The tool will attempt to copy a well-formed 'realname' library
1402
#                   The soname of the library should be constructed on the target
1403
#                   platform using ldconfig.
1404
#                   There is no provision to copy the 'linker' name
1405
#
1406
#                   Given a request to copy a library called 'fred', then the
1407
#                   well formed 'realname' will be:
1408
#                           libfred[P|D|]].so.nnnnn
1409
#                   where:
1410
#                           nnnn is the library version
1411
#                           [P|D|] indicates Production, Debug or None
1412
#
1413
#                   The 'soname' is held within the realname form of the library
1414
#                   and will be created by lsconfig.
1415
#
1416
#                   The 'linkername' would be libfred[P|D|].so. This is only
1417
#                   needed when linking against the library.
1418
#
1419
#
1420
#                   The routine will also recognize Windows DLLs
1421
#                   These are of the form fred[P|D|].nnnnn.dll
1422
#
1423
sub CopyLibFile
1424
{
1425
    return 1 unless ($ActiveSection);
1426
    CopyFileCommon( \&ResolveLibFile, @_ );
1427
}
1428
 
1429
#-------------------------------------------------------------------------------
1430
# Function        : CopyDebianPackage
1431
#
1432
# Description     : Copy a Debian Package to a target dir
1433
#                   Will look in places where Debian Packages are stored.
1434
#
1435
# Inputs          : $src        - BaseName for 'Debian Package' (no version, no extension)
1436
#                   $dst_dir    - Within the output workspace
1437
#                   Optional arguments embedded into the BaseName
1438
#                   --Arch=XXXX         - Architecture - if not current
1439
#                   --Product=XXXX      - Product - if required
1440
#                   --Debug             - If not the current type
1441
#                   --Prod              - If not the current type
1442
#
1443
# Returns         : Full path to destination file
1444
#
1445
# Notes           : Copying Debian Packages from external packages
1446
#
1447
#                   The tool will attempt to copy a well-formed debian packages
1448
#                   These are:
1449
#                   
1450
#                       "BaseName_VersionString[_Product]_Arch${PkgType}.deb";
1451
#                   
1452
#                   Where 'Product' is optional (and rare)
1453
#                   Where 'PkgType' is P or D or nothing
1454
#                   Where 'Arch' may be 'all'
1455
#                   
1456
#                   The routine will locate Debian packages in
1457
#                       - The root of the package
1458
#                       - bin/TARGET[P|D/]
1459
#                       - bin/Arch[P|D]
1460
#
1461
#
1462
sub CopyDebianPackage
1463
{
1464
    return 1 unless ($ActiveSection);
1465
    CopyFileCommon( \&ResolveDebPackage, '--FromPackage', @_ );
1466
}
1467
 
1468
#-------------------------------------------------------------------------------
1469
# Function        : CopyFileCommon
1470
#
1471
# Description     : Common ( internal File Copy )
1472
#
1473
# Inputs          : $resolver           - Ref to function to resolve source file
1474
#                   $src                - Source File Name
1475
#                   $dst_dir            - Target Dir
1476
#                   $dst_name           - Target Name (optional)
1477
#                   Options
1478
#                   Options:
1479
#                       --FromPackage
1480
#                       --FromBuild
1481
#                       --SoftLink=xxxx
1482
#                       --LinkFile=xxxx
1483
#                       --ConfFile
1484
#                       --Platform=xxxx[,yyyyy]
1485
#
1486
# Returns         : 
1487
#
1488
sub CopyFileCommon
1489
{
1490
    my $from_package = 0;
1491
    my $isa_linkfile = 0;
1492
    my $isa_configFile = 0;
1493
    my @llist;
1494
    my @args;
1495
    my @platforms;
1496
 
1497
    #
1498
    #   Parse options
1499
    #
1500
    foreach ( @_ )
1501
    {
1502
        if ( m/^--FromPackage/ ) {
1503
            $from_package = 1;
1504
 
1505
        } elsif ( m/^--FromBuild/ ) {
1506
            $from_package = 0;
1507
 
1508
        } elsif ( m/^--LinkFile/ ) {
1509
            $isa_linkfile = 1;
1510
 
1511
        } elsif ( m/^--ConfFile/i ) {
1512
            $isa_configFile = 1;
1513
 
1514
        } elsif ( m/^--SoftLink=(.+)/ ) {
1515
            push @llist, $1;
1516
 
1517
        } elsif ( m/^--Platform=(.+)/ ) {
1518
            push @platforms, split(',', $1 );
1519
 
1520
        } elsif ( m/^--/ ) {
1521
            Error ("FileCopy: Unknown option: $_");
1522
 
1523
        } else {
1524
            push @args, $_;
1525
        }
1526
    }
1527
 
1528
    #
1529
    #   Extract non-options.
1530
    #   These are the bits that are left over
1531
    #
1532
    my ($resolver, $src, $dst_dir, $dst_name ) = @args;
1533
 
1534
    #
1535
    #   Clean up dest_dir. Must start with a / and not end with one
1536
    #
1537
    $dst_dir = "/$dst_dir/";
1538
    $dst_dir =~ s~/+~/~g;
1539
    $dst_dir =~ s~/$~~;
1540
 
1541
    Verbose ("CopyFile: $src, $dst_dir, " . ($dst_name || ''));
1542
    foreach $src ( &$resolver( $from_package, $src, \@platforms ) )
1543
    {
1544
        my $dst_fname = $dst_name ? $dst_name : StripDir($src);
1545
        my $dst_file = "$dst_dir/$dst_fname";
1546
        Verbose ("CopyFile: Copy $src, $dst_file" );
1547
 
1548
 
1549
        #
1550
        #   LinkFiles are special
1551
        #   They get concatenated to any existing LINKS File
1552
        #
1553
        if ( $isa_linkfile )
1554
        {
1555
            CatFile ( $src, "$dst_dir/.LINKS" );
1556
        }
1557
        else
1558
        {
1559
            mkpath( "$WorkDir$dst_dir", 0, 0775);
1560
            unlink ("$WorkDir$dst_file");
1561
            System ('cp','-f', $src, "$WorkDir$dst_file" );
1562
 
1563
            foreach my $lname ( @llist )
1564
            {
1565
                $lname = $dst_dir . '/' . $lname unless ( $lname =~ m ~^/~ );
1566
                MakeSymLink( $dst_file ,$lname);
1567
            }
1568
        }
1569
 
1570
        #
1571
        #   ConfigFiles are marked so that they can be handled by the debain installer
1572
        #
1573
        if ($isa_configFile)
1574
        {
1575
            push @ConfigList, $WorkSubDir . $dst_file;
1576
        }
1577
    }
1578
}
1579
 
1580
#-------------------------------------------------------------------------------
1581
# Function        : ExtractTar 
1582
#
1583
# Description     : Extract a tar file into a target directory
1584
#                   Useful for massive structures and those with embedded symlinks
1585
#                   Performs an implicit merge
1586
#                   Will create output root if it does not exist
1587
#
1588
# Inputs          : $srcTar      - Source Tar file
1589
#                   $dst_dir     - Within the output workspace
1590
#                   Options
1591
#                       --Source=Name           - Source via Symbolic Name
1592
#                       --FromPackage           - Source via package roots
1593
#                       --Strip=nn              - Strip nn path elements from the dir
1594
#
1595
# Returns         : 
1596
#
1597
sub ExtractTar
1598
{
1599
    my ($srcTar, $dst_dir, @opts) = @_;
1600
    my $userSrcTar = $srcTar;
1601
    my $opt_source;
1602
    my $opt_package;
1603
    my $opt_strip;
1604
    my $opt_base;
1605
    my $from_interface;
1606
    my $dname = StripDir($userSrcTar);
1607
    my $errConfig = ErrorReConfig( prefix => "ExtractTar($dname): ");
1608
    #
1609
    #   Setup the basic options
1610
    #       May be altered as we parse user options
1611
    #
1612
    $dst_dir = $WorkDir . '/' . $dst_dir;
1613
    $dst_dir =~ s~//~/~;
1614
 
1615
    #
1616
    #   Scan and collect user options
1617
    #
1618
    foreach  ( @opts )
1619
    {
1620
        Verbose2 ("$_");
1621
        if ( m/^--Source=(.+)/ ) {
1622
            Error ("Source directory can only be specified once")
1623
                if ( defined $opt_source );
1624
            $opt_source = $1;
1625
 
1626
        } elsif ( m/^--FromPackage/ ) {
1627
            Error ("FromPackage can only be specified once")
1628
                if ( defined $opt_package );
1629
            $opt_package = 1;
1630
 
1631
        } elsif ( m/^--Strip=(\d+)$/i ) {
1632
            Error ("Strip can only be specified once")
1633
                if ( defined $opt_package );
1634
            $opt_strip = $1;
1635
 
1636
        } else {
1637
            Error ("Unknown option: $_" );
1638
        }
1639
    }
1640
 
1641
    #
1642
    #   All options have been gathered. Now process some of them
1643
    #
1644
    Error ("Cannot use both --Source and --FromPackage: $srcTar") if ($opt_source && $opt_package);
1645
 
1646
    #
1647
    #   Convert a symbolic path into a physical path
1648
    #
1649
    if ($opt_source)
1650
    {
1651
        Verbose2 ("Determine Source: $opt_source");
1652
 
1653
        $opt_source = lc($opt_source);
1654
        my %ExtractTarSymbolic = (
1655
            'interfaceincdir'   => $opt_interfaceincdir,
1656
            'interfacelibdir'   => $opt_interfacelibdir,
1657
            'interfacebindir'   => $opt_interfacebindir,
1658
            'libdir'            => $opt_libdir,
1659
            'bindir'            => $opt_bindir,
1660
            'localincdir'       => $opt_localincdir,
1661
            'locallibdir'       => $opt_locallibdir,
1662
            'localbindir'       => $opt_localbindir,
1663
            'packagebindir'     => $opt_pkgbindir,
1664
            'packagelibdir'     => $opt_pkglibdir,
1665
            'packagepkgdir'     => $opt_pkgpkgdir,
1666
            'packagedir'        => $opt_pkgdir,
1667
        );
1668
 
1669
        if ( exists $ExtractTarSymbolic{$opt_source} )
1670
        {
1671
            $opt_base = $ExtractTarSymbolic{$opt_source};
1672
 
1673
            #
1674
            #   If sourceing from interface, then follow
1675
            #   symlinks in the copy. All files will be links anyway
1676
            #
1677
            $from_interface = 1
1678
                if ( $opt_source =~ m~^interface~ );
1679
        }
1680
        else
1681
        {
1682
            DebugDumpData ("ExtractTarSymbolic", \%ExtractTarSymbolic);
1683
            Error ("Unknown Source Name: $opt_source" );
1684
        }
1685
    }
1686
 
1687
    #
1688
    #   Locate the path within an external package
1689
    #
1690
    if ($opt_package)
1691
    {
1692
        Verbose2 ("FromPackage: $srcTar");
1693
 
1694
        my @path;
1695
        my @scanned;
1696
        foreach my $entry ( getPackageList() )
1697
        {
1698
            my $base = $entry->getBase(3);
1699
            next unless ( defined $base );
1700
            push @scanned, $base;
1701
            if ( -f $base . '/' . $srcTar )
1702
            {
1703
                push @path, $base;
1704
                $from_interface = 1
1705
                    if ( $entry->{'TYPE'} eq 'interface' );
1706
            }
1707
        }
1708
 
1709
        if ( $#path < 0 )
1710
        {
1711
            Error ("Cannot find source dir in any package: $userSrcTar", @scanned);
1712
        }
1713
 
1714
        Error ("Requested path found in mutiple packages: $userSrcTar",
1715
                @path ) if ( $#path > 0 );
1716
        $opt_base = pop @path;
1717
 
1718
        #
1719
        #   If sourceing from interface, then follow symlinks in the copy.
1720
        #   All files will be links anyway
1721
        #
1722
        #   This is a very ugly test for 'interface'
1723
        #
1724
        $from_interface = 1
1725
            if ( $opt_base =~ m~/interface/~ );
1726
    }
1727
 
1728
    #
1729
    #   Create the full source path
1730
    #   May be: from a package, from a known directory, from a local directory
1731
    #
1732
    $srcTar = $opt_base . '/' . $srcTar if ( $opt_base );
1733
    $srcTar =~ s~//~/~g;
1734
 
1735
    Verbose ("$srcTar, $dst_dir");
1736
    Error ("Tar File not found: $userSrcTar") unless ( -f $srcTar );
1737
 
1738
    #
1739
    #   Create the output path if it does not exist
1740
    #
1741
    mkpath( $dst_dir ) unless -d $dst_dir;
1742
 
1743
    #
1744
    #   Generate and execute the tar command
1745
    #   
1746
    my @cmd = qw (tar -x --keep-old-files);
1747
    push @cmd, '-f', $srcTar;
1748
    push (@cmd, qw(-v --show-transformed-names)) if ($opt_verbose > 2);
1749
    push (@cmd, "--strip=$opt_strip") if (defined $opt_strip);
1750
    push @cmd, '-C', $dst_dir;
1751
    System (@cmd);
1752
}
1753
 
1754
 
1755
#-------------------------------------------------------------------------------
1756
# Function        : CopyDir
1757
#
1758
# Description     : Copy a directory to a target dir
1759
#
1760
# Inputs          : $src_dir    - Local to the user
1761
#                                 Symbolic Name
1762
#                   $dst_dir    - Within the output workspace
1763
#                   Options
1764
#                       --Merge                 - Don't delete first
1765
#                       --Source=Name           - Source via Symbolic Name
1766
#                       --FromPackage           - Source via package roots
6535 dpurdie 1767
#                       --FromPackage:Name      - Source via specified package roots
6242 dpurdie 1768
#                       --NoIgnoreDbgFiles      - Do not ignore .dbg and .debug files in dir copy
1769
#                       --IfPresent             - Not an error if the path cannot be found
1770
#                       --ConfFile              - Mark transferred files as config files
1771
#                       --Flatten               - Copy all to one directory
1772
#                       --FilterOut=xxx         - Ignore files. DOS Wildcard
1773
#                       --FilterOutRe=xxx       - Ignore files. Regular expression name
1774
#                       --FilterOutDir=xxx      - Ignore directories. DOS Wilcard
1775
#                       --FilterOutDirRe=xxx    - Ignore directories. Regular expression name
1776
#                       --SkipTLF               - Ignore files in the Top Level Directory
1777
#                       --NoRecurse             - Only process files in the Top Level Directory
1778
#                       --FilterIn=xxx          - Include files. DOS Wildcard
1779
#                       --FilterInRe=xxx        - Include files. Regular expression name
1780
#                       --FilterInDir=xxx       - Include directories. DOS Wilcard
1781
#                       --FilterInDirRe=xxx     - Include directories. Regular expression name
1782
#
1783
# Returns         :
1784
#
1785
sub CopyDir
1786
{
1787
    my ($src_dir, $dst_dir, @opts) = @_;
1788
    my $opt_base;
1789
    my $from_interface = 0;
1790
    my $ignoreDbg = 1;
1791
    my $ignoreNoDir;
1792
    my $user_src_dir = $src_dir;
1793
    my $opt_source;
1794
    my $opt_package;
6535 dpurdie 1795
    my $opt_package_name;
6242 dpurdie 1796
    my @fileList;
1797
    my $isFiltered;
1798
    return 1 unless ($ActiveSection);
1799
 
1800
    #
1801
    #   Setup the basic copy options
1802
    #       May be altered as we parse user options
1803
    #
1804
    my %copyOpts;
1805
    $copyOpts{'IgnoreDirs'} = ['.svn', '.git', '.cvs', '.hg'];
1806
    $copyOpts{'Ignore'} = ['.gbedir', '_gbedir'];
1807
    $copyOpts{'Log'} = 1 if ( $opt_verbose > 1 );
1808
    $copyOpts{'DeleteFirst'} = 1;
1809
 
1810
    $dst_dir = $WorkDir . '/' . $dst_dir;
1811
    $dst_dir =~ s~//~/~;
1812
 
1813
    #
1814
    #   Scan and collect user options
1815
    #
1816
    foreach  ( @opts )
1817
    {
1818
        Verbose2 ("CopyDir: $_");
1819
        if ( m/^--Merge/ ) {
1820
            $copyOpts{'DeleteFirst'} = 0;
1821
 
1822
        } elsif ( m/^--Source=(.+)/ ) {
1823
            Error ("Source directory can only be specified once")
1824
                if ( defined $opt_source );
1825
            $opt_source = $1;
1826
 
6535 dpurdie 1827
        } elsif ( m/^--FromPackage:(.+)/ ) {
1828
            Error ("FromPackage can only be specified once")
1829
                if ( defined $opt_package );
1830
            $opt_package = 1;
1831
            $opt_package_name = $1;
1832
 
6242 dpurdie 1833
        } elsif ( m/^--FromPackage/ ) {
1834
            Error ("FromPackage can only be specified once")
1835
                if ( defined $opt_package );
1836
            $opt_package = 1;
1837
 
1838
        } elsif ( m/^--NoIgnoreDbgFiles/ ) {
1839
            $ignoreDbg = 0;
1840
 
1841
        } elsif ( m/^--IfPresent/ ) {
1842
            $ignoreNoDir = 1;
1843
 
1844
        } elsif ( m/^--ConfFile/i ) {
1845
            $copyOpts{'FileList'} = \@fileList;
1846
 
1847
        } elsif ( m/^--Flatten/i ) {
1848
            $copyOpts{'Flatten'} = 1;
1849
 
1850
        } elsif ( m/^--FilterOut=(.+)/i ) {
1851
            push (@{$copyOpts{'Ignore'}}, $1);
1852
            $isFiltered = 1;
1853
 
1854
        } elsif ( m/^--FilterOutRe=(.+)/i ) {
1855
            push (@{$copyOpts{'IgnoreRE'}}, $1);
1856
            $isFiltered = 1;
1857
 
1858
        } elsif ( m/^--FilterOutDir=(.+)/i ) {
1859
            push (@{$copyOpts{'IgnoreDirs'}}, $1);
1860
            $isFiltered = 1;
1861
 
1862
        } elsif ( m/^--FilterOutDirRe=(.+)/i ) {
1863
            push (@{$copyOpts{'IgnoreDirsRE'}}, $1);
1864
            $isFiltered = 1;
1865
 
1866
        } elsif ( m/^--FilterIn=(.+)/i ) {
1867
            push (@{$copyOpts{'Match'}}, $1);
1868
            $isFiltered = 1;
1869
 
1870
        } elsif ( m/^--FilterInRe=(.+)/i ) {
1871
            push (@{$copyOpts{'MatchRE'}}, $1);
1872
            $isFiltered = 1;
1873
 
1874
        } elsif ( m/^--FilterInDir=(.+)/i ) {
1875
            push (@{$copyOpts{'MatchDirs'}}, $1);
1876
            $isFiltered = 1;
1877
 
1878
        } elsif ( m/^--FilterInDirRe=(.+)/i ) {
1879
            push (@{$copyOpts{'MatchDirsRE'}}, $1);
1880
            $isFiltered = 1;
1881
 
1882
        } elsif ( m/^--SkipTLF$/i ) {
1883
            $copyOpts{'SkipTLF'} = 1;
1884
 
1885
        } elsif ( m/^--NoRecurse$/i ) {
1886
            $copyOpts{'NoSubDirs'} = 1;
1887
 
1888
        } else {
1889
            Error ("CopyDir: Unknown option: $_" );
1890
        }
1891
    }
1892
 
1893
    #
1894
    #   All options have been gathered. Now process some of them
1895
    #
1896
    Error ("CopyDir: Cannot use both --Source and --FromPackage: $src_dir") if ($opt_source && $opt_package);
1897
 
1898
    #
1899
    #   Convert a symbolic path into a physical path
1900
    #
1901
    if ($opt_source)
1902
    {
1903
        Verbose2 ("CopyDir: Determine Source: $opt_source");
1904
 
1905
        $opt_source = lc($opt_source);
1906
        my %CopyDirSymbolic = (
1907
            'interfaceincdir'   => $opt_interfaceincdir,
1908
            'interfacelibdir'   => $opt_interfacelibdir,
1909
            'interfacebindir'   => $opt_interfacebindir,
1910
            'libdir'            => $opt_libdir,
1911
            'bindir'            => $opt_bindir,
1912
            'localincdir'       => $opt_localincdir,
1913
            'locallibdir'       => $opt_locallibdir,
1914
            'localbindir'       => $opt_localbindir,
1915
            'packagebindir'     => $opt_pkgbindir,
1916
            'packagelibdir'     => $opt_pkglibdir,
1917
            'packagepkgdir'     => $opt_pkgpkgdir,
1918
            'packagedir'        => $opt_pkgdir,
1919
        );
1920
 
1921
        if ( exists $CopyDirSymbolic{$opt_source} )
1922
        {
1923
            $opt_base = $CopyDirSymbolic{$opt_source};
1924
 
1925
            #
1926
            #   If sourceing from interface, then follow
1927
            #   symlinks in the copy. All files will be links anyway
1928
            #
1929
            $from_interface = 1
1930
                if ( $opt_source =~ m~^interface~ );
1931
        }
1932
        else
1933
        {
1934
            DebugDumpData ("CopyDirSymbolic", \%CopyDirSymbolic);
1935
            Error ("CopyDir: Unknown Source Name: $opt_source" );
1936
        }
1937
    }
1938
 
1939
    #
1940
    #   Locate the path within an external package
1941
    #
1942
    if ($opt_package)
1943
    {
1944
        Verbose2 ("CopyDir: FromPackage: $src_dir");
1945
 
1946
        my @path;
1947
        foreach my $entry ( getPackageList() )
1948
        {
6535 dpurdie 1949
            #
1950
            #   Locate the named package if specified
1951
            #
1952
            if (defined $opt_package_name) {
1953
                next unless ($opt_package_name eq $entry->getName() || uc($opt_package_name) eq $entry->getUnifiedName() );
1954
            }
1955
 
6242 dpurdie 1956
            my $base = $entry->getBase(3);
1957
            next unless ( defined $base );
6535 dpurdie 1958
            if ( folderHasFiles( $base . '/' . $src_dir) )
6242 dpurdie 1959
            {
1960
                push @path, $base;
1961
                $from_interface = 1
1962
                    if ( $entry->{'TYPE'} eq 'interface' );
1963
            }
1964
        }
1965
 
1966
        if ( $#path < 0 )
1967
        {
1968
            Error ("CopyDir: Cannot find source dir in any package: $user_src_dir") unless ($ignoreNoDir);
1969
            Message ("CopyDir: Optional path not found: $user_src_dir");
1970
            return;
1971
        }
1972
 
1973
        Error ("CopyDir: Requested path found in mutiple packages: $user_src_dir",
1974
                @path ) if ( $#path > 0 );
1975
        $opt_base = pop @path;
1976
 
1977
        #
1978
        #   If sourceing from interface, then follow symlinks in the copy.
1979
        #   All files will be links anyway
1980
        #
1981
        #   This is a very ugly test for 'interface'
1982
        #
1983
        $from_interface = 1
1984
            if ( $opt_base =~ m~/interface/~ );
1985
 
1986
    }
1987
 
1988
    #
1989
    #   Create the full source path
1990
    #   May be: from a package, from a known directory, from a local directory
1991
    #
1992
 
1993
    $src_dir = $opt_base . '/' . $src_dir if ( $opt_base );
1994
    $src_dir =~ s~//~/~g;
1995
    $src_dir =~ s~/$~~;
1996
 
1997
    Verbose ("CopyDir: $src_dir, $dst_dir");
1998
    unless ( -d $src_dir )
1999
    {
2000
        Error ("CopyDir: Directory not found: $user_src_dir") unless ($ignoreNoDir);
2001
        Message ("CopyDir: Optional path not found: $user_src_dir");
2002
        return;
2003
    }
2004
 
2005
    #
2006
    #   Continue to configure the copy options
2007
    #
2008
    push (@{$copyOpts{'Ignore'}}, '*.debug', '*.dbg') if $ignoreDbg;
2009
    $copyOpts{'DuplicateLinks'} = 1 unless ( $from_interface );
2010
    $copyOpts{'EmptyDirs'} = 1 unless ($isFiltered);
2011
 
2012
    #
2013
    #   Transfer the directory
2014
    #
2015
    JatsCopy::CopyDir ( $src_dir, $dst_dir, \%copyOpts );
2016
 
2017
    #
2018
    #   If requested, mark files as config files
2019
    #   Must remove the DebianWorkDir prefix
2020
    #
2021
    if(@fileList)
2022
    {
2023
        Verbose ("Mark all transfered files as ConfFiles");
2024
        my $removePrefix = length ($WorkDir);
2025
        foreach my $file (@fileList)
2026
        {
2027
            push @ConfigList, substr($file, $removePrefix);
2028
        }
2029
    }
2030
 
2031
    #
2032
    #   Expand link files that may have been copied in
2033
    #
2034
    Verbose ("Locate LINKFILES in $WorkDir");
2035
    ExpandLinkFiles();
2036
}
2037
 
2038
#-------------------------------------------------------------------------------
2039
# Function        : AddInitScript
2040
#
2041
# Description     : Add an Init Script to the target
2042
#                   Optionally create start and stop links
2043
#
2044
# Inputs          : $script     - Name of the init script
2045
#                   $start      - Start Number
2046
#                   $stop       - Stop Number
2047
#                   Options:
2048
#                       --NoCopy        - Don't copy the script, just add links
2049
#                       --Afc           - Place in AFC init area
2050
#                       --FromPackage   - Source is in a package
6535 dpurdie 2051
#                       --Hibernate     - Add hibernate symlink
2052
#                       --Resume        - Add resume symlink
6547 dpurdie 2053
#                       --Sk100Mode     - Force SK100 Mode
6242 dpurdie 2054
#
2055
# Returns         : 
2056
#
2057
sub AddInitScript
2058
{
2059
    my $no_copy;
2060
    my $basedir = "";
2061
    my @args;
2062
    my $from_package = 0;
6535 dpurdie 2063
    my $hibernate = 0;
2064
    my $resume = 0;
6988 sdenys 2065
    my $sk100 = ($opt_target eq 'SK100');
6547 dpurdie 2066
    my $afcMode;
2067
 
6242 dpurdie 2068
    return 1 unless ($ActiveSection);
2069
 
2070
    # This directive is only available on the VIX platforms
2071
    #   Kludgey test - at the moment
2072
    #
6547 dpurdie 2073
    if ($opt_pkgarch =~ m~i386~) {
6242 dpurdie 2074
        Error ("AddInitScript is not supported on this platform"); 
2075
    }
2076
 
2077
    #
2078
    #   Process and Remove options
2079
    #
2080
    foreach  ( @_ )
2081
    {
2082
        if ( m/^--NoCopy/ ) {
2083
            $no_copy = 1;
2084
 
2085
        } elsif ( m/^--Afc/ ) {
2086
            $basedir = "/afc";
6547 dpurdie 2087
            $afcMode = 1;
6242 dpurdie 2088
 
2089
        } elsif ( m/^--FromPackage/ ) {
2090
            $from_package = 1;
2091
 
6535 dpurdie 2092
        } elsif ( m/^--Hibernate=(.*)/ ) {
2093
            $hibernate = $1;
2094
 
2095
        } elsif ( m/^--Resume=(.*)/ ) {
2096
            $resume = $1;
2097
 
6547 dpurdie 2098
        } elsif ( m/^--SK100/i ) {
2099
            $sk100 = 1;
2100
 
2101
        } elsif ( m/^--NoSK100/i ) {
2102
            $sk100 = 0;
2103
 
6242 dpurdie 2104
        } elsif ( m/^--/ ) {
2105
            Error ("AddInitScript: Unknown option: $_");
2106
 
2107
        } else {
2108
            push @args, $_;
2109
 
2110
        }
2111
    }
2112
 
2113
    my( $script, $start, $stop ) = @args;
2114
    Error ("No script file specified") unless ( $script );
2115
    Warning("AddInitScript: No start or stop index specified") unless ( $start || $stop );
2116
    Verbose ("AddInitScript: $script, " . ($start || 'No Start') . ", " . ($stop || 'No Stop'));
6547 dpurdie 2117
    Error ("Resume script not supported") if ($resume && !$sk100);
2118
    Error ("Hibernate script not supported") if ($hibernate && !$sk100);
2119
    Error ("AFC mode not supported on SK100 (@args)") if ( $sk100 && $afcMode );
6242 dpurdie 2120
    $script = ResolveFile($from_package, $script );
6547 dpurdie 2121
 
2122
    my $tdir = $sk100 ?  "/etc/init.d/init.vix.d" : "/etc/init.d/init.d";
2123
    $tdir = catdir($basedir, $tdir);
6242 dpurdie 2124
    my $base = StripDir($script);
6689 dpurdie 2125
    unless ($no_copy) {
2126
        CopyFile( $script, $tdir );
2127
        SetFilePerms('a+rx', catfile($tdir,$base));
2128
    }
6242 dpurdie 2129
 
2130
    my $link;
6547 dpurdie 2131
    my $linkPath = $sk100 ? "/etc/init.d/init.vix.d/" : "/etc/init.d/";
2132
    $linkPath = catdir($basedir, $linkPath) . '/';
2133
    Verbose("InitScript: ", $base, $tdir, $linkPath);
2134
 
6535 dpurdie 2135
    if ( $start ) {
2136
        $link = sprintf ("${linkPath}S%2.2d%s", $start, $base );
6242 dpurdie 2137
        MakeSymLink( "$tdir/$base", $link);
2138
    }
2139
 
6535 dpurdie 2140
    if ( $stop ) {
2141
        $link = sprintf ("${linkPath}K%2.2d%s", $stop, $base );
6242 dpurdie 2142
        MakeSymLink( "$tdir/$base", $link);
2143
    }
6535 dpurdie 2144
 
2145
    if ( $hibernate ) {
2146
        $link = sprintf ("${linkPath}H%2.2d%s", $hibernate, $base );
2147
        MakeSymLink( "$tdir/$base", $link);
2148
    }
2149
 
2150
    if ( $resume ) {
2151
        $link = sprintf ("${linkPath}R%2.2d%s", $resume, $base );
2152
        MakeSymLink( "$tdir/$base", $link);
2153
    }
2154
 
6547 dpurdie 2155
    # In SK100 mode
2156
    #   init script must be placed in rc.local.d and must be sources and 
2157
    #   a start stop resume or suspend function must be implemented.
6535 dpurdie 2158
    # For VIX these functions will call existing initscripts already package in
2159
    # a vix folder. 
6547 dpurdie 2160
    if ( $sk100 ) {
2161
 
2162
        my $rcLocal =  "/etc/init.d/rc.local.d";
2163
        my $rcLocalFile = catfile( $rcLocal, $base);
2164
        my $rcWorkFile = catfile($WorkDir, $rcLocalFile );
2165
        my $fh;
2166
        CreateDir($rcLocal);
2167
 
2168
        Message ("creating service file: $rcLocalFile");
2169
        unless (open $fh,'>', $rcWorkFile) {
2170
            Error ("Failed to create Service file in $rcLocal, $!");
6535 dpurdie 2171
        }
6547 dpurdie 2172
        print $fh "#!/bin/sh\n# $base service file\n\n";
2173
        print $fh "start() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base start\n}\n";
2174
        print $fh "stop() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base stop\n}\n";
2175
        print $fh "suspend() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base suspend\n}\n";
2176
        print $fh "resume() {\n    [ -e /etc/init.d/init.vix.d/$base ] && /etc/init.d/init.vix.d/$base resume\n}\n";
2177
        close $fh;
6689 dpurdie 2178
        SetFilePerms('a+rx', $rcLocalFile);
6535 dpurdie 2179
    }
6547 dpurdie 2180
 
2181
    return 1;
6242 dpurdie 2182
}
2183
 
2184
#-------------------------------------------------------------------------------
2185
# Function        : CatFile
2186
#
2187
# Description     : Copy a file to the end of a file
2188
#
2189
# Inputs          : $src
2190
#                   $dst    - Within the output workspace
2191
#
2192
# Returns         :
2193
#
2194
sub CatFile
2195
{
2196
    my ($src, $dst) = @_;
2197
    return 1 unless ($ActiveSection);
2198
 
2199
    $dst = $WorkDir . '/' . $dst;
2200
    $dst =~ s~//~/~;
2201
    Verbose ("CatFile: $src, $dst");
2202
    $src = ResolveFile(0, $src );
2203
 
2204
    open (SF, '<', $src)  || Error ("CatFile: Cannot open $src");
2205
    open (DF, '>>', $dst) || Error ("CatFile: Cannot create:$dst");
2206
    while ( <SF> )
2207
    {
2208
        print DF $_;
2209
    }
2210
    close (SF);
2211
    close (DF);
2212
}
2213
 
2214
#-------------------------------------------------------------------------------
2215
# Function        : EchoFile
2216
#
2217
# Description     : Echo simple text to a file
2218
#
2219
# Inputs          : $file   - Within the output workspace
2220
#                   $text
2221
#
2222
# Returns         : 
2223
#
2224
sub EchoFile
2225
{
2226
    my ($file, $text) = @_;
2227
    return 1 unless ($ActiveSection);
2228
    Verbose ("EchoFile: $file");
2229
 
2230
    $file = $WorkDir . '/' . $file;
2231
    $file =~ s~//~/~;
2232
 
2233
    unlink $file;
2234
    open (DT, ">", $file ) || Error ("Cannot create $file");
2235
    print DT  $text || Error ("Cannot print to $file");
2236
    close DT;
2237
}
2238
 
2239
#-------------------------------------------------------------------------------
2240
# Function        : ConvertFiles
2241
#
2242
# Description     : This sub-routine is used to remove all carrage return\line
2243
#                   feeds from a line and replace them with the platform
2244
#                   specific equivalent chars.
2245
#
2246
#                   We let PERL determine what characters are written to the
2247
#                   file base on the  platform you are running on.
2248
#
2249
#                   i.e. LF    for unix
2250
#                        CR\LF for win32
2251
#
2252
# Inputs          : outPath                 - Output directory
2253
#                   flist                   - List of files in that directory
2254
#                   or
2255
#                   SearchOptions           - Search options to find files
2256
#                                           --Recurse
2257
#                                           --NoRecurse
2258
#                                           --FilterIn=xxx
2259
#                                           --FilterInRe=xxx
2260
#                                           --FilterOut=xxx
2261
#                                           --FilterOutRe=xxx
2262
#                   Common options
2263
#                                           --Dos
2264
#                                           --Unix
2265
#
2266
#
2267
# Returns         : 1
2268
#
2269
sub ConvertFiles
2270
{
2271
    my @uargs;
2272
    return 1 unless ($ActiveSection);
2273
    my $lineEnding = "\n";
2274
    my ($dosSet, $unixSet);
2275
    my $search =  JatsLocateFiles->new( '--NoRecurse' );
2276
 
2277
    #
2278
    #   Process user arguments extracting options
2279
    #
2280
    foreach  ( @_ )
2281
    {
2282
        if ( m~^--Recurse~ ) {
2283
            $search->recurse(1);
2284
 
2285
        } elsif ( m~^--NoRecurse~) {
2286
            $search->recurse(0);
2287
 
2288
        } elsif ( /^--FilterOut=(.*)/ ) {
2289
            $search->filter_out($1);
2290
 
2291
        } elsif ( /^--FilterOutRe=(.*)/ ) {
2292
            $search->filter_out_re($1);
2293
 
2294
        } elsif ( /^--FilterIn=(.*)/ ) {
2295
            $search->filter_in($1);
2296
 
2297
        } elsif ( /^--FilterInRe=(.*)/ ) {
2298
            $search->filter_in_re($1);
2299
 
2300
        } elsif ( m~^--Dos~) {
2301
            $lineEnding = "\r\n";
2302
            $dosSet = 1;
2303
 
2304
        } elsif ( m~^--Unix~) {
2305
            $lineEnding = "\n";
2306
            $unixSet = 1;
2307
 
2308
        } elsif ( m~^--~) {
2309
            Error ("ConvertFiles: Unknown option: $_");
2310
 
2311
        } else {
2312
            push @uargs, $_;
2313
        }
2314
    }
2315
 
2316
    #
2317
    #   Process non-option arguments
2318
    #       - Base dir
2319
    #       - List of files
2320
    #
2321
    my ($outPath, @flist) = @uargs;
2322
    Error ("ConvertFiles: Target Dir must be specified" ) unless ( $outPath );
2323
 
2324
    #
2325
    #   Sanity Tests
2326
    #
2327
    Error ("ConvertFiles: --Dos and --Unix are mutually exclusive" ) if ( $dosSet && $unixSet );
2328
 
2329
 
2330
    #
2331
    # Convert output path to physical path
2332
    #
2333
    my $topDir = catdir($WorkDir, $outPath);
2334
    Verbose("ConvertFiles: topDir: $topDir");
2335
    Error ("ConvertFiles: Path does not exist", $topDir) unless ( -e $topDir );
2336
    Error ("ConvertFiles: Path is not a directory", $topDir) unless ( -d $topDir );
2337
 
2338
    #
2339
    #   Need to determine if we are searching or simply using a file list
2340
    #   There are two forms of the functions. If any of the search options have
2341
    #   been used then we assume that we are searchine
2342
    #
2343
    if ( $search->has_filter() )
2344
    {
2345
        Error ("ConvertFiles: Cannot mix search options with named files") if ( @flist );
2346
        @flist = $search->search($topDir);
2347
    }
2348
    Error ("ConvertFiles: No files specified") unless ( @flist );
2349
 
2350
    #
2351
    #   Process all named files
2352
    #
2353
    foreach my $file ( @flist )
2354
    {
2355
 
2356
        # this is our file that we want to clean.
2357
        my ($ifileLoc) = "$topDir/$file";
2358
        my ($tfileLoc) = "$topDir/$file\.tmp";
2359
        Verbose("ConvertFiles: $file");
2360
 
2361
        # we will check to see if the file exists.
2362
        #
2363
        my $ifile;
2364
        my $tfile;
2365
        if ( -f "$ifileLoc" )
2366
        {
2367
            open ($ifile, "< $ifileLoc" ) or
2368
                Error("Failed to open file [$ifileLoc] : $!");
2369
 
2370
            open ($tfile, "> $tfileLoc" ) or
2371
                Error("Failed to open file [$tfileLoc] : $!");
2372
            binmode $tfile;
2373
 
2374
            while ( <$ifile> ) 
2375
            {
2376
                s~[\n\r]+$~~;               # Chomp
2377
                print $tfile "$_" . $lineEnding;
2378
            }
2379
        }
2380
        else
2381
        {
2382
            Error("ConvertFiles [$ifileLoc] does not exist.");
2383
        }
2384
 
2385
        close $ifile;
2386
        close $tfile;
2387
 
2388
 
2389
        # lets replace our original file with the new one
2390
        #
2391
        if(File::Copy::move("$tfileLoc", "$ifileLoc"))
2392
        {
2393
            Verbose2("ConvertFiles: Renamed [$tfileLoc] to [$ifileLoc] ...");
2394
        }
2395
        else
2396
        {
2397
            Error("ConvertFiles: Failed to rename file [$tfileLoc] to [$ifileLoc]: $!");
2398
        }
2399
    }
2400
 
2401
    return 1;
2402
}
2403
 
2404
#----------------------------------------------------------------------------
2405
# Function        : ReplaceTags
2406
#
2407
# Description     : This sub-routine is used to replace Tags in one or more files
2408
#
2409
# Inputs          : outPath                 - Output directory
2410
#                   flist                   - List of files in that directory
2411
#                   or
2412
#                   SearchOptions           - Search options to find files
2413
#                                           --Recurse
2414
#                                           --NoRecurse
2415
#                                           --FilterIn=xxx
2416
#                                           --FilterInRe=xxx
2417
#                                           --FilterOut=xxx
2418
#                                           --FilterOutRe=xxx
2419
#                   Common options
2420
#                                           --Tag=Tag,Replace
2421
#                                           
2422
#
2423
# Returns         : 1
2424
#
2425
sub ReplaceTags
2426
{
2427
    return 1 unless ($ActiveSection);
2428
    my @uargs;
2429
    my $search =  JatsLocateFiles->new( '--NoRecurse' );
2430
    my @tagsList;
2431
    my $tagSep = ',';
2432
    my @tagOrder;
2433
    my %tagData;
2434
 
2435
    #
2436
    #   Process user arguments extracting options
2437
    #
2438
    foreach  ( @_ )
2439
    {
2440
        if ( m~^--Recurse~ ) {
2441
            $search->recurse(1);
2442
 
2443
        } elsif ( m~^--NoRecurse~) {
2444
            $search->recurse(0);
2445
 
2446
        } elsif ( /^--FilterOut=(.*)/ ) {
2447
            $search->filter_out($1);
2448
 
2449
        } elsif ( /^--FilterOutRe=(.*)/ ) {
2450
            $search->filter_out_re($1);
2451
 
2452
        } elsif ( /^--FilterIn=(.*)/ ) {
2453
            $search->filter_in($1);
2454
 
2455
        } elsif ( /^--FilterInRe=(.*)/ ) {
2456
            $search->filter_in_re($1);
2457
 
2458
        } elsif ( m~^--Tag=(.*)~) {
2459
            push @tagsList, $1;
2460
 
2461
        } elsif ( m~^--~) {
2462
            Error ("ReplaceTags: Unknown option: $_");
2463
 
2464
        } else {
2465
            push @uargs, $_;
2466
        }
2467
    }
2468
 
2469
    #
2470
    #   Process non-option arguments
2471
    #       - Base dir
2472
    #       - List of files
2473
    #
2474
    my ($outPath, @flist) = @uargs;
2475
    Error ("ReplaceTags: Target Dir must be specified" ) unless ( $outPath );
2476
 
2477
    #
2478
    #   Sanity Tests
2479
    #
2480
    Error ("ReplaceTags: No tags specified" ) unless ( @tagsList );
2481
 
2482
    #
2483
    # Convert output path to physical path
2484
    #
2485
    my $topDir = catdir($WorkDir, $outPath);
2486
    Verbose("ReplaceTags: topDir: $topDir");
2487
    Error ("ReplaceTags: Path does not exist", $topDir) unless ( -e $topDir );
2488
    Error ("ReplaceTags: Path is not a directory", $topDir) unless ( -d $topDir );
2489
 
2490
    #
2491
    #   Convert Tags into pairs for latter use
2492
    #
2493
    my $sep = quotemeta ($tagSep );
2494
    foreach my $tag ( @tagsList )
2495
    {
2496
        my ($tname,$tvalue) = split ( $sep, $tag, 2 );
2497
        Error ("No tag value in: $tag" ) unless ( defined $tvalue );
2498
        Error ("Duplicate Tag: $tname" ) if ( exists $tagData{$tname} );
2499
        Verbose ("Tag: $tname :: $tvalue");
2500
        push @tagOrder, $tname;
2501
        $tagData{$tname} = $tvalue;
2502
    }
2503
 
2504
    #
2505
    #   Need to determine if we are searching or simply using a file list
2506
    #   There are two forms of the functions. If any of the search options have
2507
    #   been used then we assume that we are searchine
2508
    #
2509
    if ( $search->has_filter() )
2510
    {
2511
        Error ("ReplaceTags: Cannot mix search options with named files") if ( @flist );
2512
        @flist = $search->search($topDir);
2513
    }
2514
    Error ("ReplaceTags: No files specified") unless ( @flist );
2515
 
2516
    #
2517
    #   Process all named files
2518
    #
2519
    foreach my $file ( @flist )
2520
    {
2521
 
2522
        # this is our file that we want to clean.
2523
        my ($ifileLoc) = "$topDir/$file";
2524
        my ($tfileLoc) = "$topDir/$file\.tmp";
2525
        Verbose("ReplaceTags: $file");
2526
 
2527
        # we will check to see if the file exists.
2528
        #
2529
        my $ifile;
2530
        my $tfile;
2531
        if ( -f "$ifileLoc" )
2532
        {
2533
            open ($ifile, "< $ifileLoc" ) or
2534
                Error("Failed to open file [$ifileLoc] : $!");
2535
 
2536
            open ($tfile, "> $tfileLoc" ) or
2537
                Error("Failed to open file [$tfileLoc] : $!");
2538
 
2539
            while ( <$ifile> ) 
2540
            {
2541
                s~[\n\r]+$~~;               # Chomp
2542
 
2543
                #
2544
                #   Perform tag replacement
2545
                #
2546
                foreach my $tag ( @tagOrder )
2547
                {
2548
                    my $value = $tagData{$tag};
2549
                    if ( s~$tag~$value~g )
2550
                    {
2551
                        Verbose2("Replaced: $tag with $value");
2552
                    }
2553
                }
2554
 
2555
                print $tfile "$_\n";
2556
            }
2557
        }
2558
        else
2559
        {
2560
            Error("ReplaceTags [$ifileLoc] does not exist.");
2561
        }
2562
 
2563
        close $ifile;
2564
        close $tfile;
2565
 
2566
 
2567
        # lets replace our original file with the new one
2568
        #
2569
        if(File::Copy::move("$tfileLoc", "$ifileLoc"))
2570
        {
2571
            Verbose2("ReplaceTags: Renamed [$tfileLoc] to [$ifileLoc] ...");
2572
        }
2573
        else
2574
        {
2575
            Error("ReplaceTags: Failed to rename file [$tfileLoc] to [$ifileLoc]: $!");
2576
        }
2577
    }
2578
 
2579
    return 1;
2580
}
2581
 
2582
#-------------------------------------------------------------------------------
2583
# Function        : SetFilePerms
2584
#
2585
# Description     : Set file permissions on one or more files or directories
2586
#                   Use SetPermissions
2587
#
2588
# Inputs          : $perm           - Perm Mask
2589
#                   @paths          - List of paths/files to process
2590
#                   Options
2591
#                       --Recurse   - Recurse subdirs
2592
#
2593
# Returns         : 
2594
#
2595
sub SetFilePerms
2596
{
2597
 
2598
    return 1 unless ($ActiveSection);
2599
    my @args;
2600
    my $perms;
2601
    my $recurse = 0;
2602
 
2603
    #
2604
    #   Process and Remove options
2605
    #
2606
    foreach  ( @_ )
2607
    {
2608
        if ( m/^--Recurse/ ) {
2609
            $recurse = 1;
2610
 
2611
        } elsif ( m/^--/ ) {
2612
            Error ("SetFilePerms: Unknown option: $_");
2613
 
2614
        } else {
2615
            push @args, $_;
2616
 
2617
        }
2618
    }
2619
 
2620
    $perms = shift @args;
2621
    Error ("SetFilePerms: No Permissions" ) unless ( $perms );
2622
 
2623
    foreach my $path ( @args )
2624
    {
2625
        Verbose ("Set permissions; $perms, $path");
2626
        my $full_path = $WorkDir . '/' . $path;
2627
        if ( -f $full_path )
2628
        {
2629
            System ('chmod', $perms, $full_path );
2630
        }
2631
        elsif ( -d $full_path )
2632
        {
2633
            System ('chmod', '-R', $perms, $full_path ) if ($recurse);
2634
            System ('chmod', $perms, $full_path ) unless ($recurse);
2635
        }
2636
        else
2637
        {
2638
            Warning("SetFilePerms: Path not found: $path");
2639
        }
2640
    }
2641
    return 1;
2642
}
2643
 
2644
#-------------------------------------------------------------------------------
2645
# Function        : SetPermissions 
2646
#
2647
# Description     : Called to set permissions of files/dirs in a directory structure.
2648
#                   With no options sets DirTag and all files/dirs in it to perms
2649
#   
2650
# Inputs          : path        - The directory tag to start setting permissions on
2651
#                   Options     - See below
2652
#       
2653
#   Required Options:
2654
#       One or both of
2655
#               --FilePerms=    Sets the permissions of files to this permission.
2656
#                               If not supplied then no files have their permissions changed
2657
#               --DirPerms=     Sets the permissions of directories to this permission
2658
#                               If not supplied then no directories have their permissions changed
2659
#       OR
2660
#               --Perms=        Sets the permissions of both files and directories to this permissions
2661
#                               Equivalent to supplying both --FilePerms=X && --DirPerms=X
2662
#               
2663
#   Options:                    
2664
#               --RootOnly      Only sets the permissions on the 'path' directory/file, 
2665
#                               all other options ignored
2666
#               --SkipRoot      Does not set permissions on the 'path' directory/file, 
2667
#                               obviously mutually exlusive with --RootOnly
2668
#   
2669
#       Any option supported by JatsLocateFiles. 
2670
#       Some of these include:
2671
#               
2672
#               --Recurse       Recurse the directory tree.  Does a depth first recurse so that all 
2673
#                               dir entries are processed before the dir itself (default)
2674
#               --NoRecurse     Dont recurse
2675
#               --FilterIn=     Apply permissions to files/directories that matches this value.
2676
#               --FilterInRe=   Perl RE's can be used (Not Shell wildcards) and this option
2677
#                               can be supplied mulitple times
2678
#               --FilterOut=    Dont apply permissions to any files/directories matching this value
2679
#               --FilterOutRe=  Perl RE's can be used (Not Shell wildcards) and this option
2680
#                               can be supplied mulitple times
2681
#               
2682
#                               FilterIn is applied before FilterOut.  If Recurse is specified 
2683
#                               the directory will be recursed regardless of these filters, however
2684
#                               the filter will be applied when it comes time to chmod the dir 
2685
#
2686
#------------------------------------------------------------------------------
2687
sub SetPermissions
2688
{
2689
    return 1 unless ($ActiveSection);
2690
    my ( $path, $filePerms, $dirPerms, $someDone );
2691
    my ( $rootOnly, $skipRoot ) = ( 0, 0 );
2692
 
2693
    my $search =  JatsLocateFiles->new( '--Recurse', '--DirsToo' );
2694
 
2695
    foreach ( @_ )
2696
    {
2697
        if ( m/^--Perms=(.*)/ ) {
2698
            $filePerms = $1;
2699
            $dirPerms = $1;
2700
 
2701
        } elsif (m/^--FilePerms=(.*)/ )  {
2702
            $filePerms = $1;
2703
 
2704
        } elsif ( m/^--DirPerms=(.*)/ )  {
2705
            $dirPerms = $1;
2706
 
2707
        }  elsif ( m/^--RootOnly/ ) {
2708
            $rootOnly = 1;
2709
 
2710
        } elsif ( m/^--SkipRoot/ )  {
2711
            $skipRoot = 1;
2712
 
2713
        } elsif ( m/^--Filter/ && $search->option( $_ ) ) {
2714
            Verbose2 ("Search Option: $_" );
2715
 
2716
        } elsif ( m/^--Recurse|--NoRecurse/ && $search->option( $_ ) ) {
2717
            Verbose2 ("Search Option: $_" );
2718
 
2719
        } elsif (m/^--/ ) {
2720
            Error ("SetPermissions: Unknown option: $_");
2721
 
2722
        } else  {
2723
            Error("SetPermissions 'path' already set", "Path: $_") if ( $path );
2724
            $path = $_;
2725
        }
2726
    }
2727
 
2728
    #
2729
    #   Sanity test
2730
    #
2731
    Error("SetPermissions called with out a 'path' parameter") if ( !defined($path) );
2732
    Error("SetPermissions called with out any Permissions specified") if ( !defined($filePerms) && !defined($dirPerms) );
2733
    Error("SetPermissions: Options --RootOnly & --SkipRoot are mutually exclusive" ) if ( $rootOnly && $skipRoot );
2734
 
2735
 
2736
    #   Convert the target directory name into a physical path
2737
    #   User specifies '/' as the root of the image
2738
    #   User specifies 'name' as relateve to the root of the image
2739
    #
2740
    my $topDir = $WorkDir . '/' . $path;
2741
    $topDir =~ s~/+$~~;
2742
 
2743
    Verbose("SetPermissions: Called with options " . join(", ", @_));
2744
 
2745
    #
2746
    #   Only set perms on the root directory
2747
    #       This is a trivial operation
2748
    #
2749
    if ( $rootOnly )
2750
    {
2751
        $someDone += chmodItem( $topDir, $filePerms, $dirPerms );
2752
    }
2753
    else
2754
    {
2755
        #
2756
        #   Create a list of files/dirs to process
2757
        #
2758
        my @elements = $search->search( $topDir );
2759
 
2760
        foreach my $dirEntry ( @elements )
2761
        {
2762
            my $fullPath = "$topDir/$dirEntry";
2763
 
2764
            # A dir and we dont have dirperms, so skip
2765
            if ( -d $fullPath && !defined($dirPerms) )
2766
            {
2767
                Verbose2("SetPermissions: Skipping dir $fullPath as we have no dir permissions");
2768
                next;
2769
            }
2770
 
2771
            # A file and we dont have fileperms, so skip
2772
            if ( -f $fullPath && !defined($filePerms) )
2773
            {
2774
                Verbose2("SetPermissions: Skipping file $fullPath as we have no file permissions");
2775
                next;
2776
            }
2777
 
2778
            # a file or a dir and have the right permissions and we are not recursing
2779
            if ( -f $fullPath || -d $fullPath )
2780
            {
2781
                $someDone += chmodItem( $fullPath, $filePerms, $dirPerms );
2782
            }
2783
            else
2784
            {
2785
                Warning("SetPermissions: Skipping $fullPath as its not a file or directory");
2786
            }
2787
        }
2788
 
2789
        #
2790
        #   Process the topDir
2791
        #   May not be modified if --SkipRoot has been requested
2792
        #
2793
        if ( !$skipRoot && -e $topDir )
2794
        {
2795
            $someDone += chmodItem( $topDir, $filePerms, $dirPerms );
2796
        }
2797
    }
2798
 
2799
    #   Final warning
2800
    #
2801
    Warning ("SetPermissions: No files located", "Args: @_") unless ( $someDone );
2802
}
2803
 
2804
#************ INTERNAL USE ONLY  **********************************************
2805
# Function        : chmodItem 
2806
#
2807
# Description     : Internal
2808
#                   chmod a file or a folder
2809
#
2810
# Inputs          : item                        - Item to mod
2811
#                   filePerms                   - File perms
2812
#                   dirPerms                    - dire perms
2813
#
2814
# Returns         : 1   - Item modified
2815
#                   0   - Item not modified
2816
#
2817
#************ INTERNAL USE ONLY  **********************************************
2818
sub chmodItem
2819
{
2820
    my ($item, $filePerms, $dirPerms) = @_;
2821
 
2822
    if ( -d $item && defined $dirPerms)
2823
    {
2824
        Verbose("SetPermissions: $dirPerms : $item");
2825
        System ('chmod', $dirPerms, $item );
2826
        return 1;
2827
    }
2828
 
2829
    if ( -f $item  && defined $filePerms)
2830
    {
2831
        Verbose("SetPermissions: $filePerms : $item");
2832
        System ('chmod', $filePerms, $item );
2833
        return 1;
2834
    }
2835
 
2836
    return 0;
2837
}
2838
 
2839
 
2840
#-------------------------------------------------------------------------------
2841
# Function        : CreateDir
2842
#
2843
# Description     : Create a directory within the target workspace
2844
#
2845
# Inputs          : $path           - Name of the target directory
2846
#                   @opts           - Options
2847
#                     --Owner       - Tells RPM Builder that this package. Owns this directory
2848
#
2849
# Returns         : Nothing
2850
#
2851
sub CreateDir
2852
{
2853
    my ($path, @opts) = @_;
2854
    return 1 unless ($ActiveSection);
2855
    Verbose ("Create Dir: $path");
2856
    my $owner  = 0;
2857
    foreach ( @opts) {
2858
        if (m~^--Owner~i ) {
2859
            $owner = 1;
2860
        } else {
2861
            ReportError ("SetBaseDir: Unknown option: $_");
2862
        }
2863
    }
2864
    ErrorDoExit();
2865
 
2866
    $path =~ s~^/+~~;
2867
    $path = '/' . $path;
2868
    $OwnedDirs{$path} = $owner if $owner;
2869
    mkpath( $WorkDir . $path );
2870
}
2871
 
2872
#-------------------------------------------------------------------------------
2873
# Function        : RpmSetDefAttr 
2874
#
2875
# Description     : RPM only: Set the defAttr values 
2876
#
2877
# Inputs          : Expect 4 or less argument
2878
#                       The default permissions, or "mode" for files.
2879
#                       The default user id.
2880
#                       The default group id.
2881
#                       The default permissions, or "mode" for directories.
2882
#                   
2883
sub RpmSetDefAttr
2884
{
2885
    return 1 unless ($ActiveSection);
2886
    return 1 unless $opt_rpm;
2887
    my @args = @_;
2888
    Error ("RpmSetDefAttr: Expecting 4 arguments") if (scalar @args ne 4);
2889
    @RpmDefAttr = @_;
2890
    return 1;
2891
}
2892
 
2893
#-------------------------------------------------------------------------------
2894
# Function        : RpmSetAttr 
2895
#
2896
# Description     : RPM Only : Specify specific file attributes
2897
#
2898
# Inputs          : $file - file to target
2899
#                   $mode - File mode to place on the file (optional)
2900
#                   $user - user name to place on the file  (optional)
2901
#                   $group  - group name to place eon the file (optional)
2902
#
2903
sub RpmSetAttr
2904
{
2905
    return 1 unless ($ActiveSection);
2906
    return 1 unless $opt_rpm;
2907
    my ($file, $mode, $user, $group, @extra) = @_;
2908
    Error ("RpmSetAttr: Too many arguments") if @extra;
2909
 
2910
    #
2911
    #   Validate the file
2912
    #
2913
    $file = '/' . $file;
2914
    $file =~ s~//~/~g;
2915
    my $full_path = $WorkDir . $file;
2916
    Error ("RpmSetAttr: File not found: $WorkSubDir$file") unless (-x $full_path );
2917
 
2918
    my @data;
2919
    $data[0] = $WorkSubDir . $file;
2920
    $data[1] = $mode || '-';
2921
    $data[2] = $user || '-';
2922
    $data[3] = $group ||'-';
2923
    push @RpmAttrList, \@data;
2924
    return 1;
2925
}
2926
 
2927
 
2928
#-------------------------------------------------------------------------------
2929
# Function        : IsProduct
2930
#                   IsPlatform
2931
#                   IsTarget
2932
#                   IsVariant
2933
#                   IsAlias
2934
#                   IsDebian
2935
#                   IsRpm
2936
#                   IsTar
6937 dpurdie 2937
#                   IsZip
6242 dpurdie 2938
#
2939
# Description     : This function allows some level of control in the
2940
#                   packaging scripts. It will return true if the current
2941
#                   product is listed.
2942
#
2943
#                   Ugly after thought
2944
#
2945
#                   Intended use:
2946
#                       Xxxxxx(...) if (IsProduct( 'aaa',bbb' );
2947
#
2948
# Inputs          : products    - a list of products to compare against
2949
#
2950
# Returns         : True if the current build is for one of the listed products
2951
#
2952
sub IsProduct
2953
{
2954
    foreach ( @_ )
2955
    {
2956
        return 1 if ( $opt_product eq $_ );
2957
    }
2958
    return 0;
2959
}
2960
 
2961
sub IsPlatform
2962
{
2963
    foreach ( @_ )
2964
    {
2965
        return 1 if ( $opt_platform eq $_ );
2966
    }
2967
    return 0;
2968
}
2969
 
2970
sub IsTarget
2971
{
2972
    foreach ( @_ )
2973
    {
2974
        return 1 if ( $opt_target eq $_ );
2975
    }
2976
    return 0;
2977
}
2978
 
2979
sub IsVariant
2980
{
2981
    foreach ( @_ )
2982
    {
2983
        return 1 if ( $opt_variant eq $_ );
2984
    }
2985
    return 0;
2986
}
2987
 
2988
sub IsAlias
2989
{
2990
 
2991
    #
2992
    #   Get the aliases from the build info
2993
    #   This function was introduced late so its not always available
2994
    #
2995
    Error("IsAlias not supported in this version of JATS")
2996
        unless (defined &ReadBuildConfig::getAliases);
2997
    #
2998
    #   Create an hash of aliases to simplify testing
2999
    #   Do it once and cache the results
3000
    #
3001
    unless (%opt_aliases) {
3002
        %opt_aliases = map { $_ => 1 } getAliases();
3003
    }
3004
 
3005
    foreach ( @_ )
3006
    {
3007
        return 1 if ( exists $opt_aliases{$_} );
3008
    }
3009
    return 0;
3010
}
3011
 
3012
sub IsDebian()
3013
{
3014
    return $opt_debian ? 1 : 0;
3015
}
3016
 
3017
sub IsRpm()
3018
{
3019
    return $opt_rpm ? 1 : 0;
3020
}
3021
 
3022
sub IsTar()
3023
{
3024
    return $opt_tarFile ? 1 : 0;
3025
}
3026
 
6937 dpurdie 3027
sub IsZip()
3028
{
3029
    return $opt_zipFile ? 1 : 0;
3030
}
3031
 
3032
 
6242 dpurdie 3033
#-------------------------------------------------------------------------------
3034
# Function        : PackageVersion 
3035
#
3036
# Description     : Return the version of the named package 
3037
#
3038
# Inputs          : pkgName - Name of the package 
3039
#                   Options
3040
#                       --format=SomeString. The text replacements
3041
#                           {VERSION}
3042
#                           {VERSIONNUMVER}
3043
#                           {PROJECT}
3044
#                           {NAME}
3045
#                           {TYPE}
3046
#                           {ARCH}
3047
#
3048
# Returns         : A string 
3049
#
3050
sub PackageVersion
3051
{
3052
    my ($pkgName, @args) = @_;
3053
    my ($version, $versionNumber, $project, $format);
3054
 
3055
    foreach ( @args)
3056
    {
3057
        if (m~^--format=(.+)~i) {
3058
            $format = $1
3059
        } else {
3060
            Error ("PackageVersion: Unknown option: $_")
3061
        }
3062
    }
3063
 
3064
    foreach my $entry ( getPackageList() )
3065
    {
3066
        if ($entry->getName() eq $pkgName ) {
3067
            $version = $entry->getVersion();
3068
            ($versionNumber = $version ) =~ s~\.[^.]+$~~;
3069
            ($project = $version ) =~ s~.*\.~~;
3070
            last;
3071
        }
3072
    }
3073
 
3074
    Error ("PackageVersion: $pkgName is not a dependent package") unless defined $version;
3075
 
3076
    #
3077
    #   Format the string
3078
    #
3079
    if ($format) {
3080
        $format =~ s~{NAME}~$pkgName~g;
3081
        $format =~ s~{VERSION}~$version~g;
3082
        $format =~ s~{VERSIONNUMBER}~$versionNumber~g;
3083
        $format =~ s~{PROJECT}~$project~g;
3084
        $format =~ s~{TYPE}~$opt_type~g;
3085
        $format =~ s~{ARCH}~$opt_pkgarch~g;
3086
 
3087
        $version = $format;
3088
    }
3089
 
3090
    return $version;
3091
}
3092
 
3093
 
3094
#************ INTERNAL USE ONLY  **********************************************
3095
# Function        : FindFiles
3096
#
3097
# Description     : Locate files within a given dir tree
3098
#
3099
# Inputs          : $root           - Base of the search
3100
#                   $match          - Re to match
3101
#
3102
# Returns         : A list of files that match
3103
#
3104
#************ INTERNAL USE ONLY  **********************************************
3105
my @FIND_LIST;
3106
my $FIND_NAME;
3107
 
3108
sub FindFiles
3109
{
3110
    my ($root, $match ) = @_;
3111
    Verbose2("FindFiles: Root: $root, Match: $match");
3112
 
3113
    #
3114
    #   Becareful of closure, Must use globals
3115
    #
3116
    @FIND_LIST = ();
3117
    $FIND_NAME = $match;
3118
    File::Find::find( \&find_files, $root);
3119
 
3120
    #
3121
    #   Find callback program
3122
    #
3123
    sub find_files
3124
    {
3125
        my $item =  $File::Find::name;
3126
 
3127
        return if ( -d $File::Find::name );
3128
        return unless ( $_ =~ m~$FIND_NAME~ );
3129
        push @FIND_LIST, $item;
3130
    }
3131
    return @FIND_LIST;
3132
}
3133
 
3134
#-------------------------------------------------------------------------------
3135
# Function        : CalcRelPath
3136
#
3137
# Description     : Return the relative path to the current working directory
3138
#                   as provided in $Cwd
3139
#
3140
# Inputs          : $Cwd - Base dir
3141
#                   $base - Path to convert
3142
#
3143
# Returns         : Relative path from the $Cwd
3144
#
3145
sub CalcRelPath
3146
{
3147
    my ($Cwd, $base) = @_;
3148
 
3149
    my @base = split ('/', $base );
3150
    my @here = split ('/', $Cwd );
3151
    my $result;
3152
 
3153
    Debug("RelPath: Source: $base");
3154
 
3155
    return $base unless ( $base =~ m~^/~ );
3156
 
3157
    #
3158
    #   Remove common bits from the head of both lists
3159
    #
3160
    while ( $#base >= 0 && $#here >= 0 && $base[0] eq $here[0] )
3161
    {
3162
        shift @base;
3163
        shift @here;
3164
    }
3165
 
3166
    #
3167
    #   Need to go up some directories from here and then down into base
3168
    #
3169
    $result = '../' x ($#here + 1);
3170
    $result .= join ( '/', @base);
3171
    $result = '.' unless ( $result );
3172
    $result =~ s~//~/~g;
3173
    $result =~ s~/$~~;
3174
 
3175
    Debug("RelPath: Result: $result");
3176
    return $result;
3177
}
3178
 
3179
#-------------------------------------------------------------------------------
6535 dpurdie 3180
# Function        : folderHasFiles  
3181
#
3182
# Description     : Detect empty folders
3183
#
3184
# Inputs          : dirname - Path to examine 
3185
#
3186
# Returns         : TRUE - Is a folder and it has files
3187
#
3188
 
3189
sub folderHasFiles {
3190
    my $dirname = shift;
3191
    my $rv = 0;
6937 dpurdie 3192
    my $dh;
3193
    return 0 unless -d $dirname;
6535 dpurdie 3194
 
6937 dpurdie 3195
    opendir($dh, $dirname) || return 0;
3196
    while (my $file = readdir $dh)
6535 dpurdie 3197
    {
6937 dpurdie 3198
        next unless (defined $file);
3199
        next if ($file eq "." || $file eq "..");
6535 dpurdie 3200
        $rv = 1;
3201
        last;
3202
    }
3203
    closedir $dh;
3204
    return $rv;
3205
}
3206
 
3207
#-------------------------------------------------------------------------------
6242 dpurdie 3208
# Function        : ExpandLinkFiles
3209
#
3210
# Description     : Look for .LINK files in the output image and expand
3211
#                   the links into softlinks
3212
#
3213
# Inputs          : None
3214
#                   The routine works on the $WorkDir directory tree
3215
#
3216
# Returns         : Nothing
3217
#                   Will remove .LINKS files that are processed
3218
#
3219
sub ExpandLinkFiles
3220
{
3221
    return 1 unless ($ActiveSection);
3222
    foreach my $linkfile ( FindFiles( $WorkDir, ".LINKS" ))
3223
    {
3224
        next if ( $linkfile =~ m~/\.svn/~ );
3225
        my $BASEDIR = StripFileExt( $linkfile );
3226
        $BASEDIR =~ s~^$WorkDir/~~;
3227
        Verbose "Expand links: $BASEDIR";
3228
 
3229
        open (LF, "<", $linkfile ) || Error ("Cannot open link file: $linkfile" );
3230
        while ( <LF> )
3231
        {
3232
            chomp;
3233
            next if ( m~^#~ );
3234
            next unless ( $_ );
3235
            my ($link, $file) = split;
3236
 
3237
            MakeSymLink($file ,"$BASEDIR/$link", '--NoDotDot' );
3238
        }
3239
        close (LF);
3240
        unlink $linkfile;
3241
    }
3242
}
3243
 
3244
#************ INTERNAL USE ONLY  **********************************************
3245
# Function        : ResolveFile
3246
#
3247
# Description     : Determine where the source for a file is
3248
#                   Will look in (default):
3249
#                       Local directory
3250
#                       Local Include
3251
#                   Or  (FromPackage)
3252
#                       Our Package directory
3253
#                       Interface directory (BuildPkgArchives)
3254
#                       Packages (LinkPkgArchive)
3255
#
3256
#                   Will scan 'parts' subdirs
3257
#
3258
# Inputs          : $from_package       - 0 - Local File
3259
#                   $file
3260
#                   $refPlatforms       - Not used
3261
#
3262
# Returns         : Path
3263
#
3264
#************ INTERNAL USE ONLY  **********************************************
3265
sub ResolveFile
3266
{
3267
    my ($from_package, $file,$refPlatforms) = @_;
3268
    my $wildcard = ($file =~ /[*?]/);
3269
    my @path;
3270
 
3271
    #
3272
    #   Determine the paths to search
3273
    #
3274
    if ( $from_package )
3275
    {
3276
        unless ( @ResolveFileList )
3277
        {
3278
            push @ResolveFileList, $opt_pkgdir;
3279
            foreach my $entry ( getPackageList() )
3280
            {
3281
                push @ResolveFileList, $entry->getBase(3);
3282
            }
3283
        }
3284
        @path = @ResolveFileList;
3285
    }
3286
    else
3287
    {
3288
        @path = ('.', $opt_localincdir);
3289
    }
3290
 
3291
    #   Determine a full list of 'parts' to search
3292
    #       Default: Provided within the build information
3293
    #       User   : Can provide a list
3294
    my @parts = getPlatformPartsList($refPlatforms);
3295
 
3296
    my @done;
3297
    foreach my $root (  @path )
3298
    {
3299
        foreach my $subdir ( @parts )
3300
        {
3301
            my $sfile;
3302
            $sfile = "$root/$subdir/$file";
3303
            $sfile =~ s~//~/~g;
3304
            $sfile =~ s~^./~~g;
3305
            Verbose2("LocateFile: $sfile, $root, $subdir");
3306
            if ( $wildcard )
3307
            {
3308
                push @done, glob ( $sfile );
3309
            }
3310
            else
3311
            {
3312
                push @done, $sfile if ( -f $sfile || -l $sfile )
3313
            }
3314
        }
3315
    }
3316
 
3317
    DisplaySearchPath('ResolveFile', $file, \@parts, undef, \@path) unless (@done) ;
3318
 
3319
    Warning ("ResolveFile: Multiple instances of file found. Only first is used", @done)
3320
        if ( $#done > 0 && ! $wildcard && !wantarray );
3321
 
3322
    return wantarray ? @done : $done[0];
3323
}
3324
 
3325
#-------------------------------------------------------------------------------
3326
# Function        : ResolveBinFile
3327
#
3328
# Description     : Determine where the source for a BIN file is
3329
#                   Will look in (default):
3330
#                       Local directory
3331
#                       Local Include
3332
#                   Or  (FromPackage)
3333
#                       Our Package directory
3334
#                       Interface directory (BuildPkgArchives)
3335
#                       Packages (LinkPkgArchive)
3336
#                   Will scan 'parts' subdirs (default)
3337
#                   May scan user-provided parts (cross platform packaging)
3338
#
3339
# Inputs          : $from_package       - 0 - Local File
3340
#                   $file
3341
#                   $refPlatforms       - (optional) Ref to an array of platforms to scan
3342
#
3343
# Returns         : Path
3344
#
3345
sub ResolveBinFile
3346
{
3347
    my ($from_package, $file, $refPlatforms) = @_;
3348
    my @path;
3349
    my @types;
3350
    my $wildcard = ($file =~ /[*?]/);
3351
 
3352
    #
3353
    #   Determine the paths to search
3354
    #
3355
    if ( $from_package )
3356
    {
3357
        unless ( @ResolveBinFileList )
3358
        {
3359
            push @ResolveBinFileList, $opt_pkgdir . '/bin';
3360
            foreach my $entry ( getPackageList() )
3361
            {
3362
                if ( my $path = $entry->getBase(3) )
3363
                {
3364
                    $path .= '/bin';
3365
                    push @ResolveBinFileList, $path if ( -d $path );
3366
                }
3367
            }
3368
        }
3369
        @path = @ResolveBinFileList;
3370
        @types = ($opt_type, '');
3371
    }
3372
    else
3373
    {
3374
        @path = ($opt_bindir, $opt_localbindir);
3375
        @types = '';
3376
    }
3377
 
3378
    #
3379
    #   Determine a full list of 'parts' to search
3380
    #       Default: Provided within the build information
3381
    #       User   : Can provide a list
3382
    #
3383
    my @parts = getPlatformPartsList($refPlatforms);
3384
 
3385
    my @done;
3386
    foreach my $root (  @path )
3387
    {
3388
        foreach my $subdir ( @parts )
3389
        {
3390
            foreach my $type ( @types )
3391
            {
3392
                my $sfile;
3393
                $sfile = "$root/$subdir$type/$file";
3394
                $sfile =~ s~//~/~g;
3395
                Verbose2("LocateBinFile: $sfile");
3396
                if ( $wildcard )
3397
                {
3398
                    foreach  ( glob ( $sfile ) )
3399
                    {
3400
                        # Ignore .dbg (vix) and .debug (qt) files.
3401
                        next if ( m~\.dbg$~ );
3402
                        next if ( m~\.debug$~ );
3403
                        push @done, $_;
3404
                    }
3405
                }
3406
                else
3407
                {
3408
                    push @done, $sfile if ( -f $sfile || -l $sfile )
3409
                }
3410
            }
3411
        }
3412
    }
3413
 
3414
    #
3415
    #   Pretty display the search path - on error
3416
    #       Will not return.
3417
    #
3418
    DisplaySearchPath('ResolveBinFile', $file, \@parts, \@types, \@path) unless (@done) ;
3419
 
3420
    if ( $#done > 0 && ! $wildcard )
3421
    {
3422
        Warning ("ResolveBinFile: Multiple instances of file found. Only first is used", @done);
3423
        splice (@done, 1);
3424
    }
3425
 
3426
    return wantarray ? @done : $done[0];
3427
}
3428
 
3429
#-------------------------------------------------------------------------------
3430
# Function        : ResolveLibFile
3431
#
3432
# Description     : Determine where the source for a LIB file is
3433
#                   Will look in (default):
3434
#                       Local directory
3435
#                       Local Include
3436
#                   Or  (FromPackage)
3437
#                       Our Package directory
3438
#                       Interface directory (BuildPkgArchives)
3439
#                       Packages (LinkPkgArchive)
3440
#                   Will scan 'parts' subdirs
3441
#
3442
# Inputs          : $from_package   - 0:Local File
3443
#                   $file           - Basename for a 'realname'
3444
#                                     Do not provide 'lib' or '.so' or version info
3445
#                                     May contain embedded options
3446
#                                       --Dll           - Use Windows style versioned DLL
3447
#                                       --VersionDll    - Use the versioned DLL
3448
#                                       --3rdParty      - Use exact name provided
3449
#                   $refPlatforms       - Ref to an array of platforms to scan
3450
#
3451
# Returns         : Path
3452
#
3453
sub ResolveLibFile
3454
{
3455
    my ($from_package, $file, $refPlatforms) = @_;
3456
    my $wildcard = ($file =~ /[*?]/);
3457
    my @options;
3458
    my $num_dll;
3459
    my @types;
3460
    my @path;
3461
    #
3462
    #   Extract options from file
3463
    #
3464
    $num_dll = 0;
3465
    ($file, @options) = split ( ',', $file);
3466
    foreach ( @options )
3467
    {
3468
        if ( m/^--Dll/ ) {
3469
            $num_dll = 1;
3470
        } elsif ( m/^--VersionDll/ ) {
3471
            $num_dll = 2;
3472
        } elsif ( m/^--3rdParty/ ) {
3473
            $num_dll = 3;
3474
        } else {
3475
            Error ("Unknown suboption to ResolveLibFile: $_" );
3476
        }
3477
    }
3478
 
3479
    #
3480
    #   Determine the paths to search
3481
    #
3482
    if ( $from_package )
3483
    {
3484
        unless ( @ResolveLibFileList )
3485
        {
3486
            push @ResolveLibFileList, $opt_pkgdir . '/lib';
3487
            foreach my $entry ( getPackageList() )
3488
            {
3489
                push @ResolveLibFileList, $entry->getLibDirs(3);
3490
            }
3491
        }
3492
        @path = @ResolveLibFileList;
3493
    }
3494
    else
3495
    {
3496
        @path = ($opt_libdir, $opt_locallibdir);
3497
    }
3498
 
3499
    #   Determine a full list of 'parts' to search
3500
    #       Default: Provided within the build information
3501
    #       User   : Can provide a list
3502
    my @parts = getPlatformPartsList($refPlatforms);
3503
 
3504
    @types = ( $opt_type, '');
3505
 
3506
    my @done;
3507
    foreach my $root (  @path )
3508
    {
3509
        foreach my $type ( @types )
3510
        {
3511
            foreach my $subdir ( @parts )
3512
            {
3513
                my $sfile;
3514
                my $exact;
3515
                if ( $num_dll == 2 ) {
3516
                    $sfile = $file . $type . '.*.dll' ;
3517
                } elsif ( $num_dll == 1 ) {
3518
                    $sfile = $file . $type . '.dll' ;
3519
                    $exact = 1;
3520
                } elsif ( $num_dll == 3 ) {
3521
                    $sfile = $file;
3522
                    $exact = 1;
3523
                } else {
3524
                    $sfile = "lib" . $file . $type . '.so.*';
3525
                }
3526
 
3527
                $sfile = "$root/$subdir/$sfile";
3528
                $sfile =~ s~//~/~g;
3529
                Verbose2("LocateLibFile: $sfile");
3530
                if ( $exact )
3531
                {
6689 dpurdie 3532
                    UniquePush(\@done, $sfile) if ( -f $sfile || -l $sfile );
6242 dpurdie 3533
                }
3534
                elsif ($num_dll)
3535
                {
3536
                    push @done, glob ( $sfile );
3537
                }
3538
                else
3539
                {
3540
                    #
3541
                    #   Looking for .so files
3542
                    #   Filter out the soname so files
3543
                    #   Assume that the soname is shorter than the realname
3544
                    #       Ignore .dbg (vix) and .debug (qt) files.
3545
                    #
3546
                    my %sieve;
3547
                    foreach ( glob ( $sfile )  )
3548
                    {
3549
                        next if ( m~\.dbg$~ );
3550
                        next if ( m~\.debug$~ );
3551
                        m~(.*\.so\.)([\d\.]*\d)$~;
3552
                        if ( $1 )
3553
                        {
3554
                            my $file = $1;
3555
                            my $len = exists $sieve{$file} ? length($sieve{$file}) : 0;
3556
                            $sieve{$file} = $_
3557
                                if ( $len == 0 || length($_) > $len );
3558
                        }                                
3559
                    }
3560
 
3561
                    push @done, values %sieve;
3562
                }
3563
            }
3564
        }
3565
    }
3566
 
3567
    DisplaySearchPath('ResolveLibFile', $file, \@parts, \@types, \@path) unless (@done) ;
3568
 
3569
    if ( $#done > 0 && ! $wildcard )
3570
    {
3571
        Warning ("ResolveLibFile: Multiple instances of file found. Only first is used", @done);
3572
        splice (@done, 1);
3573
    }
3574
    return wantarray ? @done : $done[0];
3575
}
3576
 
3577
#-------------------------------------------------------------------------------
3578
# Function        : ResolveDebPackage
3579
#
3580
# Description     : Determine where the source for a Debian Package is
3581
#                   Will look in (default):
3582
#                       Local directory
3583
#                       Local Include
3584
#                   Or  (FromPackage)
3585
#                       Our Package directory
3586
#                       Interface directory (BuildPkgArchives)
3587
#                       Packages (LinkPkgArchive)
3588
#
3589
# Inputs          : $from_package   - 0:Local File
3590
#                   $baseName       - Basename for a 'DebianPackage'
3591
#                                     Do not provide version info, architecture or suffix
3592
#                                     May contain embedded options
3593
#                                       --Arch=XXX      - Specify alternate architcuture
3594
#                                       --Product=YYYY  - Specify product family
3595
#                                       --Debug         - Use alternate build type
3596
#                                       --Prod          - Use alternate build type
3597
#                   $refPlatforms       - Ref to an array of platforms to scan
3598
#
3599
# Returns         : Path
3600
#
3601
sub ResolveDebPackage
3602
{
3603
    my ($from_package, $file, $refPlatforms) = @_;
3604
    my @path;
3605
    my $arch;
3606
    my $product;
3607
    my $buildType;
3608
    my @types;
3609
    my $baseName;
3610
    my @options;
3611
 
3612
    #
3613
    #   Extract options from file
3614
    #
3615
    ($baseName, @options) = split ( ',', $file);
3616
    foreach ( @options )
3617
    {
3618
        if ( m/^--Arch=(.+)/ ) {
3619
            $arch=$1;
3620
        } elsif ( m/^--Product=(.+)/ ) {
3621
            $product = $1;
3622
        } elsif ( m/^--Debug/ ) {
3623
            Error ("ResolveDebPackage: Cannot specify --Prod and --Debug") if defined $buildType;
3624
            $buildType = 'D';
3625
        } elsif ( m/^--Prod/ ) {
3626
            Error ("ResolveDebPackage: Cannot specify --Prod and --Debug") if defined $buildType;
3627
            $buildType = 'P';
3628
        } else {
3629
            Error ("Unknown suboption to ResolveDebPackage: $_" );
3630
        }
3631
    }
3632
 
3633
    #
3634
    #   Insert defaults
3635
    #
3636
    $buildType = $opt_type unless ($buildType);
3637
    $arch = $opt_target unless ($arch);
3638
 
3639
    #
3640
    #   Determine the paths to search
3641
    #
3642
    if ( $from_package )
3643
    {
3644
        unless ( @ResolveDebFileList )
3645
        {
3646
            push @ResolveDebFileList,  $opt_pkgdir, $opt_pkgdir . '/bin';
3647
            foreach my $entry ( getPackageList() )
3648
            {
3649
                if ( my $path = $entry->getBase(3) )
3650
                {
3651
                    push @ResolveDebFileList, $path if ( -d $path );
3652
 
3653
                    $path .= '/bin';
3654
                    push @ResolveDebFileList, $path if ( -d $path );
3655
                }
3656
            }
3657
        }
3658
        @path = @ResolveDebFileList;
3659
        @types = ($buildType, '');
3660
    }
3661
    else
3662
    {
3663
        @path = ($opt_bindir, $opt_localbindir);
3664
        @types = ($buildType, '');
3665
    }
3666
 
3667
    #
3668
    #   The debian  package name is
3669
    #   In packages BIN dir
3670
    #       (BaseName)_VersionString(_Product)(_Arch).deb
3671
    #       
3672
    #   In root of package
3673
    #       (BaseName)_VersionString(_Product)(_Arch)(_Type).deb
3674
    #
3675
    #       
3676
    #   The package may be found in
3677
    #       Package Root
3678
    #       Package bin directory
3679
    #       
3680
    $file = $baseName . '_*';
3681
    if (defined $product) {
3682
        $file .= ( '_' . $product)
3683
        }
3684
    $file .= '_' . $arch;
3685
 
3686
    #   Determine a full list of 'parts' to search
3687
    #       Default: Provided within the build information
3688
    #       User   : Can provide a list
3689
    my @parts = getPlatformPartsList($refPlatforms);
3690
 
3691
    my @done;
3692
    foreach my $root (  @path )
3693
    {
3694
        foreach my $subdir ( @parts )
3695
        {
3696
            foreach my $type ( @types )
3697
            {
3698
                my $sfile;
3699
                $sfile = "$root/$subdir$type/$file";
3700
                $sfile =~ s~//~/~g;
3701
                foreach my $type2 ( @types )
3702
                {
3703
                    my $tfile = $sfile;
3704
                    $tfile .= '_' . $type2 if $type2;
3705
                    $tfile .= '.deb';
3706
                    Verbose2("ResolveDebPackage: $tfile");
3707
                    foreach  ( glob ( $tfile ) )
3708
                    {
3709
                        push @done, $_;
3710
                    }
3711
                }
3712
            }
3713
        }
3714
    }
3715
 
3716
    DisplaySearchPath('ResolveDebPackage', $file, \@parts, \@types, \@path) unless (@done) ;
3717
 
3718
    if ( $#done > 0 )
3719
    {
3720
        Error ("ResolveDebPackage: Multiple instances of Package found.", @done);
3721
    }
3722
    return wantarray ? @done : $done[0];
3723
}
3724
 
3725
#-------------------------------------------------------------------------------
3726
# Function        : prettyArray 
3727
#
3728
# Description     : Generate a quoted string from an array
3729
#
3730
# Inputs          : Array Ref
3731
#
3732
# Returns         : A string
3733
#
3734
sub prettyArray
3735
{
3736
    my ($arrayRef) = @_;
3737
    return join(',', map { qq!"$_"! }  @{$arrayRef})
3738
}
3739
 
3740
#-------------------------------------------------------------------------------
3741
# Function        : DisplaySearchPath 
3742
#
3743
# Description     : Pretty display of the search path
3744
#                   Error display
3745
#
3746
# Inputs          : $name   - Function Name
3747
#                   $file   - Base filename being searched
3748
#                   $parts  - Ref to array of parts searched
3749
#                   $types  - Ref to array of types searched - may be undef
3750
#                   $path   - Ref to array of paths searched
3751
#
3752
# Returns         : Will not return
3753
#
3754
sub DisplaySearchPath
3755
{
3756
    my ($name, $file, $parts, $types, $path) = @_;
3757
    my @text;
3758
 
3759
    push @text, $name . ': File not found: ' . $file;
3760
    push @text, 'Search Platforms: ' . prettyArray($parts);
3761
    push @text, 'Search Types: ' . prettyArray($types) if defined $types;
3762
    push @text, 'Search Path:', @$path;
3763
    Error (@text);
3764
}
3765
 
3766
#-------------------------------------------------------------------------------
3767
# Function        : getPlatformPartsList  
3768
#
3769
# Description     : Determine a full list of 'parts' to search
3770
#                       Default: Provided within the build information
3771
#                       User   : Can provide a list
3772
#
3773
# Inputs          : $refPlatforms - Ref to an array of user provided platforms
3774
#                                   If provided will override the internal list
3775
#
3776
# Returns         : An array 
3777
#
3778
sub getPlatformPartsList
3779
{
3780
    my ($refPlatforms) = @_;
3781
    my @parts;
3782
 
3783
    if ($refPlatforms && scalar @{$refPlatforms}) {
3784
        @parts = @{$refPlatforms};
3785
 
3786
    } else {
3787
        @parts = getPlatformParts ();
3788
    }
3789
    push @parts, '';
3790
    return @parts;
3791
}
3792
 
3793
#-------------------------------------------------------------------------------
3794
# Function        : AUTOLOAD
3795
#
3796
# Description     : Intercept unknown user directives and issue a nice error message
3797
#                   This is a simple routine to report unknown user directives
3798
#                   It does not attempt to distinguish between user errors and
3799
#                   programming errors. It assumes that the program has been
3800
#                   tested. The function simply report filename and line number
3801
#                   of the bad directive.
3802
#
3803
# Inputs          : Original function arguments ( not used )
3804
#
3805
# Returns         : This function does not return
3806
#
3807
our $AUTOLOAD;
3808
sub AUTOLOAD
3809
{
3810
    my $fname = $AUTOLOAD;
3811
    $fname =~ s~^main::~~;
3812
    my ($package, $filename, $line) = caller;
3813
    my $prefix;
3814
 
3815
    #
3816
    #   Some directives are applicable to Rpm and/or Debian only
3817
    #   If a directive starts with Rpm, Debian or All, then invoke
3818
    #   the underlying directive iff we are process a Debian/Rpm file
3819
    #   
3820
    #   The underlying directive will start with MULTI_
3821
    #   It will be called with the first argument being the name of the function
3822
    #   that it is being called as.
3823
    #
3824
    $fname =~ m~^(Rpm|Debian|All)(.*)~;
3825
    if (defined $1) {
3826
        my $type = $1;
3827
        my $tfname = 'MULTI_' . $2;
3828
        my $fRef = \&{$tfname}; 
3829
 
3830
        if (defined &{$tfname}) {
3831
            if ($type eq 'Rpm') {
3832
                $fRef->($fname, @_) if $opt_rpm;
3833
 
3834
            } elsif ($type eq 'Debian') {
3835
                $fRef->($fname, @_) if $opt_debian;
3836
 
3837
            } elsif ($type eq 'All') {
3838
                $fRef->($fname, @_);
3839
            }
3840
            return 1;
3841
        }
3842
    }
3843
 
3844
    Error ("Directive not known or not allowed in this context: $fname",
3845
           "Directive: $fname( @_ );",
3846
           "File: " . RelPath($filename) . ", Line: $line" );
3847
}
3848
 
3849
1;
3850