Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

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