Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
263 dpurdie 1
########################################################################
7300 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
227 dpurdie 3
#
5499 dpurdie 4
# Module name   : create_dpkg.pl
4549 dpurdie 5
# Module type   : Makefile system
263 dpurdie 6
# Compiler(s)   : Perl
4549 dpurdie 7
# Environment(s): jats
227 dpurdie 8
#
263 dpurdie 9
# Description   : This script is used to create a dpkg_archive.
5527 dpurdie 10
#                 Features:
4549 dpurdie 11
#                   * No user interaction
5527 dpurdie 12
#                   * Generates files list for ReleaseNote integration
13
#                   * Can generate package fragemts as a tarball for build system
227 dpurdie 14
#
4549 dpurdie 15
# Usage:        : See POD
227 dpurdie 16
#
263 dpurdie 17
#......................................................................#
227 dpurdie 18
 
4549 dpurdie 19
 
263 dpurdie 20
require 5.008_002;
227 dpurdie 21
 
22
# Include Standard Perl Functions
23
#
24
use strict;
263 dpurdie 25
use warnings;
227 dpurdie 26
use Cwd;
27
use Getopt::Long;
28
use File::Basename;
29
use File::Find;
30
use File::Path;
31
use File::Copy;
32
use Pod::Usage;
263 dpurdie 33
use Digest::MD5;
4549 dpurdie 34
use XML::Simple;
4633 dpurdie 35
use Encode qw(decode encode);
227 dpurdie 36
 
37
use JatsError;
263 dpurdie 38
use JatsEnv;
227 dpurdie 39
use DescPkg;
40
use FileUtils;
5527 dpurdie 41
use JatsSystem;
7300 dpurdie 42
use JatsVersionUtils;
227 dpurdie 43
 
363 dpurdie 44
#
45
#   Under Windows we need the Win32::FileSecurity module
46
#   It only exists under windows
47
#
48
my $Win32 = eval "require Win32::FileSecurity";
49
 
227 dpurdie 50
# define Global variables
51
#
4549 dpurdie 52
my $VERSION = "3.0.0";
227 dpurdie 53
my $PROGNAME = "create_dpkg.pl";
54
 
279 dpurdie 55
# Globals imported from environment
56
#
57
our $GBE_MACHTYPE;
58
our $GBE_HOSTNAME;
59
our $USER;
60
our $GBE_ABT;
227 dpurdie 61
 
279 dpurdie 62
# Global variables
63
#
227 dpurdie 64
my $DPKG_NAME     = "";
65
my $DESC_NAME     = "";
66
my $DPKG_VERSION  = "";
7300 dpurdie 67
my $DPKG_PRJ      = "";
7301 dpurdie 68
my $DPKG_SIGNATURE = "";
227 dpurdie 69
my $DESCPKG_FILE  = "";
70
my $DESCPKG_TYPE  = "";
71
my $CWD_DIR       = cwd;
72
my $SRC_ROOT;
73
my $DPKG_DIR;
74
my $DPKG_ROOT;
4003 dpurdie 75
my $PKG_BASE;
263 dpurdie 76
my $bad_merge_count = 0;
4424 dpurdie 77
my @bad_symlinks;
4549 dpurdie 78
my @fileList;
79
my $descPkgCount = 0;
5578 dpurdie 80
my @tmpFiles;
227 dpurdie 81
 
82
#
83
#   Option variables
84
#
85
my $opt_help = 0;
86
my $opt_manual = 0;
87
my $opt_verbose = 0;
88
my $opt_quiet = 0;
4549 dpurdie 89
my $opt_delete = 0;
227 dpurdie 90
my $opt_override = 0;
91
my $opt_merge = 0;
92
my $opt_archive;
93
my $opt_generic;
94
my $opt_pname;
95
my $opt_pversion;
96
my $opt_test;
263 dpurdie 97
my $opt_md5 = 1;
4549 dpurdie 98
my $opt_outfile;
99
my $opt_info;
5527 dpurdie 100
my $opt_tarmode;
101
my $opt_testArchive;
5550 dpurdie 102
my $opt_noBuild;
5578 dpurdie 103
my $opt_keepTemp;
227 dpurdie 104
 
105
 
106
#
107
#   Structure to translate -archive=xxx option to archive variable
108
#   These are the various dpkg_archives known to JATS
109
#
4688 dpurdie 110
my %Archive2Var =( 'main'      => 'GBE_DPKG',
111
                   'store'     => 'GBE_DPKG_STORE',
112
                   'cache'     => 'GBE_DPKG_CACHE',
113
                   'local'     => 'GBE_DPKG_LOCAL',
114
                   'sandbox'   => 'GBE_DPKG_SBOX',
115
                   'deploy'    => 'GBE_DPLY',
116
                   'replica'   => 'GBE_DPKG_REPLICA',
7319 dpurdie 117
                   'escrow'    => 'GBE_DPKG_ESCROW',
227 dpurdie 118
                   );
119
 
120
#------------------------------------------------------------------------------
121
#------------------------------------------------------------------------------
122
# Subroutines
123
#------------------------------------------------------------------------------
124
#------------------------------------------------------------------------------
125
 
126
#------------------------------------------------------------------------------
127
sub LogFileOp
128
#
129
# Description:
130
#       This sub-routine is used to generate a consistent informational log
131
#------------------------------------------------------------------------------
132
{
133
    my ($opr, $file) = @_;
5582 dpurdie 134
 
7300 dpurdie 135
    $file =~ s/\Q$DPKG_DIR\E/PKGDIR/;
5532 dpurdie 136
    $file =~ s/\Q$DPKG_ROOT\E/DPKG/;
137
    $file =~ s/\Q$SRC_ROOT\E/PKG/;
5578 dpurdie 138
    $file =~ s/\Q$CWD_DIR\E/CWD/;
227 dpurdie 139
 
140
    Information (sprintf( "%-15s [%s]", $opr, $file));
141
}
142
 
4549 dpurdie 143
#-------------------------------------------------------------------------------
144
# Function        : addFile 
145
#
146
# Description     : Add a file to the list of transferred files
147
#
148
# Inputs          : $type           - File type
149
#                   $source         - Source file - full path
150
#                                     Use local copy, not network copy for file ops
151
#                   $target         - Target file name
152
#                   $md5sum         - Precalculated MD5 sum 
153
#
154
# Returns         : 
155
#
156
sub addFile
157
{
158
    my ($type, $source, $target, $md5sum) = @_;
159
    my %data;
160
 
161
    if ((not defined $md5sum) && ($type eq 'file'))
162
    {
163
        Verbose("Calculate MD5 Digest: $source");
164
        open(my $fh , $source) or Error ("Can't open '$source': $!");
165
        binmode $fh, ':crlf';
166
        $md5sum = Digest::MD5->new->addfile($fh)->hexdigest;
167
        close $fh;
168
    }
169
 
5532 dpurdie 170
    $target =~ s~\Q$DPKG_DIR\E~~;
4549 dpurdie 171
    $target =~ s~^/~~;
172
    $target =~ s~/$~~;
173
 
4633 dpurdie 174
    #
175
    #   Convert from iso-8859-1 into utf-8
176
    #
177
    $target = decode( 'iso-8859-1', $target );
178
    $target = encode( 'utf-8', $target );
179
 
4549 dpurdie 180
    if ($type eq 'dir')
181
    {
182
        $data{path} = $target;
183
    }
184
    else
185
    {
186
        $data{path} = StripFileExt($target);
187
        $data{name} = StripDir($target);
188
        if ($type eq 'file')
189
        {
190
            $data{size} = (stat($source))[7];
191
            $data{md5sum} = $md5sum;
192
        }
193
    }
194
 
195
    $data{fullname} = $target;
196
    $data{type} = $type;
197
    $data{machtype} = $GBE_MACHTYPE;
198
    $data{host} = $GBE_HOSTNAME;
199
 
5499 dpurdie 200
    # Put a nice '/' on the end of the path elements
4549 dpurdie 201
    $data{path} .= '/'
202
        if ( exists ($data{path}) && length($data{path}) > 0);
203
 
204
    push @fileList, \%data;
205
}
206
 
