Subversion Repositories DevTools

Rev

Rev 1344 | Rev 1356 | 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-2004 ERG Limited, All rights reserved
3
#
4
# Module name   : jats_svnlabel.pl
5
# Module type   : Jats Utility
6
# Compiler(s)   : Perl
7
# Environment(s): Jats
8
#
9
# Description   : A script to perform a number of labeling operations
10
#                 The script will:
11
#                   label a workspace       - Create a tag
12
#                   delete a label          - Deletes a tag
13
#                   rename a label          - Renames a tag
14
#                   clone a label           - Clones a tag
15
#
16
#......................................................................#
17
 
18
require 5.006_001;
19
use strict;
20
use warnings;
21
use JatsError;
22
use JatsSvn;
23
 
24
use Pod::Usage;                             # required for help support
25
use Getopt::Long;
26
use Cwd;
27
 
28
my $VERSION = "1.0.0";                      # Update this
29
 
30
#
31
#   Options
32
#
33
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
34
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
35
my $opt_help = 0;
36
my $opt_check;
37
my $opt_avail;
38
my $opt_label;
39
my $opt_replace;
40
my $opt_delete;
41
my $opt_rename;
42
my $opt_clone;
43
my $opt_comment;
44
my $opt_workspace;
45
my $opt_packagebase;
46
my $opt_branch;
47
my $opt_list;
385 dpurdie 48
my $opt_author;
49
my $opt_date;
50
my $opt_complexTag;
267 dpurdie 51
 
52
#
53
#   Globals
54
#
55
my $session;                                # Subversion Session
56
my $label;                                  # User argument - one label
57
my $src_label;                              # User specified source label
58
my $pkg_root;                               # Root of corresponding package
59
my $opr_done;                               # User has done something
60
 
61
#-------------------------------------------------------------------------------
62
# Function        : Mainline Entry Point
63
#
64
# Description     :
65
#
66
# Inputs          :
67
#
68
my $result = GetOptions (
385 dpurdie 69
                'help:+'        => \$opt_help,              # flag, multiple use allowed
70
                'manual:3'      => \$opt_help,              # flag
71
                'verbose:+'     => \$opt_verbose,           # flag, multiple use allowed
72
                'check'         => \$opt_check,             # Flag
73
                'available'     => \$opt_avail,             # Flag
74
                'label'         => \$opt_label,             # Flag
75
                'auto'          => \$opt_label,             # Same as -label
76
                'delete'        => \$opt_delete,            # Flag
77
                'replace!'      => \$opt_replace,           # Flag
78
                'rename=s'      => \$opt_rename,            # String
79
                'clone=s'       => \$opt_clone,             # String
80
                'comment=s'     => \$opt_comment,           # String
81
                'workspace=s'   => \$opt_workspace,         # String
82
                'packagebase=s' => \$opt_packagebase,       # String
83
                'branch'        => \$opt_branch,            # Flag
84
                'list'          => \$opt_list,              # Flag
85
                'author=s'      => \$opt_author,            # String
86
                'date=s'        => \$opt_date,              # String
1270 dpurdie 87
                'allowlocalmods!'   => \$opt_complexTag,    # [no]aaaaaa
267 dpurdie 88
                );
89
 
90
                #
91
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
92
                #
93
 
94
#
95
#   Process help and manual options
96
#
97
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
98
pod2usage(-verbose => 1) if ($opt_help == 2 );
99
pod2usage(-verbose => 2) if ($opt_help > 2);
100
 
101
#
102
#   Configure the error reporting process now that we have the user options
103
#
104
ErrorConfig( 'name'    =>'SVNLABEL',
105
             'verbose' => $opt_verbose,
106
            );
107
 
