Subversion Repositories DevTools

Rev

Rev 4688 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
263 dpurdie 1
########################################################################
4549 dpurdie 2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
227 dpurdie 3
#
4549 dpurdie 4
# Module name   : create_dpkg2.pl
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.
4549 dpurdie 10
#                 Based on create_dpkg with following changes
11
#                   * No user interaction
12
#                   * Generates files list for ReleaseNote integration 
227 dpurdie 13
#
4549 dpurdie 14
# Usage:        : See POD
227 dpurdie 15
#
263 dpurdie 16
#......................................................................#
227 dpurdie 17
 
4549 dpurdie 18
 
263 dpurdie 19
require 5.008_002;
227 dpurdie 20
 
21
# Include Standard Perl Functions
22
#
23
use strict;
263 dpurdie 24
use warnings;
227 dpurdie 25
use Cwd;
26
use Getopt::Long;
27
use File::Basename;
28
use File::Find;
29
use File::Path;
30
use File::Copy;
31
use Pod::Usage;
263 dpurdie 32
use Digest::MD5;
4549 dpurdie 33
use XML::Simple;
4633 dpurdie 34
use Encode qw(decode encode);
227 dpurdie 35
 
36
use JatsError;
263 dpurdie 37
use JatsEnv;
227 dpurdie 38
use DescPkg;
39
use FileUtils;
40
 
363 dpurdie 41
#
42
#   Under Windows we need the Win32::FileSecurity module
43
#   It only exists under windows
44
#
45
my $Win32 = eval "require Win32::FileSecurity";
46
 
227 dpurdie 47
# define Global variables
48
#
4549 dpurdie 49
my $VERSION = "3.0.0";
227 dpurdie 50
my $PROGNAME = "create_dpkg.pl";
51
 
279 dpurdie 52
# Globals imported from environment
53
#
54
our $GBE_MACHTYPE;
55
our $GBE_HOSTNAME;
56
our $USER;
57
our $GBE_ABT;
227 dpurdie 58
 
279 dpurdie 59
# Global variables
60
#
227 dpurdie 61
my $DPKG_NAME     = "";
62
my $DESC_NAME     = "";
63
my $DPKG_VERSION  = "";
64
my $DESCPKG_FILE  = "";
65
my $DESCPKG_TYPE  = "";
66
my $CWD_DIR       = cwd;
67
my $SRC_ROOT;
68
my $DPKG_DIR;
69
my $DPKG_ROOT;
4003 dpurdie 70
my $PKG_BASE;
263 dpurdie 71
my $bad_merge_count = 0;
4424 dpurdie 72
my @bad_symlinks;
4549 dpurdie 73
my @fileList;
74
my $descPkgCount = 0;
227 dpurdie 75
 
76
#
77
#   Option variables
78
#
79
my $opt_help = 0;
80
my $opt_manual = 0;
81
my $opt_verbose = 0;
82
my $opt_quiet = 0;
4549 dpurdie 83
my $opt_delete = 0;
227 dpurdie 84
my $opt_override = 0;
85
my $opt_merge = 0;
86
my $opt_archive;
87
my $opt_generic;
88
my $opt_pname;
89
my $opt_pversion;
90
my $opt_test;
263 dpurdie 91
my $opt_md5 = 1;
4549 dpurdie 92
my $opt_outfile;
93
my $opt_info;
227 dpurdie 94
 
95
 
96
#
97
#   Structure to translate -archive=xxx option to archive variable
98
#   These are the various dpkg_archives known to JATS
99
#
4688 dpurdie 100
my %Archive2Var =( 'main'      => 'GBE_DPKG',
101
                   'store'     => 'GBE_DPKG_STORE',
102
                   'cache'     => 'GBE_DPKG_CACHE',
103
                   'local'     => 'GBE_DPKG_LOCAL',
104
                   'sandbox'   => 'GBE_DPKG_SBOX',
105
                   'deploy'    => 'GBE_DPLY',
106
                   'replica'   => 'GBE_DPKG_REPLICA',
227 dpurdie 107
                   );
108
 
109
#------------------------------------------------------------------------------
110
#------------------------------------------------------------------------------
111
# Subroutines
112
#------------------------------------------------------------------------------
113
#------------------------------------------------------------------------------
114
 
115
#------------------------------------------------------------------------------
116
sub LogFileOp
117
#
118
# Description:
119
#       This sub-routine is used to generate a consistent informational log
120
#------------------------------------------------------------------------------
121
{
122
    my ($opr, $file) = @_;
123
    $file =~ s/$DPKG_ROOT/DPKG/;
124
 
125
    Information (sprintf( "%-15s [%s]", $opr, $file));
126
}
127
 
