Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
267 dpurdie 1
########################################################################
1348 dpurdie 2
# Copyright (C) 1998-2012 Vix Technology, All rights reserved
267 dpurdie 3
#
4
# Module name   : jats_svnrelease.pl
5
# Module type   : Jats Utility
6
# Compiler(s)   : Perl
7
# Environment(s): Jats
8
#
9
# Description   : A script to build a package from a SubVersion
10
#                 The script will:
11
#                   Create a workspace
12
#                   Checkout the files
13
#                   Locate the build file
14
#                   Build the packages
15
#                   Install packages
16
#                   Remove the view
17
#
18
#               The script can do a lot of other things too.
19
#
20
# Notes         : A lot of this code is common to jats_ccrelease.pl
21
#                 Will need to refactor if both are to be used
22
#
23
#......................................................................#
24
 
25
require 5.006_001;
26
use strict;
27
use warnings;
28
use JatsError;
29
use JatsSystem;
30
use FileUtils;
31
use JatsBuildFiles;
32
use ArrayHashUtils;
33
use JatsSvn;
34
 
35
use Pod::Usage;                             # required for help support
36
use Getopt::Long;
37
use File::Find;
38
use File::Copy;
39
use File::Path;
40
use Cwd;
41
 
42
my $VERSION = "1.0.0";                      # Update this
43
 
44
#
45
#   Options
46
#
47
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
48
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
49
my $opt_help = 0;                           # User help level
50
my @opt_spec;                               # Labels used as a base for the view
51
my $opt_dpkg = 1;                           # Transfer built package to dpkg_archive
52
my $opt_copy = 0;                           # Copy built package to user
53
my $opt_reuse = 0;                          # Re-user view if it exists
54
my $opt_viewname;                           # View Name
1348 dpurdie 55
my $opt_extract = 0;                        # Just create a static view
267 dpurdie 56
my $opt_extract_files;                      # Just extract files to user - no view
1348 dpurdie 57
my $opt_devModeStr;                         # Development mode string
58
my $opt_devMode = '';                       # Development mode (cleaned up)
267 dpurdie 59
my $opt_delete = 0;                         # Just delete the view. 2 to force
60
my @opt_build;                              # build files to use (kludge)
61
my $opt_test;                               # Test the build process - no copy
62
my $opt_cache;                              # Cache external packages
63
my $opt_keep = 0;                           # Keep view if successful
64
my $opt_beta;                               # Create beta release
65
my $opt_merge;                              # Merge release
66
my $opt_path;                               # Path for view spec
67
my $opt_runtests = 1;                       # Run unit tests after build
68
my $opt_branch;                             # Create config spec with branch
69
my $opt_debug_build = 0;                    # Build Debug Only
70
my $opt_prod_build = 0;                     # Build ion Only
71
my $opt_view_root = $ENV{'GBE_VIEWBASE'};   # Root of the view
72
my $opt_prefix = 1;                         # Prefix the view tag with user-name
351 dpurdie 73
my $opt_tag;                                # View tag insert (build or export or user)
341 dpurdie 74
my $bad_label_name = 0;                     # Badly formed label
267 dpurdie 75
 
76
#
77
#   Globals - Provided by the JATS environment
78
#
79
my $USER            = $ENV{'USER'};
80
my $UNIX            = $ENV{'GBE_UNIX'};
81
my $GBE_SANDBOX     = $ENV{'GBE_SANDBOX'};
82
my $GBE_ABT         = $ENV{'GBE_ABT'} || '0';
279 dpurdie 83
my $MACHINENAME     = $ENV{'GBE_HOSTNAME'};
343 dpurdie 84
my $GBE_VIEWBASE    = $ENV{'GBE_VIEWBASE'};   # Root of the view
267 dpurdie 85
 
86
#
87
#   Globals
88
#
343 dpurdie 89
my $VIEWDIR_ROOT;                           # Root of the static view
267 dpurdie 90
my $VIEWDIR;                                # Absolute path to the view
91
my $VIEWPATH;                               # Path relative to clearcase
1348 dpurdie 92
my $view_prefix     = "${USER}_";           # Default WorkSpace prefix
93
my $user_cwd;                               # Initial User Directory
94
my $error = 0;                              # Build Error Flag/Counter
267 dpurdie 95
my $label_count = 0;                        # Number of labels to create the view
96
my @label_not_pegged;                       # List of unpegged labels
1348 dpurdie 97
my @messageText;                            # Messages to be displayed AFTER extraction
98
my $workSpace;                              # Path to created workspace (or extact)
99
my $svnSession;                             # Primary Subversion Session
100
my $noReleaseWs = 1;                        # Do not officially release from this
101
my $checkDelta = 1;                         # Check Diffs between Tag and Head
102
                                            #   0 - Don't do anything
103
                                            #   1 - Warn about diffs
104
                                            #   2 - Error if diffs
267 dpurdie 105
 
1348 dpurdie 106
#
107
#   Data about the package-version
108
#
109
my $srcPathPkg;                             # Root of the package
110
my $devBranch;                              # Development Branch - within the package
111
my $devBranchPeg;                           # May be pegged
112
my $devBranchHead;                          # Revision of the HEAD of the development branch
113
my $tagLabel;                               # Label in 'tags'
114
my $tagPeg;                                 # May be pegged
115
my $tagLabelDistance;                       # Number of changes made to tag after taken
116
my $tagLabelBranch;                         # Tagged from this branch: Discovered
117
my $tagLabelBranchPeg;                      # Tagged from this branch at this peg: Discovered
118
my $ttbType;                                # trunk, tags or branches
119
my $urlType;                                # 'jats' or 'url'
120
my $initialUrl;                             # Initial URL of target
267 dpurdie 121
 
122
#-------------------------------------------------------------------------------
123
# Function        : Mainline Entry Point
124
#
1348 dpurdie 125
# Description     : Main entry point
267 dpurdie 126
#
1348 dpurdie 127
# Inputs          : ARGV[]      - See documentation below
267 dpurdie 128
#
129
 
130
#
131
#   Alter some option defaults if we are creating a view within a sandbox
132
#
133
if ( $GBE_SANDBOX )
134
{
343 dpurdie 135
   $GBE_VIEWBASE = $GBE_SANDBOX;
267 dpurdie 136
   $opt_prefix = 0;
137
}
138
 
139
#
140
#   Parse the user options
141
#
142
my $result = GetOptions (
1348 dpurdie 143
                'help:+'        => \$opt_help,                  # flag, multiple use allowed
144
                'manual:3'      => \$opt_help,                  # flag
145
                'v|verbose:+'   => \$opt_verbose,               # flag, multiple use allowed
146
                'label=s'       => \@opt_spec,                  # Array of build specs
147
                'view=s'        => \$opt_viewname,              # String
148
                'dpkg!'         => \$opt_dpkg,                  # [no]flag
149
                'copy!'         => \$opt_copy,                  # [no]flag
150
                'reuse!'        => \$opt_reuse,                 # [no]flag
151
                'extract:+'     => \$opt_extract,               # flag
152
                'extractfiles'  => \$opt_extract_files,         # flag
153
                'delete:+'      => \$opt_delete,                # flag
154
                'build=s'       => \@opt_build,                 # An array of build
155
                'test!'         => \$opt_test,                  # [no]flag
156
                'cache'         => \$opt_cache,                 # flag
157
                'keep!'         => \$opt_keep,                  # [no]flag
158
                'beta!'         => \$opt_beta,                  # [no]flag
159
                'merge'         => \$opt_merge,                 # [no]flag
160
                'path=s'        => \$opt_path,                  # string
161
                'runtests!'     => \$opt_runtests,              # [no]flag
162
                'branch=s'      => \$opt_branch,                # String
163
                'mkbranch=s'    => \$opt_branch,                # String
164
                'prodOnly'      => \$opt_prod_build,            # flag
165
                'debugOnly'     => \$opt_debug_build,           # flag
166
                'root=s'        => \$GBE_VIEWBASE,              # string
167
                'prefix!'       => \$opt_prefix,                # flag
168
                'tag=s'         => \$opt_tag,                   # string
169
                'devMode=s'     => \$opt_devModeStr,            # string
267 dpurdie 170
                );
171
 
172
                #
173
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
174
                #
175
 
176
#
177
#   Process help and manual options
178
#
179
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
180
pod2usage(-verbose => 1)  if ($opt_help == 2 );
181
pod2usage(-verbose => 2)  if ($opt_help > 2 );
182
 
183
InitFileUtils();
184
#
185
#   Configure the error reporting process now that we have the user options
186
#
187
ErrorConfig( 'name'    => 'SVNRELEASE',
188
             'verbose' => $opt_verbose );
189
 
190
#
191
#   Validate user options
192
#   Use either -label or one command line argument
193
#
1348 dpurdie 194
Error ("Cannot mix -extractfiles and -branch")
195
    if ( $opt_branch && $opt_extract_files );