108
#
109
#   Validate user options
110
#   Need one command line argument
111
#
112
Error ("No labels provided") if ( $#ARGV < 0 && !$opt_list );
113
Error ("Too many labels provided") if ( $#ARGV > 0);
375 dpurdie 114
Error ("Conflicting options. Clone and Label") if ( $opt_clone && $opt_label );
115
Error ("Conflicting options. Rename and Label") if ( $opt_rename && $opt_label );
267 dpurdie 116
$label = $ARGV[0];
1347 dpurdie 117
$label =~ s~^SVN::~~ if $label;
267 dpurdie 118
 
119
#
120
#   Locate package and workspace roots
121
#
122
LocateRoots ();
123
 
124
################################################################################
125
#
126
#   Validate one or more labels
127
#   Intended to be used within scripts for testing
128
#
129
if ( $opt_check )
130
{
131
    $session->SvnValidateTarget
132
    (
133
        'target'    => make_src_label ($pkg_root, $label),
341 dpurdie 134
        'cmd'       => 'Validate Existence',
267 dpurdie 135
        'require'   => 1,
136
    );
137
    $opr_done = 1;
138
}
139
 
140
if ( $opt_avail )
141
{
142
    $session->SvnValidateTarget
143
    (
144
        'target'    => make_src_label ($pkg_root, $label),
145
        'cmd'       => 'Validate Availablility',
146
        'available' => 1,
147
    );
148
    $opr_done = 1;
149
}
150
 
151
################################################################################
152
#
153
#   List labels
154
#
155
if ( $opt_list )
156
{
157
    my $pList = $session->ListLabels (make_label ($pkg_root, '') );
158
 
159
    #
379 dpurdie 160
    #   Remove trailing / on all directory names
267 dpurdie 161
    #
162
    chop @{$pList};
163
 
164
    my $type = $opt_branch ? 'branch' : 'tag';
165
    Information ( "Package: " . $session->Path,
166
                    ,map ( $type . ': ' . $_, @{$pList})
167
                    );
168
    $opr_done = 1;
169
}
170
 
171
 
172
################################################################################
173
#
174
#   Rename a label
175
#   This has implications for stuff that is stored within release manager
176
#
177
#   Renaming a pegged version is problematical
178
#   At the moment we do a copy ( rename, without the delete)
179
#
180
if ( $opt_rename )
181
{
182
    #
183
    #   Create old and new paths for the full label
184
    #
185
    my $ws_label_old = make_src_label ($pkg_root, $label);
1347 dpurdie 186
    my $label_new = SvnIsaSimpleLabel($opt_rename);
187
    my $ws_label_new = make_label ($pkg_root , $label_new);
267 dpurdie 188
 
189
    $session->SvnRename (
190
                'old' => $ws_label_old,
191
                'new' => $ws_label_new,
192
                'comment' => $opt_comment ? $opt_comment : 'Renamed by Jats Svnlabel',
193
                'replace' => $opt_replace ? 1 : 0,
194
                );
195
 
196
    Message ("Repository Ref: " . $session->RmRef);
1347 dpurdie 197
    Message ("Vcs Tag       : " . $session->SvnTag);
385 dpurdie 198
    updateProperties();
267 dpurdie 199
    $opr_done = 1;
200
}
201
 
202
################################################################################
203
#   
204
#   The Svn Label need a package root
205
#   If we are in a WorkSpace, then we can determine the package root
206
#
207
if ( $opt_label )
208
{
209
    #
210
    #   Can now create a nice pathname for the label
211
    #
1347 dpurdie 212
    $label = SvnIsaSimpleLabel ($label);
213
    my $ws_label = make_label( $pkg_root, $label );
267 dpurdie 214
 
215
    #
216
    #   Don't let the user create a tag from a workspace that is
217
    #   also created from a tag.
218
    #
219
    #   They should be using a branch.
220
    #   Can't stop them - but can make it difficult.
221
    #
222
    Error ("Cannot tag a Workspace based on a 'tag'",
223
           "You should be working in a branch",
224
           "WorkSpace: $session->{WSURL}" )
379 dpurdie 225
        if ( !$opt_branch && (($session->WsType) eq 'tags') );
267 dpurdie 226
 
1328 dpurdie 227
    #
228
    #   The label operation *should* be a server side operation only
229
    #   If the user has commited chaages, but not yet updated the local
230
    #   workspace, then subversion will do a client side copy
231
    #   This is not good.
232
    #       If the 'tags' area is not writable then we get a cryptic message
233
    #       If the 'tags' area is writable then we commit the changes twice
234
    #
235
    #   Solution - ensure that the Workspace is upto date
236
    #              This is done within SvnCopyWs
237
    #
238
 
267 dpurdie 239
    $session->SvnCopyWs (
240
                   target => $ws_label,
385 dpurdie 241
                   'allowLocalMods' => $opt_complexTag,
267 dpurdie 242
                   'noswitch' => 1,
243
                   'replace' => $opt_replace ? 1 : 0,
244
                   'comment' => $opt_comment ? $opt_comment : 'Created by Jats Svnlabel',
245
                   );
246
 
247
    Message ("Repository Ref: " . $session->RmRef);
1347 dpurdie 248
    Message ("Vcs Tag       : " . $session->SvnTag);
385 dpurdie 249
    updateProperties();
267 dpurdie 250
    $opr_done = 1;
251
}
252
 
253
################################################################################
254
#
255
#   Delete a label
256
#   Can't really delete one, but we can remove it from the head
257
#   If SVN ever gets an 'obliterate' command then prehaps we could use it
258
#
259
if ( $opt_delete )
260
{
261
    #
262
    #   Calculate the label name to delete
263
    #
264
    my $ws_label = make_src_label( $pkg_root, $label );
265
    $session->SvnDelete ( 'target' => $ws_label,
266
                          'comment' => $opt_comment ? $opt_comment : 'Deleted by Jats Svnlabel',
1270 dpurdie 267
                          'noerror' => 0 );
267 dpurdie 268
    $opr_done = 1;
269
}
270
 
271
################################################################################
272
#
273
#   Clone a label
274
#   Essentially a copy of a tag
275
#
276
#
277
if ( $opt_clone )
278
{
279
    #
280
    #   Create old and new paths for the full label
281
    #
282
    my $ws_label_old = make_src_label ($pkg_root, $label);
1347 dpurdie 283
    my $new_label = SvnIsaSimpleLabel($opt_clone);
284
    my $ws_label_new = make_label ($pkg_root , $new_label);
1341 dpurdie 285
    #
286
    #   Backtrack label so that we clone the tag source, not the tag
287
    #
288
    if ( $ws_label_old =~ m~/tags/~ )
289
    {
1344 dpurdie 290
        $ws_label_old = $session->backTrackSvnLabel( 'tags/' . $label);
1341 dpurdie 291
        Verbose2 ("Tag back tracked to: $ws_label_old");
292
        $ws_label_old = $pkg_root . '/' . $ws_label_old;
293
    }
294
 
267 dpurdie 295
    $session->SvnCopy (
296
                'old' => $ws_label_old,
297
                'new' => $ws_label_new,
1341 dpurdie 298
                'comment' => $opt_comment ? $opt_comment : 'Copied by Jats Svnlabel Clone',
267 dpurdie 299
                'replace' => $opt_replace ? 1 : 0,
300
                );
301
 
302
    Message ("Repository Ref: " . $session->RmRef);
1347 dpurdie 303
    Message ("Vcs Tag       : " . $session->SvnTag);
385 dpurdie 304
    updateProperties();
267 dpurdie 305
    $opr_done = 1;
306
}
307
 
308
 
309
Error ("No valid operations specified. Try -h") unless ( $opr_done );
310
exit 0;
311
 
312
 
313
#-------------------------------------------------------------------------------
314
# Function        : make_label
315
#
316
# Description     : Create a label ( tag or branch )
317
#
318
# Inputs          : $base
319
#                   $name
320
#
321
# Returns         : Full label
322
#
323
sub make_label
324
{
325
    my ($base, $name) = @_;
326
    my $join = $opt_branch ? '/branches/' : '/tags/';
327
    return $base . $join . $name;
328
}
329
 
330
#-------------------------------------------------------------------------------
331
# Function        : make_src_label
332
#
333
# Description     : Create a source label ( tag or branch )
334
#
1341 dpurdie 335
#                   Calculation may be bypassed if the global $src_label
379 dpurdie 336
#                   is specified.
337
#
267 dpurdie 338
# Inputs          : $base
379 dpurdie 339
#                   $name           - May contain hint
340
#                                     Prefixed with 'tags/' or 'branches/'
267 dpurdie 341
#
342
# Returns         : Full label
343
#
344
sub make_src_label
345
{
346
    return $src_label if ( $src_label );
347
    my ($base, $name) = @_;
379 dpurdie 348
    my $result = $name;
1328 dpurdie 349
    unless ( $name =~ m~(^branches/)|(^tags)|(^trunk\@)~ )
379 dpurdie 350
    {
351
        $result = ($opt_branch ? 'branches/' : 'tags/' ) . $name;
352
    }
353
    return $base . '/' . $result;
267 dpurdie 354
}
355
 
356
 
357
#-------------------------------------------------------------------------------
358
# Function        : LocateRoots
359
#
360
# Description     : Determine workspace root and associated
361
#                   package root
362
#
363
#                   Uses several hint to figure it out
364
#                       The default is the package in the current directory
365
#                       -workspace - may address a workspace
366
#                       -packagebase - may specify a package base
367
#                                      Does not work with -label
368
#                                      as we need a workspace
369
#
370
#
371
# Inputs          : None - uses globals
372
#
373
# Returns         : Setup global variables
374
#
375
sub LocateRoots
376
{
377
    #
378
    #   Use current directory as the workspace unless the user
379
    #   has specified a different one
380
    #
381
    $session = NewSessionByWS( $opt_workspace || '.', $opt_workspace ? 0 : 1 );
382
 
383
    Verbose ("Determine the current workspace root" );
384
    my $ws_root = $session->SvnLocateWsRoot(1) || '';
385
 
386
    #
387
    #   Only need a WS root for the label operation
388
    #   Every thing else can live without it
389
    #
390
    Error ("Cannot determine source Workspace") if ( $opt_label && !$ws_root );
391
 
392
    #
393
    #   Calculate the package base
394
    #       - User specified
395
    #       - Extacted from label
396
    #       - Extracted from WorkSpace
397
    #           - User specified Workspace
398
    #           - Current directory
399
    #
400
    if ( $opt_packagebase )
401
    {
402
        #
403
        #   User has given us the package base
404
        #
361 dpurdie 405
        $session = NewSessionByUrl ( $opt_packagebase, 0, $session );
267 dpurdie 406
        $session->SvnValidatePackageRoot();
407
    }
375 dpurdie 408
    elsif ( (!$opt_label ) && $label && $label =~ m~(.+)(/(tags|branches|trunk)(/|@)(.+))~ )
267 dpurdie 409
    {
410
        #
375 dpurdie 411
        #   Attempt to extract it from the label, but only if we are not
412
        #   labeling a sandbox.
267 dpurdie 413
        #   Remove it from the label
414
        #
415
        $src_label = $2;
416
        $label = $5;
361 dpurdie 417
        $session = NewSessionByUrl ( $1, 0, $session );
267 dpurdie 418
        $session->SvnValidatePackageRoot();
419
        $src_label = $session->Full . $src_label;
420
    }
421
    elsif ( $ws_root )
422
    {
423
        # $s2 = $session;
424
    }
425
    else
426
    {
427
        Error ("Cannot determine the Package Base");
428
    }
429
    $pkg_root = $session->Full;
430
 
431
    #
432
    #   Everything needs a $pkg_root
433
    #
434
    Error ("Cannot determine Package Base") unless ( $pkg_root  );
435
 
436
    Verbose ("Workspace root: $ws_root");
437
    Verbose ("Package root  : $pkg_root");
438
#DebugDumpData ("Session", $session );
439
}
440
 
441
#-------------------------------------------------------------------------------
385 dpurdie 442
# Function        : updateProperties
443
#
444
# Description     : Update the properties, if present
445
#
446
# Inputs          : Globals
447
#
448
# Returns         : Nothing
449
#
450
sub updateProperties
451
{
452
    $session->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));
453
    $session->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));