4549 dpurdie 128
#-------------------------------------------------------------------------------
129
# Function        : addFile 
130
#
131
# Description     : Add a file to the list of transferred files
132
#
133
# Inputs          : $type           - File type
134
#                   $source         - Source file - full path
135
#                                     Use local copy, not network copy for file ops
136
#                   $target         - Target file name
137
#                   $md5sum         - Precalculated MD5 sum 
138
#
139
# Returns         : 
140
#
141
sub addFile
142
{
143
    my ($type, $source, $target, $md5sum) = @_;
144
    my %data;
145
 
146
    if ((not defined $md5sum) && ($type eq 'file'))
147
    {
148
        Verbose("Calculate MD5 Digest: $source");
149
        open(my $fh , $source) or Error ("Can't open '$source': $!");
150
        binmode $fh, ':crlf';
151
        $md5sum = Digest::MD5->new->addfile($fh)->hexdigest;
152
        close $fh;
153
    }
154
 
155
    $target =~ s~$DPKG_DIR~~;
156
    $target =~ s~^/~~;
157
    $target =~ s~/$~~;
158
 
4633 dpurdie 159
    #
160
    #   Convert from iso-8859-1 into utf-8
161
    #
162
    $target = decode( 'iso-8859-1', $target );
163
    $target = encode( 'utf-8', $target );
164
 
4549 dpurdie 165
    if ($type eq 'dir')
166
    {
167
        $data{path} = $target;
168
    }
169
    else
170
    {
171
        $data{path} = StripFileExt($target);
172
        $data{name} = StripDir($target);
173
        if ($type eq 'file')
174
        {
175
            $data{size} = (stat($source))[7];
176
            $data{md5sum} = $md5sum;
177
        }
178
    }
179
 
180
    $data{fullname} = $target;
181
    $data{type} = $type;
182
    $data{machtype} = $GBE_MACHTYPE;
183
    $data{host} = $GBE_HOSTNAME;
184
 
185
    # Put a nice '/' on the end of the patch elements
186
    $data{path} .= '/'
187
        if ( exists ($data{path}) && length($data{path}) > 0);
188
 
189
    push @fileList, \%data;
190
}
191
 
192
#-------------------------------------------------------------------------------
193
# Function        : writeFileInfo 
194
#
195
# Description     : Write out an XML file that contains this processes
196
#                   contribution to the output package 
197
#
198
# Inputs          : 
199
#
200
# Returns         : 
201
#
202
sub writeFileInfo
203
{
204
    my $data;
205
    $data->{file} = \@fileList;
206
 
207
    #
208
    #   Write out sections of XML
209
    #       Want control over the output order
210
    #       Use lots of attributes and only elements for arrays
211
    #       Save as one attribute per line - for readability
212
    #
213
    $opt_outfile = $opt_generic ? "$DPKG_DIR/built.files.generic.xml" : "$DPKG_DIR/built.files.$GBE_HOSTNAME.xml";
214
 
215
    LogFileOp ('Meta File', $opt_outfile);
216
    my $xs = XML::Simple->new( NoAttr =>0, AttrIndent => 1 );
217
 
218
    open (my $XML, '>', $opt_outfile) || Error ("Cannot create output file: $opt_outfile", $!);
219
    $xs->XMLout($data, 
220
                'RootName' => 'files', 
221
                'XMLDecl'  => '<?xml version="1.0" encoding="UTF-8"?>',
222
                'OutputFile' => $XML);
223
    close $XML;
224
 
225
}
226
 
