Subversion Repositories DevTools

Rev

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