454
}
455
 
456
#-------------------------------------------------------------------------------
267 dpurdie 457
#   Documentation
458
#
459
 
460
=pod
461
 
361 dpurdie 462
=for htmltoc    GENERAL::Subversion::
463
 
267 dpurdie 464
=head1 NAME
465
 
466
jats_svnlabel - Subversion label operations
467
 
468
=head1 SYNOPSIS
469
 
361 dpurdie 470
jats svnlabel [options] C<label>
267 dpurdie 471
 
472
 Options:
473
    -help                  - brief help message
474
    -help -help            - Detailed help message
475
    -man                   - Full documentation
385 dpurdie 476
    -available             - Check for label availability
267 dpurdie 477
    -check                 - Check for label existence
478
    -clone=xxx             - Clone a package version
479
    -delete                - Delete label from the repository
480
    -label                 - Labels a Package
383 dpurdie 481
    -auto                  - Same as -label
385 dpurdie 482
    -list                  - List labels in a package
267 dpurdie 483
    -rename=xxx            - Rename a label
385 dpurdie 484
 
267 dpurdie 485
 Modifiers
486
    -branch                - Use branches, not tags
487
    -replace               - Replace existing labels. Use with -label
488
    -comment=text          - Comment to add to repository operations
489
    -workspace=path        - Path to a workspace to label