207
#-------------------------------------------------------------------------------
208
# Function        : writeFileInfo 
209
#
210
# Description     : Write out an XML file that contains this processes
211
#                   contribution to the output package 
212
#
5527 dpurdie 213
# Inputs          : $targetDir          - Base directory for the file 
4549 dpurdie 214
#
215
# Returns         : 
216
#
217
sub writeFileInfo
218
{
5527 dpurdie 219
    my ($targetDir) = @_;
4549 dpurdie 220
    my $data;
221
    $data->{file} = \@fileList;
222
 
223
    #
224
    #   Write out sections of XML
225
    #       Want control over the output order
226
    #       Use lots of attributes and only elements for arrays
227
    #       Save as one attribute per line - for readability
228
    #
5527 dpurdie 229
    $opt_outfile = $opt_generic ? "built.files.generic.xml" : "built.files.$GBE_HOSTNAME.xml";
230
    $opt_outfile = catfile( $targetDir, $opt_outfile); 
4549 dpurdie 231
 
232
    LogFileOp ('Meta File', $opt_outfile);
233
    my $xs = XML::Simple->new( NoAttr =>0, AttrIndent => 1 );
234
 
235
    open (my $XML, '>', $opt_outfile) || Error ("Cannot create output file: $opt_outfile", $!);
236
    $xs->XMLout($data, 
237
                'RootName' => 'files', 
238
                'XMLDecl'  => '<?xml version="1.0" encoding="UTF-8"?>',
239
                'OutputFile' => $XML);
240
    close $XML;
241
 
242
}
243
 
227 dpurdie 244
#------------------------------------------------------------------------------
245
sub Init
246
#
247
# Description:
248
#     This function is used to process any command line arguements
249
#     and print the start banner.
250
#
251
#------------------------------------------------------------------------------
252
{
253
    # Process any command line arguements...
254
    my $result = GetOptions (
5527 dpurdie 255
                'help:+'        => \$opt_help,              # flag, multiple use allowed
256
                'manual:3'      => \$opt_help,              # flag
257
                'verbose:+'     => \$opt_verbose,           # flag, multiple use allowed
258
                'override!'     => \$opt_override,          # [no]flag (No longer used. Backward compat with build tool)
259
                'delete!'       => \$opt_delete,            # [no]flag
260
                'merge|m!'      => \$opt_merge,             # [no]flag.
261
                'archive=s'     => \$opt_archive,           # string
262
                'quiet+'        => \$opt_quiet,             # Flag
263
                'generic!'      => \$opt_generic,           # [no]Flag
264
                'pname=s'       => \$opt_pname,             # string
265
                'pversion=s'    => \$opt_pversion,          # string
266
                'test!'         => \$opt_test,              # [no]flag
267
                'md5!'          => \$opt_md5,               # [no]flag
268
                'info!'         => \$opt_info,              # [no]flag
269
                'tarmode!'      => \$opt_tarmode,           # [no]flag
270
                'testArchive'   => \$opt_testArchive,       # [no]flag
5550 dpurdie 271
                'nobuild'       => \$opt_noBuild,           # flag
5578 dpurdie 272
                'keepTemp'      => \$opt_keepTemp,          # flag
227 dpurdie 273
                );
274
 
275
 
276
    #
277
    #   Process help and manual options
278
    #
279
    pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
280
    pod2usage(-verbose => 1)  if ($opt_help == 2 );
263 dpurdie 281
    pod2usage(-verbose => 2)  if ($opt_help > 2);
227 dpurdie 282
 
283
    #
284
    #   Init the error and message subsystem
285
    #
286
    ErrorConfig( 'name'    =>'CREATE_DPKG',
287
                 'verbose' => $opt_verbose,
288
                 'quiet'   => $opt_quiet );
289
 
290
    if ($opt_verbose)
291
    {
292
       Verbose ("Program: $PROGNAME");
293
       Verbose ("Version: $VERSION");
294
    }
295
 
296
    #
263 dpurdie 297
    #   Needed EnvVars
298
    #
299
    EnvImport ('GBE_MACHTYPE');
279 dpurdie 300
    EnvImport ('GBE_HOSTNAME');
301
    EnvImport ('USER' );
302
    EnvImportOptional ('GBE_ABT', "");
7319 dpurdie 303
    EnvImportOptional ('GBE_DPKG_ESCROW', "");
5578 dpurdie 304
    $CWD_DIR = catdir($CWD_DIR);
263 dpurdie 305
 
4003 dpurdie 306
    #
307
    #   Determine the target archive
308
    #   The default archive is GBE_DPKG, but this may be changed
309
    #
7319 dpurdie 310
    unless ( $opt_archive )
311
    {
312
        $opt_archive = 'main';
313
        $opt_archive = 'escrow' if ($::GBE_DPKG_ESCROW);
314
    }
4003 dpurdie 315
    my $archive_tag = $Archive2Var{$opt_archive};
316
    Error("Unknown archive specified: $opt_archive")
317
        unless ( $archive_tag );
318
    $DPKG_ROOT = $ENV{$archive_tag} || '';
319
    Verbose ("Archive Variable: $archive_tag" );
320
    Verbose2 ("Archive Path: $DPKG_ROOT" );
279 dpurdie 321
 
263 dpurdie 322
    #
5527 dpurdie 323
    #   Append testArchive path
324
    #
325
    $DPKG_ROOT = catdir ($DPKG_ROOT, '.dpkg_archive', 'test_dpkg') if $opt_testArchive;
326
 
327
    #
4003 dpurdie 328
    #   Detect NoBuild marker
329
    #   This will bypass most of the operation of this package
330
    #
5550 dpurdie 331
    $opt_noBuild = 2 if -f 'noBuild.gbe';
332
    if ( $opt_noBuild)
4003 dpurdie 333
    {
7319 dpurdie 334
        Verbose ("NoBuild Marker file found");
4003 dpurdie 335
 
336
        $SRC_ROOT = '';
337
        $DPKG_NAME = 'pkg';
338
        $DESCPKG_FILE = 'descpkg';
339
        $PKG_BASE =$CWD_DIR;
5550 dpurdie 340
 
4003 dpurdie 341
        return;
342
    }
343
 
344
    #
227 dpurdie 345
    #   Check for a "pkg" directory
346
    #   This may be in:
347
    #       1) The deploy directory (DEPLOY) build/deploy/descpkg
348
    #       2) The build directory (ANT)     build/pkg/descpkg
349
    #       3) The current directory (JATS)  pkg/xxxx/descpkg
350
    #
4003 dpurdie 351
    $PKG_BASE = "$CWD_DIR/build/deploy";
227 dpurdie 352
    Verbose2 ("Looking for descpkg: $PKG_BASE");
353
    if ( -f "$PKG_BASE/descpkg" )
354
    {
355
        #
356
        #   This is a deployment package.
357
        #   Force the use of the GBE_DPLY
358
        #
359
        $opt_archive = 'deploy' unless ( $opt_archive );
360
    }
361
    else
362
    {
363
        $PKG_BASE = "$CWD_DIR/build/pkg";
364
        Verbose ("Looking for descpkg: $PKG_BASE");
365
        if ( ! -f  "$PKG_BASE/descpkg" )
366
        {
367
            $PKG_BASE = "$CWD_DIR/pkg";
368
            Verbose ("Looking for descpkg: $PKG_BASE");
369
            Error("Failed to find a package to transfer. Looked in:",
370
                  "./build/deploy",
371
                  "./build/pkg",
372
                  "./pkg"
373
                  )
374
                unless( -d $PKG_BASE );
375
        }
376
    }
377
    Verbose("Package directory: $PKG_BASE");
378
 
379
    Error("Repository location not specified: $archive_tag")
380
        unless $DPKG_ROOT;
381
 
382
    Error("Failed to find Repository: $DPKG_ROOT")
383
        unless ( -d $DPKG_ROOT );
384
 
385
    #   Locate the package
386
    #   Packages are located by looking for a file called descpkg within the
387
    #   main package directory.
388
    #
389
    #   This installation process only handles one such file
390
    #
4549 dpurdie 391
    $descPkgCount = 0;
227 dpurdie 392
    File::Find::find( \&pkgFind, $PKG_BASE);
4549 dpurdie 393
 
394
    if ($descPkgCount > 1 )
395
    {
396
        Warning ("Package contains multiple ($descPkgCount) descpkg files");
397
    }
4003 dpurdie 398
}
227 dpurdie 399
 
