Subversion Repositories DevTools

Rev

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