385 dpurdie 490
    -packagebase=path      - Repository path to package base
491
    -author=name           - Force author of changes
492
    -date=dateString       - Force date of changes
493
    -allowLocalMods        - Allow complex tagging
267 dpurdie 494
 
495
=head1 OPTIONS
496
 
497
=over 8
498
 
499
=item B<-help>
500
 
501
Print a brief help message and exits.
502
 
503
=item B<-help -help>
504
 
505
Print a detailed help message with an explanation for each option.
506
 
507
=item B<-man>
508
 
509
Prints the manual page and exits.
510
 
511
=item B<-clone=xxx>
512
 
385 dpurdie 513
This option will copy a labeled version of a package to a new label.
267 dpurdie 514
 
515
=item B<-delete>
516
 
517
This option will delete the specified label from the repository
518
 
519
=item B<-available>
520
 
385 dpurdie 521
This option will check for the labels non-existence. An error will be reported
267 dpurdie 522
if the label exists.
523
 
524
=item B<-check>
525
 
385 dpurdie 526
This option will check for the labels existence. An error will be reported
267 dpurdie 527
if the label does not exist.
528
 
529
=item B<-label>
530
 
531
This option will label a workspace.
532
 
533
The -replace option may be used to force labels to be moved.
534
 
383 dpurdie 535
=item B<-auto>
536
 