4003 dpurdie 400
#-------------------------------------------------------------------------------
401
# Function        : CheckDescPkg
402
#
403
# Description     : Check the descpkg file
404
#
405
# Inputs          : Globals
406
#
407
# Returns         : Will not return on error
408
#
409
sub CheckDescPkg
410
{
5550 dpurdie 411
 
227 dpurdie 412
    # Get the dpkg_archive version number we are  going to create.
413
    #
414
    Error("Descpkg file not found in package directory: $PKG_BASE")
415
        unless ( -f "$DESCPKG_FILE" );
416
 
417
    #
418
    #   Read in the package description and validate essential fields
419
    #
420
    GetDpkgArchiveVersion($DESCPKG_FILE);
421
    unless ( "$DPKG_VERSION" )
422
    {
423
        Error ("Incorrect descpkg content detected.",
424
               "Check JATS build.pl config.");
425
    }
426
 
427
    #
428
    #   Need to support two forms of pkg subdirectory
429
    #       1) packages are in a named subdir within 'pkg'
430
    #       2) package is within 'pkg' or 'deploy'
431
    #
432
    if ( $DPKG_NAME eq 'pkg' || $DPKG_NAME eq 'deploy' )
433
    {
434
        $DPKG_NAME = $DESC_NAME;
435
        unless ( $DESC_NAME )
436
        {
437
            Error ("Cannot determine package name",
438
                   "The packages 'descpkg' file is bad or missing");
439
        }
440
    }
441
    elsif ( $DESC_NAME ne $DPKG_NAME )
442
    {
443
        Error ("Package name MUST match package description",
444
               "Check build.pl and package.pl",
445
               "Package name: $DPKG_NAME",
446
               "Description : $DESC_NAME" );
447
    }
448
 
449
    #
450
    # lets just check to see if we have a version number before
451
    # we proceed.
452
    #
453
    unless ( $DPKG_VERSION )
454
    {
455
        Error("Cannot determine dpkg_archive version number.",
456
              "Check JATS build config.");
457
    }
458
 
7300 dpurdie 459
    my ($pn, $pv, $ps ) = SplitPackage ($DPKG_NAME, $DPKG_VERSION );
460
    $DPKG_PRJ = '.' . $ps if ( $ps ); 
461
 
227 dpurdie 462
    #
463
    #   Sanity test package name and version, if provided
464
    #
465
    if ( $opt_pname )
466
    {
467
        ReportError ("Package Name does not match expected name",
468
                     "Expected: '$opt_pname'",
469
                     "Descpkg : '$DPKG_NAME'") unless ( $DPKG_NAME eq $opt_pname );
470
    }
471
    if ( $opt_pversion )
472
    {
473
        ReportError ("Package Version does not match expected version",
474
                     "Expected: '$opt_pversion'",
475
                     "Descpkg : '$DPKG_VERSION'") unless ( $DPKG_VERSION eq $opt_pversion );
476
    }
477
    ErrorDoExit();
4003 dpurdie 478
}
227 dpurdie 479
 
4003 dpurdie 480
#-------------------------------------------------------------------------------
481
# Function        : ShowInfo
482
#
483
# Description     : Show info to the user
484
#
485
# Inputs          : 
486
#
487
# Returns         : 
488
#
489
sub ShowInfo
490
{
227 dpurdie 491
    #
492
    #   Set up the target directory path and name
493
    #   It will be created later
494
    #
5527 dpurdie 495
    if ($opt_tarmode)
496
    {
497
        $DPKG_DIR = catdir($DPKG_ROOT, '.dpkg_archive', 'fragments');
498
    }
7301 dpurdie 499
    elsif ( $DPKG_SIGNATURE )
500
    {
501
        $DPKG_DIR = catdir($DPKG_ROOT, $DPKG_NAME . $DPKG_PRJ, $DPKG_SIGNATURE );
502
    }
5527 dpurdie 503
    else
504
    {
505
        $DPKG_DIR = catdir($DPKG_ROOT, $DPKG_NAME, $DPKG_VERSION );
506
    }
4003 dpurdie 507
 
227 dpurdie 508
    #
509
    #   Information for the user
510
    #
511
    Information ("---------------------------------------------------------------");
512
    Information ("Dpkg archive creation tool...");
513
    Information ("Version: $VERSION");
514
    Information ("");
515
    Information ("Information:");
7319 dpurdie 516
    Information ("Escrow Build") if ($opt_archive eq 'escrow');
227 dpurdie 517
    Information ("Working dir   = [$CWD_DIR]");
518
    Information ("Package Root  = [$SRC_ROOT]");
4549 dpurdie 519
    Information ("Repository    = [$DPKG_ROOT]");
7319 dpurdie 520
    Information ("                *Non Standard archive") unless ($opt_archive eq 'main' || $opt_archive eq 'escrow');
227 dpurdie 521
    Information ("Target dir    = [$DPKG_DIR]");
522
    Information1("DPKG_NAME     = [$DPKG_NAME]");
523
    Information1("DPKG_VERSION  = [$DPKG_VERSION]");
7300 dpurdie 524
    Information1("DPKG_PRJ      = [$DPKG_PRJ]");
7301 dpurdie 525
    Information1("DPKG_SIGNATURE= [$DPKG_SIGNATURE]") if $DPKG_SIGNATURE;
227 dpurdie 526
    Information1("GBE_MACHTYPE  = [$GBE_MACHTYPE]");
279 dpurdie 527
    Information1("GBE_HOSTNAME  = [$GBE_HOSTNAME]");
528
    Information1("GBE_ABT       = [$GBE_ABT]");
529
    Information1("USER          = [$USER]");
5550 dpurdie 530
    Information ("")                                if ( $opt_merge || $opt_delete || $opt_info || $opt_tarmode || $opt_testArchive || $opt_noBuild);
531
    Information ("Opt:NoBuild       = Enabled")     if ( $opt_noBuild );
5527 dpurdie 532
    Information ("Opt:TarMode       = Enabled")     if ( $opt_tarmode );
533
    Information ("Opt:Delete        = Enabled")     if ( $opt_delete );
534
    Information ("Opt:Merge         = Enabled")     if ( $opt_merge );
535
    Information ("Opt:testArchive   = Enabled")     if ( $opt_testArchive );
536
    Information ("Opt:TestMode      = Enabled. No Package Transferred") if ( $opt_test );
537
    Information ("Opt:Info          = Enabled. No Package Transferred") if ( $opt_info );
538
    Warning     ("Sandbox Build     = Yes") if ($ENV{GBE_DPKG_SBOX}) ;
227 dpurdie 539
    Information ("---------------------------------------------------------------");
540
 
369 dpurdie 541
    #
542
    #   If the environment variable GBE_DPKG_SBOX is defined then the package
543
    #   is being built within a development sandbox. In such a sandbox the
544
    #   version numbers of the packages are ignored. Publishing a package
5499 dpurdie 545
    #   from such an environment is certainly not reproducible - so don't allow
369 dpurdie 546
    #   it to happen
547
    #
548
    #   Allow versions of 99.99.99 as these are known to be test versions
549
    #
7319 dpurdie 550
    unless ( $opt_archive eq 'local' || $opt_archive eq 'sandbox' || $opt_testArchive || $::GBE_DPKG_ESCROW)
369 dpurdie 551
    {
552
        if ( $ENV{GBE_DPKG_SBOX} )
553
        {
554
            unless ( $DPKG_VERSION =~ /^99.99.99/ )
555
            {
556
                Error("Cannot not publish a package that has been generated",
557
                   "within a Sandbox as the version of dependent packages",
558
                   "is not guaranteed.",
559
                   "Only version 99.99.99 is allowed");
560
            }
561
        }
562
    }
4003 dpurdie 563
}
369 dpurdie 564
 