227 dpurdie 227
#------------------------------------------------------------------------------
228
sub Init
229
#
230
# Description:
231
#     This function is used to process any command line arguements
232
#     and print the start banner.
233
#
234
#------------------------------------------------------------------------------
235
{
236
    # Process any command line arguements...
237
    my $result = GetOptions (
263 dpurdie 238
                "help:+"        => \$opt_help,              # flag, multiple use allowed
239
                "manual:3"      => \$opt_help,              # flag
240
                "verbose:+"     => \$opt_verbose,           # flag, multiple use allowed
4549 dpurdie 241
                "override!"     => \$opt_override,          # [no]flag (No longer used. Backward compat with build tool)
242
                "delete!"       => \$opt_delete,            # [no]flag
227 dpurdie 243
                "merge|m!"      => \$opt_merge,             # [no]flag.
244
                "archive=s"     => \$opt_archive,           # string
245
                "quiet+"        => \$opt_quiet,             # Flag
246
                "generic!"      => \$opt_generic,           # [no]Flag
247
                "pname=s"       => \$opt_pname,             # string
248
                "pversion=s"    => \$opt_pversion,          # string
249
                "test!"         => \$opt_test,              # [no]flag
263 dpurdie 250
                "md5!"          => \$opt_md5,               # [no]flag
4549 dpurdie 251
                "info!"         => \$opt_info,              # [no]flag
227 dpurdie 252
                );
253
 
254
 
255
    #
256
    #   Process help and manual options
257
    #
258
    pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
259
    pod2usage(-verbose => 1)  if ($opt_help == 2 );
263 dpurdie 260
    pod2usage(-verbose => 2)  if ($opt_help > 2);
227 dpurdie 261
 
262
    #
263
    #   Init the error and message subsystem
264
    #
265
    ErrorConfig( 'name'    =>'CREATE_DPKG',
266
                 'verbose' => $opt_verbose,
267
                 'quiet'   => $opt_quiet );
268
 
269
    if ($opt_verbose)
270
    {
271
       Verbose ("Program: $PROGNAME");
272
       Verbose ("Version: $VERSION");
273
    }
274
 
275
    #
263 dpurdie 276
    #   Needed EnvVars
277
    #
278
    EnvImport ('GBE_MACHTYPE');
279 dpurdie 279
    EnvImport ('GBE_HOSTNAME');
280
    EnvImport ('USER' );
281
    EnvImportOptional ('GBE_ABT', "");
263 dpurdie 282
 
4003 dpurdie 283
    #
284
    #   Determine the target archive
285
    #   The default archive is GBE_DPKG, but this may be changed
286
    #
287
    $opt_archive = 'main' unless ( $opt_archive );
288
    my $archive_tag = $Archive2Var{$opt_archive};
289
    Error("Unknown archive specified: $opt_archive")
290
        unless ( $archive_tag );
291
    $DPKG_ROOT = $ENV{$archive_tag} || '';
292
    Verbose ("Archive Variable: $archive_tag" );
293
    Verbose2 ("Archive Path: $DPKG_ROOT" );
279 dpurdie 294
 
263 dpurdie 295
    #
4003 dpurdie 296
    #   Detect NoBuild marker
297
    #   This will bypass most of the operation of this package
298
    #
299
    if ( -f 'noBuild.gbe' )
300
    {
301
        Verbose ("No Build Marker file found");
302
        Error("Use of noBuild marker should only be done by a build daemon")
303
            unless ( $GBE_ABT );
304
 
305
        $SRC_ROOT = '';
306
        $DPKG_NAME = 'pkg';
307
        $DESCPKG_FILE = 'descpkg';
308
        $PKG_BASE =$CWD_DIR;
309
        return;
310
    }
311
 
312
    #
227 dpurdie 313
    #   Check for a "pkg" directory
314
    #   This may be in:
315
    #       1) The deploy directory (DEPLOY) build/deploy/descpkg
316
    #       2) The build directory (ANT)     build/pkg/descpkg
317
    #       3) The current directory (JATS)  pkg/xxxx/descpkg
318
    #
4003 dpurdie 319
    $PKG_BASE = "$CWD_DIR/build/deploy";
227 dpurdie 320
    Verbose2 ("Looking for descpkg: $PKG_BASE");
321
    if ( -f "$PKG_BASE/descpkg" )
322
    {
323
        #
324
        #   This is a deployment package.
325
        #   Force the use of the GBE_DPLY
326
        #
327
        $opt_archive = 'deploy' unless ( $opt_archive );
328
    }
329
    else
330
    {
331
        $PKG_BASE = "$CWD_DIR/build/pkg";
332
        Verbose ("Looking for descpkg: $PKG_BASE");
333
        if ( ! -f  "$PKG_BASE/descpkg" )
334
        {
335
            $PKG_BASE = "$CWD_DIR/pkg";
336
            Verbose ("Looking for descpkg: $PKG_BASE");
337
            Error("Failed to find a package to transfer. Looked in:",
338
                  "./build/deploy",
339
                  "./build/pkg",
340
                  "./pkg"
341
                  )
342
                unless( -d $PKG_BASE );
343
        }
344
    }
345
    Verbose("Package directory: $PKG_BASE");
346
 
347
    Error("Repository location not specified: $archive_tag")
348
        unless $DPKG_ROOT;
349
 
350
    Error("Failed to find Repository: $DPKG_ROOT")
351
        unless ( -d $DPKG_ROOT );
352
 
353
    #   Locate the package
354
    #   Packages are located by looking for a file called descpkg within the
355
    #   main package directory.
356
    #
357
    #   This installation process only handles one such file
358
    #
4549 dpurdie 359
    $descPkgCount = 0;
227 dpurdie 360
    File::Find::find( \&pkgFind, $PKG_BASE);
4549 dpurdie 361
 
362
    if ($descPkgCount > 1 )
363
    {
364
        Warning ("Package contains multiple ($descPkgCount) descpkg files");
365
    }
4003 dpurdie 366
}
227 dpurdie 367
 
4003 dpurdie 368
#-------------------------------------------------------------------------------
369
# Function        : CheckDescPkg
370
#
371
# Description     : Check the descpkg file
372
#
373
# Inputs          : Globals
374
#
375
# Returns         : Will not return on error
376
#
377
sub CheckDescPkg
378
{
227 dpurdie 379
    # Get the dpkg_archive version number we are  going to create.
380
    #
381
    Error("Descpkg file not found in package directory: $PKG_BASE")
382
        unless ( -f "$DESCPKG_FILE" );
383
 
384
    #
385
    #   Read in the package description and validate essential fields
386
    #
387
    GetDpkgArchiveVersion($DESCPKG_FILE);
388
    unless ( "$DPKG_VERSION" )
389
    {
390
        Error ("Incorrect descpkg content detected.",
391
               "Check JATS build.pl config.");
392
    }
393
 
394
    #
395
    #   Need to support two forms of pkg subdirectory
396
    #       1) packages are in a named subdir within 'pkg'
397
    #       2) package is within 'pkg' or 'deploy'
398
    #
399
    if ( $DPKG_NAME eq 'pkg' || $DPKG_NAME eq 'deploy' )
400
    {
401
        $DPKG_NAME = $DESC_NAME;
402
        unless ( $DESC_NAME )
403
        {
404
            Error ("Cannot determine package name",
405
                   "The packages 'descpkg' file is bad or missing");
406
        }
407
    }
408
    elsif ( $DESC_NAME ne $DPKG_NAME )
409
    {
410
        Error ("Package name MUST match package description",
411
               "Check build.pl and package.pl",
412
               "Package name: $DPKG_NAME",
413
               "Description : $DESC_NAME" );
414
    }
415
 
416
    #
417
    # lets just check to see if we have a version number before
418
    # we proceed.
419
    #
420
    unless ( $DPKG_VERSION )
421
    {
422
        Error("Cannot determine dpkg_archive version number.",
423
              "Check JATS build config.");
424
    }
425
 
426
    #
427
    #   Sanity test package name and version, if provided
428
    #
429
    if ( $opt_pname )
430
    {
431
        ReportError ("Package Name does not match expected name",
432
                     "Expected: '$opt_pname'",
433
                     "Descpkg : '$DPKG_NAME'") unless ( $DPKG_NAME eq $opt_pname );
434
    }
435
    if ( $opt_pversion )
436
    {
437
        ReportError ("Package Version does not match expected version",
438
                     "Expected: '$opt_pversion'",
439
                     "Descpkg : '$DPKG_VERSION'") unless ( $DPKG_VERSION eq $opt_pversion );
440
    }
441
    ErrorDoExit();
4003 dpurdie 442
}
227 dpurdie 443
 