537
This option is the same as '-label'. It is provided for compatibility with other
538
labeling tools.
539
 
267 dpurdie 540
=item B<-rename=xxx>
541
 
542
This option will rename a label. The new name of the label is provided as the
543
argument after the option. If any further operation are to be performed the
544
new label name will be used.
545
 
546
=item B<-list>
547
 
385 dpurdie 548
This option will case all labels for the related package to be shown. The
267 dpurdie 549
command assumes that the repository is in a trunk/tags/branches format.
550
 
551
By default tags are shown. Branches may be shown with the -branches option.
552
 
553
=item B<-replace>
554
 
555
This option may be used with the -label command to allow existing labels to
556
be replaced.
557
 
558
=item B<-comment=text>
559
 
560
This option provides text to be used to document the operation in the log.
561
 
562
If none is provided, then the utility will use a simple comment of its own.
563
 
564
=item B<-workspace=path>
565
 
566
This option can be used to specify the path to a workspace to be labeled.
567
 
568
If not provided then the utility will use the current directory to determine
569
the root of the workspace.
570
 
571
=item B<packagebase=path>
572
 
573
This option can be used to specify the path to a package within a repository.
574
 
575
If the 'label' contains a package base, then it will be extracted and used.
576
 
577
If not provided and the utility is within a workspace, then the package base will
578
be taken to be that of the package in the workspace.
579
 
580
=item B<-branch>
581
 
582
This option modifies all commands. It causes the labeling operations to be
1341 dpurdie 583
performed on a packages 'branches' area instead of the default 'tags'
267 dpurdie 584
area.
585
 
