Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
267 dpurdie 1
########################################################################
2
# Copyright (C) 1998-2008 ERG Limited, All rights reserved
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
55
my $opt_extract;                            # Just create a static view
56
my $opt_extract_files;                      # Just extract files to user - no view
57
my $opt_delete = 0;                         # Just delete the view. 2 to force
58
my @opt_build;                              # build files to use (kludge)
59
my $opt_test;                               # Test the build process - no copy
60
my $opt_cache;                              # Cache external packages
61
my $opt_keep = 0;                           # Keep view if successful
62
my $opt_beta;                               # Create beta release
63
my $opt_merge;                              # Merge release
64
my $opt_path;                               # Path for view spec
65
my $opt_runtests = 1;                       # Run unit tests after build
66
my $opt_branch;                             # Create config spec with branch
67
my $opt_debug_build = 0;                    # Build Debug Only
68
my $opt_prod_build = 0;                     # Build ion Only
69
my $opt_view_root = $ENV{'GBE_VIEWBASE'};   # Root of the view
70
my $opt_prefix = 1;                         # Prefix the view tag with user-name
351 dpurdie 71
my $opt_tag;                                # View tag insert (build or export or user)
341 dpurdie 72
my $bad_label_name = 0;                     # Badly formed label
267 dpurdie 73
 
74
#
75
#   Globals - Provided by the JATS environment
76
#
77
my $USER            = $ENV{'USER'};
78
my $UNIX            = $ENV{'GBE_UNIX'};
79
my $GBE_SANDBOX     = $ENV{'GBE_SANDBOX'};
80
my $GBE_ABT         = $ENV{'GBE_ABT'} || '0';
279 dpurdie 81
my $MACHINENAME     = $ENV{'GBE_HOSTNAME'};
343 dpurdie 82
my $GBE_VIEWBASE    = $ENV{'GBE_VIEWBASE'};   # Root of the view
267 dpurdie 83
 
84
#
85
#   Globals
86
#
343 dpurdie 87
my $VIEWDIR_ROOT;                           # Root of the static view
267 dpurdie 88
my $VIEWDIR;                                # Absolute path to the view
89
my $VIEWPATH;                               # Path relative to clearcase
90
my $user_cwd;
91
my $error = 0;
92
my $label_count = 0;                        # Number of labels to create the view
93
my @label_not_pegged;                       # List of unpegged labels
94
 
95
my $view_prefix     = "${USER}_";
96
 
97
#-------------------------------------------------------------------------------
98
# Function        : Mainline Entry Point
99
#
100
# Description     :
101
#
102
# Inputs          :
103
#
104
 
105
#
106
#   Alter some option defaults if we are creating a view within a sandbox
107
#
108
if ( $GBE_SANDBOX )
109
{
343 dpurdie 110
   $GBE_VIEWBASE = $GBE_SANDBOX;
267 dpurdie 111
   $opt_prefix = 0;
112
}
113
 
114
#
115
#   Parse the user options
116
#
117
my $result = GetOptions (
118
                "help:+"        => \$opt_help,              # flag, multiple use allowed
119
                "manual:3"      => \$opt_help,              # flag
120
                "v|verbose:+"     => \$opt_verbose,           # flag, multiple use allowed
121
                "label=s"       => \@opt_spec,              # Array of build specs
122
                "view=s"        => \$opt_viewname,          # String
123
                "dpkg!"         => \$opt_dpkg,              # [no]flag
124
                "copy!"         => \$opt_copy,              # [no]flag
125
                "reuse!"        => \$opt_reuse,             # [no]flag
126
                "extract"       => \$opt_extract,           # flag
127
                "extractfiles"  => \$opt_extract_files,     # flag
128
                "delete:+"      => \$opt_delete,            # flag
129
                "build=s"       => \@opt_build,             # An array of build
130
                "test!"         => \$opt_test,              # [no]flag
131
                "cache"         => \$opt_cache,             # flag
132
                "keep!"         => \$opt_keep,              # [no]flag
133
                "beta!"         => \$opt_beta,              # [no]flag
134
                "merge"         => \$opt_merge,             # [no]flag
135
                "path=s"        => \$opt_path,              # string
136
                "runtests!"     => \$opt_runtests,          # [no]flag
137
                "branch=s"      => \$opt_branch,            # String
138
                "mkbranch=s"    => \$opt_branch,            # String
139
                "prodOnly"      => \$opt_prod_build,        # flag
140
                "debugOnly"     => \$opt_debug_build,       # flag
343 dpurdie 141
                "root=s"        => \$GBE_VIEWBASE,          # string
267 dpurdie 142
                "prefix!"       => \$opt_prefix,            # flag
351 dpurdie 143
                "tag=s"         => \$opt_tag,               # string
267 dpurdie 144
                );
145
 
146
                #
147
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
148
                #
149
 
150
#
151
#   Process help and manual options
152
#
153
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
154
pod2usage(-verbose => 1)  if ($opt_help == 2 );
155
pod2usage(-verbose => 2)  if ($opt_help > 2 );
156
 
157
InitFileUtils();
158
 
159
#
160
#   Configure the error reporting process now that we have the user options
161
#
162
ErrorConfig( 'name'    => 'SVNRELEASE',
163
             'verbose' => $opt_verbose );
164
 