4003 dpurdie 444
#-------------------------------------------------------------------------------
445
# Function        : ShowInfo
446
#
447
# Description     : Show info to the user
448
#
449
# Inputs          : 
450
#
451
# Returns         : 
452
#
453
sub ShowInfo
454
{
227 dpurdie 455
    #
456
    #   Set up the target directory path and name
457
    #   It will be created later
458
    #
459
    $DPKG_DIR = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION";
4003 dpurdie 460
 
227 dpurdie 461
    #
462
    #   Information for the user
463
    #
464
    Information ("---------------------------------------------------------------");
465
    Information ("Dpkg archive creation tool...");
466
    Information ("Version: $VERSION");
467
    Information ("");
468
    Information ("Information:");
469
    Information ("Working dir   = [$CWD_DIR]");
470
    Information ("Package Root  = [$SRC_ROOT]");
4549 dpurdie 471
    Information ("Repository    = [$DPKG_ROOT]");
472
    Information ("                *Non Standard archive") unless $opt_archive eq 'main';
227 dpurdie 473
    Information ("Target dir    = [$DPKG_DIR]");
474
    Information1("DPKG_NAME     = [$DPKG_NAME]");
475
    Information1("DPKG_VERSION  = [$DPKG_VERSION]");
476
    Information1("GBE_MACHTYPE  = [$GBE_MACHTYPE]");
279 dpurdie 477
    Information1("GBE_HOSTNAME  = [$GBE_HOSTNAME]");
478
    Information1("GBE_ABT       = [$GBE_ABT]");
479
    Information1("USER          = [$USER]");
4549 dpurdie 480
    Information ("")                                if ( $opt_merge || $opt_delete || $opt_info);
481
    Information ("Opt:Delete    = Enabled")         if ( $opt_delete );
227 dpurdie 482
    Information ("Opt:Merge     = Enabled")         if ( $opt_merge );
483
    Information ("Opt:TestMode  = Enabled. No Package Transferred") if ( $opt_test );
4549 dpurdie 484
    Information ("Opt:Info      = Enabled. No Package Transferred") if ( $opt_info );
369 dpurdie 485
    Warning     ("Sandbox Build = Yes") if ($ENV{GBE_DPKG_SBOX}) ;
227 dpurdie 486
    Information ("---------------------------------------------------------------");
487
 
369 dpurdie 488
    #
489
    #   If the environment variable GBE_DPKG_SBOX is defined then the package
490
    #   is being built within a development sandbox. In such a sandbox the
491
    #   version numbers of the packages are ignored. Publishing a package
492
    #   fromm such an environment is certainly not reproducible - so don't allow
493
    #   it to happen
494
    #
495
    #   Allow versions of 99.99.99 as these are known to be test versions
496
    #
497
    unless ( $opt_archive eq 'local' || $opt_archive eq 'sandbox' )
498
    {
499
        if ( $ENV{GBE_DPKG_SBOX} )
500
        {
501
            unless ( $DPKG_VERSION =~ /^99.99.99/ )
502
            {
503
                Error("Cannot not publish a package that has been generated",
504
                   "within a Sandbox as the version of dependent packages",
505
                   "is not guaranteed.",
506
                   "Only version 99.99.99 is allowed");
507
            }
508
        }
509
    }
4003 dpurdie 510
}
369 dpurdie 511
 
512
 
227 dpurdie 513
#------------------------------------------------------------------------------
514
sub pkgFind
515
#
516
# Description:
235 dpurdie 517
#     This subroutine is used to locate the FIRST descpkg file in
227 dpurdie 518
#     the local pkg dir.
519
#
520
#------------------------------------------------------------------------------
521
{
522
    my($item)= "$File::Find::name";
523
    my($file)= File::Basename::basename($item);
524
 
525
    # we get the absolute path from the find, but we only require
526
    # a relative path from the starting dir.
527
    # so our start dir.
528
 
529
    # we need to determine which file we are dealing with
235 dpurdie 530
    if ( ! -d $item && $file =~ /^descpkg$/ )
227 dpurdie 531
    {
4549 dpurdie 532
        $descPkgCount++;
533
 
235 dpurdie 534
        #
535
        #   Only grab the first one
536
        #
537
        if ( $DESCPKG_FILE )
538
        {
4549 dpurdie 539
            $item =~ s~$PKG_BASE/~~;
540
            Verbose ("Multiple descpkg files:", $item );
235 dpurdie 541
            return;
542
        }
543
 
227 dpurdie 544
        $DESCPKG_FILE = $item;
545
        my($dir)= File::Basename::dirname($item);
546
        $DPKG_NAME = File::Basename::basename($dir);
547
        $SRC_ROOT = $dir;
548
    }
549
}
550
 
551
 