267 dpurdie 196
Error ("Unexpected command line arguments present.","Cannot mix -label and command line label" )
197
    if ( $#opt_spec >= 0 && $#ARGV >= 0);
198
 
199
push @opt_spec, @ARGV;
200
 
201
unless(  @opt_spec  )
202
{
1348 dpurdie 203
    Error ("Need a workspace or a label. -help for options") if ( $opt_delete  && ! $opt_viewname );
204
    Error ("Need a Subversion Reference or URL. -help for options") unless $opt_delete;
267 dpurdie 205
}
206
 
1348 dpurdie 207
#   Determine extraction mode
208
#       Working- Default
209
#               Extract point on development branch were tag was taken
210
#               Update build files
211
#               Warn about files that have changed
267 dpurdie 212
#
1348 dpurdie 213
#       Tag   - Extract point on development branch were tag was taken
214
#               Update build files
215
#               Error if tag is not the tip
267 dpurdie 216
#
1348 dpurdie 217
#       Tip   - Extact tip of the development branch
218
#               Warn about files that have changed between head and tagPoint
219
#
220
#       Exact - What the user specified
221
#               May be a tag and thus not usable
222
#
223
if ( $opt_devModeStr )
267 dpurdie 224
{
1348 dpurdie 225
    if ( $opt_devModeStr =~ m/^(Tip)|(BranchTip)$/i) {
226
        $opt_devMode = 'tip';
227
        $checkDelta = 1;
228
    } elsif ( $opt_devModeStr =~ m/^(Tag)|(TagPoint)$/i) {
229
        $opt_devMode = 'tag';
230
        $checkDelta = 2;
231
        $checkDelta = 1 if ( $opt_branch );
232
        $noReleaseWs = 0;
233
    } elsif ( $opt_devModeStr =~ m/^(Work)|(Working)$/i) {
234
        $opt_devMode = '';
235
        $checkDelta = 1;
236
    } elsif ( $opt_devModeStr =~ m/^Exact$/i) {
237
        $opt_devMode = 'exact';
238
        $checkDelta = 1;
239
        $noReleaseWs = 0;
240
        Error ('Not allowed to mix -branch and -devMode=exact') if ( $opt_branch );
241
    } else {
242
        Error ("Unknown development mode: $opt_devModeStr");
243
    }
267 dpurdie 244
}
245
 
246
#
1348 dpurdie 247
#   The buildtool works in a known environment
248
#
249
if ( $GBE_ABT )
250
{
251
    $noReleaseWs = 0;       # can always Release
252
    $checkDelta = 0;        # The build system doesn't need to worry about
253
}
254
 
255
#
267 dpurdie 256
#   Limit the user to ONE label/tag/
257
#   Reason: Under Subversion its not possible to 'pinch' files from another
258
#           package. Don't need to create a workspace with multiple labels
259
#
260
#           It was a bad practice under clearcase
261
#
262
if ( $#opt_spec >= 1 )
263
{
264
    Error ("Multiple labels not supported",
265
           "Use one label to describe a package" );
266
}
1348 dpurdie 267
parseSubversionRef($opt_spec[0]);
268
Error ("INTERNAL: initialUrl not set") unless ( $initialUrl );
269
Error ("Cannot interprete the URL or Subversion Reference: $opt_spec[0]") unless ( $srcPathPkg  );
267 dpurdie 270
 
271
#
1348 dpurdie 272
#   Check branch name
383 dpurdie 273
#
274
if ( $opt_branch )
275
{
276
    $opt_branch = SvnIsaSimpleLabel($opt_branch);
277
}
278
 
279
#
267 dpurdie 280
#   User has specified both debug and production
281
#   Then set both to 0 : ie default
282
#
283
if ( $opt_debug_build + $opt_prod_build > 1 )
284
{
285
    $opt_debug_build = 0;
286
    $opt_prod_build = 0;
287
}
288
 
289
#
290
#   User has requested test mode
291
#       - Don't copy
1348 dpurdie 292
#       - Don't package
267 dpurdie 293
#
294
if ( $opt_test )
295
{
296
    $opt_dpkg = 0;
297
    $opt_copy = 0;
298
}
299
 
300
#
301
#   Determine the machine type
302
#
303
Verbose ("Machine Type: UNIX=$UNIX");
304
 
305
Error ("Machine Name not determined")
306
    unless ( $MACHINENAME );
307
$user_cwd = getcwd;
308
 
309
Error ("USER name not determined" )
310
    unless ( $USER );
311
 
312
#
343 dpurdie 313
#   Clean up the view root directory
267 dpurdie 314
#
343 dpurdie 315
$VIEWDIR_ROOT = Realpath($GBE_VIEWBASE) || $GBE_VIEWBASE;
267 dpurdie 316
 
317
Verbose ("Viewpath: $VIEWDIR_ROOT");
318
Error ("Cannot locate view root directory: $VIEWDIR_ROOT" ) unless (-d $VIEWDIR_ROOT);
319
 
320
#
321
#   Remove any user name from the front of the view name
322
#   Simplifies the deletion process as the user can provide
323
#   the directory name
324
#
1348 dpurdie 325
$view_prefix = '' unless ( $opt_prefix );
267 dpurdie 326
 
327
#
328
#   Create a class to describe the complete SVN label
1348 dpurdie 329
#   This will parse the label and create a number of nice elements that will
330
#   be used in determing the name of the workspace
267 dpurdie 331
#
1348 dpurdie 332
$svnSession = NewSessionByUrl ( $initialUrl, 1 );
333
#DebugDumpData("New Session", $svnSession );
267 dpurdie 334
 
335
#
1348 dpurdie 336
#   Test for a pegged label
337
#
338
push @label_not_pegged, $svnSession->Full
339
    unless ( $svnSession->Peg );
340
 
341
#
267 dpurdie 342
#   Setup user specified workspace
343
#   Include the user name to ensure that the view name is unique-ish
344
#   Keep the name as short as possible as some compilers display a fixed
345
#   length filename in error messages and this name is part of the path
346
#
347
#   Base the viewname on the view label. This will simplify the creation
348
#   of multiple views and reduce the risk of unexpected deletion
349
#
350
if ( $opt_viewname )
351
{
352
    Error ("View Name contains invalid characters" )
383 dpurdie 353
        unless ( $opt_viewname =~ m~^[0-9a-z]([-.:0-9a-z_]*[0-9a-z])?$~i )
267 dpurdie 354
}
355
else
356
{
357
    #
1348 dpurdie 358
    #   Create a view name based on the provide URL or SVN Reference
383 dpurdie 359
    #   Unless creating a branch. Branch name will be appended later
267 dpurdie 360
    #
1348 dpurdie 361
    if ( $svnSession->Type )
267 dpurdie 362
    {
1348 dpurdie 363
        $opt_viewname = $svnSession->Path;
364
        $opt_viewname .= '_' . ($svnSession->Version || 'trunk') unless $opt_branch;
363 dpurdie 365
 
366
        #
367
        #   Tags and Branches 'should' include the package name
368
        #   This will lead to a duplication of the package name
369
        #   ie: aaaaa/package/tags/package_version
370
        #   Attempt to remove these
371
        #
372
        if ( $opt_viewname =~ s~[_/]([\-.:0-9a-zA-Z]+)_\1_~_$1_~ )
373
        {
374
            Verbose ("Removed duplicate package name: $1 from $opt_viewname");
375
        }
267 dpurdie 376
    }
377
    else
378
    {
1348 dpurdie 379
        $opt_viewname = $svnSession->Path;
267 dpurdie 380
        $bad_label_name = 1;
381
    }
382
 
383
    #
1348 dpurdie 384
    #   Append information to indicate the exact type of the WorkSpace
385
    #   Normally mutually exclusive
267 dpurdie 386
    #
1348 dpurdie 387
    $opt_viewname .= '_Tip' if ( $opt_devMode eq 'tip' );
388
    $opt_viewname .= '_Tag' if ( $opt_devMode eq 'tag' );
389
    $opt_viewname .= '_Exact' if ( $opt_devMode eq 'exact' );
267 dpurdie 390
    $opt_viewname .= '_' . $opt_branch if ( $opt_branch );
391
 
392
    #
351 dpurdie 393
    #   Create a simple dir name
394
    #       Remove path sep characters and replace with _
395
    #       Remove Peg marker (@) as this breaks svn
396
    #       Replace multiple _ with a single _
361 dpurdie 397
    #       Remove trailing _ - caused by URL with a trailing /
267 dpurdie 398
    #
351 dpurdie 399
    $opt_viewname =~ s~[^\-.:0-9a-zA-Z_]~_~g;
400
    $opt_viewname =~ tr~_~_~s;
361 dpurdie 401
    $opt_viewname =~ s~_+$~~;
267 dpurdie 402
}
403
$opt_viewname =~ s~^$view_prefix~~ if (defined($opt_viewname) && $view_prefix && $opt_delete );
404
 
405
#
406
#   Create a clearcase view to be used for the view
407
#
408
$VIEWPATH = "$view_prefix$opt_viewname";
409
$VIEWDIR = "$VIEWDIR_ROOT/$VIEWPATH";
299 dpurdie 410
$VIEWDIR =~ tr~\\/~/~s;
267 dpurdie 411
Verbose( "Hostname: $MACHINENAME" );
412
Verbose( "Viewpath: $VIEWPATH" );
413
Verbose( "Viewdir : $VIEWDIR" );
414
 
415
#
416
#   If the user has specified a "source path", then we must ensure that it is
417
#   valid. It will be used to create the WorkSpace
418
#
419
#   Ensure that the path is a defined variable. If used prepend a / to simplify
420
#   concatenation.
421
#
422
Verbose("Validate Source Path");
423
if ( $opt_path )
424
{
425
    $opt_path =~ tr~\\/~/~s;
426
    $opt_path =~ s~/$~~;
427
    $opt_path =~ s~^/~~;
428
 
429
    Error( "Source Path has drive specifier" ) if ( $opt_path =~ m~^[A-Za-z]\:~ );
430
    $opt_path = '/'.$opt_path ;
431
}
432
else
433
{
434
    $opt_path = '';
435
}
1348 dpurdie 436
$workSpace = $VIEWDIR . $opt_path;
437
Verbose( "workSpace : $workSpace" );
267 dpurdie 438
 
439
#
440
#   If the view currently exists then it will be deleted if allowed
441
#
442
delete_view()
299 dpurdie 443
    unless ( $opt_reuse );
267 dpurdie 444
 
445
#
446
#   If the user is simply deleting the view then all has been done
447
#
448
exit 0
449
    if ( $opt_delete );
450
 
451
#
1348 dpurdie 452
#   Ensure that the label is present within the specified Repository
267 dpurdie 453
#
454
Verbose("Ensure Labels can be found in a Repository");
1348 dpurdie 455
Verbose ("Testing label: ". $svnSession->Full );
267 dpurdie 456
$label_count++;
457
 
1348 dpurdie 458
$svnSession->SvnValidateTarget (
267 dpurdie 459
                    'cmd'    => 'SvnRelease',
1348 dpurdie 460
                    'target' => $svnSession->Full,
267 dpurdie 461
                    'require' => 1,
462
                    );
1348 dpurdie 463
 
267 dpurdie 464
#
1348 dpurdie 465
#   If the user did not provide a peg then examine
466
#   the 'tag' in the repo and determine when it was created
467
#   This will not work to well if the user is allowed to move the tag
267 dpurdie 468
#
1348 dpurdie 469
unless ( $svnSession->Peg() )
470
{
471
    $svnSession->SvnInfo( $svnSession->Full, 'InfoRepo' );
472
    my $peg = $svnSession->{'InfoRepo'}{'Last Changed Rev'};
267 dpurdie 473
 
1348 dpurdie 474
    $svnSession->{'PEG'} = '@' . $peg;
475
    if ( $tagLabel ) {
476
        $tagPeg = $peg;
477
    } elsif ( $devBranch ) {
478
        $devBranchPeg = $peg;
479
    }
480
}
481
#debugDumpRefInfo('Get Peg');
482
 
267 dpurdie 483
#
1348 dpurdie 484
#   Trace back from the tag to the point at which it was copied
485
#   This should be the same as the user provided development branch
486
#   but it may not be the same if the user is changing the branch
487
#
488
if ( $tagLabel )
489
{
490
    my $btData;
491
    my $labelBranch = $svnSession->backTrackSvnLabel( join ('@', $tagLabel, $tagPeg), \$btData );
492
    $tagLabelDistance = $btData->{entryCount};
493
    if ( $tagLabelDistance <= 0 )
494
    {
495
        Warning("Cannot trace package label back to a development branch");
496
    }
497
    else
498
    {
499
        Error ("INTERNAL: Cannot parse result of backTrackSvnLabel: $labelBranch")
500
            unless ($labelBranch =~ m~^(.*)@(\d+)$~);
501
        $tagLabelBranch = $1;
502
        $tagLabelBranchPeg = $2;
503
 
504
        #
505
        #   Verify that the Development Barnch matches that provided by the user
506
        #
507
        if ( $devBranch && ($devBranch ne $tagLabelBranch) )
508
        {
509
            # If the user is creating a branch, then allow this mismatch
510
            #
511
            unless ( $opt_branch && ($devBranch =~ m~/$opt_branch$~) )
512
            {
513
                Error("The package Tag was not taken from the development branch",
514
                      "Development Branch: $devBranch\@$tagPeg",
515
                      "Tag traced back to: $tagLabelBranch\@$tagLabelBranchPeg" );
516
            }
517
        }
518
        $devBranchPeg = $tagLabelBranchPeg unless ( $devBranchPeg );
519
 
520
        #   Ensure that the TAG has not been modified since it was taken
521
        #   The extraction algorithm assumes that the tag directory is
522
        #   immutable.
523
        #
524
        if ( $btData->{entryCount} > 1 )
525
        {
526
            Error ("Tag has been modified since created") if ( $GBE_ABT );
527
            Warning ("Tag has been modified since created");
528
        }
529
    }
530
}
531
#debugDumpRefInfo('BackTrack Label');
532
 
533
#
534
#   Examine the HEAD of the development branch and determine if there
535
#   have been any changes since the tag was taken
536
#
537
determineChangedFiles();
538
 
539
################################################################################
540
#   Create a workspace based on the tag
541
#   It will be back tracked to the branch that was tagged:
542
#       - Ripple build tags look better in version tree
543
#       - User can develop in the workspace as its not linked to an immutable 'tags'
544
#
545
#   So far we have:
546
#       $initialUrl         - Url to the version that the user specified
547
#       $initialUrlBranch   - Url to the branch from which the initialUrl was taken
548
#                             Iff based on a Tag
549
#       $urlDevBranchHead   - Head of the Development Branch
550
#
551
 
552
$initialUrl = substr( $initialUrl, 1 + length($srcPathPkg));
553
 
554
my $initialUrlBranch;
555
if ( $tagLabelBranch )
556
{
557
    $initialUrlBranch  = $tagLabelBranch;
558
    $initialUrlBranch .= '@' . $tagLabelBranchPeg;
559
}
560
 
561
my $urlDevBranchHead;
562
if ( $devBranch )
563
{
564
    $urlDevBranchHead  = $devBranch;
565
}
566
else
567
{
568
    $urlDevBranchHead  = $tagLabelBranch;
569
}
570
 
571
#
572
#   Debug information
573
#
574
if ( IsVerbose(1) ) {
575
    debugDumpRefInfo('Creating workspaces');
576
    Verbose ('------------');
577
    Verbose ("initialUrl       :", $initialUrl);
578
    Verbose ("initialUrlBranch :", $initialUrlBranch );
579
    Verbose ("urlDevBranchHead :", $urlDevBranchHead );
580
    Verbose ("opt_viewname     :", $opt_viewname );
581
#    DebugDumpData("svn_label", $svnSession );
582
}
583
 
584
#
267 dpurdie 585
#   If we are only extracting files then ...
586
#
587
if ( $opt_extract_files )
588
{
589
    extract_files_from_view();
590
    exit (0);
591
}
592
 
593
#
594
#   Create a new workspace
1348 dpurdie 595
#       This is not done if the user is reusing an existing workspace
596
#       AND the existing workspace exists.
267 dpurdie 597
#
598
if (! -d $VIEWDIR || ! $opt_reuse )
599
{
1348 dpurdie 600
    Message( "Create the workspace" . ($GBE_SANDBOX ? " in a SANDBOX" : ''));
267 dpurdie 601
 
1348 dpurdie 602
    my $branch;
603
    my $view_tag;
604
    my $update_tagsChanges;
605
    if ( $opt_devMode eq 'tip' ) {
606
        $view_tag =  $urlDevBranchHead;
607
    } elsif ( $opt_devMode eq 'exact' ) {
608
        $view_tag =  $initialUrl;
609
    } else {
610
        $view_tag = $initialUrlBranch || $initialUrl;
611
        $update_tagsChanges = 1;
612
    }
613
    Message ("Creating Workspace based on: $view_tag");
614
    $view_tag = $svnSession->FullPath() . '/' .$view_tag;
615
    Verbose("Creating Workspace:", $view_tag);
616
 
267 dpurdie 617
    #
1270 dpurdie 618
    #   If a branch is required ...
1348 dpurdie 619
    #   Ensure that the branch is NOT in the Repository
267 dpurdie 620
    #
621
    if ( $opt_branch )
622
    {
1348 dpurdie 623
        $branch = $svnSession->BranchName($opt_branch, 'branches' );
624
        $svnSession->SvnValidateTarget (
625
                        'cmd'    => 'SvnRelease: Validate Branch',
1270 dpurdie 626
                        'target' => $branch,
1348 dpurdie 627
                        'available' => 1,
1270 dpurdie 628
                        );
267 dpurdie 629
    }
1348 dpurdie 630
 
1270 dpurdie 631
    #
632
    #   Create the workspace
633
    #
1348 dpurdie 634
    $svnSession->SvnCo ( $view_tag, $workSpace );
267 dpurdie 635
    Error ("Cannot locate the created Workspace")
1348 dpurdie 636
        unless ( -d $workSpace);
637
    importTagChanges()
638
        if ($update_tagsChanges);
267 dpurdie 639
 
640
    #
1348 dpurdie 641
    #   If we need to create a branch then
642
    #       Copy the WS to URL
643
    #       Switch to new URL
644
    #   The bulk of the copy will be done on the server-side
645
    #   and not over the network. This is  good.
646
    #
647
    if ( $opt_branch )
648
    {
649
        #
650
        #   Branch does not exist
651
        #   Create it be copying the base view
652
        #
653
        Message ("Creating branch: $opt_branch");
654
        my $branch_tag = $svnSession->SvnCopy (
655
                        'old' => $workSpace,
656
                        'new' => $branch,
657
                        'comment' => 'Created by Jats SvnRelease branch request',
658
                        'replace' => 0 );
659
 
660
        Verbose ("Switching to new branch: $opt_branch");
661
        $branch_tag = SvnPath2Url($branch_tag);
662
        $svnSession->SvnSwitch ($branch_tag,
663
                               $workSpace,
664
                               '--NoPrint' );
665
    }
666
 
667
    #
267 dpurdie 668
    #   Create a local package archive
669
    #   May be needed for multipackage builds and it will prevent JATS from
670
    #   finding any outside the view
671
    #
672
    mkdir ( $VIEWDIR . '/local_dpkg_archive')
673
        unless ($GBE_SANDBOX);
1348 dpurdie 674
 
675
    #
676
    #   Display messages AFTER the extraction text
677
    #   Will ensure that the user has a chace to see them
678
    #
679
    Warning(@messageText );
680
 
267 dpurdie 681
}
682
 
285 dpurdie 683
#   Place a tag-file in the user-specified source path
684
#   This will be used by the build-tool to locate the 'source-path' of the
685
#   view, primarily for determining metrics.
267 dpurdie 686
#
1348 dpurdie 687
#   Calculate where the dynamic view will be
285 dpurdie 688
#   This differ between UNIX/WINDOWS
689
#
351 dpurdie 690
if ( $GBE_ABT)
285 dpurdie 691
{
1348 dpurdie 692
    Message("Create Build tagfile");
693
    TouchFile ( "$workSpace/.jats.packageroot" )
694
        if ( -d $workSpace )
285 dpurdie 695
}
696
 
697
#
267 dpurdie 698
#   Locate the JATS build files within the populated view
699
#
1348 dpurdie 700
chdir ($VIEWDIR) or Error("Cannot chdir to $VIEWDIR");
267 dpurdie 701
Message( "Locating build files");
702
 
703
my $bscanner = BuildFileScanner( $VIEWDIR, 'build.pl', '--LocateAll' );
704
$bscanner->scan();
705
my @build_list = $bscanner->getInfo();
706
foreach my $be ( @build_list )
707
{
1348 dpurdie 708
    Message(DisplayPath ("Build file: $be->{dir} Name: $be->{file}"));
267 dpurdie 709
}
710
 
711
#
712
#   If we are extracting the view then we are done
713
#   Display useful information for the user
714
#
715
if ( $opt_extract )
716
{
717
    Message  DisplayPath "View in: $VIEWDIR";
718
    Warning ("No build files found" )   if ( $#build_list < 0 );
719
    Warning( "Multiple build files found" )if ( $#build_list > 0 );
720
    Message ("Not all labels are pegged") if ( @label_not_pegged  );
721
    Message ("All labels are pegged") unless ( @label_not_pegged  );
722
    Message ("Badly formed label name" ) if ( $bad_label_name );
1348 dpurdie 723
    Message ("Development Mode: $opt_devModeStr") if ( $opt_devModeStr );
267 dpurdie 724
    Message ("Development Sandbox") if ( $GBE_SANDBOX );
725
 
726
    exit 0;
727
}
728
 
729
Error ("No build files found")  if ( $#build_list < 0 );
730
 
731
#
732
#   Determine the list of builds to perform
733
#   Ensure that the user-requested build files are present
734
#
735
#   The user specifies the build file, via the mangled package name
736
#   This is package_name . project extension (daf_utils.cr)
737
#
738
if ( $#opt_build  >= 0)
739
{
740
    Verbose( "Check and locate the build files");
741
    @build_list = ();
742
    foreach my $bentry ( @opt_build )
743
    {
744
        if ($bscanner->match( $bentry) )
745
        {
746
            UniquePush (\@build_list, $bscanner->getMatchList() );
747
            Verbose ("Found: $bentry");
748
        }
749
        else
750
        {
751
            Error ("Cannot locate requested build files for: $bentry")
752
        }
753
    }
754
}
755
 
756
#
757
#   Sanity test if we will transfer the generated package to dpkg_archive
758
#   There are some limits
759
#       1) Must have built from one label
760
#       2) That label must be locked
761
#       3) Only one build file
762
#       4) The view must not have been reused
763
#       5) The view has a branch rule
764
#       6) Cannot release from a sandbox
765
#
766
my @elist;
767
push @elist, "Package built from multiple labels" unless ( $label_count == 1 );
768
push @elist, "Package built from an unpegged label" if ( @label_not_pegged  );
769
push @elist, "Package built with multiple build files" if ( scalar @build_list > 1 );
770
push @elist, "Package from a reused view" if ( $opt_reuse && ! $opt_beta );
771
push @elist, "Package from a development sandbox" if ( $GBE_SANDBOX );
1348 dpurdie 772
push @elist, "Package from a development workspace" if ($noReleaseWs);
267 dpurdie 773
push @elist, "View contains a branch" if ( $opt_branch );
774
push @elist, "User has specified build files" if ( $#opt_build > 0 );
775
push @elist, "Badly formed label name" if ( $bad_label_name );
776
 
777
if ( @elist )
778
{
779
    Warning ("Cannot officially release the package.", @elist);
780
    Error ("Build terminated as it cannot be released") if ($opt_dpkg && ! $opt_beta);
781
}
782
Warning ("Beta Release") if $opt_beta;
783
 
784
#
785
#   Process each of the build files in the specified order
786
#
787
foreach my $be (@build_list)
788
{
789
 
790
    #
791
    #   We need to change to the build directory
792
    #   Moreover we need the local name of the build directory.
793
    #   Windows does not handle a UNC pathname to well (at all)
794
    #
795
    my $build_dir = $be->{dir};
796
    chdir ("$build_dir") or Error( "Cannot chdir to build directory: $build_dir");
797
 
798
    if ( $be->{file} =~ m/^build.pl$/ )
799
    {
800
        Message ("Using JATS: $build_dir");
801
        #
802
        #   Invoke JATS to build the package and make the package
803
        #
804
        my @build_args = qw(--expert --cache);
805
        push @build_args, '--cache' if $opt_cache;
806
 
807
        my $make_type = 'all';
808
        $make_type = 'all_prod'  if ( $opt_prod_build );
809
        $make_type = 'all_debug' if ( $opt_debug_build );
810
 
811
 
812
        JatsCmd('build', @build_args)               and Error("Package did not build");
813
        JatsCmd('make', $make_type, 'NODEPEND=1')   and Error("Package did not make");
814
        JatsCmd('install');
815
 
816
        if ( $opt_runtests )
817
        {
321 dpurdie 818
            JatsCmd('make', 'run_unit_tests')      and Error("Tests did not run correctly");
267 dpurdie 819
        }
820
    }
821
    else
822
    {
823
        #
824
        #   Ant build files
825
        #
826
        my $pname =  $be->{file};
827
        Message ("Using ANT: $build_dir, $pname");
828
        $pname =~ s~depends.xml$~.xml~;
829
        copy($be->{file}, "auto.xml");
830
        JatsCmd('-buildfile', $pname, 'ant', 'build')        and Error("Package did not build");
831
        JatsCmd('-buildfile', $pname, 'ant', 'make_package') and Error("Package did not make_package");
832
    }
833
}
834
 
835
#
836
#   Copy the generated packages
837
#       1) dpkg_archive
838
#       2) Users local directory
839
#
840
foreach my $be (@build_list)
841
{
842
    my $build_dir = $be->{dir};
843
    chdir ("$build_dir") or Error( "Cannot chdir to build directory: $build_dir");
844
    if ( $opt_dpkg )
845
    {
846
        Message ("Using: $build_dir");
279 dpurdie 847
        my @create_opts = "-o";
848
        push @create_opts ,"-m" if ( $opt_merge );
849
        JatsCmd('-here', 'create_dpkg', @create_opts, '-pname', $be->{name}, '-pversion', $be->{version}) and $error++;
267 dpurdie 850
    }
851
 
852
    if ( $opt_copy )
853
    {
854
        Message ("Copy package to $user_cwd");
855
        copy_directory( 'pkg', $user_cwd, '' );
856
    }
857
 
858
    #
859
    #   Test structure of the package
860
    #   Ensure that it has a descpkg file
861
    #   Validate the package name and version
862
    #   More important for ANT projects than JATS as JATS has a sanity test
863
    #
864
    if ( $opt_test )
865
    {
866
        JatsCmd('-here', 'create_dpkg', '-test', '-pname', $be->{name}, '-pversion', $be->{version}) and $error++;
867
    }
868
 
869
}
870
Error ("Package not transferred")
871
    if ( $error );
872
 
1348 dpurdie 873
chdir ($user_cwd) or Error( "Cannot chdir to $user_cwd");
267 dpurdie 874
 
875
#
876
#   Delete the view
877
#
878
if ( ! $opt_reuse && ! $error && ! $opt_keep )
879
{
880
    delete_view();
881
}
882
else
883
{
884
    Message( "View left in: $VIEWDIR" );
885
}
886
 
887
Message ("End program");
888
exit 0;
889
 
890
#-------------------------------------------------------------------------------
891
# Function        : delete_view
892
#
893
# Description     : Delete a view
894
#
895
# Inputs          : None
896
#                   $VIEWDIR - path of the view
897
#
898
# Returns         :
899
#
900
sub delete_view
901
{
902
    my $cofound = 0;
903
    my $uuid;
904
    #
299 dpurdie 905
    #   Simple delete
267 dpurdie 906
    #
299 dpurdie 907
    if ( $opt_extract_files )
267 dpurdie 908
    {
299 dpurdie 909
        if ( -d $VIEWDIR )
910
        {
911
            Message("Remove extracted files: $VIEWDIR");
361 dpurdie 912
            RmDirTree( $VIEWDIR );
299 dpurdie 913
        }
914
    }
915
    else
916
    {
267 dpurdie 917
        #
1348 dpurdie 918
        #   If the view physically exists then attempt to physically remove it
267 dpurdie 919
        #
299 dpurdie 920
        if ( -d $VIEWDIR )
921
        {
922
            #
923
            #   Determine if there are any checked out files in the view
924
            #
925
            Message("Remove the view: $VIEWDIR");
926
            Verbose("Look for checked out files");
267 dpurdie 927
 
928
 
1348 dpurdie 929
            SvnRmView ('path'     => $workSpace,
930
                       'force'    => ($opt_delete > 1) || ($opt_extract > 1),
299 dpurdie 931
                       'modified' => [ 'local_dpkg_archive' ] );
932
        }
361 dpurdie 933
        Error ("View was not deleted. Will Delete view directory")
1348 dpurdie 934
            if ( -d $workSpace );
361 dpurdie 935
        RmDirTree( $VIEWDIR ) if $opt_path;
267 dpurdie 936
    }
299 dpurdie 937
 
267 dpurdie 938
    Error ("View was not deleted")
299 dpurdie 939
        if ( -d $VIEWDIR );
267 dpurdie 940
}
941
 
942
#-------------------------------------------------------------------------------
943
# Function        : copy_directory
944
#
945
# Description     : Copy a directory tree
946
#
947
# Inputs          : Source directory
948
#                   Target directory
949
#                   Strip
950
#
951
#                   Should be full pathnames
952
#
953
# Returns         :
954
#
955
my $copy_error;
956
my $copy_count;
957
sub copy_directory
958
{
959
    our ($src_dir, $dest_dir, $strip) = @_;
960
    our $slength = length ($strip);
961
 
962
    #
963
    #   Prevent File::Find from generating warnings
964
    #
965
    no warnings 'File::Find';
966
 
967
 
968
    #
969
    #   Helper routine to copy files
970
    #
971
    sub copy_file_wanted
972
    {
973
        #
974
        #   Do not copy directories
975
        #   Just make the directory entry. May result in empty directories
976
        #
977
        if ( -d $_ )
978
        {
979
            my $tdir = "$dest_dir/" . substr( $File::Find::dir, $slength);
980
            $tdir .= "/$_";
981
            File::Path::mkpath( $tdir )
982
                unless ( -d $tdir);
983
            return;
984
        }
985
 
986
        #
987
        #   When used to copy file from within a clearcase dynamic view the
988
        #   files may not actually exist. This will generate an error later
1348 dpurdie 989
        #   so check for existence of file file now.
267 dpurdie 990
        #
991
        return unless ( -e $_ );
992
 
993
        #
994
        #   Have been chdir'ed to the source directory
995
        #   when invoked
996
        #
997
        my $tdir = "$dest_dir/" . substr( $File::Find::dir, $slength);
998
        my $tfile = "$tdir/$_";
999
        my $sfile = "$File::Find::dir/$_";
1000
        Verbose ("Copy: $sfile -> $tfile");
1001
 
1002
        File::Path::mkpath( $tdir )
1003
            unless ( -d $tdir);
1004
 
1005
        unlink ( $tfile )
1006
            if ( -f $tfile );
1007
 
1008
        if( ! File::Copy::copy ( $_ , $tfile ) )
1009
        {
1010
            $copy_error++;
1011
            Message "Error copying $sfile";
1012
        }
1013
        else
1014
        {
1015
            my $perm = (stat $_)[2] & 07777;
1016
            chmod($perm, $tfile);
1017
 
1018
            $copy_count++;
1019
        }
1020
    }
1021
 
1022
    #
1023
    #   Locate all files to copy
1024
    #
1025
    $copy_error = 0;
1026
    $copy_count = 0;
1027
    File::Find::find ( \&copy_file_wanted, $src_dir );
1028
    return $copy_error;
1029
}
1030
 
1031
#-------------------------------------------------------------------------------
1032
# Function        : count_files
1033
#
1034
# Description     : Count files in a workspace
1035
#                   Ignore .svn stuff
1036
#
1037
# Inputs          : Source directory
1038
#
1039
# Returns         :
1040
#
1041
sub count_files
1042
{
1043
    my ($src_dir) = @_;
1044
 
1045
    #
1046
    #   Prevent File::Find from generating warnings
1047
    #
1048
    no warnings 'File::Find';
1049
 
1050
 
1051
    #
1052
    #   Helper routine to copy files
1053
    #
1054
    sub count_file_wanted
1055
    {
1056
        #
1057
        #   Do not count dirs, only files
1058
        #
1059
        return if ( -d $_ );
1060
        $copy_count++;
1061
    }
1062
 
1063
    #
1064
    #   Locate all files
1065
    #
1066
    $copy_count = 0;
1067
    File::Find::find ( \&count_file_wanted, $src_dir );
1068
}
1069
 
1070
 
1071
#-------------------------------------------------------------------------------
1072
# Function        : extract_files_from_view
1073
#
1074
# Description     : This function will
1348 dpurdie 1075
#                       Extract the files from the required source
1076
#                       This is a simple operation under subversion
267 dpurdie 1077
#
1078
#                   Its used in the creation of escrow directories
1079
#
1080
# Inputs          : None
1081
#                   All done via globals
1082
#
1083
# Returns         : 
1084
#
1085
sub extract_files_from_view
1086
{
1087
    #
1088
    #   Determine the target directory for the extracted files
1089
    #       Delete the output subdir
1090
    #       Create the config spec in that directory
1091
    #
1092
    Verbose("Extracting files into $VIEWDIR");
1093
    if ( -d $VIEWDIR )
1094
    {
1095
        Verbose "Delete Directory: $VIEWDIR\n";
361 dpurdie 1096
        RmDirTree( $VIEWDIR );
267 dpurdie 1097
    }
1098
 
1348 dpurdie 1099
    #
1100
    #   Determine URL to extract
1101
    #       work : Same as exact
1102
    #       exact: Use user provided tag
1103
    #              No need to backtrack to the branch and then
1104
    #              Update files
1105
    #
1106
    #       tag:   Don't update build files
1107
    #              This is different normal mode
1108
    #              Perhaps should change to be the same as exact - just extract
1109
    #              the user provided tag
1110
    #
1111
    #       tip:   Don't update build files
1112
    #
1113
    my $view_tag;
1114
    if ( $opt_devMode eq 'tip' ) {
1115
        $view_tag =  $urlDevBranchHead;
1116
    } elsif ( $opt_devMode eq 'tag' ) {
1117
        $view_tag = $initialUrlBranch;
1118
    } else {
1119
        $view_tag = $initialUrl;
1120
    }
267 dpurdie 1121
 
1348 dpurdie 1122
    $svnSession->SvnCo ( $svnSession->FullPath() . '/' . $view_tag,
1123
                        $VIEWDIR,
1124
                        '--Export',
1125
                        '--NoPrint' );
1126
 
267 dpurdie 1127
    #
1128
    #   Count this files in the view
1348 dpurdie 1129
    #   Done so that its clear when we have a empty workspace in escrow extractions
267 dpurdie 1130
    #
1131
    Verbose ("Examine View contents");
1132
    count_files ( $VIEWDIR );
1133
    Message ("View files in: $VIEWDIR, Files: $copy_count" );
1348 dpurdie 1134
}
267 dpurdie 1135
 
1348 dpurdie 1136
#-------------------------------------------------------------------------------
1137
# Function        : importTagChanges
1138
#
1139
# Description     : import changes from a 'tag' into the target workspace
1140
#                   Use with a workspace as well as an exported target
1141
#
1142
# Background      :
1143
#   The workspace has been created on the branch from which the tag was taken
1144
#   BUT this may not be the same as the tag because:
1145
#       1) Developer is not respecting the use of tags
1146
#       2) The automated build system will place the rippled build files
1147
#          within the tag.
1148
#   The most effective way that I have found of getting the modified build
1149
#   files into the workspace is to:
1150
#       Parse the log of the tag
1151
#       Determine files that have been modified as a part of the tag
1152
#       export them into the workspace
1153
#
1154
#   If we are creating a workspace that we are about to branch, then
1155
#   we use 'switch' to copy in the new file
1156
#   Otherwise, use a 'co -export'. If we use a switch, then the files
1157
#   that have been switched in cannot be commit if changed as they will
1158
#   be within the 'tags' area.
1159
#
1160
# Inputs          : None
1161
#                   Globals
1162
#
1163
# Returns         : Error code
1164
#
1165
sub importTagChanges
1166
{
1167
    return unless ( $tagLabel );
1168
    my $data;
1169
    my $labelBranch = $svnSession->backTrackSvnLabel( join ('@', $tagLabel, $tagPeg ), \$data);
1170
#    DebugDumpData("importTagChanges", $svnSession );
1171
#    DebugDumpData("Data", $data );
1172
 
1173
    #
1174
    #   Process the data from the backtrack log and determine the files
1175
    #   that we need to transfer.
1176
    #       Only expect files to be changed
1177
    #
1178
    foreach my $entry ( @{$data->{data}} )
1179
    {
1180
        if ( $entry->{kind} eq 'file' )
1181
        {
1182
            $entry->{target} =~ m~(/tags/.*)$~;
1183
            my $srcFile = $1 .'@' . $tagPeg;
1184
            Verbose("importTagChanges: $srcFile");
1185
            if ( $opt_branch )
1186
            {
1187
                $srcFile =~ m~/tags/.*?(/.*)@\d+~;
1188
                my $tfile = $1;
1189
                $svnSession->SvnSwitch ($svnSession->FullPath() . $srcFile,
1190
                                       $workSpace . $tfile);
1191
            }
1192
            else
1193
            {
1194
                $svnSession->SvnCo ($svnSession->FullPath() . $srcFile,
1195
                                   $workSpace, '--Export', '--Force', '--PreText=Replacing ' );
1196
            }
1197
        }
1198
    }
267 dpurdie 1199
}
1200
 
1201
#-------------------------------------------------------------------------------
1348 dpurdie 1202
# Function        : determineChangedFiles
1203
#
1204
# Description     : Display a list of files that have been changed between
1205
#                   the tagPoint and the head of the branch
1206
#
1207
# Inputs          : Only Globals
1208
#
1209
# Returns         : Will not return if changes are not allowed
1210
#
1211
sub determineChangedFiles
1212
{
1213
    my @msgText;
267 dpurdie 1214
 
1348 dpurdie 1215
    #
1216
    #   No checking required
1217
    #   Skip the hard bit if running on a build machine
1218
    #
1219
    return unless ( $checkDelta );
267 dpurdie 1220
 
1348 dpurdie 1221
    Debug ('determineChangedFiles');
1222
#debugDumpRefInfo('determineChangedFiles');
1223
 
1224
    #
1225
    #   Examine the HEAD of the development branch and determine if there
1226
    #   have been any changes since the tag was taken
1227
    #
1228
    #   Determine the Repo Revision for the HEAD of the devBranch
1229
    #
1230
    Error ("Internal: No devBranch calculated") unless ( $devBranch || $tagLabelBranch );
1231
 
1232
    my $basePeg = $tagLabelBranchPeg || $devBranchPeg;
1233
    my $baseBranch = $tagLabelBranch || $devBranch;
1234
    Error ("Internal logic. Expecting tagLabelBranchPeg or devBranchPeg to be defined") unless ( $basePeg );
1235
    Error ("Internal logic. Expecting tagLabelBranch or devBranch to be defined") unless ( $baseBranch );
1236
 
1237
    my $svn_check = NewSessionByUrl ( join( '/', $srcPathPkg, $baseBranch), 1 );
1238
    my $rv = $svn_check->SvnInfo( $svn_check->Full, 'InfoRepo' );
1239
    if ( $rv )
1240
    {
1241
        push (@msgText, "Cannot read information for the head of the development branch",
1242
                        "Branch may not exist: $baseBranch");
1243
    }
1244
    else
1245
    {
1246
        $devBranchHead = $svn_check->{'InfoRepo'}{'Last Changed Rev'};
1247
        Verbose2("devBranchHead: $devBranchHead");
1248
    #debugDumpRefInfo('Dev Branch Head');
1249
 
1250
 
1251
        #
1252
        #   If the Rev of the HEAD is greater than the point at which we
1253
        #   are interested then changes may have occured. Otherwise we know
1254
        #   that changes cannot have occured
1255
        #
1256
        if ( $devBranchHead <= $basePeg )
1257
        {
1258
            return;
1259
        }
1260
 
1261
        if ( $tagLabelBranchPeg )
1262
        {
1263
            push @msgText,  "Development Branch has changed since Tag was taken",
1264
                            "Head last changed in Rev: $devBranchHead",
1265
                            "Tag traced back to Rev  : $basePeg";
1266
        } else
1267
        {
1268
            push @msgText,  "Development Branch has changed since specified version",
1269
                            "Head last changed in Rev: $devBranchHead",
1270
                            "Specified branch Rev    : $basePeg";
1271
        }
1272
 
1273
 
1274
        my $diffBase = $svn_check->FullPath() . '/' . $baseBranch;
1275
        $svn_check->{tmp}{path_length} = length($diffBase);
1276
        $svn_check->{tmp}{count}  = 0;
1277
        @{$svn_check->{tmp}{files}}  = ();
1278
 
1279
        $rv = $svn_check->SvnCmd ( 'diff', '--summarize',
1280
                                   $diffBase,
1281
                                   '--revision', $basePeg . ':HEAD',
1282
                                   {
1283
                                        'process' => \&ProcessDiff,
1284
                                        'credentials' => 1,
1285
                                        'nosavedata' => 1,
1286
                                   }
1287
                                );
1288
        #
1289
        #   Prepare message to be displayed
1290
        #   Prepend text to the list of files
1291
        #
1292
 
1293
        $rv = $svn_check->{tmp}{count};
1294
        return unless ( $rv );
1295
        push (@msgText, "No files changed") unless ( $rv );
1296
        push (@msgText, "Changed file count: $rv") if ( $rv );
1297
        push (@msgText, "More than 10 files have changed. First 10 are:") if ( $rv > 10);
1298
        push (@msgText, @{$svn_check->{tmp}{files}} );
1299
    }
1300
 
1301
    if ( $checkDelta == 1) {
1302
        push @messageText, @msgText;
1303
    } else {
1304
        Error ( @msgText );
1305
    }
1306
}
1307
 
1308
sub ProcessDiff
1309
{
1310
    my $self = shift;
1311
    my $data = shift;
1312
 
1313
    #
1314
    #   Extract filename from line
1315
    #       First 8 chars are status
1316
    #       Remove WS path too
1317
    #
1318
    my $path_length = $self->{tmp}{path_length} + 1 + 8;
1319
    if ( length $data >= $path_length )
1320
    {
1321
        my $file = substr ( $data, $path_length );
1322
        push @{$self->{tmp}{files}}, '  Changed: ' .  $file
1323
            if ( $self->{tmp}{count}++ < 10 );
1324
    }
1325
 
1326
    return 0;
1327
}
1328
 
267 dpurdie 1329
#-------------------------------------------------------------------------------
1348 dpurdie 1330
# Function        : parseSubversionRef
1331
#
1332
# Description     : Parse the user-provided Subversion Ref
1333
#
1334
#                   Convert label with embedded VCS information into a 'normal' form.
1335
#                   Form:
1336
#                       SVN::<SourcePath>::<Label>
1337
#                       SVN::<SourcePath>::<Peg>
1338
#                   
1339
#                   Allow optional 'SVN::' prefix
1340
#                   Allow Full or Symbolic URL
1341
#                       [SVN::]<SourcePath>::<Label>
1342
#                       [SVN::]<SourcePath>::<Peg>
1343
#                       [SVN::]<URL>
1344
#
1345
# Inputs          : $opt_spec               - User Provided Ref
1346
#
1347
# Returns         : Will not retirn on gross error
1348
#                   Values return in global variables
1349
#
1350
sub parseSubversionRef
1351
{
1352
    my ($opt_spec) = @_;
1353
 
1354
    $opt_spec =~ s~^SVN::~~;
1355
    if ( $opt_spec =~ m~(.+)::(.+)~ )
1356
    {
1357
        my $sourcePath = $1;
1358
        my $label = $2;
1359
        $urlType = 'jats';
1360
 
1361
        #
1362
        #   Sanity test of sourcePath
1363
        #
1364
        Error ("Invalid use of a peg: $opt_spec[0]")
1365
            if ( $sourcePath =~ m~\@\d+$~ );
1366
 
1367
        #
1368
        #   Remove anything after a ttb (truck, tags, branch) element
1369
        #   This will be the root of the package within the repo
1370
        #
1371
        if (  $sourcePath =~ m~(.*)/((tags|branches|trunk)(/|$)(.*))~ )
1372
        {
1373
            Error ("Source Path has insufficient items")
1374
                if ( $1 eq '' );
1375
 
1376
            Error ("SourcePath contains invalid items after '$3': '$5'")
1377
                if ( ($3 eq 'tags' || $3 eq 'trunk') && $5 ne '' );
1378
 
1379
            Error ("SourcePath must contain items after 'branches'")
1380
                if ( $3 eq 'branches' && $5 eq '');
1381
 
1382
            $srcPathPkg = $1;
1383
            $ttbType = $3;
1384
            $devBranch = $3;
1385
            $devBranch .= '/' . $5 if ( $5 ne '' );
1386
        }
1387
        else
1388
        {
1389
            Error ("Source Path does not contain tags or trunk or branches component");
1390
        }
1391
 
1392
        #
1393
        #   Pull apart the 2nd argument
1394
        #   May be a raw peg - on the development branch
1395
        #   May be a tag and a peg
1396
        #
1397
        $initialUrl = $srcPathPkg;
1398
        if ( $label =~ m~^@*(\d+)$~ )
1399
        {
1400
            # Full numeric label - is a peg on the development branch
1401
            $devBranchPeg = $1;
1402
            $initialUrl .= '/' . $devBranch . '@' . $devBranchPeg;
1403
        }
1404
        elsif ( $label =~ m~^([^@]+)@(\d+)$~ )
1405
        {
1406
            $tagLabel = 'tags/' . $1;
1407
            $tagPeg = $2;
1408
            $initialUrl .= '/tags/' . $label;
1409
 
1410
        }
1411
        elsif ( $label !~ m~@~ )
1412
        {
1413
            $tagLabel = 'tags/' . $label;
1414
            $initialUrl .= '/tags/' . $label;
1415
        }
1416
        else
1417
        {
1418
            Error ("Subversion Tag badly formed: $label");
1419
        }
1420
    } elsif ($opt_spec =~ m~::~) {
1421
        Error ("Badly formed Subversion Reference: $opt_spec[0]");
1422
 
1423
    }
1424
    else
1425
    {
1426
        # Have a full URL and not a JATS enhanced spec
1427
        # Cannot determine the development branch and the tag
1428
        #
1429
        $urlType = 'url';
1430
        $initialUrl = $opt_spec;
1431
 
1432
        # Extact any peg
1433
        my $peg;
1434
        if ( $opt_spec =~ m~(.*)@(\d+)$~ )
1435
        {
1436
            $opt_spec = $1;
1437
            $peg = $2;
1438
        }
1439
 
1440
        if (  $opt_spec =~ m~(.*)/((tags|branches|trunk)(/|$)(.*))~ )
1441
        {
1442
            Error ("Subversion URL has insufficient items")
1443
                if ( $1 eq '' );
1444
            $srcPathPkg = $1;
1445
            $ttbType = $3;
1446
 
1447
            if ( $ttbType eq 'trunk' ) {
1448
                Error ("Subversion URL must NOT contain items after '$ttbType'")
1449
                    if ( $5 ne '' );
1450
                $devBranch = $2;
1451
                $devBranchPeg = $peg;
1452
 
1453
            } elsif ( $ttbType eq 'tags' ) {
1454
                Error ("Subversion URL must contain items after '$ttbType'")
1455
                    unless ( $5 ne '' );
1456
                $tagLabel = $2;
1457
                $tagPeg = $peg;
1458
 
1459
            } else {
1460
                Error ("Subversion URL must contain items after '$ttbType'")
1461
                    unless ( $5 ne '' );
1462
                $devBranch = $2;
1463
                $devBranchPeg = $peg;
1464
            }
1465
        }
1466
        else
1467
        {
1468
            Error ("Subversion URL does not contain tags or trunk or branches component");
1469
        }
1470
    }
1471
    #debugDumpRefInfo('First Parse');
1472
}
1473
 
1474
#-------------------------------------------------------------------------------
1475
# Function        : debugDumpRefInfo
1476
#
1477
# Description     : Dump the current Ref Information
1478
#
1479
# Inputs          : $text
1480
#
1481
# Returns         : 
1482
#
1483
sub debugDumpRefInfo
1484
{
1485
    Verbose0 ('-' x 40);
1486
    Verbose0 ('debugDumpRefInfo:' , @_ );
1487
    Verbose0 ('ttbType           :', $ttbType);
1488
    Verbose0 ('urlType           :', $urlType);
1489
    Verbose0 ('Base              :', $svnSession->FullPath() ) if $svnSession;
1490
    Verbose0 ('initialUrl        :', $initialUrl);
1491
    Verbose0 ('srcPathPkg        :', $srcPathPkg);
1492
    Verbose0 ('devBranch         :', $devBranch);
1493
    Verbose0 ('devBranchPeg      :', $devBranchPeg);
1494
    Verbose0 ('devBranchHead     :', $devBranchHead);
1495
    Verbose0 ('tagLabel          :', $tagLabel);
1496
    Verbose0 ('tagPeg            :', $tagPeg);
1497
    Verbose0 ('tagLabelDistance  :', $tagLabelDistance);
1498
    Verbose0 ('tagLabelBranch    :', $tagLabelBranch);
1499
    Verbose0 ('tagLabelBranchPeg :', $tagLabelBranchPeg);
1500
}
1501
 
1502
#-------------------------------------------------------------------------------
1503
 
1504
 
1505
#-------------------------------------------------------------------------------
267 dpurdie 1506
#   Documentation
1507
#
1508
 
1509
=pod
1510
 
361 dpurdie 1511
=for htmltoc    GENERAL::Subversion::
1512
 
267 dpurdie 1513
=head1 NAME
1514
 
1515
jats_svnrelease - Build a package given a SubVersion label
1516
 
1517
=head1 SYNOPSIS
1518
 
1519
  jats svnrelease [options] [-label=]label
1520
 
1521
 Options:
1522
    -help              - brief help message
1523
    -help -help        - Detailed help message
1524
    -man               - Full documentation
1525
    -label=xxx         - Subversion label
1526
    -spec=xxx          - Same as -label=xxx
1527
    -path=xxx          - Source Path
1528
    -view=xxx          - Modify the name of the created view
1529
    -build=xxx         - Package Name to build
1530
    -root=xxx          - Root directory for generated view
1531
    -[mk]branch=xxx    - Will create a view with a branch rule
1348 dpurdie 1532
    -tag=xxx           - Compatibility. Not used
267 dpurdie 1533
    -extract           - Extract the view and exit
1534
    -extractfiles      - Extract files, without a view
1348 dpurdie 1535
    -devMode=xxx       - Create Workspace suitable for development.(Tip,Tag,...)
267 dpurdie 1536
    -cache             - Refresh local dpkg_archive cache
361 dpurdie 1537
    -delete[=n]        - Remove any existing view and exit
267 dpurdie 1538
    -debugOnly         - Make only the debug version
1539
    -prodOnly          - Make only the production version
1540
    -[no]dpkg          - Transfer package into dpkg_archive
1541
    -[no]copy          - Transfer pkg directory to the current user directory
1542
    -[no]reuse         - Reuse the view
1543
    -[no]test          - Test package build. Implies nocopy and nodpkg
1544
    -[no]keep          - Keep the view after the build
1545
    -[no]beta          - Release a beta package
1546
    -[no]merge         - Merge packages into dpkg_archive
1547
    -[no]runtests      - Run units tests. Default is runtests
1348 dpurdie 1548
    -[no]prefix        - Suppress user prefix in view name. Default prefix is USER
267 dpurdie 1549
 
1550
=head1 OPTIONS
1551
 
1552
=over 8
1553
 
1554
=item B<-help>
1555
 
1556
Print a brief help message and exits.
1557
 
1558
=item B<-help -help>
1559
 
1560
Print a detailed help message with an explanation for each option.
1561
 
1562
=item B<-man>
1563
 
1564
Prints the manual page and exits.
1565
 
1566
=item B<-label> or B<-spec>
1567
 
1348 dpurdie 1568
The Subversion label to use as the base for the workspace. The utility will
1569
accept the following forms of label identifier, each with an optional 'SVN::' prefix.
267 dpurdie 1570
 
1348 dpurdie 1571
=over 4
267 dpurdie 1572
 
1348 dpurdie 1573
=item Full URL
1574
 
1575
This form is identified by the complete lack of the '::' subfield delimiter. The
1576
URL is used as provided. It is not modified.
1577
 
1578
 Eg: AUPERASVN01/DPG_SWBASE/daf_utils_math/tags/daf_utils_math_3.2.1@12345
1579
 Eg: https://auperasvn01.aupera.erggroup.com/svn/DPG_SWBASE/daf_utils_math/tags/daf_utils_math_3.2.1@12345
1580
 
1581
 
1582
=item SourcePath::Tag
1583
 
1584
The SourcePath component is used to calculate the root of the package directory.
1585
The source path is then caclulated assuming that the 'Tag' exists within a
1586
'/tags' subdirectory of the root of the package.
1587
 
1588
This is the form preferred by Release Manager and the VIX build system.
1589
 
1590
 Eg: AUPERASVN01/DPG_SWBASE/daf_utils_math/trunk::daf_utils_math_3.2.1@12345
1591
 
1592
=item SourcePath::Peg
1593
 
1594
A special case of of the 'SourcePath::Tag' form is invoked if the 'Tag' component
1595
is numeric. It will be treated as a peg of the Base Path.
1596
 
1597
 Eg: AUPERASVN01/DPG_SWBASE/daf_utils_math/trunk::12345
1598
 
1599
=back
1600
 
267 dpurdie 1601
=item B<-view name>
1602
 
1603
Specified an alternate view name and tag to be used. This option does not provide the
1604
full name of the view.
1605
 
361 dpurdie 1606
The view path will be: "${USER}_${NAME}"
267 dpurdie 1607
 
1608
The default "NAME" is the first label specified with the repository and tag removed.
1609
 
1610
If the user provides a view "name" that is prefixed with their user name
1611
('${USER}_'), then the username will be stripped of for internal processing.
1612
This allows a user to provide a view path when deleting a view.
1613
 
1614
=item B<-path=xxx>
1615
 
1616
Specifies the source path to the root of the extracted file tree. This option is
1348 dpurdie 1617
not mandatory and is only used to maintain toolset compatibility with other
267 dpurdie 1618
,similar, tools.
1619
 
1620
If provided, then the Workspace will be created within the named subdirectory
1621
tree within the base of the view.
1622
 
1623
=item B<-build=xxx>
1624
 
1625
This option allows the user to specify the packages to be built and the
1626
order in which the packages are to be built.
1627
This is useful if the extracted view contains multiple build files
1628
 
1629
This option may be used multiple times.
1630
 
1631
There are two forms in which the build target can be specified. It can be
1348 dpurdie 1632
specified as a full package name and version, or as a package name and the
267 dpurdie 1633
project suffix.
1634
 
1635
By default the program will assume that there is only one build file in the
1636
view and will not build if multiple files are present, unless the package to be
1637
built can be resolved.
1638
 
1639
The location mechanism operates for both JATS and ANT build files.
1640
 
1641
Example: -build=jats-api.1.0.0000.cr
1642
 
1643
This will locate the build file that builds version 1.0.0000.cr of the jats-api
1644
package. The version numbers must match exactly.
1645
 
1646
Example: -build=jats-api.cr -build=jats-lib.cr
1647
 
1648
This will located the build files that build the jats_api (cr) package and the
1649
jats-lib (cr) package. The version of the packages will not be considered.
1650
 
1651
=item B<-root=xxx>
1652
 
1653
This option allows the location of the generated view to be specified on the
1348 dpurdie 1654
command line. It overrides the value of GBE_VIEWBASE.
267 dpurdie 1655
 
1348 dpurdie 1656
If the command is invoked within a development sandbox, then the default
267 dpurdie 1657
location will be the root directory of the development sandbox.
1658
 
1659
=item B<-branch=xxx or -mkbranch=xxx>
1660
 
1270 dpurdie 1661
This option will create a workspace associated with a branch within the
1662
repository. This is intended to facilitate the maintenance of existing packages
1663
and the creation of project or development branches in a manner similar to
1664
ClearCase.
267 dpurdie 1665
 
1270 dpurdie 1666
If the named branch exists, then the workspace will be based on the branch and
1667
not on the specified label.
267 dpurdie 1668
 
1270 dpurdie 1669
If the named branch does not exist, then this tool will copy the specified
1670
source version to the branch and then create a workspace based on the branch.
267 dpurdie 1671
 
383 dpurdie 1672
A branch name of TIMESTAMP will be treated in special manner. The name will be
1673
replaced with a unique name based on the users name and the current date time.
1674
 
351 dpurdie 1675
=item B<-tag=text>
1676
 
1677
This option is not used.
1348 dpurdie 1678
It is present to maintain compatibility with the buildtool interface.
351 dpurdie 1679
 
267 dpurdie 1680
=item B<-extract>
1681
 
1682
With this option the view is created and the left in place. The user may then
1683
access the files within the view. The view should not be used for a
1684
production release.
1685
 
1686
=item B<-extractfiles>
1687
 
1688
With this option the utility will create a dynamic view and transfer files from
1348 dpurdie 1689
the view to the user's target. The dynamic view is then removed.
267 dpurdie 1690
 
1691
This command is intended to simplify the process of creating an escrow.
1692
 
1348 dpurdie 1693
=item B<-devMode=mode>
1694
 
1695
This option controls the exact form of the Workspace create. The svnRelease
1696
command supports the following modes (default is working):
1697
 
1698
=over 4
1699
 
1700
=item   Tag or TagPoint
1701
 
1702
The workspace will contain the point on the packages development branch from
1703
which the specified tag was copied.
1704
 
1705
The extraction process will highlight file differences between the specified tag
1706
and the tip. If any differences are found then these will be treated as an error.
1707
 
1708
The user B<should> resolve this error by selecting, in Release Manager, a
1709
version of the package based on the tip of the Development Branch.
1710
 
1711
This is the preferred Development Mode for working on a package as it provides
1712
checks to ensure that the Meta Data held in Release Manager is consistient.
1713
 
1714
=item   Work or Working
1715
 
1716
The workspace will contain the point on the packages development branch from
1717
which the specified tag was copied.
1718
 
1719
The extraction process will highlight file differences between the specified tag
1720
and the tip of the Development Branch. Unlike the 'Tag' Mode, such differences
1721
are not treated as an error.
1722
 
1723
This mode of WorkSpace has several features and constraints:
1724
 
1725
=over 4
1726
 
1727
=item *
1728
 
1729
The build files from the 'tagged' version will be transferred into the
1730
WorkSpace. These will be seen as modified files.
1731
 
1732
=item *
1733
 
1734
This style of workspace can be converted into a 'Tip' style through the use of the
1735
Subversion 'update' command.
1736
 
1737
=item *
1738
 
1739
If there have been changes to the Development Branch, then it not be possible to
1740
'commit' the workspace. It may need to be branched first.
1741
 
1742
=back
1743
 
1744
=item Tip or BranchTip
1745
 
1746
The workspace will contain the 'tip' of the Packages Development Branch.
1747
 
1748
The extraction process will highlight file differences between the specified tag
1749
and the tip.
1750
 
1751
=item Exact
1752
 
1753
The workspace will be directly based on the Tag or URL provided by the user.
1754
 
1755
The resultant workspace may not be suitable for development.
1756
 
1757
The extraction process will highlight file differences between the specified tag
1758
and the tip of any associated Development Branch.
1759
 
1760
=back
1761
 
1762
The four extraction points are shouwn in the following image:
1763
 
1764
     /branches/...    /tags/...
1765
            v            v
1766
            |
1767
        +---+---+
1768
  [Tag] | Work  |    +-------+
1769
        +---+---+----+ Exact |
1770
            |        +-------+
1771
        +---+---+
1772
        |       |
1773
        +---+---+
1774
            |
1775
        +---+---+
1776
        |  Tip  |
1777
        +---+---+
1778
 
267 dpurdie 1779
=item B<-cache>
1780
 
1781
Forces external packages to be placed in the local dpkg_archive cache.
1782
 
1783
The normal operation is to copy the packages, only if they do not already exist
1784
in the local cache. This option may be used to ensure that the local copy is
1785
correct and up to date.
1786
 
361 dpurdie 1787
=item B<-delete[=level]>
267 dpurdie 1788
 
1789
Delete the view used by the program, if it exists. This option may be used to
1790
cleanup after an error.
1791
 
361 dpurdie 1792
The default 'level' is 1.
267 dpurdie 1793
 
361 dpurdie 1794
If the delete level is 1, then ensure that no files are open in the view and
1795
that the users current working directory is not in the view as these will
1796
prevent the view from being deleted.
1797
 
1798
If the delete level is greater than one, then the view will be deleted, even
1799
if there are checkout out files.
1800
 
267 dpurdie 1801
=item B<-debugOnly>
1802
 
1803
Make only the debug version of the package. The default it to create both the
1804
debug and production version of the package. The type of build may be  further
1805
limited by options within the package.
1806
 
1807
=item B<-prodOnly>
1808
 
1809
Make only the production version of the package. The default it to create both the
1810
debug and production version of the package. The type of build may be  further
1811
limited by options within the package.
1812
 
1813
=item B<-[no]dpkg>
1814
 
1815
Copy the generated package into dpkg_archive. This is the default mode of
1816
operation.
1817
 
1818
=item B<-[no]copy>
1819
 
1820
Copy the built "pkg" directory to the users current directory. The entire
1821
"pkg" subdirectory includes the full package named directory for the package
1822
that has been built.
1823
 
1824
=item B<-[no]reuse>
1825
 
1826
This flag allows the view created by the program to be re-used.
1827
 
1828
=over 8
1829
 
361 dpurdie 1830
=item *
267 dpurdie 1831
 
361 dpurdie 1832
The view is not deleted before being populated.
267 dpurdie 1833
 
361 dpurdie 1834
=item *
267 dpurdie 1835
 
361 dpurdie 1836
The view will not be populated if it does exist.
1837
 
1838
=item *
1839
 
1840
The view will not be deleted at the end the process.
1841
 
267 dpurdie 1842
=back
1843
 
1844
This option is useful for debugging a build process.
1845
 
1846
=item B<-[no]test>
1847
 
1848
Test the building of the package. This option implies "nocopy" and "nodpkg".
1849
 
1850
=item B<-[no]keep>
1851
 
361 dpurdie 1852
Keep the workspace after the build. The default option is "nokeep"
267 dpurdie 1853
 
1854
This option is different to the "reuse" in that the view will be deleted, if
1855
it exists, before the build, but will be retained at the completion of the
1856
process. The user may then manually extract the created package.
1857
 
1858
The view may be deleted with the the "delete" option; taking care to ensure that
1859
no files are open in the view and that the users current working directory is
1860
not in the view.
1861
 
1862
=item B<-[no]beta>
1863
 
1864
This option overrides many of the package release tests to allow a beta package
1865
to be released.
1866
 
1867
=item B<-[no]merge>
1868
 
1869
This option will merge packages being built on multiple machines into
1870
dpkg_archive. By default, if a package already exists in the archive it will be
1871
deleted and replaced. With this option the package will be merged. The merge
1872
process does not over write files found in the archive.
1873
 
1874
=item B<-[no]runtests>
1875
 
1876
This option will allow the suppression of the running of the unit tests included
1877
with the component. By default the tests are run. This can be suppressed
1878
without affecting the release process.
1879
 
1880
=back
1881
 
1882
=head1 DESCRIPTION
1883
 
1884
This program is the primary tool for the creation, recreation and release of
1270 dpurdie 1885
packages within the B<VIX> build environment, although the program can perform a
267 dpurdie 1886
number of very useful operations required during normal development and
1887
maintenance.
1888
 
1889
This program will build a system containing one or more inter-related build
1890
files using the JATS build tools.
1891
 
1892
In normal operation the program will:
1893
 
1894
=over 8
1895
 
1896
=item Remove Workspace
1897
 
1898
Remove any existing workspace of the same name. The workspace will not be
1899
removed if it contains checked-out files.
1900
 
1901
The workspace removal may fail if there are any files B<open> within the view or if
1902
any shell has a subdirectory of the view set as a B<current working directory>.
1903
 
1904
=item Create the workspace
1905
 
1906
Create a workspace to contain the files described by the Subversion
1907
label being processed.
1908
 
1909
=item Populate the workspace
1910
 
1911
Loads files into the workspace.
1912
 
1913
I<Note:> If the workspace files are simply being extracted, then this is the end
1914
of the program. The extracted workspace is left in place.
1915
 
1916
=item Sanity Test
1917
 
1918
If the build is being used as a release into dpkg_archive then
1919
various tests are performed to ensure the repeatability of the view and the
1920
build. These tests include:
1921
 
1922
=over 8
1923
 
361 dpurdie 1924
=item   *
267 dpurdie 1925
 
361 dpurdie 1926
The view must be constructed from one label
267 dpurdie 1927
 
361 dpurdie 1928
=item   *
267 dpurdie 1929
 
361 dpurdie 1930
That label must be pegged
267 dpurdie 1931
 
361 dpurdie 1932
=item   *
1933
 
1934
The labelled view must contain exactly one build file
1935
 
1936
=item   *
1937
 
1938
The view cannot have been re-used.
1939
 
267 dpurdie 1940
=back
1941
 
1942
=item Locate build files
1943
 
1944
Locate the build file within the view.
1945
 
1946
It is an error to have multiple build files within the workspace, unless the
1947
B<-build> option is used. By default, only one package will be built.
1948
 
1949
=item Package the results
1950
 
1951
Use JATS to build and make the package.
1952
 
1953
The resultant package may be copied to a numbers of locations. These include
1954
 
1955
=over 8
1956
 
1957
=item 1
1958
 
1959
The master dpkg_archive as an official release. This is the default operation.
1960
 
1961
=item 2
1962
 
1963
The users current directory. The package directory from the built package is
1964
copied locally. The "pkg" directory is copied. This is only performed with the
1965
B<-copy> option.
1966
 
1967
=back
1968
 
1969
=item Delete the workspace
1970
 
1971
Delete the workspace and all related files.
1972
 
1973
The workspace will not be deleted if an error was detected in the build process, or
1974
the "reuse" or "keep" options are present.
1975
 
1976
=back
1977
 
1978
=cut
1979