565
 
227 dpurdie 566
#------------------------------------------------------------------------------
567
sub pkgFind
568
#
569
# Description:
235 dpurdie 570
#     This subroutine is used to locate the FIRST descpkg file in
227 dpurdie 571
#     the local pkg dir.
572
#
573
#------------------------------------------------------------------------------
574
{
575
    my($item)= "$File::Find::name";
576
    my($file)= File::Basename::basename($item);
577
 
578
    # we get the absolute path from the find, but we only require
579
    # a relative path from the starting dir.
580
    # so our start dir.
581
 
582
    # we need to determine which file we are dealing with
235 dpurdie 583
    if ( ! -d $item && $file =~ /^descpkg$/ )
227 dpurdie 584
    {
4549 dpurdie 585
        $descPkgCount++;
586
 
235 dpurdie 587
        #
588
        #   Only grab the first one
589
        #
590
        if ( $DESCPKG_FILE )
591
        {
5532 dpurdie 592
            $item =~ s~\Q$PKG_BASE\E/~~;
4549 dpurdie 593
            Verbose ("Multiple descpkg files:", $item );
235 dpurdie 594
            return;
595
        }
596
 
227 dpurdie 597
        $DESCPKG_FILE = $item;
598
        my($dir)= File::Basename::dirname($item);
599
        $DPKG_NAME = File::Basename::basename($dir);
5582 dpurdie 600
        $SRC_ROOT = catdir($dir);
227 dpurdie 601
    }
602
}
603
 
604
 
605
#------------------------------------------------------------------------------
606
sub GetDpkgArchiveVersion
607
#
608
# Description:
609
#     This subroutine is used to determine the version of the dpkg_archive.
610
#     We assume that the version number is in the descpkg file.
611
#
612
#     Need to allow for two forms of descpkg. Some one decided that a Java
613
#     Manifest would be a good descpkg file - a long time after the rest of the
614
#     world had been using an existing file format.
615
#
616
#     Lines are tagged
617
#
618
#     Once the version number is determined we set the
619
#     global DPKG_VERSION variable.
620
#
621
#------------------------------------------------------------------------------
622
{
623
    my ($path) = @_;
624
    my $line;
625
    my $type;
626
 
627
    #
628
    #   Use a common routine to parse the package descriptor
629
    #   There are several forms that may need to be processed
630
    #
631
    my $pkg_data = ReadDescpkg( $path );
632
    Error("Failed to open file [$path].") unless $pkg_data;
633
 
634
    $DESC_NAME    = $pkg_data->{'NAME'};
635
    $DPKG_VERSION = $pkg_data->{'VERSION_FULL'};
7301 dpurdie 636
    $DPKG_SIGNATURE = $pkg_data->{'SIGNATURE'};
227 dpurdie 637
}
638
 
639
#-------------------------------------------------------------------------------
640
# Function        : TransferDescpkg
641
#
642
# Description     : Copy and process the descpkg file to the target
643
#
644
# Inputs          :
645
#
646
# Returns         :
647
#
648
sub TransferDescpkg
649
{
650
    my $result = CopyDescpkg( @_ );
651
    Error("Transfer descpkg: $result") if ( $result );
652
}
653
 
654
#------------------------------------------------------------------------------
655
sub CreateDpkgArchive
656
#
657
# Description:
658
#     This subroutine is used to create the dpkg_archive in the $DPKG_ROOT
659
#     location 
660
#
4969 dpurdie 661
#     We use the global DPKG_ROOT, DPKG_DIR, DPKG_NAME, and DPKG_VERSION
227 dpurdie 662
#     to create the required directory structure.
663
#
664
#     If the dpkg_archive is new (ie not a new version) it is assumed the user
665
#     has access to create the top level dir for the new dpkg_archive.
666
#
667
#     The new dpkg_archive is created with the permission of the user 
668
#     executing this script.
669
#
670
#     If an error ocurs during the dpkg_archive creation the script
671
#     will terminate.
672
#
673
#------------------------------------------------------------------------------
674
{
263 dpurdie 675
    #
227 dpurdie 676
    # first we need to ensure we have the top level directory
677
    #
678
    if ( -d $DPKG_DIR )
679
    {
680
        Warning("Detected previous dpkg_archive [$DPKG_DIR]");
4549 dpurdie 681
        Error ("Package already exists and Package merging not selected")
682
            unless ( $opt_delete || $opt_merge );
263 dpurdie 683
 
684
        #
685
        #   Target exists
686
        #   Unless we are merging, we need to blow the entire tree away
687
        #
688
        unless ( $opt_merge )
689
        {
690
            LogFileOp("Remove Prev Pkg",$DPKG_DIR);
691
            rmtree($DPKG_DIR);
692
 
693
            #
694
            #   At this point the target directory 'should not' exist
695
            #   but it may. Some packges (like JATS) have Unix links within
696
            #   dpkg_archive filesystem. These cannot be deleted under windows
697
            #
698
            #   Not nice, but we live with it.
699
            #
700
            Warning ("Unable to delete previous instance of the package")
701
                if ( -d $DPKG_DIR );
702
        }
227 dpurdie 703
    }
704
    Information("");
705
 
706
    #
707
    #   Create the top level directory
708
    #
709
    mkpath($DPKG_DIR, 0, 0775);
710
 
711
    #
4003 dpurdie 712
    #   Transfer source directory, unless this is a noBuild
713
    #
714
    if ( $SRC_ROOT ne '' )
227 dpurdie 715
    {
4003 dpurdie 716
        # Process the files
717
        #
718
        if ( -d $SRC_ROOT )
719
        {
720
            File::Find::find( \&pkgFind2, $SRC_ROOT );
263 dpurdie 721
 
4424 dpurdie 722
            if (@bad_symlinks)
723
            {
724
                my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
725
                $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
726
            }
727
 
4003 dpurdie 728
            if ( $bad_merge_count )
729
            {
730
                my $msg = "Merged files that differ: $bad_merge_count";
4424 dpurdie 731
                $opt_md5 ? ReportError($msg) : Warning($msg);
4003 dpurdie 732
            }
4424 dpurdie 733
            ErrorDoExit();
4003 dpurdie 734
        }
735
        else
263 dpurdie 736
        {
4003 dpurdie 737
            Error("Failed to find dir [$SRC_ROOT]",
738
                  "Check JATS config.");
263 dpurdie 739
        }
227 dpurdie 740
    }
741
 
742
    #
743
    #   Transfer of data is complete
4424 dpurdie 744
    #       Mark the archive with the build machine to indicate which parts of
745
    #       a multi-machine build have been performed
227 dpurdie 746
    #
5527 dpurdie 747
    my $touchfile = createBuiltFile($DPKG_DIR);
4634 dpurdie 748
    addFile('file', $touchfile, $touchfile);
227 dpurdie 749
 
750
    #
751
    #   If there is a .lnk file in the archive then remove it now that the
752
    #   archive has been transferred. The .lnk files are created in 'local'
753
    #   archives in order to simplify multi-package builds
754
    #
755
    my $link_file = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION.lnk";
756
    if ( -f $link_file )
757
    {
758
        LogFileOp("Removing Link",$link_file);
759
        unlink $link_file;
760
    }
761
 
4969 dpurdie 762
    #
5527 dpurdie 763
    #   Create the MD5 info file
764
    #   
765
    writeFileInfo($DPKG_DIR);
227 dpurdie 766
    return 1;
767
}
768
 