552
#------------------------------------------------------------------------------
553
sub GetDpkgArchiveVersion
554
#
555
# Description:
556
#     This subroutine is used to determine the version of the dpkg_archive.
557
#     We assume that the version number is in the descpkg file.
558
#
559
#     Need to allow for two forms of descpkg. Some one decided that a Java
560
#     Manifest would be a good descpkg file - a long time after the rest of the
561
#     world had been using an existing file format.
562
#
563
#     Lines are tagged
564
#
565
#     Once the version number is determined we set the
566
#     global DPKG_VERSION variable.
567
#
568
#------------------------------------------------------------------------------
569
{
570
    my ($path) = @_;
571
    my $line;
572
    my $type;
573
 
574
    #
575
    #   Use a common routine to parse the package descriptor
576
    #   There are several forms that may need to be processed
577
    #
578
    my $pkg_data = ReadDescpkg( $path );
579
    Error("Failed to open file [$path].") unless $pkg_data;
580
 
581
    $DESC_NAME    = $pkg_data->{'NAME'};
582
    $DPKG_VERSION = $pkg_data->{'VERSION_FULL'};
583
}
584
 
585
#-------------------------------------------------------------------------------
586
# Function        : TransferDescpkg
587
#
588
# Description     : Copy and process the descpkg file to the target
589
#
590
# Inputs          :
591
#
592
# Returns         :
593
#
594
sub TransferDescpkg
595
{
596
    my $result = CopyDescpkg( @_ );
597
    Error("Transfer descpkg: $result") if ( $result );
598
}
599
 
600
#------------------------------------------------------------------------------
601
sub CreateDpkgArchive
602
#
603
# Description:
604
#     This subroutine is used to create the dpkg_archive in the $DPKG_ROOT
605
#     location 
606
#
607
#     We use the global DPKG_DIR, DPKG_NAME, and DPKG_VERSION
608
#     to create the required directory structure.
609
#
610
#     If the dpkg_archive is new (ie not a new version) it is assumed the user
611
#     has access to create the top level dir for the new dpkg_archive.
612
#
613
#     The new dpkg_archive is created with the permission of the user 
614
#     executing this script.
615
#
616
#     If an error ocurs during the dpkg_archive creation the script
617
#     will terminate.
618
#
619
#------------------------------------------------------------------------------
620
{
263 dpurdie 621
    #
227 dpurdie 622
    # first we need to ensure we have the top level directory
623
    #
624
    if ( -d $DPKG_DIR )
625
    {
626
        Warning("Detected previous dpkg_archive [$DPKG_DIR]");
4549 dpurdie 627
        Error ("Package already exists and Package merging not selected")
628
            unless ( $opt_delete || $opt_merge );
263 dpurdie 629
 
630
        #
631
        #   Target exists
632
        #   Unless we are merging, we need to blow the entire tree away
633
        #
634
        unless ( $opt_merge )
635
        {
636
            LogFileOp("Remove Prev Pkg",$DPKG_DIR);
637
            rmtree($DPKG_DIR);
638
 
639
            #
640
            #   At this point the target directory 'should not' exist
641
            #   but it may. Some packges (like JATS) have Unix links within
642
            #   dpkg_archive filesystem. These cannot be deleted under windows
643
            #
644
            #   Not nice, but we live with it.
645
            #
646
            Warning ("Unable to delete previous instance of the package")
647
                if ( -d $DPKG_DIR );
648
        }
227 dpurdie 649
    }
650
    Information("");
651
 
652
    #
653
    #   Create the top level directory
654
    #
655
    mkpath($DPKG_DIR, 0, 0775);
656
 
657
    #
4003 dpurdie 658
    #   Transfer source directory, unless this is a noBuild
659
    #
660
    if ( $SRC_ROOT ne '' )
227 dpurdie 661
    {
4003 dpurdie 662
        # Process the files
663
        #
664
        if ( -d $SRC_ROOT )
665
        {
666
            File::Find::find( \&pkgFind2, $SRC_ROOT );
263 dpurdie 667
 
4424 dpurdie 668
            if (@bad_symlinks)
669
            {
670
                my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
671
                $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
672
            }
673
 
4003 dpurdie 674
            if ( $bad_merge_count )
675
            {
676
                my $msg = "Merged files that differ: $bad_merge_count";
4424 dpurdie 677
                $opt_md5 ? ReportError($msg) : Warning($msg);
4003 dpurdie 678
            }
4424 dpurdie 679
            ErrorDoExit();
4003 dpurdie 680
        }
681
        else
263 dpurdie 682
        {
4003 dpurdie 683
            Error("Failed to find dir [$SRC_ROOT]",
684
                  "Check JATS config.");
263 dpurdie 685
        }
227 dpurdie 686
    }
687
 
688
    #
689
    #   Transfer of data is complete
4424 dpurdie 690
    #       Mark the archive with the build machine to indicate which parts of
691
    #       a multi-machine build have been performed
227 dpurdie 692
    #
345 dpurdie 693
    my $touchfile = $opt_generic ? "$DPKG_DIR/built.generic" : "$DPKG_DIR/built.$GBE_HOSTNAME";
279 dpurdie 694
 
227 dpurdie 695
    #
4003 dpurdie 696
    #   Create a string to be appended to the 'built' file
697
    #   Comma seperated list of (possibly) useful info
279 dpurdie 698
    #       Date-Time ( Local and GMT)
699
    #       machine type, machine name and the user
700
    #       GBE_ABT value
701
    #
702
    my $built_info = localtime() ."," . gmtime() . " GMT,$GBE_MACHTYPE,$GBE_HOSTNAME,$USER,$GBE_ABT";
227 dpurdie 703
    LogFileOp("Mark File",$touchfile);
279 dpurdie 704
    FileAppend ( $touchfile, $built_info );
4634 dpurdie 705
    addFile('file', $touchfile, $touchfile);
227 dpurdie 706
 
4634 dpurdie 707
 
227 dpurdie 708
    #
709
    #   If there is a .lnk file in the archive then remove it now that the
710
    #   archive has been transferred. The .lnk files are created in 'local'
711
    #   archives in order to simplify multi-package builds
712
    #
713
    my $link_file = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION.lnk";
714
    if ( -f $link_file )
715
    {
716
        LogFileOp("Removing Link",$link_file);
717
        unlink $link_file;
718
    }
719
 
720
    return 1;
721
}
722
 