165
#
166
#   Validate user options
167
#   Use either -label or one command line argument
168
#
169
Error ("Unexpected command line arguments present.","Cannot mix -label and command line label" )
170
    if ( $#opt_spec >= 0 && $#ARGV >= 0);
171
 
172
push @opt_spec, @ARGV;
173
 
174
unless(  @opt_spec  )
175
{
176
    Error ("Need a view or a label. -help for options") if ( $opt_delete  && ! $opt_viewname );
383 dpurdie 177
    Error ("Need a label or URL. -help for options") unless $opt_delete;
267 dpurdie 178
}
179
 
180
#
181
#   Convert label with embedded VCS information into a 'normal' form.
182
#   Form:
183
#       SVN::<URL>
184
#
185
foreach ( @opt_spec )
186
{
187
    s~^SVN::~~;
188
    Error ("Label contains invalid Version Control Identifier: $_")
189
        if ( m~^(.+)::.+~ );
190
    Verbose ("Clean URL: $_");
191
}
192
 
193
#
194
#   Limit the user to ONE label/tag/
195
#   Reason: Under Subversion its not possible to 'pinch' files from another
196
#           package. Don't need to create a workspace with multiple labels
197
#
198
#           It was a bad practice under clearcase
199
#
200
#
201
if ( $#opt_spec >= 1 )
202
{
203
    Error ("Multiple labels not supported",
204
           "Use one label to describe a package" );
205
}
206
 
207
#
383 dpurdie 208
#   Check branch and tags names
209
#
210
if ( $opt_branch )
211
{
212
#    Error ("Branch Name cannot start with '-'") if ( $opt_branch =~ m/^-/ );
213
    $opt_branch = SvnIsaSimpleLabel($opt_branch);
214
}
215
 
216
#
267 dpurdie 217
#   User has specified both debug and production
218
#   Then set both to 0 : ie default
219
#
220
if ( $opt_debug_build + $opt_prod_build > 1 )
221
{
222
    $opt_debug_build = 0;
223
    $opt_prod_build = 0;
224
}
225
 
226
#
227
#   User has requested test mode
228
#       - Don't copy
229
#       - Don't packgae
230
#
231
if ( $opt_test )
232
{
233
    $opt_dpkg = 0;
234
    $opt_copy = 0;
235
}
236
 
237
#
238
#   Determine the machine type
239
#
240
Verbose ("Machine Type: UNIX=$UNIX");
241
 
242
Error ("Machine Name not determined")
243
    unless ( $MACHINENAME );
244
$user_cwd = getcwd;
245
 
246
Error ("USER name not determined" )
247
    unless ( $USER );
248
 
343 dpurdie 249
 
267 dpurdie 250
#
343 dpurdie 251
#   Clean up the view root directory
267 dpurdie 252
#
343 dpurdie 253
$VIEWDIR_ROOT = Realpath($GBE_VIEWBASE) || $GBE_VIEWBASE;
267 dpurdie 254
 
255
Verbose ("Viewpath: $VIEWDIR_ROOT");
256
Error ("Cannot locate view root directory: $VIEWDIR_ROOT" ) unless (-d $VIEWDIR_ROOT);
257
 
258
#
259
#   Remove any user name from the front of the view name
260
#   Simplifies the deletion process as the user can provide
261
#   the directory name
262
#
263
$view_prefix = "" unless ( $opt_prefix );
264
 
265
#
266
#   Create a class to describe the complete SVN label
267
#   This will parse the label and create a number of nice elements
268
#
361 dpurdie 269
my $svn_label = NewSessionByUrl ( $opt_spec[0], 1 );
267 dpurdie 270
 
271
#
272
#   Setup user specified workspace
273
#   Include the user name to ensure that the view name is unique-ish
274
#   Keep the name as short as possible as some compilers display a fixed
275
#   length filename in error messages and this name is part of the path
276
#
277
#   Base the viewname on the view label. This will simplify the creation
278
#   of multiple views and reduce the risk of unexpected deletion
279
#
280
if ( $opt_viewname )
281
{
282
    Error ("View Name contains invalid characters" )
383 dpurdie 283
        unless ( $opt_viewname =~ m~^[0-9a-z]([-.:0-9a-z_]*[0-9a-z])?$~i )
267 dpurdie 284
}
285
else
286
{
287
    #
288
    #   Create a view name based on the provide 'label'
383 dpurdie 289
    #   Unless creating a branch. Branch name will be appended later
267 dpurdie 290
    #
291
    if ( $svn_label->Type )
292
    {
341 dpurdie 293
        $opt_viewname = $svn_label->Path;
383 dpurdie 294
        $opt_viewname .= '_' . ($svn_label->Version || 'trunk') unless $opt_branch;
363 dpurdie 295
 
296
        #
297
        #   Tags and Branches 'should' include the package name
298
        #   This will lead to a duplication of the package name
299
        #   ie: aaaaa/package/tags/package_version
300
        #   Attempt to remove these
301
        #
302
        if ( $opt_viewname =~ s~[_/]([\-.:0-9a-zA-Z]+)_\1_~_$1_~ )
303
        {
304
            Verbose ("Removed duplicate package name: $1 from $opt_viewname");
305
        }
267 dpurdie 306
    }
307
    else
308
    {
309
        $opt_viewname = $svn_label->Path;
310
        $bad_label_name = 1;
311
    }
312
 
313
    #
314
    #   If creating a branch, then insert the branch name
315
    #   into the workspace name
316
    #
317
    $opt_viewname .= '_' . $opt_branch if ( $opt_branch );
318
 
319
    #
351 dpurdie 320
    #   Create a simple dir name
321
    #       Remove path sep characters and replace with _
322
    #       Remove Peg marker (@) as this breaks svn
323
    #       Replace multiple _ with a single _
361 dpurdie 324
    #       Remove trailing _ - caused by URL with a trailing /
267 dpurdie 325
    #
351 dpurdie 326
    $opt_viewname =~ s~[^\-.:0-9a-zA-Z_]~_~g;
327
    $opt_viewname =~ tr~_~_~s;
361 dpurdie 328
    $opt_viewname =~ s~_+$~~;
267 dpurdie 329
}
330
$opt_viewname =~ s~^$view_prefix~~ if (defined($opt_viewname) && $view_prefix && $opt_delete );
331
 
332
#
333
#   Create a clearcase view to be used for the view
334
#
335
$VIEWPATH = "$view_prefix$opt_viewname";
336
$VIEWDIR = "$VIEWDIR_ROOT/$VIEWPATH";
299 dpurdie 337
$VIEWDIR =~ tr~\\/~/~s;
267 dpurdie 338
Verbose( "Hostname: $MACHINENAME" );
339
Verbose( "Viewpath: $VIEWPATH" );
340
Verbose( "Viewdir : $VIEWDIR" );
341
 
342
#
343
#   If the user has specified a "source path", then we must ensure that it is
344
#   valid. It will be used to create the WorkSpace
345
#
346
#   Ensure that the path is a defined variable. If used prepend a / to simplify
347
#   concatenation.
348
#
349
Verbose("Validate Source Path");
350
if ( $opt_path )
351
{
352
    $opt_path =~ tr~\\/~/~s;
353
    $opt_path =~ s~/$~~;
354
    $opt_path =~ s~^/~~;
355
 
356
    Error( "Source Path has drive specifier" ) if ( $opt_path =~ m~^[A-Za-z]\:~ );
357
    $opt_path = '/'.$opt_path ;
358
}
359
else
360
{
361
    $opt_path = '';
362
}
363
 
364
#
365
#   If the view currently exists then it will be deleted if allowed
366
#
367
delete_view()
299 dpurdie 368
    unless ( $opt_reuse );
267 dpurdie 369
 
370
#
371
#   If the user is simply deleting the view then all has been done
372
#
373
exit 0
374
    if ( $opt_delete );
375
 
376
 
377
#
378
#   Ensure that the label is present within the specified VOB
379
#
380
Verbose("Ensure Labels can be found in a Repository");
381
Verbose ("Testing label: ". $svn_label->Full );
382
$label_count++;
383
 
384
$svn_label->SvnValidateTarget (
385
                    'cmd'    => 'SvnRelease',
386
                    'target' => $svn_label->Full,
387
                    'require' => 1,
388
                    );
389
#
390
#   Test for a pegged label
391
#
392
push @label_not_pegged, $svn_label->Full
393
    unless ( $svn_label->Peg );
394
 
395
#
396
#   If we are only extracting files then ...
397
#
398
if ( $opt_extract_files )
399
{
400
    extract_files_from_view();
401
    exit (0);
402
}
403
 
404
#
405
#   Create a new workspace
406
#
407
if (! -d $VIEWDIR || ! $opt_reuse )
408
{
409
    Message( "Create the workspace" . ($GBE_SANDBOX ? " in a SANDBOX" : ""));
410
 
411
    my $view_tag = $svn_label->Full;
412
    #
1270 dpurdie 413
    #   If a branch is required ...
414
 
415
    #   If the branch exists, then use it
416
    #   If the branch does not exist, then create it
417
    #       Copy the source to the branch
418
    #       Check it out
267 dpurdie 419
    #
420
    if ( $opt_branch )
421
    {
1270 dpurdie 422
        Verbose ("Test branch existence");
267 dpurdie 423
        #
424
        #   Create the name of the branch
425
        #   Will be based on the current package
426
        #
427
        my $branch = $svn_label->BranchName($opt_branch, 'branches' );
1270 dpurdie 428
        my $rv = $svn_label->SvnValidateTarget (
429
                        'cmd'    => 'SvnRelease',
430
                        'target' => $branch,
431
                        'test' => 1,
432
                        );
267 dpurdie 433
 
1270 dpurdie 434
        if ( $rv )
435
        {
436
            #
437
            #   The named branch exists
438
            #   Use it in place of the users named version
439
            #   This mimics the clearcase behaviour
440
            #   Assumes that it is a project branch
441
            #
442
            Warning ("Specified branch \"$opt_branch\" exists",
443
                     "It will be used as the base for this Workspace",
444
                     "The workspace will conatin the current HEAD of this branch");
445
 
446
            #
447
            #   Setup the base of the Workspace
448
            #   It will be based on the branch
449
            #
450
            $view_tag = $branch;
451
        }
452
        else
453
        {
454
            #
455
            #   Branch does not exist
456
            #   Create it be copying the base view
457
            #
458
            $view_tag = $svn_label->SvnCopy (
267 dpurdie 459
                            'old' => $view_tag,
460
                            'new' => $branch,
461
                            'comment' => 'Created by Jats SvnRelease branch request',
462
                            'replace' => 0 );
463
 
1270 dpurdie 464
            $view_tag = SvnPath2Url($view_tag);
465
 
466
        }
267 dpurdie 467
    }
468
 
1270 dpurdie 469
    #
470
    #   Create the workspace
471
    #
267 dpurdie 472
    $svn_label->SvnCo ( $view_tag, $VIEWDIR . $opt_path );
473
    Error ("Cannot locate the created Workspace")
474
        unless ( -d $VIEWDIR . $opt_path);
475
 
476
    #
477
    #   Create a local package archive
478
    #   May be needed for multipackage builds and it will prevent JATS from
479
    #   finding any outside the view
480
    #
481
    mkdir ( $VIEWDIR . '/local_dpkg_archive')
482
        unless ($GBE_SANDBOX);
483
}
484
 
285 dpurdie 485
#   Place a tag-file in the user-specified source path
486
#   This will be used by the build-tool to locate the 'source-path' of the
487
#   view, primarily for determining metrics.
267 dpurdie 488
#
285 dpurdie 489
#   Calculate where the dynmaic view will be
490
#   This differ between UNIX/WINDOWS
491
#
351 dpurdie 492
if ( $GBE_ABT)
285 dpurdie 493
{
494
    Message( "Create Build tagfile");
287 dpurdie 495
    my $cpath = $VIEWDIR . $opt_path;
285 dpurdie 496
    if ( -d $cpath )
497
    {
498
        TouchFile ( "$cpath/.jats.packageroot" );
499
    }
500
}
501
 
502
#
267 dpurdie 503
#   Locate the JATS build files within the populated view
504
#
505
chdir ($VIEWDIR) or Error( "Cannot chdir to $VIEWDIR");
506
Message( "Locating build files");
507
 
508
my $bscanner = BuildFileScanner( $VIEWDIR, 'build.pl', '--LocateAll' );
509
$bscanner->scan();
510
my @build_list = $bscanner->getInfo();
511
foreach my $be ( @build_list )
512
{
513
    Message( DisplayPath ("Build file: $be->{dir} Name: $be->{file}"));
514
}
515
 
516
#
517
#   If we are extracting the view then we are done
518
#   Display useful information for the user
519
#
520
if ( $opt_extract )
521
{
522
    Message  DisplayPath "View in: $VIEWDIR";
523
    Warning ("No build files found" )   if ( $#build_list < 0 );
524
    Warning( "Multiple build files found" )if ( $#build_list > 0 );
525
    Message ("Not all labels are pegged") if ( @label_not_pegged  );
526
    Message ("All labels are pegged") unless ( @label_not_pegged  );
527
    Message ("Badly formed label name" ) if ( $bad_label_name );
528
    Message ("Development Sandbox") if ( $GBE_SANDBOX );
529
 
530
    exit 0;
531
}
532
 
533
Error ("No build files found")  if ( $#build_list < 0 );
534
 
535
#
536
#   Determine the list of builds to perform
537
#   Ensure that the user-requested build files are present
538
#
539
#   The user specifies the build file, via the mangled package name
540
#   This is package_name . project extension (daf_utils.cr)
541
#
542
if ( $#opt_build  >= 0)
543
{
544
    Verbose( "Check and locate the build files");
545
    @build_list = ();
546
    foreach my $bentry ( @opt_build )
547
    {
548
        if ($bscanner->match( $bentry) )
549
        {
550
            UniquePush (\@build_list, $bscanner->getMatchList() );
551
            Verbose ("Found: $bentry");
552
        }
553
        else
554
        {
555
            Error ("Cannot locate requested build files for: $bentry")
556
        }
557
    }
558
}
559
 
560
#
561
#   Sanity test if we will transfer the generated package to dpkg_archive
562
#   There are some limits
563
#       1) Must have built from one label
564
#       2) That label must be locked
565
#       3) Only one build file
566
#       4) The view must not have been reused
567
#       5) The view has a branch rule
568
#       6) Cannot release from a sandbox
569
#
570
my @elist;
571
push @elist, "Package built from multiple labels" unless ( $label_count == 1 );
572
push @elist, "Package built from an unpegged label" if ( @label_not_pegged  );
573
push @elist, "Package built with multiple build files" if ( scalar @build_list > 1 );
574
push @elist, "Package from a reused view" if ( $opt_reuse && ! $opt_beta );
575
push @elist, "Package from a development sandbox" if ( $GBE_SANDBOX );
576
push @elist, "View contains a branch" if ( $opt_branch );
577
push @elist, "User has specified build files" if ( $#opt_build > 0 );
578
push @elist, "Badly formed label name" if ( $bad_label_name );
579
 
580
if ( @elist )
581
{
582
    Warning ("Cannot officially release the package.", @elist);
583
    Error ("Build terminated as it cannot be released") if ($opt_dpkg && ! $opt_beta);
584
}
585
Warning ("Beta Release") if $opt_beta;
586
 
587
#
588
#   Process each of the build files in the specified order
589
#
590
foreach my $be (@build_list)
591
{
592
 
593
    #
594
    #   We need to change to the build directory
595
    #   Moreover we need the local name of the build directory.
596
    #   Windows does not handle a UNC pathname to well (at all)
597
    #
598
    my $build_dir = $be->{dir};
599
    chdir ("$build_dir") or Error( "Cannot chdir to build directory: $build_dir");
600
 
601
    if ( $be->{file} =~ m/^build.pl$/ )
602
    {
603
        Message ("Using JATS: $build_dir");
604
        #
605
        #   Invoke JATS to build the package and make the package
606
        #
607
        my @build_args = qw(--expert --cache);
608
        push @build_args, '--cache' if $opt_cache;
609
 
610
        my $make_type = 'all';
611
        $make_type = 'all_prod'  if ( $opt_prod_build );
612
        $make_type = 'all_debug' if ( $opt_debug_build );
613
 
614
 
615
        JatsCmd('build', @build_args)               and Error("Package did not build");
616
        JatsCmd('make', $make_type, 'NODEPEND=1')   and Error("Package did not make");
617
        JatsCmd('install');
618
 
619
        if ( $opt_runtests )
620
        {
321 dpurdie 621
            JatsCmd('make', 'run_unit_tests')      and Error("Tests did not run correctly");
267 dpurdie 622
        }
623
    }
624
    else
625
    {
626
        #
627
        #   Ant build files
628
        #
629
        my $pname =  $be->{file};
630
        Message ("Using ANT: $build_dir, $pname");
631
        $pname =~ s~depends.xml$~.xml~;
632
        copy($be->{file}, "auto.xml");
633
        JatsCmd('-buildfile', $pname, 'ant', 'build')        and Error("Package did not build");
634
        JatsCmd('-buildfile', $pname, 'ant', 'make_package') and Error("Package did not make_package");
635
    }
636
}
637
 
638
#
639
#   Copy the generated packages
640
#       1) dpkg_archive
641
#       2) Users local directory
642
#
643
foreach my $be (@build_list)
644
{
645
    my $build_dir = $be->{dir};
646
    chdir ("$build_dir") or Error( "Cannot chdir to build directory: $build_dir");
647
    if ( $opt_dpkg )
648
    {
649
        Message ("Using: $build_dir");
279 dpurdie 650
        my @create_opts = "-o";
651
        push @create_opts ,"-m" if ( $opt_merge );
652
        JatsCmd('-here', 'create_dpkg', @create_opts, '-pname', $be->{name}, '-pversion', $be->{version}) and $error++;
267 dpurdie 653
    }
654
 
655
    if ( $opt_copy )
656
    {
657
        Message ("Copy package to $user_cwd");
658
        copy_directory( 'pkg', $user_cwd, '' );
659
    }
660
 
661
    #
662
    #   Test structure of the package
663
    #   Ensure that it has a descpkg file
664
    #   Validate the package name and version
665
    #   More important for ANT projects than JATS as JATS has a sanity test
666
    #
667
    if ( $opt_test )
668
    {
669
        JatsCmd('-here', 'create_dpkg', '-test', '-pname', $be->{name}, '-pversion', $be->{version}) and $error++;
670
    }
671
 
672
}
673
Error ("Package not transferred")
674
    if ( $error );
675
 
363 dpurdie 676
chdir ($user_cwd) or Error( "Cannot chdir to $$user_cwd");
267 dpurdie 677
 
678
#
679
#   Delete the view
680
#
681
if ( ! $opt_reuse && ! $error && ! $opt_keep )
682
{
683
    delete_view();
684
}
685
else
686
{
687
    Message( "View left in: $VIEWDIR" );
688
}
689
 
690
Message ("End program");
691
exit 0;
692
 
693
#-------------------------------------------------------------------------------
694
# Function        : delete_view
695
#
696
# Description     : Delete a view
697
#
698
# Inputs          : None
699
#                   $VIEWDIR - path of the view
700
#
701
# Returns         :
702
#
703
sub delete_view
704
{
705
    my $cofound = 0;
706
    my $uuid;
707
    #
299 dpurdie 708
    #   Simple delete
267 dpurdie 709
    #
299 dpurdie 710
    if ( $opt_extract_files )
267 dpurdie 711
    {
299 dpurdie 712
        if ( -d $VIEWDIR )
713
        {
714
            Message("Remove extracted files: $VIEWDIR");
361 dpurdie 715
            RmDirTree( $VIEWDIR );
299 dpurdie 716
        }
717
    }
718
    else
719
    {
267 dpurdie 720
        #
299 dpurdie 721
        #   If the view physically exists then attempt to phyically remove it
267 dpurdie 722
        #
299 dpurdie 723
        if ( -d $VIEWDIR )
724
        {
725
            #
726
            #   Determine if there are any checked out files in the view
727
            #
728
            Message("Remove the view: $VIEWDIR");
729
            Verbose("Look for checked out files");
267 dpurdie 730
 
731
 
299 dpurdie 732
            SvnRmView ('path'     => $VIEWDIR . $opt_path,
733
                       'force'    => $opt_delete > 1,
734
                       'modified' => [ 'local_dpkg_archive' ] );
735
        }
361 dpurdie 736
        Error ("View was not deleted. Will Delete view directory")
299 dpurdie 737
            if ( -d $VIEWDIR . $opt_path );
361 dpurdie 738
        RmDirTree( $VIEWDIR ) if $opt_path;
267 dpurdie 739
    }
299 dpurdie 740
 
267 dpurdie 741
    Error ("View was not deleted")
299 dpurdie 742
        if ( -d $VIEWDIR );
267 dpurdie 743
}
744
 
745
#-------------------------------------------------------------------------------
746
# Function        : copy_directory
747
#
748
# Description     : Copy a directory tree
749
#
750
# Inputs          : Source directory
751
#                   Target directory
752
#                   Strip
753
#
754
#                   Should be full pathnames
755
#
756
# Returns         :
757
#
758
my $copy_error;
759
my $copy_count;
760
sub copy_directory
761
{
762
    our ($src_dir, $dest_dir, $strip) = @_;
763
    our $slength = length ($strip);
764
 
765
    #
766
    #   Prevent File::Find from generating warnings
767
    #
768
    no warnings 'File::Find';
769
 
770
 
771
    #
772
    #   Helper routine to copy files
773
    #
774
    sub copy_file_wanted
775
    {
776
        #
777
        #   Do not copy directories
778
        #   Just make the directory entry. May result in empty directories
779
        #
780
        if ( -d $_ )
781
        {
782
            my $tdir = "$dest_dir/" . substr( $File::Find::dir, $slength);
783
            $tdir .= "/$_";
784
            File::Path::mkpath( $tdir )
785
                unless ( -d $tdir);
786
            return;
787
        }
788
 
789
        #
790
        #   When used to copy file from within a clearcase dynamic view the
791
        #   files may not actually exist. This will generate an error later
792
        #   so check for existance of file file now.
793
        #
794
        return unless ( -e $_ );
795
 
796
        #
797
        #   Have been chdir'ed to the source directory
798
        #   when invoked
799
        #
800
        my $tdir = "$dest_dir/" . substr( $File::Find::dir, $slength);
801
        my $tfile = "$tdir/$_";
802
        my $sfile = "$File::Find::dir/$_";
803
        Verbose ("Copy: $sfile -> $tfile");
804
 
805
        File::Path::mkpath( $tdir )
806
            unless ( -d $tdir);
807
 
808
        unlink ( $tfile )
809
            if ( -f $tfile );
810
 
811
        if( ! File::Copy::copy ( $_ , $tfile ) )
812
        {
813
            $copy_error++;
814
            Message "Error copying $sfile";
815
        }
816
        else
817
        {
818
            my $perm = (stat $_)[2] & 07777;
819
            chmod($perm, $tfile);
820
 
821
            $copy_count++;
822
        }
823
    }
824
 
825
    #
826
    #   Locate all files to copy
827
    #
828
    $copy_error = 0;
829
    $copy_count = 0;
830
    File::Find::find ( \&copy_file_wanted, $src_dir );
831
    return $copy_error;
832
}
833
 
834
#-------------------------------------------------------------------------------
835
# Function        : count_files
836
#
837
# Description     : Count files in a workspace
838
#                   Ignore .svn stuff
839
#
840
# Inputs          : Source directory
841
#
842
# Returns         :
843
#
844
sub count_files
845
{
846
    my ($src_dir) = @_;
847
 
848
    #
849
    #   Prevent File::Find from generating warnings
850
    #
851
    no warnings 'File::Find';
852
 
853
 
854
    #
855
    #   Helper routine to copy files
856
    #
857
    sub count_file_wanted
858
    {
859
        #
860
        #   Do not count dirs, only files
861
        #
862
        return if ( -d $_ );
863
        $copy_count++;
864
    }
865
 
866
    #
867
    #   Locate all files
868
    #
869
    $copy_count = 0;
870
    File::Find::find ( \&count_file_wanted, $src_dir );
871
}
872
 
873
 
874
#-------------------------------------------------------------------------------
875
# Function        : extract_files_from_view
876
#
877
# Description     : This function will
878
#                       Create a dynamic view
879
#                       Copy all the files out of the view
880
#                       Delete the view
881
#
882
#                   Its used in the creation of escrow directories
883
#
884
# Inputs          : None
885
#                   All done via globals
886
#
887
# Returns         : 
888
#
889
sub extract_files_from_view
890
{
891
    #
892
    #   Determine the target directory for the extracted files
893
    #       Delete the output subdir
894
    #       Create the config spec in that directory
895
    #
896
    Verbose("Extracting files into $VIEWDIR");
897
    if ( -d $VIEWDIR )
898
    {
899
        Verbose "Delete Directory: $VIEWDIR\n";
361 dpurdie 900
        RmDirTree( $VIEWDIR );
267 dpurdie 901
    }
902
 
1270 dpurdie 903
    $svn_label->SvnCo ( $svn_label->Full, $VIEWDIR, '--Export', '--NoPrint' );
267 dpurdie 904
 
905
    #
906
    #   Count this files in the view
907
    #   Done so that its clear when we have a empty workspace
908
    #
909
    Verbose ("Examine View contents");
910
    count_files ( $VIEWDIR );
911
    Message ("View files in: $VIEWDIR, Files: $copy_count" );
912
 
913
}
914
 
915
#-------------------------------------------------------------------------------
916
 
917
 
918
#-------------------------------------------------------------------------------
919
#   Documentation
920
#
921
 
922
=pod
923
 
361 dpurdie 924
=for htmltoc    GENERAL::Subversion::
925
 
267 dpurdie 926
=head1 NAME
927
 
928
jats_svnrelease - Build a package given a SubVersion label
929
 
930
=head1 SYNOPSIS
931
 
932
  jats svnrelease [options] [-label=]label
933
 
934
 Options:
935
    -help              - brief help message
936
    -help -help        - Detailed help message
937
    -man               - Full documentation
938
    -label=xxx         - Subversion label
939
    -spec=xxx          - Same as -label=xxx
940
    -path=xxx          - Source Path
941
    -view=xxx          - Modify the name of the created view
942
    -build=xxx         - Package Name to build
943
    -root=xxx          - Root directory for generated view
944
    -[mk]branch=xxx    - Will create a view with a branch rule
351 dpurdie 945
    -tag=xxx           - Compatability. Not used
267 dpurdie 946
    -extract           - Extract the view and exit
947
    -extractfiles      - Extract files, without a view
948
    -cache             - Refresh local dpkg_archive cache
361 dpurdie 949
    -delete[=n]        - Remove any existing view and exit
267 dpurdie 950
    -debugOnly         - Make only the debug version
951
    -prodOnly          - Make only the production version
952
    -[no]dpkg          - Transfer package into dpkg_archive
953
    -[no]copy          - Transfer pkg directory to the current user directory
954
    -[no]reuse         - Reuse the view
955
    -[no]test          - Test package build. Implies nocopy and nodpkg
956
    -[no]keep          - Keep the view after the build
957
    -[no]beta          - Release a beta package
958
    -[no]merge         - Merge packages into dpkg_archive
959
    -[no]runtests      - Run units tests. Default is runtests
960
    -[no]prefix        - Supress user prefix in view name. Default prefix is USER
961
 
962
=head1 OPTIONS
963
 
964
=over 8
965
 
966
=item B<-help>
967
 
968
Print a brief help message and exits.
969
 
970
=item B<-help -help>
971
 
972
Print a detailed help message with an explanation for each option.
973
 
974
=item B<-man>
975
 
976
Prints the manual page and exits.
977
 
978
=item B<-label> or B<-spec>
979
 
980
The Subversion label to use as the base for the workspace.
981
 
982
Eg: DPG_SWBASE/daf_utils_math/tags/3.2.1@12345
983
 
984
=item B<-view name>
985
 
986
Specified an alternate view name and tag to be used. This option does not provide the
987
full name of the view.
988
 
361 dpurdie 989
The view path will be: "${USER}_${NAME}"
267 dpurdie 990
 
991
The default "NAME" is the first label specified with the repository and tag removed.
992
 
993
If the user provides a view "name" that is prefixed with their user name
994
('${USER}_'), then the username will be stripped of for internal processing.
995
This allows a user to provide a view path when deleting a view.
996
 
997
=item B<-path=xxx>
998
 
999
Specifies the source path to the root of the extracted file tree. This option is
1000
not mandatory and is only used to mnaintain toolset compatability woth other
1001
,similar, tools.
1002
 
1003
If provided, then the Workspace will be created within the named subdirectory
1004
tree within the base of the view.
1005
 
1006
=item B<-build=xxx>
1007
 
1008
This option allows the user to specify the packages to be built and the
1009
order in which the packages are to be built.
1010
This is useful if the extracted view contains multiple build files
1011
 
1012
This option may be used multiple times.
1013
 
1014
There are two forms in which the build target can be specified. It can be
1015
specified as a full package name and vesrion, or as a package name and the
1016
project suffix.
1017
 
1018
By default the program will assume that there is only one build file in the
1019
view and will not build if multiple files are present, unless the package to be
1020
built can be resolved.
1021
 
1022
The location mechanism operates for both JATS and ANT build files.
1023
 
1024
Example: -build=jats-api.1.0.0000.cr
1025
 
1026
This will locate the build file that builds version 1.0.0000.cr of the jats-api
1027
package. The version numbers must match exactly.
1028
 
1029
Example: -build=jats-api.cr -build=jats-lib.cr
1030
 
1031
This will located the build files that build the jats_api (cr) package and the
1032
jats-lib (cr) package. The version of the packages will not be considered.
1033
 
1034
=item B<-root=xxx>
1035
 
1036
This option allows the location of the generated view to be specified on the
343 dpurdie 1037
command line. It overides the value of GBE_VIEWBASE.
267 dpurdie 1038
 
1039
If the comamnd is invoked within a development sandbox, then the default
1040
location will be the root directory of the development sandbox.
1041
 
1042
=item B<-branch=xxx or -mkbranch=xxx>
1043
 
1270 dpurdie 1044
This option will create a workspace associated with a branch within the
1045
repository. This is intended to facilitate the maintenance of existing packages
1046
and the creation of project or development branches in a manner similar to
1047
ClearCase.
267 dpurdie 1048
 
1270 dpurdie 1049
If the named branch exists, then the workspace will be based on the branch and
1050
not on the specified label.
267 dpurdie 1051
 
1270 dpurdie 1052
If the named branch does not exist, then this tool will copy the specified
1053
source version to the branch and then create a workspace based on the branch.
267 dpurdie 1054
 
383 dpurdie 1055
A branch name of TIMESTAMP will be treated in special manner. The name will be
1056
replaced with a unique name based on the users name and the current date time.
1057
 
351 dpurdie 1058
=item B<-tag=text>
1059
 
1060
This option is not used.
1061
It is present to maintain compatability with the buildtool interface.
1062
 
267 dpurdie 1063
=item B<-extract>
1064
 
1065
With this option the view is created and the left in place. The user may then
1066
access the files within the view. The view should not be used for a
1067
production release.
1068
 
1069
=item B<-extractfiles>
1070
 
1071
With this option the utility will create a dynamic view and transfer files from
1072
the view to the user's tararget. The dynamic view is then removed.
1073
 
1074
This command is intended to simplify the process of creating an escrow.
1075
 
1076
=item B<-cache>
1077
 
1078
Forces external packages to be placed in the local dpkg_archive cache.
1079
 
1080
The normal operation is to copy the packages, only if they do not already exist
1081
in the local cache. This option may be used to ensure that the local copy is
1082
correct and up to date.
1083
 
361 dpurdie 1084
=item B<-delete[=level]>
267 dpurdie 1085
 
1086
Delete the view used by the program, if it exists. This option may be used to
1087
cleanup after an error.
1088
 
361 dpurdie 1089
The default 'level' is 1.
267 dpurdie 1090
 
361 dpurdie 1091
If the delete level is 1, then ensure that no files are open in the view and
1092
that the users current working directory is not in the view as these will
1093
prevent the view from being deleted.
1094
 
1095
If the delete level is greater than one, then the view will be deleted, even
1096
if there are checkout out files.
1097
 
267 dpurdie 1098
=item B<-debugOnly>
1099
 
1100
Make only the debug version of the package. The default it to create both the
1101
debug and production version of the package. The type of build may be  further
1102
limited by options within the package.
1103
 
1104
=item B<-prodOnly>
1105
 
1106
Make only the production version of the package. The default it to create both the
1107
debug and production version of the package. The type of build may be  further
1108
limited by options within the package.
1109
 
1110
=item B<-[no]dpkg>
1111
 
1112
Copy the generated package into dpkg_archive. This is the default mode of
1113
operation.
1114
 
1115
=item B<-[no]copy>
1116
 
1117
Copy the built "pkg" directory to the users current directory. The entire
1118
"pkg" subdirectory includes the full package named directory for the package
1119
that has been built.
1120
 
1121
=item B<-[no]reuse>
1122
 
1123
This flag allows the view created by the program to be re-used.
1124
 
1125
=over 8
1126
 
361 dpurdie 1127
=item *
267 dpurdie 1128
 
361 dpurdie 1129
The view is not deleted before being populated.
267 dpurdie 1130
 
361 dpurdie 1131
=item *
267 dpurdie 1132
 
361 dpurdie 1133
The view will not be populated if it does exist.
1134
 
1135
=item *
1136
 
1137
The view will not be deleted at the end the process.
1138
 
267 dpurdie 1139
=back
1140
 
1141
This option is useful for debugging a build process.
1142
 
1143
=item B<-[no]test>
1144
 
1145
Test the building of the package. This option implies "nocopy" and "nodpkg".
1146
 
1147
=item B<-[no]keep>
1148
 
361 dpurdie 1149
Keep the workspace after the build. The default option is "nokeep"
267 dpurdie 1150
 
1151
This option is different to the "reuse" in that the view will be deleted, if
1152
it exists, before the build, but will be retained at the completion of the
1153
process. The user may then manually extract the created package.
1154
 
1155
The view may be deleted with the the "delete" option; taking care to ensure that
1156
no files are open in the view and that the users current working directory is
1157
not in the view.
1158
 
1159
=item B<-[no]beta>
1160
 
1161
This option overrides many of the package release tests to allow a beta package
1162
to be released.
1163
 
1164
=item B<-[no]merge>
1165
 
1166
This option will merge packages being built on multiple machines into
1167
dpkg_archive. By default, if a package already exists in the archive it will be
1168
deleted and replaced. With this option the package will be merged. The merge
1169
process does not over write files found in the archive.
1170
 
1171
=item B<-[no]runtests>
1172
 
1173
This option will allow the suppression of the running of the unit tests included
1174
with the component. By default the tests are run. This can be suppressed
1175
without affecting the release process.
1176
 
1177
=back
1178
 
1179
=head1 DESCRIPTION
1180
 
1181
This program is the primary tool for the creation, recreation and release of
1270 dpurdie 1182
packages within the B<VIX> build environment, although the program can perform a
267 dpurdie 1183
number of very useful operations required during normal development and
1184
maintenance.
1185
 
1186
This program will build a system containing one or more inter-related build
1187
files using the JATS build tools.
1188
 
1189
In normal operation the program will:
1190
 
1191
=over 8
1192
 
1193
=item Remove Workspace
1194
 
1195
Remove any existing workspace of the same name. The workspace will not be
1196
removed if it contains checked-out files.
1197
 
1198
The workspace removal may fail if there are any files B<open> within the view or if
1199
any shell has a subdirectory of the view set as a B<current working directory>.
1200
 
1201
=item Create the workspace
1202
 
1203
Create a workspace to contain the files described by the Subversion
1204
label being processed.
1205
 
1206
=item Populate the workspace
1207
 
1208
Loads files into the workspace.
1209
 
1210
I<Note:> If the workspace files are simply being extracted, then this is the end
1211
of the program. The extracted workspace is left in place.
1212
 
1213
=item Sanity Test
1214
 
1215
If the build is being used as a release into dpkg_archive then
1216
various tests are performed to ensure the repeatability of the view and the
1217
build. These tests include:
1218
 
1219
=over 8
1220
 
361 dpurdie 1221
=item   *
267 dpurdie 1222
 
361 dpurdie 1223
The view must be constructed from one label
267 dpurdie 1224
 
361 dpurdie 1225
=item   *
267 dpurdie 1226
 
361 dpurdie 1227
That label must be pegged
267 dpurdie 1228
 
361 dpurdie 1229
=item   *
1230
 
1231
The labelled view must contain exactly one build file
1232
 
1233
=item   *
1234
 
1235
The view cannot have been re-used.
1236
 
267 dpurdie 1237
=back
1238
 
1239
=item Locate build files
1240
 
1241
Locate the build file within the view.
1242
 
1243
It is an error to have multiple build files within the workspace, unless the
1244
B<-build> option is used. By default, only one package will be built.
1245
 
1246
=item Package the results
1247
 
1248
Use JATS to build and make the package.
1249
 
1250
The resultant package may be copied to a numbers of locations. These include
1251
 
1252
=over 8
1253
 
1254
=item 1
1255
 
1256
The master dpkg_archive as an official release. This is the default operation.
1257
 
1258
=item 2
1259
 
1260
The users current directory. The package directory from the built package is
1261
copied locally. The "pkg" directory is copied. This is only performed with the
1262
B<-copy> option.
1263
 
1264
=back
1265
 
1266
=item Delete the workspace
1267
 
1268
Delete the workspace and all related files.
1269
 
1270
The workspace will not be deleted if an error was detected in the build process, or
1271
the "reuse" or "keep" options are present.
1272
 
1273
=back
1274
 
1275
=cut
1276