769
#------------------------------------------------------------------------------
770
sub pkgFind2
771
#
772
# Description:
773
#   This subroutine is used to locate all associated pkg files in
774
#   the local pkg dir.
775
#
776
#   This routine is called for each file and directory within the package
777
#   Some files and directories are treated in a special manner
778
#       - Top level directory is ignored
779
#
780
#
781
#
782
#------------------------------------------------------------------------------
783
{
784
    my $item = $File::Find::name;
785
    my $base = File::Basename::basename($item);
786
 
787
    #
788
    #   Calculate the target directory name
789
    #
790
    my $target = $item;
241 dpurdie 791
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 792
 
793
    if ( -d $item )
794
    {
795
        #
796
        #   Ignore the top level directory
797
        #   It has already been created
798
        #
799
        return
800
            if ( $item eq $SRC_ROOT );
801
 
802
        #
803
        #   Directories are handled differently
804
        #       - Directories are created with nice permissions
263 dpurdie 805
        #       - If the directory already exists then it is being merged.
227 dpurdie 806
        #
807
        if ( ! -d "$target" )
808
        {
809
            LogFileOp("Creating Dir", $target);
810
            mkpath("$target", 0, 0775);
4549 dpurdie 811
            addFile('dir', $item , $target);
227 dpurdie 812
        }
813
    }
814
    else
815
    {
816
        #
817
        #   File copy
818
        #   If merging then do not overwrite an existing file
819
        #
820
        unless ( $opt_merge && -f $target )
821
        {
822
            if ( $item =~ m~/descpkg$~ )
823
            {
824
                LogFileOp("Rewrite File",$target);
4549 dpurdie 825
                TransferDescpkg( $item, $target );
363 dpurdie 826
                CORE::chmod oct("0664"), $target;
4549 dpurdie 827
                addFile('file', $item, $target);
227 dpurdie 828
            }
829
            else
830
            {
831
                #
832
                #   Copy file to destination
833
                #   If the file is a link, then duplicate the link contents
834
                #   Use: Unix libraries are created as two files:
835
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
836
                #
837
                if ( -l $item )
838
                {
4424 dpurdie 839
                    if (-f $item)
227 dpurdie 840
                    {
4424 dpurdie 841
                        LogFileOp("Copying Link", $target);
842
                        my $link = readlink $item;
843
                        Verbose( "Link: $item, $link");
844
                        symlink ($link, $target );
845
                        unless ( $link && -l $target )
846
                        {
847
                            Error("Failed to copy link [$item] to [$target]: $!");
848
                        }
4549 dpurdie 849
                        addFile('link', $item , $target);
227 dpurdie 850
                    }
4424 dpurdie 851
                    else
852
                    {
853
                        # Don't copy broken Symlinks
854
                        # Perhaps this should be an error - but is will break escrow builds
855
                        #
856
                        LogFileOp("Broken SymLink", $target);
857
                        push @bad_symlinks, substr ( $item, 1+length ($SRC_ROOT) );
858
                    }
227 dpurdie 859
                }
860
                elsif (File::Copy::copy($item, $target))
861
                {
862
                    LogFileOp("Copying File",$target);
363 dpurdie 863
                    #
864
                    #   Mark the file as executable by all
865
                    #   Under windows, this is tricky
866
                    #
867
                    if ( $Win32 )
868
                    {
869
                        my %hash;
870
                        $hash{Everyone} = Win32::FileSecurity::MakeMask( qw( FULL  ) );
871
                        Win32::FileSecurity::Set( $target, \%hash );
872
                    }
873
                    else
874
                    {
875
                        CORE::chmod oct("0775"), $target;
876
                    }
4549 dpurdie 877
                    addFile('file', $item, $target);
227 dpurdie 878
                }
879
                else
880
                {
881
                    Error("Failed to copy file [$item] to [$target]: $!");
882
                }
883
            }
884
        }
885
        else
886
        {
887
            #
888
            #   Merging packages
889
            #   Ensure that the descpkg file is "touched" so that caches
890
            #   that use this file as a timestamp can be updated
891
            #
892
            if ( $item =~ m~/descpkg$~ )
893
            {
894
                LogFileOp("Touch File",$target);
895
                TouchFile( $target ) && Error ( "Failed to touch: $target" );
4549 dpurdie 896
                addFile('merge', $item, $target);
227 dpurdie 897
            }
898
            else
899
            {
263 dpurdie 900
                #
901
                #   MD5 digest the files that are being merged
902
                #   Ignore version_*.h files as these are generated
903
                #   and may contain different dates and line endings
904
                #
267 dpurdie 905
                #   Don't put the files into 'binmode'
906
                #   Need to handle some level of Unix/DOS file endings
907
                #
908
                #
263 dpurdie 909
                my $msg = "Merge Skip File";
910
                unless ( $target =~ m~/version[^/]*\.h$~ )
911
                {
912
                    $msg = "Merge Test File";
913
                    #
914
                    #   Compare the two files with an MD5
915
                    #
916
                    local *FILE;
917
                    open(FILE, $target) or Error ("Can't open '$target': $!");
267 dpurdie 918
                    binmode FILE, ':crlf';
263 dpurdie 919
                    my $target_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
920
                    close FILE;
921
 
922
                    open(FILE, $item) or Error ("Can't open '$item': $!");
267 dpurdie 923
                    binmode FILE, ':crlf';
263 dpurdie 924
                    my $source_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
925
                    close FILE;
926
 
927
                    unless ( $source_md5 eq $target_md5 )
928
                    {
929
                        $msg = "DIFF: Merge Test File";
930
                        $bad_merge_count ++;
931
                    }
4549 dpurdie 932
                    addFile('merge', $item, $target, $target_md5);
263 dpurdie 933
                }
934
                LogFileOp($msg,$target);
227 dpurdie 935
            }
936
        }
937
    }
938
}
939
 
940
#-------------------------------------------------------------------------------
5527 dpurdie 941
# Function        : CreateDpkgArchiveTarBall 
942
#
943
# Description     : Similar to CreateDpkgArchive, but it will create a tar file within the target
944
#                   directory.
945
#                   
946
#                   This is used by the build system to:
947
#                       1) Greatly speedup the transfer of packages with a very large number of files
948
#                       2) Remove the need for an multi-filesytem, multi OS atomic lock on the package
949
#                       
950
#                   The build system will process the tarball and create the package archive
951
#                   In doing so it will handle merge errors
952
#
953
# Inputs          : 
954
#
955
# Returns         : 
956
#
957
sub CreateDpkgArchiveTarBall
958
{
959
    Information("");
960
    InitFileUtils();
961
 
962
 
963
    #
964
    #   If a 'noBuild' then create a dummy package directory simply
965
    #   to contain the metadata. 
966
    #   Delete any existing dir of the same name to ensure its clean.
967
    #
968
    if ( $SRC_ROOT eq '' )
969
    {
5582 dpurdie 970
        $SRC_ROOT = catdir(AbsPath('pkg/noBuild'));
5527 dpurdie 971
        RmDirTree ($SRC_ROOT);
972
        mkpath($SRC_ROOT, 0, 0775);
973
    }
974
 
975
    #
976
    #   Mark the archive with the build machine to indicate which parts of
977
    #   a multi-machine build have been performed
978
    #
979
    createBuiltFile($SRC_ROOT);
980
 
981
    #   Process the source directory
982
    #   A NoBuild will contain one metafile
983
    #
984
    if ( -d $SRC_ROOT )
985
    {
986
        File::Find::find( \&pkgFindTarBall, $SRC_ROOT );
987
 
988
        if (@bad_symlinks)
989
        {
990
            my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
991
            $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
992
        }
993
        ErrorDoExit();
994
    }
995
    else
996
    {
997
        Error("Failed to find dir [$SRC_ROOT]",
998
              "Check JATS config.");
999
    }
1000
 
1001
    #
1002
    #   Create the MD5 info file
5582 dpurdie 1003
    #   Mark it as a temp file as it not being created locally
5527 dpurdie 1004
    #   
1005
    writeFileInfo($SRC_ROOT);
5582 dpurdie 1006
    push @tmpFiles, $opt_outfile;
5527 dpurdie 1007
 
1008
    #
1009
    #   Create the target path in the target archive
1010
    #
1011
    LogFileOp ('Creating', $DPKG_DIR);
1012
    mkpath($DPKG_DIR, 0, 0775);
1013
 
1014
    #
5578 dpurdie 1015
    #   Create a tar.gz file an transfer to the final location
5527 dpurdie 1016
    #
5578 dpurdie 1017
    #   Have failed to find a nice windows utility to create a tar.gz
1018
    #       bsdtar - crashed under server 2003
1019
    #       cygwin - design decision. JATS will not include cygwin
1020
    #
5527 dpurdie 1021
    my $tarTarget = join('_', $DPKG_NAME, $DPKG_VERSION, $GBE_HOSTNAME) . '.tar.gz';
1022
    my $tarPath = catfile($DPKG_DIR, $tarTarget);
5578 dpurdie 1023
    $FileUtils::isUnix ? createUnixTar($tarPath) : createWindowsTar($tarPath); 
1024
}
1025
 