723
 
724
#------------------------------------------------------------------------------
725
sub pkgFind2
726
#
727
# Description:
728
#   This subroutine is used to locate all associated pkg files in
729
#   the local pkg dir.
730
#
731
#   This routine is called for each file and directory within the package
732
#   Some files and directories are treated in a special manner
733
#       - Top level directory is ignored
734
#
735
#
736
#
737
#------------------------------------------------------------------------------
738
{
739
    my $item = $File::Find::name;
740
    my $base = File::Basename::basename($item);
741
 
742
    #
743
    #   Calculate the target directory name
744
    #
745
    my $target = $item;
241 dpurdie 746
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 747
 
748
    if ( -d $item )
749
    {
750
        #
751
        #   Ignore the top level directory
752
        #   It has already been created
753
        #
754
        return
755
            if ( $item eq $SRC_ROOT );
756
 
757
        #
758
        #   Directories are handled differently
759
        #       - Directories are created with nice permissions
263 dpurdie 760
        #       - If the directory already exists then it is being merged.
227 dpurdie 761
        #
762
        if ( ! -d "$target" )
763
        {
764
            LogFileOp("Creating Dir", $target);
765
            mkpath("$target", 0, 0775);
4549 dpurdie 766
            addFile('dir', $item , $target);
227 dpurdie 767
        }
768
    }
769
    else
770
    {
771
        #
772
        #   File copy
773
        #   If merging then do not overwrite an existing file
774
        #
775
        unless ( $opt_merge && -f $target )
776
        {
777
            if ( $item =~ m~/descpkg$~ )
778
            {
779
                LogFileOp("Rewrite File",$target);
4549 dpurdie 780
                TransferDescpkg( $item, $target );
363 dpurdie 781
                CORE::chmod oct("0664"), $target;
4549 dpurdie 782
                addFile('file', $item, $target);
227 dpurdie 783
            }
784
            else
785
            {
786
                #
787
                #   Copy file to destination
788
                #   If the file is a link, then duplicate the link contents
789
                #   Use: Unix libraries are created as two files:
790
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
791
                #
792
                if ( -l $item )
793
                {
4424 dpurdie 794
                    if (-f $item)
227 dpurdie 795
                    {
4424 dpurdie 796
                        LogFileOp("Copying Link", $target);
797
                        my $link = readlink $item;
798
                        Verbose( "Link: $item, $link");
799
                        symlink ($link, $target );
800
                        unless ( $link && -l $target )
801
                        {
802
                            Error("Failed to copy link [$item] to [$target]: $!");
803
                        }
4549 dpurdie 804
                        addFile('link', $item , $target);
227 dpurdie 805
                    }
4424 dpurdie 806
                    else
807
                    {
808
                        # Don't copy broken Symlinks
809
                        # Perhaps this should be an error - but is will break escrow builds
810
                        #
811
                        LogFileOp("Broken SymLink", $target);
812
                        push @bad_symlinks, substr ( $item, 1+length ($SRC_ROOT) );
813
                    }
227 dpurdie 814
                }
815
                elsif (File::Copy::copy($item, $target))
816
                {
817
                    LogFileOp("Copying File",$target);
363 dpurdie 818
                    #
819
                    #   Mark the file as executable by all
820
                    #   Under windows, this is tricky
821
                    #
822
                    if ( $Win32 )
823
                    {
824
                        my %hash;
825
                        $hash{Everyone} = Win32::FileSecurity::MakeMask( qw( FULL  ) );
826
                        Win32::FileSecurity::Set( $target, \%hash );
827
                    }
828
                    else
829
                    {
830
                        CORE::chmod oct("0775"), $target;
831
                    }
4549 dpurdie 832
                    addFile('file', $item, $target);
227 dpurdie 833
                }
834
                else
835
                {
836
                    Error("Failed to copy file [$item] to [$target]: $!");
837
                }
838
            }
839
        }
840
        else
841
        {
842
            #
843
            #   Merging packages
844
            #   Ensure that the descpkg file is "touched" so that caches
845
            #   that use this file as a timestamp can be updated
846
            #
847
            if ( $item =~ m~/descpkg$~ )
848
            {
849
                LogFileOp("Touch File",$target);
850
                TouchFile( $target ) && Error ( "Failed to touch: $target" );
4549 dpurdie 851
                addFile('merge', $item, $target);
227 dpurdie 852
            }
853
            else
854
            {
263 dpurdie 855
                #
856
                #   MD5 digest the files that are being merged
857
                #   Ignore version_*.h files as these are generated
858
                #   and may contain different dates and line endings
859
                #
267 dpurdie 860
                #   Don't put the files into 'binmode'
861
                #   Need to handle some level of Unix/DOS file endings
862
                #
863
                #
263 dpurdie 864
                my $msg = "Merge Skip File";
865
                unless ( $target =~ m~/version[^/]*\.h$~ )
866
                {
867
                    $msg = "Merge Test File";
868
                    #
869
                    #   Compare the two files with an MD5
870
                    #
871
                    local *FILE;
872
                    open(FILE, $target) or Error ("Can't open '$target': $!");
267 dpurdie 873
                    binmode FILE, ':crlf';
263 dpurdie 874
                    my $target_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
875
                    close FILE;
876
 
877
                    open(FILE, $item) or Error ("Can't open '$item': $!");
267 dpurdie 878
                    binmode FILE, ':crlf';
263 dpurdie 879
                    my $source_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
880
                    close FILE;
881
 
882
                    unless ( $source_md5 eq $target_md5 )
883
                    {
884
                        $msg = "DIFF: Merge Test File";
885
                        $bad_merge_count ++;
886
                    }
4549 dpurdie 887
                    addFile('merge', $item, $target, $target_md5);
263 dpurdie 888
                }
889
                LogFileOp($msg,$target);
227 dpurdie 890
            }
891
        }
892
    }
893
}
894
 