385 dpurdie 586
=item -author=name
587
 
588
This option will force the author of changes as recorded in the repository.
589
The repository must be configured to allow such changes.
590
 
591
This option may not work for non-admin users.
592
 
593
=item -date=dateString
594
 
595
This option will force the date of the changes as recorded in the repository.
596
The repository must be configured to allow such changes.
597
The dateString is in a restricted ISO 8601 format: ie 2009-02-12T00:44:04.921324Z
598
 
599
This option may not work for non-admin users.
600
 
601
=item -allowLocalMods
602
 
603
This option modifies the checking that is done when the workspace is labeled.
604
The default is to 'not' allow local modifications. All modifications must be
605
committed before the label is created.
606
 
607
If local modifications are allowed, then the utility will warn about local
608
modifications, but the labelling process will continue. This allows
609
for 'complex' tagging. The modified files will be transferred to the repository
610
and will form a part of the tag.
611
 
612
This mode of operation should NOT be used for normal labeling. It is useful for
613
the preservation of 'Mixed Workspaces'.
614
 
267 dpurdie 615
=back
616
 
617
=head1 DESCRIPTION
618
 
619
This program provides a number of useful Subversion labeling operations. These
620
are:
621
 
622
=over 8
623
 
361 dpurdie 624
=item   *
267 dpurdie 625
 
385 dpurdie 626
check - check existence of a label
267 dpurdie 627
 
361 dpurdie 628
=item   *
267 dpurdie 629
 
385 dpurdie 630
available - check non-existence of a label
267 dpurdie 631
 
361 dpurdie 632
=item   *
267 dpurdie 633
 
375 dpurdie 634
list - list the labels on a package
267 dpurdie 635
 
361 dpurdie 636
=item   *
267 dpurdie 637
 
361 dpurdie 638
rename - rename a label
639
 
640
=item   *
641
 
642
label - label a workspace
643
 
644
=item   *
645
 
646
delete - delete a label
647
 
648
=item   *
649
 
650
clone - duplicate a label
651
 
267 dpurdie 652
=back
653
 
654
The various operations may be mixed in the one command. The order of the
655
operations is: check, available, list, rename, label, delete and clone
656
 
657
=head2 LABEL format
658
 
659
A 'label' as used by JATS within a Subversion repository, may have four elements.
660
These are:
661
 
662
=over
663
 
664
=item   * Package Path
665
 
385 dpurdie 666
Any text proceeding a / will be taken to be a package path. This identifies the
267 dpurdie 667
root of the package within the repository.
668
 
669
=item   * Label Type
670
 
671
This will be one of 'trunk', 'branches' or 'tags'.
672
 
673
Normally labels are placed on the 'tags' subdirectory of a package.
674
 
675
=item   * Simple Label
676
 
341 dpurdie 677
The label tag. It can only contain Alphanumerics and the characters :-_.
267 dpurdie 678
In practice this can be a simple version number as the labels are held the
679
context of a package.
680
 
383 dpurdie 681
A simple label of TIMESTAMP will be treated in special manner. The name will be
682
replaced with a unique name based on the users name and the current date time.
683
 
267 dpurdie 684
=item   * Peg
685
 
686
A peg consists of a '@' and a number string at the end of the label.
687
 
688
=back
689
 
690
An example of a full label is: repo/package/component/tags/label_text@1234
691
 
692
Not all operation support the full label syntax. The 'peg' is not allowed in
693
a label that will be used as a target of a repository copy operation, nor
694
is the 'Package Path'.
695
 
696
Full labels can be used in operations that specify the source of a
697
copy operation, such as a delete, rename or clone operation.
698
 
699
All operations report a 'Full Label' that can be used to reference the
341 dpurdie 700
repository at any time in the future. This is the 'tag' that needs to be
267 dpurdie 701
provided to 'Release Manager in order to reproduce the package.
702
 
703
=head1 EXAMPLE
704
 
705
jats svnlabel -label daf_br_23.0.0.syd
706
 
707
=cut
708