1026
#-------------------------------------------------------------------------------
1027
# Function        : createUnixTar  
1028
#
1029
# Description     : Create a tar.gz file under unix
1030
#
1031
# Inputs          : $tarPath    - Place tarfile here 
1032
#                   $SRC_ROOT   - Directory to tar
1033
#
1034
# Returns         : Will not return on error
1035
#
1036
sub createUnixTar
1037
{
1038
    my ($tarPath) = @_;
1039
 
1040
    #
1041
    #   Locate the tar utility
1042
    #   Use gtar if its available otherwise use tar
1043
    #   
1044
    my $tarProg = LocateProgInPath('gtar', '--All');
1045
    $tarProg = LocateProgInPath('tar', '--All') unless $tarProg;
1046
    Error ("Tar utility not found in path") unless $tarProg;
1047
 
1048
    #
1049
    #   Tar and gzip file directly into the final location
5527 dpurdie 1050
    LogFileOp ('TarZip', $tarPath);
1051
    my @tarArgs;
1052
    push @tarArgs, '-v' if IsVerbose(1);
1053
    my $rv = System ('--NoShell', '--NoExit',$tarProg, @tarArgs, '-czf', $tarPath, '-C', $SRC_ROOT, '.' );
1054
    if ($rv)
1055
    {
5578 dpurdie 1056
        push @tmpFiles, $tarPath;
5527 dpurdie 1057
        Error ('Cannot create tarball', "Path:$tarPath");
1058
    }
5578 dpurdie 1059
}
5527 dpurdie 1060
 
5578 dpurdie 1061
#-------------------------------------------------------------------------------
1062
# Function        : createWindowsTar  
1063
#
1064
# Description     : Create a tar.gz file under Windows
1065
#                   Use 7zip (part of JATS)
1066
#                   7zip cannot do this in one step
1067
#                       Create tar file
1068
#                       Create zip file
1069
#
1070
# Inputs          : $tarPath    - Place tarfile here 
1071
#                   $SRC_ROOT   - Directory to tar
1072
#
1073
# Returns         : Will not return on error
1074
#
1075
sub createWindowsTar
1076
{
1077
    my ($tarPath) = @_;
5582 dpurdie 1078
    my @verboseArgs = qw(-bb1);
5578 dpurdie 1079
    my $verboseCopyArg = '9';
1080
    #
1081
    #   Ensure that the target file does not exist
1082
    #   7z cannot ovewrite it
1083
    #
1084
    LogFileOp ('Delete', $tarPath);
1085
    RmDirTree($tarPath) && Error ("Target file cannot be deleted", "Target: $tarPath");
1086
 
1087
    #
1088
    #   Setup NON-verbose arguments for 7zip
1089
    # 
1090
    unless (IsVerbose(1)) {
1091
        @verboseArgs = qw(-bb0 -bso0 -bsp0);
1092
        $verboseCopyArg = '0';
1093
    }
1094
 
1095
    #
1096
    #   Create a tar file of the required output
1097
    #   Create the tar file into a temp file that will be deleted on exit
1098
    #   
1099
    my $tmpTarFile = catfile($CWD_DIR, join('_', $DPKG_NAME, $DPKG_VERSION) . '.tar' );
1100
    Verbose("TempTar: $tmpTarFile");
1101
    RmDirTree($tmpTarFile) && Error ("Target file cannot be deleted", "Target: $tmpTarFile");
1102
    push @tmpFiles, $tmpTarFile;
1103
    LogFileOp ('TempTar', $tmpTarFile);
1104
 
1105
    chdir ($SRC_ROOT) || Error ("Cannot change directory: $?", "Dir: $SRC_ROOT");
1106
    my $rv = System ('--NoShell', '--NoExit','7z.exe', 'a', '-r','-y', @verboseArgs, '-ttar', $tmpTarFile, '.' );
1107
    if ($rv)
1108
    {
1109
        Error ('Cannot create tar file');
1110
    }
1111
    chdir ($CWD_DIR) || Error ("Cannot change directory: $?", "Dir: $CWD_DIR");
1112
 
1113
    #
1114
    #   gzip the tar file to a temp (local) location
1115
    # 
1116
    my $tmpTarGzFile = catfile($CWD_DIR, join('_', $DPKG_NAME, $DPKG_VERSION) . '.tar.gz' );
1117
    Verbose("TempTarGz: $tmpTarGzFile");
1118
    RmDirTree($tmpTarGzFile) && Error ("Target file cannot be deleted", "Target: $tmpTarFile");
1119
    push @tmpFiles, $tmpTarGzFile;
1120
    LogFileOp ('TempTarGz', $tmpTarGzFile);
1121
 
1122
    $rv = System ('--NoShell', '--NoExit','7z.exe', 'a', '-y', @verboseArgs, '-tgzip', $tmpTarGzFile, $tmpTarFile );
1123
    if ($rv)
1124
    {
1125
        Error ('Cannot gzip tar file');
1126
    }
1127
 
1128
    #
1129
    #   Copy the file to the target
1130
    #   Note: Jats internal copy
1131
    #         Args are strange as it was designed to work with makefile stuff
1132
    #
1133
    LogFileOp ('CopyTarZip', $tarPath);
1134
    $rv = System ('--NoShell', '--NoExit','JatsFileUtil.exe', 'c' . $verboseCopyArg, 'copyFile', $tarPath, $tmpTarGzFile, '+w' );
1135
    if ($rv)
1136
    {
1137
        push @tmpFiles, $tarPath;
1138
        Error ('Cannot transfer tarball', "Path:$tarPath");
1139
    }
5527 dpurdie 1140
}
1141
 
5578 dpurdie 1142
 
5527 dpurdie 1143
#-------------------------------------------------------------------------------
1144
# Function        : pkgFindTarBall 
1145
#
1146
# Description     : Used by CreateDpkgArchiveTarBall
1147
#                   File::Find processing function
1148
#                   
1149
#                   This routine is called for each file and directory within the package
1150
#
1151
# Inputs          : As per File::Find 
1152
#
1153
# Returns         : Nothing
1154
#
1155
sub pkgFindTarBall
1156
{
1157
    my $item = $File::Find::name;
1158
    my $base = File::Basename::basename($item);
1159
    my $type;
1160
 
1161
    #
1162
    #   Ignore the top level directory
1163
    #
1164
    return
1165
        if ( $item eq $SRC_ROOT );
1166
 
1167
    #
1168
    #   Determine type of this item
1169
    #       file
1170
    #       link, badlink
1171
    #       dir
1172
    if ( -l $item)
1173
    {
1174
        if (-f $item) {
1175
            $type = 'link';
1176
        }
1177
        else
1178
        {
1179
            # Broken symlink
1180
            #   Remove it from the 'pkg'
1181
            #   Could try other ways of excluding it from the tar, but this is the simplest  
1182
            LogFileOp("Broken SymLink", $item);
1183
            push @bad_symlinks, substr ( $item, 1+length ($SRC_ROOT) );
1184
            $type = 'badlink';
1185
            unlink $item;
1186
            return;
1187
        }
1188
    } elsif ( -f $item) {
1189
        $type = 'file';
1190
    } elsif ( -d $item) {
1191
        $type = 'dir';
1192
    } else {
1193
        Error("Unknown file type. Cannot be packaged");
1194
    }
1195
 
1196
    #
1197
    #   Calculate the target directory name
1198
    #
1199
    my $target = $item;
1200
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
1201
 
1202
    addFile($type, $item, $target);
1203
    LogFileOp('Process',$item);
1204
}
1205
 