895
#-------------------------------------------------------------------------------
896
# Function        : TestDpkgArchive
897
#
898
# Description     : Test the structure of the source achive
899
#                   Ensure that it has some files
900
#                   Warn if files are present in the root directory
901
#
902
# Inputs          : None
903
#
904
# Returns         : Warnings
905
#
906
my $test_dir_count = 0;
907
my $test_file_count = 0;
908
my @test_root_file = ();
909
sub TestDpkgArchive
910
{
911
    $test_dir_count = 0;
912
    $test_file_count = 0;
913
    @test_root_file = ();
914
 
4003 dpurdie 915
    if ( $SRC_ROOT ne '' )
916
    {
917
        Error("Failed to find dir [$SRC_ROOT]",
918
              "Check JATS config.") unless ( -d $SRC_ROOT );
919
 
920
 
921
        #
922
        #   Scan the package counting files and folders
923
        #
924
        File::Find::find( \&pkgFind3, $SRC_ROOT );
925
    }
926
 
227 dpurdie 927
    Information ("Package contains:",
928
                 "Files: $test_file_count",
929
                 "Dirs: $test_dir_count",
930
                 );
931
    #
932
    #   There shouldn't be any files in the root directory
933
    #   other than the descpkg and incpkg.
934
    #
935
    Warning ("Unexpected files in package root:", @test_root_file)
936
        if ( @test_root_file  );
4424 dpurdie 937
 
938
    Error ("Bad symbolic links found:", @bad_symlinks)
939
            if ( @bad_symlinks );
940
 
227 dpurdie 941
}
942
 
943
sub pkgFind3
944
{
945
 
946
    #
947
    #   Calculate the target directory name
948
    #
949
    my $target = $File::Find::dir;
263 dpurdie 950
    $target = substr ( $target, length ($SRC_ROOT) );
951
    $target =~ s~^.~~;
227 dpurdie 952
 
953
    if ( -d $_ ) {
954
        $test_dir_count++;
955
    } else {
956
        $test_file_count++;
957
        unless ( $target )
958
        {
241 dpurdie 959
            #
960
            #   Locate files in the package root directory that
961
            #   are not expected to be there.
962
            #
263 dpurdie 963
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ))
964
            {
965
                push @test_root_file, $_;
966
            }
227 dpurdie 967
        }
4424 dpurdie 968
        if (-l $_ && ! -f $_)
969
        {
970
            push @bad_symlinks, substr ( $File::Find::name, 1+length ($SRC_ROOT) );
971
        }
227 dpurdie 972
    }
973
}
974
 
975
# ---------------------------------------------------------
976
# ---------------------------------------------------------
977
# Main
978
# ---------------------------------------------------------
979
# ---------------------------------------------------------
980
 
981
 
982
# Initialise our world
983
#
984
Init();
4003 dpurdie 985
CheckDescPkg();
986
ShowInfo();
4549 dpurdie 987
unless ($opt_info)
227 dpurdie 988
{
4549 dpurdie 989
    unless ( $opt_test )
227 dpurdie 990
    {
4549 dpurdie 991
        Information("Creating dpkg_archive package:", $DPKG_DIR);
992
        CreateDpkgArchive();
993
        writeFileInfo();
227 dpurdie 994
    }
4549 dpurdie 995
    else
996
    {
997
        Information("Testing user package.");
998
        TestDpkgArchive();
999
    }
227 dpurdie 1000
}
1001
 
1002
# Done
1003
#
1004
Information ("Done.");
1005
exit 0;
1006
 
1007
 
1008
#-------------------------------------------------------------------------------
1009
#   Documentation
1010
#
1011
 
1012
=pod
1013
 
361 dpurdie 1014
=for htmltoc    SYSUTIL::
1015
 
227 dpurdie 1016
=head1 NAME
1017
 
1018
create_dpkg - Create a dpkg_archive entry
1019
 
1020
=head1 SYNOPSIS
1021
 
1022
 jats create_dpkg [options]
1023
 
1024
 Options:
1025
    -help              - Brief help message
1026
    -help -help        - Detailed help message
1027
    -man               - Full documentation
1028
    -quiet             - Suppress progress messages, then warning messages
1029
    -verbose           - Display additional progress messages
4549 dpurdie 1030
    -override          - Deprecated option
1031
    -delete            - Delete any previous version of the package
263 dpurdie 1032
    -[no]merge         - merge with existing version of the package
227 dpurdie 1033
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy)
1034
    -pname=name        - Ensure package is named correctly