1206
#-------------------------------------------------------------------------------
227 dpurdie 1207
# Function        : TestDpkgArchive
1208
#
1209
# Description     : Test the structure of the source achive
1210
#                   Ensure that it has some files
1211
#                   Warn if files are present in the root directory
1212
#
1213
# Inputs          : None
1214
#
1215
# Returns         : Warnings
1216
#
1217
my $test_dir_count = 0;
1218
my $test_file_count = 0;
1219
my @test_root_file = ();
1220
sub TestDpkgArchive
1221
{
1222
    $test_dir_count = 0;
1223
    $test_file_count = 0;
1224
    @test_root_file = ();
1225
 
4003 dpurdie 1226
    if ( $SRC_ROOT ne '' )
1227
    {
1228
        Error("Failed to find dir [$SRC_ROOT]",
1229
              "Check JATS config.") unless ( -d $SRC_ROOT );
1230
 
1231
 
1232
        #
1233
        #   Scan the package counting files and folders
1234
        #
1235
        File::Find::find( \&pkgFind3, $SRC_ROOT );
1236
    }
1237
 
227 dpurdie 1238
    Information ("Package contains:",
1239
                 "Files: $test_file_count",
1240
                 "Dirs: $test_dir_count",
1241
                 );
1242
    #
1243
    #   There shouldn't be any files in the root directory
1244
    #   other than the descpkg and incpkg.
1245
    #
1246
    Warning ("Unexpected files in package root:", @test_root_file)
1247
        if ( @test_root_file  );
4424 dpurdie 1248
 
1249
    Error ("Bad symbolic links found:", @bad_symlinks)
1250
            if ( @bad_symlinks );
1251
 
227 dpurdie 1252
}
1253
 
1254
sub pkgFind3
1255
{
1256
 
1257
    #
1258
    #   Calculate the target directory name
1259
    #
1260
    my $target = $File::Find::dir;
263 dpurdie 1261
    $target = substr ( $target, length ($SRC_ROOT) );
1262
    $target =~ s~^.~~;
227 dpurdie 1263
 
1264
    if ( -d $_ ) {
1265
        $test_dir_count++;
1266
    } else {
1267
        $test_file_count++;
1268
        unless ( $target )
1269
        {
241 dpurdie 1270
            #
1271
            #   Locate files in the package root directory that
1272
            #   are not expected to be there.
1273
            #
263 dpurdie 1274
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ))
1275
            {
1276
                push @test_root_file, $_;
1277
            }
227 dpurdie 1278
        }
4424 dpurdie 1279
        if (-l $_ && ! -f $_)
1280
        {
1281
            push @bad_symlinks, substr ( $File::Find::name, 1+length ($SRC_ROOT) );
1282
        }
227 dpurdie 1283
    }
1284
}
1285
 
5527 dpurdie 1286
#-------------------------------------------------------------------------------
1287
# Function        : createBuiltFile 
1288
#
1289
# Description     : Create the packages built.xxxx file
1290
#                   Used to track which build machines have contributed to the build 
1291
#
1292
# Inputs          : $targetDir          - Base directory for the file 
1293
#
1294
# Returns         : Full pathname of the generatde file
1295
#
1296
sub createBuiltFile
1297
{
1298
    my ($targetDir) = @_;
1299
 
1300
    #
1301
    #   Mark the archive with the build machine to indicate which parts of
1302
    #   a multi-machine build have been performed
1303
    #
1304
    my $touchfile = catfile( $targetDir, $opt_generic ? 'built.generic' : "built.$GBE_HOSTNAME");
1305
 
1306
    #
1307
    #   Create a string to be appended to the 'built' file
1308
    #   Comma seperated list of (possibly) useful info
1309
    #       Date-Time ( Local and GMT)
1310
    #       machine type, machine name and the user
1311
    #       GBE_ABT value
1312
    #
1313
    #   Having build issues where the file is not seen for a very long time
1314
    #
1315
    my $built_info = localtime() ."," . gmtime() . " GMT,$GBE_MACHTYPE,$GBE_HOSTNAME,$USER,$GBE_ABT";
1316
    LogFileOp("Mark File",$touchfile);
1317
    FileAppend ( $touchfile, $built_info );
1318
 
1319
    return $touchfile;
1320
}
1321
 
5578 dpurdie 1322
#-------------------------------------------------------------------------------
1323
# Function        : END Block 
1324
#
1325
# Description     : Post execution cleanup
1326
#
1327
# Inputs          : 
1328
#
1329
# Returns         : 
1330
#
1331
END
1332
{
1333
    #
1334
    #   Save the programs exit code
1335
    #   This END block may use the 'system' call and this will clobber the value in $?
1336
    #   which is the systems exit code
1337
    #
1338
    Verbose2("Cleanup processing");
1339
    local $?;
5527 dpurdie 1340
 
5578 dpurdie 1341
    #
1342
    #   Delete temp files
1343
    #
1344
    foreach my $tmpFile ( @tmpFiles)
1345
    {
1346
        if ($opt_keepTemp)
1347
        {
1348
            Information("Retain Temp file: " . $tmpFile);
1349
        }
1350
        else
1351
        {
1352
            Verbose ("Delete file: " . $tmpFile);
1353
            RmDirTree ($tmpFile) && Warning("$tmpFile not deleted");
1354
        }
1355
    }
1356
 
1357
}
1358
 
1359
 
227 dpurdie 1360
# ---------------------------------------------------------
1361
# ---------------------------------------------------------
1362
# Main
1363
# ---------------------------------------------------------
1364
# ---------------------------------------------------------
1365
 
1366
 
1367
# Initialise our world
1368
#
1369
Init();
4003 dpurdie 1370
CheckDescPkg();
1371
ShowInfo();
4549 dpurdie 1372
unless ($opt_info)
227 dpurdie 1373
{
4549 dpurdie 1374
    unless ( $opt_test )
227 dpurdie 1375
    {
5527 dpurdie 1376
        if ($opt_tarmode)
1377
        {
7300 dpurdie 1378
            LogFileOp("Creating dpkg_archive tarball:", $DPKG_DIR);
5527 dpurdie 1379
            CreateDpkgArchiveTarBall();
1380
        }
1381
        else
1382
        {
7300 dpurdie 1383
            LogFileOp("Creating dpkg_archive package:", $DPKG_DIR);
5527 dpurdie 1384
            CreateDpkgArchive();
1385
        }
227 dpurdie 1386
    }
4549 dpurdie 1387
    else
1388
    {
1389
        Information("Testing user package.");
1390
        TestDpkgArchive();
1391
    }
227 dpurdie 1392
}
1393
 
1394
# Done
1395
#
1396
Information ("Done.");
1397
exit 0;
1398
 
1399
 
1400
#-------------------------------------------------------------------------------
1401
#   Documentation
1402
#
1403
 
1404
=pod
1405
 
361 dpurdie 1406
=for htmltoc    SYSUTIL::
1407
 
227 dpurdie 1408
=head1 NAME
1409
 
1410
create_dpkg - Create a dpkg_archive entry
1411
 
1412
=head1 SYNOPSIS
1413
 
1414
 jats create_dpkg [options]
1415
 
1416
 Options:
1417
    -help              - Brief help message
1418
    -help -help        - Detailed help message
1419
    -man               - Full documentation
1420
    -quiet             - Suppress progress messages, then warning messages
1421
    -verbose           - Display additional progress messages
4549 dpurdie 1422
    -override          - Deprecated option
1423
    -delete            - Delete any previous version of the package
263 dpurdie 1424
    -[no]merge         - merge with existing version of the package
7319 dpurdie 1425
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy, escrow)
227 dpurdie 1426
    -pname=name        - Ensure package is named correctly
1427
    -pversion=version  - Ensure package version is correct
1428
    -generic           - Create a built.generic file
5550 dpurdie 1429
    -noBuild           - Create dummy build files
5527 dpurdie 1430
    -[no]tarmode       - Transfer package as tarball
4549 dpurdie 1431
    -[no]md5           - Use MD5 comparison of merged files(enabled)
5527 dpurdie 1432
 
1433
  Debug and Testing:
263 dpurdie 1434
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1435
    -[no]info          - Display packaging info. Do not transfer.
5527 dpurdie 1436
    -[no]testArchive   - Perform operations within a test archive
5578 dpurdie 1437
    -keepTemp          - Do not delete temp files
227 dpurdie 1438
 
1439
=head1 OPTIONS
1440
 
1441
=over 8
1442
 
1443
=item B<-help>
1444
 
1445
Print a brief help message and exits.
1446
 
1447
=item B<-help -help>
1448
 
1449
Print a detailed help message with an explanation for each option.
1450
 
1451
=item B<-man>
1452
 
1453
Prints the manual page and exits.
1454
 
1455
=item B<-quiet>
1456
 
1457
This option will suppress almost all of the progress messages, except for a single
1458
copy message. It is intended to be used when the program is called from another
1459
script.
1460
 
1461
=item B<-override>
1462
 
4549 dpurdie 1463
If this option has been deprecated. It has no effect.
1464
 
1465
It is still present to preserve backward compatability with the automated 
1466
build system.
1467
 
1468
=item B<-delete>
1469
 
227 dpurdie 1470
If this option is enabled then any previous version of the target package will
4549 dpurdie 1471
be deleted.
227 dpurdie 1472
 
1473
=item B<-merge>
1474
 
1475
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1476
package. This option is used by the auto build tool to assemble multi-machine 
1477
packages in dpkg_archive.
227 dpurdie 1478
 
1479
=item B<-archive=name>
1480
 
1481
This option specifies the destination archive to be used. The following names
1482
are supported:
1483
 
361 dpurdie 1484
=over 8
1485
 
1486
=item cache
1487
 
1488
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1489
 
1490
=item local
1491
 
1492
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1493
 
1494
=item main (default)
1495
 
1496
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1497
default target archive.
1498
 
1499
=item store
1500
 
1501
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1502
 
4688 dpurdie 1503
=item replica
1504
 
1505
The location of the target archive will be taken from C<GBE_DPKG_REPLICA>.
1506
 
361 dpurdie 1507
=item sandbox
1508
 
1509
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1510
 
1511
=item deploy
1512
 
7319 dpurdie 1513
The location of the target archive will be taken from C<GBE_DPLY>.
361 dpurdie 1514
 
7319 dpurdie 1515
Note: This archive is no longer fully supported.
1516
 
1517
=item escrow
1518
 
1519
The location of the target archive will be taken from C<GBE_DPKG_ESCROW>.
1520
 
1521
This is the default target archive if an escrow build is detected.
1522
 
361 dpurdie 1523
=back
1524
 
227 dpurdie 1525
=item B<-pname=name>
1526
 
1527
If this option is provided, the utility will ensure that the package is named
1528
correctly.
1529
 
1530
=item B<-pversion=version>
1531
 
1532
If this option is provided, the utility will ensure that the package version is
1533
that expected.
1534
 
4549 dpurdie 1535
=item B<-generic>
227 dpurdie 1536
 
4549 dpurdie 1537
This option will create a built.generic file, instead of one based on the machine
1538
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1539
 
5550 dpurdie 1540
=item B<-noBuild>
1541
 
1542
This option is only used by the build daemons. It is used to create all required 
1543
files to indicate that the build has occured correctly. It will only be used by ANT 
1544
based builds as true JATS builds handle this situation internally.
1545
 
5527 dpurdie 1546
=item B<-[no]tarmode>
1547
 
1548
This option will cause the package to be transferred into the package archive as
1549
a tar ball. Used in the build system to address two issues:
1550
 
1551
=over 4
1552
 
1553
=item 1 
1554
 
1555
Slow speed in copying lots of files from the build machine to the package server.
1556
 
1557
=item 2 
1558
 
1559
Need for cross platform file lock in order to prevent copy collisions.  
1560
 
1561
=back
1562
 
263 dpurdie 1563
=item B<-[no]md5>
1564
 
1565
If package builds are being merged then a validity check is performed using
1566
an MD5 digest over the current and the existing file.
1567
 
1568
By default, it is an error for the user file to differ from the merged file.
1569
 
1570
This option disabled the error. The test is still done and the results are
1571
reported.
1572
 
4549 dpurdie 1573
=item B<-test>
227 dpurdie 1574
 
4549 dpurdie 1575
If this option is enabled the utility will perform initial sanity testing, but
1576
it will not perform the copy.
227 dpurdie 1577
 
4549 dpurdie 1578
=item B<-[no]info>
1579
 
1580
This option will cause the program to display information about the packaging 
1581
process and then exit. 
1582
 
1583
No data will be transferred to the archive.
1584
 
5527 dpurdie 1585
=item B<-[no]testArchive>
1586
 
1587
If this option is enabled then the assembly operation is performed within a test area within
1588
the currently configured dpkg_archive. The test area is a subdirectory 
1589
called C<.dpkg_archive/test_dpkg>
1590
 
1591
This option is intended for testing use only.
1592
 
5578 dpurdie 1593
=item B<-keepTemp>
1594
 
1595
This option will prevent temp files, created by this utilty, from being deleted when the utilty
1596
exists.
1597
 
1598
This option is intended for testing use only.
1599
 
227 dpurdie 1600
=back
1601
 
1602
=head1 DESCRIPTION
1603
 
1604
This utility program is used to transfer a package that has been built into
1605
dpkg_archive. The package is then available for general consumption.
1606
 
4549 dpurdie 1607
The utility will perform several operations in the transfer process. These incude:
1608
 
1609
=over 4
1610
 
1611
=item * 
1612
 
1613
Create a tag file to indicate the machine that has performed the transfer
1614
 
1615
=item * 
1616
 
1617
Create an XML file of files that have been transferred. This file contains information
1618
used by the build system when it releases the package, including: name, size and MD5SUM.
1619
 
1620
=item *
1621
 
1622
Detect file conflicts when different builds are merged into a single package. Header files are 
1623
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1624
reproducible if file conflicts exist.
1625
 
5527 dpurdie 1626
In 'tarmode' the package merging needs to be done by another utility.
1627
 
4549 dpurdie 1628
=item *
1629
 
1630
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1631
removed from the transferred image.
1632
 
1633
=back
1634
 
227 dpurdie 1635
=head2 PACKAGE LOCATION
1636
 
1637
The utility will locate a package by examining the following directores for
1638
the package description file(descpkg).
1639
 
1640
=over 8
1641
 
1642
=item ./build/deploy
1643
 
1644
This format is generated by the deployment builds. The default target archive
1645
will be taken from the environment variable GBE_DPLY.
1646
 
1647
=item ./pkg
1648
 
1649
This format is generated by JATS builds.
1650
 
1651
=item ./build/pkg
1652
 
1653
This format is generated by ANT builds.
1654
 
5527 dpurdie 1655
=item ./pkg/noBuild
1656
 
1657
This format is used internally by this utilty. It will be generated by the build system 
1658
in cases where there is no build to be performs on the current machine.
1659
 
227 dpurdie 1660
=back
1661
 
1662
The program should be run in the same directory as the build control files as
1663
the package subdirectory will be created in that directory.
1664
 
1665
=head1 EXAMPLE
1666
 
1667
=head2 jats create_dpkg
1668
 
1669
This will locate a generated package and install it into the dpkg_archive repository.
1670
 
1671
=cut
1672