1035
    -pversion=version  - Ensure package version is correct
1036
    -generic           - Create a built.generic file
4549 dpurdie 1037
    -[no]md5           - Use MD5 comparison of merged files(enabled)
263 dpurdie 1038
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1039
    -[no]info          - Display packaging info. Do not transfer.
227 dpurdie 1040
 
1041
=head1 OPTIONS
1042
 
1043
=over 8
1044
 
1045
=item B<-help>
1046
 
1047
Print a brief help message and exits.
1048
 
1049
=item B<-help -help>
1050
 
1051
Print a detailed help message with an explanation for each option.
1052
 
1053
=item B<-man>
1054
 
1055
Prints the manual page and exits.
1056
 
1057
=item B<-quiet>
1058
 
1059
This option will suppress almost all of the progress messages, except for a single
1060
copy message. It is intended to be used when the program is called from another
1061
script.
1062
 
1063
=item B<-override>
1064
 
4549 dpurdie 1065
If this option has been deprecated. It has no effect.
1066
 
1067
It is still present to preserve backward compatability with the automated 
1068
build system.
1069
 
1070
=item B<-delete>
1071
 
227 dpurdie 1072
If this option is enabled then any previous version of the target package will
4549 dpurdie 1073
be deleted.
227 dpurdie 1074
 
1075
=item B<-merge>
1076
 
1077
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1078
package. This option is used by the auto build tool to assemble multi-machine 
1079
packages in dpkg_archive.
227 dpurdie 1080
 
1081
=item B<-archive=name>
1082
 
1083
This option specifies the destination archive to be used. The following names
1084
are supported:
1085
 
361 dpurdie 1086
=over 8
1087
 
1088
=item cache
1089
 
1090
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1091
 
1092
=item local
1093
 
1094
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1095
 
1096
=item main (default)
1097
 
1098
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1099
default target archive.
1100
 
1101
=item store
1102
 
1103
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1104
 
4688 dpurdie 1105
=item replica
1106
 
1107
The location of the target archive will be taken from C<GBE_DPKG_REPLICA>.
1108
 
361 dpurdie 1109
=item sandbox
1110
 
1111
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1112
 
1113
=item deploy
1114
 
1115
The location of the target archive will be taken from C<GBE_DPLY>. This is the
1116
default target archive is a deployment package is detected.
1117
 
1118
=back
1119
 
227 dpurdie 1120
=item B<-pname=name>
1121
 
1122
If this option is provided, the utility will ensure that the package is named
1123
correctly.
1124
 
1125
=item B<-pversion=version>
1126
 
1127
If this option is provided, the utility will ensure that the package version is
1128
that expected.
1129
 
4549 dpurdie 1130
=item B<-generic>
227 dpurdie 1131
 
4549 dpurdie 1132
This option will create a built.generic file, instead of one based on the machine
1133
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1134
 
263 dpurdie 1135
=item B<-[no]md5>
1136
 
1137
If package builds are being merged then a validity check is performed using
1138
an MD5 digest over the current and the existing file.
1139
 
1140
By default, it is an error for the user file to differ from the merged file.
1141
 
1142
This option disabled the error. The test is still done and the results are
1143
reported.
1144
 
4549 dpurdie 1145
=item B<-test>
227 dpurdie 1146
 
4549 dpurdie 1147
If this option is enabled the utility will perform initial sanity testing, but
1148
it will not perform the copy.
227 dpurdie 1149
 
4549 dpurdie 1150
=item B<-[no]info>
1151
 
1152
This option will cause the program to display information about the packaging 
1153
process and then exit. 
1154
 
1155
No data will be transferred to the archive.
1156
 
227 dpurdie 1157
=back
1158
 
1159
=head1 DESCRIPTION
1160
 
1161
This utility program is used to transfer a package that has been built into
1162
dpkg_archive. The package is then available for general consumption.
1163
 
4549 dpurdie 1164
The utility will perform several operations in the transfer process. These incude:
1165
 
1166
=over 4
1167
 
1168
=item * 
1169
 
1170
Create a tag file to indicate the machine that has performed the transfer
1171
 
1172
=item * 
1173
 
1174
Create an XML file of files that have been transferred. This file contains information
1175
used by the build system when it releases the package, including: name, size and MD5SUM.
1176
 
1177
=item *
1178
 
1179
Detect file conflicts when different builds are merged into a single package. Header files are 
1180
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1181
reproducible if file conflicts exist.
1182
 
1183
=item *
1184
 
1185
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1186
removed from the transferred image.
1187
 
1188
=back
1189
 
227 dpurdie 1190
=head2 PACKAGE LOCATION
1191
 
1192
The utility will locate a package by examining the following directores for
1193
the package description file(descpkg).
1194
 
1195
=over 8
1196
 
1197
=item ./build/deploy
1198
 
1199
This format is generated by the deployment builds. The default target archive
1200
will be taken from the environment variable GBE_DPLY.
1201
 
1202
=item ./pkg
1203
 
1204
This format is generated by JATS builds.
1205
 
1206
=item ./build/pkg
1207
 
1208
This format is generated by ANT builds.
1209
 
1210
=back
1211
 
1212
The program should be run in the same directory as the build control files as
1213
the package subdirectory will be created in that directory.
1214
 
1215
=head1 EXAMPLE
1216
 
1217
=head2 jats create_dpkg
1218
 
1219
This will locate a generated package and install it into the dpkg_archive repository.
1220
 
1221
=cut
1222