Subversion Repositories DevTools

Rev

Rev 1328 | Rev 1344 | 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];
1341 dpurdie 117
$label =~ s~^SVN::~~;
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);
186
    my $ws_label_new = make_label ($pkg_root ,SvnIsaSimpleLabel($opt_rename));
187
 
188
    $session->SvnRename (
189
                'old' => $ws_label_old,
190
                'new' => $ws_label_new,
191
                'comment' => $opt_comment ? $opt_comment : 'Renamed by Jats Svnlabel',
192
                'replace' => $opt_replace ? 1 : 0,
193
                );
194
 
195
    Message ("Repository Ref: " . $session->RmRef);
385 dpurdie 196
    updateProperties();
267 dpurdie 197
    $opr_done = 1;
198
}
199
 
200
################################################################################
201
#   
202
#   The Svn Label need a package root
203
#   If we are in a WorkSpace, then we can determine the package root
204
#
205
if ( $opt_label )
206
{
207
    #
208
    #   Can now create a nice pathname for the label
209
    #
210
    my $ws_label = make_label( $pkg_root, SvnIsaSimpleLabel ($label));
211
 
212
    #
213
    #   Don't let the user create a tag from a workspace that is
214
    #   also created from a tag.
215
    #
216
    #   They should be using a branch.
217
    #   Can't stop them - but can make it difficult.
218
    #
219
    Error ("Cannot tag a Workspace based on a 'tag'",
220
           "You should be working in a branch",
221
           "WorkSpace: $session->{WSURL}" )
379 dpurdie 222
        if ( !$opt_branch && (($session->WsType) eq 'tags') );
267 dpurdie 223
 
1328 dpurdie 224
    #
225
    #   The label operation *should* be a server side operation only
226
    #   If the user has commited chaages, but not yet updated the local
227
    #   workspace, then subversion will do a client side copy
228
    #   This is not good.
229
    #       If the 'tags' area is not writable then we get a cryptic message
230
    #       If the 'tags' area is writable then we commit the changes twice
231
    #
232
    #   Solution - ensure that the Workspace is upto date
233
    #              This is done within SvnCopyWs
234
    #
235
 
267 dpurdie 236
    $session->SvnCopyWs (
237
                   target => $ws_label,
385 dpurdie 238
                   'allowLocalMods' => $opt_complexTag,
267 dpurdie 239
                   'noswitch' => 1,
240
                   'replace' => $opt_replace ? 1 : 0,
241
                   'comment' => $opt_comment ? $opt_comment : 'Created by Jats Svnlabel',
242
                   );
243
 
244
    Message ("Repository Ref: " . $session->RmRef);
385 dpurdie 245
    updateProperties();
267 dpurdie 246
    $opr_done = 1;
247
}
248
 
249
################################################################################
250
#
251
#   Delete a label
252
#   Can't really delete one, but we can remove it from the head
253
#   If SVN ever gets an 'obliterate' command then prehaps we could use it
254
#
255
if ( $opt_delete )
256
{
257
    #
258
    #   Calculate the label name to delete
259
    #
260
    my $ws_label = make_src_label( $pkg_root, $label );
261
    $session->SvnDelete ( 'target' => $ws_label,
262
                          'comment' => $opt_comment ? $opt_comment : 'Deleted by Jats Svnlabel',
1270 dpurdie 263
                          'noerror' => 0 );
267 dpurdie 264
    $opr_done = 1;
265
}
266
 
267
################################################################################
268
#
269
#   Clone a label
270
#   Essentially a copy of a tag
271
#
272
#
273
if ( $opt_clone )
274
{
275
    #
276
    #   Create old and new paths for the full label
277
    #
278
    my $ws_label_old = make_src_label ($pkg_root, $label);
279
    my $ws_label_new = make_label ($pkg_root ,SvnIsaSimpleLabel($opt_clone));
1341 dpurdie 280
    #
281
    #   Backtrack label so that we clone the tag source, not the tag
282
    #
283
    if ( $ws_label_old =~ m~/tags/~ )
284
    {
285
        $ws_label_old = $session->backTrackSvnLabel($label);
286
        Verbose2 ("Tag back tracked to: $ws_label_old");
287
        $ws_label_old = $pkg_root . '/' . $ws_label_old;
288
    }
289
 
267 dpurdie 290
    $session->SvnCopy (
291
                'old' => $ws_label_old,
292
                'new' => $ws_label_new,
1341 dpurdie 293
                'comment' => $opt_comment ? $opt_comment : 'Copied by Jats Svnlabel Clone',
267 dpurdie 294
                'replace' => $opt_replace ? 1 : 0,
295
                );
296
 
297
    Message ("Repository Ref: " . $session->RmRef);
385 dpurdie 298
    updateProperties();
267 dpurdie 299
    $opr_done = 1;
300
}
301
 
302
 
303
Error ("No valid operations specified. Try -h") unless ( $opr_done );
304
exit 0;
305
 
306
 
307
#-------------------------------------------------------------------------------
308
# Function        : make_label
309
#
310
# Description     : Create a label ( tag or branch )
311
#
312
# Inputs          : $base
313
#                   $name
314
#
315
# Returns         : Full label
316
#
317
sub make_label
318
{
319
    my ($base, $name) = @_;
320
    my $join = $opt_branch ? '/branches/' : '/tags/';
321
    return $base . $join . $name;
322
}
323
 
324
#-------------------------------------------------------------------------------
325
# Function        : make_src_label
326
#
327
# Description     : Create a source label ( tag or branch )
328
#
1341 dpurdie 329
#                   Calculation may be bypassed if the global $src_label
379 dpurdie 330
#                   is specified.
331
#
267 dpurdie 332
# Inputs          : $base
379 dpurdie 333
#                   $name           - May contain hint
334
#                                     Prefixed with 'tags/' or 'branches/'
267 dpurdie 335
#
336
# Returns         : Full label
337
#
338
sub make_src_label
339
{
340
    return $src_label if ( $src_label );
341
    my ($base, $name) = @_;
379 dpurdie 342
    my $result = $name;
1328 dpurdie 343
    unless ( $name =~ m~(^branches/)|(^tags)|(^trunk\@)~ )
379 dpurdie 344
    {
345
        $result = ($opt_branch ? 'branches/' : 'tags/' ) . $name;
346
    }
347
    return $base . '/' . $result;
267 dpurdie 348
}
349
 
350
 
351
#-------------------------------------------------------------------------------
352
# Function        : LocateRoots
353
#
354
# Description     : Determine workspace root and associated
355
#                   package root
356
#
357
#                   Uses several hint to figure it out
358
#                       The default is the package in the current directory
359
#                       -workspace - may address a workspace
360
#                       -packagebase - may specify a package base
361
#                                      Does not work with -label
362
#                                      as we need a workspace
363
#
364
#
365
# Inputs          : None - uses globals
366
#
367
# Returns         : Setup global variables
368
#
369
sub LocateRoots
370
{
371
    #
372
    #   Use current directory as the workspace unless the user
373
    #   has specified a different one
374
    #
375
    $session = NewSessionByWS( $opt_workspace || '.', $opt_workspace ? 0 : 1 );
376
 
377
    Verbose ("Determine the current workspace root" );
378
    my $ws_root = $session->SvnLocateWsRoot(1) || '';
379
 
380
    #
381
    #   Only need a WS root for the label operation
382
    #   Every thing else can live without it
383
    #
384
    Error ("Cannot determine source Workspace") if ( $opt_label && !$ws_root );
385
 
386
    #
387
    #   Calculate the package base
388
    #       - User specified
389
    #       - Extacted from label
390
    #       - Extracted from WorkSpace
391
    #           - User specified Workspace
392
    #           - Current directory
393
    #
394
    if ( $opt_packagebase )
395
    {
396
        #
397
        #   User has given us the package base
398
        #
361 dpurdie 399
        $session = NewSessionByUrl ( $opt_packagebase, 0, $session );
267 dpurdie 400
        $session->SvnValidatePackageRoot();
401
    }
375 dpurdie 402
    elsif ( (!$opt_label ) && $label && $label =~ m~(.+)(/(tags|branches|trunk)(/|@)(.+))~ )
267 dpurdie 403
    {
404
        #
375 dpurdie 405
        #   Attempt to extract it from the label, but only if we are not
406
        #   labeling a sandbox.
267 dpurdie 407
        #   Remove it from the label
408
        #
409
        $src_label = $2;
410
        $label = $5;
361 dpurdie 411
        $session = NewSessionByUrl ( $1, 0, $session );
267 dpurdie 412
        $session->SvnValidatePackageRoot();
413
        $src_label = $session->Full . $src_label;
414
    }
415
    elsif ( $ws_root )
416
    {
417
        # $s2 = $session;
418
    }
419
    else
420
    {
421
        Error ("Cannot determine the Package Base");
422
    }
423
    $pkg_root = $session->Full;
424
 
425
    #
426
    #   Everything needs a $pkg_root
427
    #
428
    Error ("Cannot determine Package Base") unless ( $pkg_root  );
429
 
430
    Verbose ("Workspace root: $ws_root");
431
    Verbose ("Package root  : $pkg_root");
432
#DebugDumpData ("Session", $session );
433
}
434
 
435
#-------------------------------------------------------------------------------
385 dpurdie 436
# Function        : updateProperties
437
#
438
# Description     : Update the properties, if present
439
#
440
# Inputs          : Globals
441
#
442
# Returns         : Nothing
443
#
444
sub updateProperties
445
{
446
    $session->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));
447
    $session->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));
448
}
449
 
450
#-------------------------------------------------------------------------------
267 dpurdie 451
#   Documentation
452
#
453
 
454
=pod
455
 
361 dpurdie 456
=for htmltoc    GENERAL::Subversion::
457
 
267 dpurdie 458
=head1 NAME
459
 
460
jats_svnlabel - Subversion label operations
461
 
462
=head1 SYNOPSIS
463
 
361 dpurdie 464
jats svnlabel [options] C<label>
267 dpurdie 465
 
466
 Options:
467
    -help                  - brief help message
468
    -help -help            - Detailed help message
469
    -man                   - Full documentation
385 dpurdie 470
    -available             - Check for label availability
267 dpurdie 471
    -check                 - Check for label existence
472
    -clone=xxx             - Clone a package version
473
    -delete                - Delete label from the repository
474
    -label                 - Labels a Package
383 dpurdie 475
    -auto                  - Same as -label
385 dpurdie 476
    -list                  - List labels in a package
267 dpurdie 477
    -rename=xxx            - Rename a label
385 dpurdie 478
 
267 dpurdie 479
 Modifiers
480
    -branch                - Use branches, not tags
481
    -replace               - Replace existing labels. Use with -label
482
    -comment=text          - Comment to add to repository operations
483
    -workspace=path        - Path to a workspace to label
385 dpurdie 484
    -packagebase=path      - Repository path to package base
485
    -author=name           - Force author of changes
486
    -date=dateString       - Force date of changes
487
    -allowLocalMods        - Allow complex tagging
267 dpurdie 488
 
489
=head1 OPTIONS
490
 
491
=over 8
492
 
493
=item B<-help>
494
 
495
Print a brief help message and exits.
496
 
497
=item B<-help -help>
498
 
499
Print a detailed help message with an explanation for each option.
500
 
501
=item B<-man>
502
 
503
Prints the manual page and exits.
504
 
505
=item B<-clone=xxx>
506
 
385 dpurdie 507
This option will copy a labeled version of a package to a new label.
267 dpurdie 508
 
509
=item B<-delete>
510
 
511
This option will delete the specified label from the repository
512
 
513
=item B<-available>
514
 
385 dpurdie 515
This option will check for the labels non-existence. An error will be reported
267 dpurdie 516
if the label exists.
517
 
518
=item B<-check>
519
 
385 dpurdie 520
This option will check for the labels existence. An error will be reported
267 dpurdie 521
if the label does not exist.
522
 
523
=item B<-label>
524
 
525
This option will label a workspace.
526
 
527
The -replace option may be used to force labels to be moved.
528
 
383 dpurdie 529
=item B<-auto>
530
 
531
This option is the same as '-label'. It is provided for compatibility with other
532
labeling tools.
533
 
267 dpurdie 534
=item B<-rename=xxx>
535
 
536
This option will rename a label. The new name of the label is provided as the
537
argument after the option. If any further operation are to be performed the
538
new label name will be used.
539
 
540
=item B<-list>
541
 
385 dpurdie 542
This option will case all labels for the related package to be shown. The
267 dpurdie 543
command assumes that the repository is in a trunk/tags/branches format.
544
 
545
By default tags are shown. Branches may be shown with the -branches option.
546
 
547
=item B<-replace>
548
 
549
This option may be used with the -label command to allow existing labels to
550
be replaced.
551
 
552
=item B<-comment=text>
553
 
554
This option provides text to be used to document the operation in the log.
555
 
556
If none is provided, then the utility will use a simple comment of its own.
557
 
558
=item B<-workspace=path>
559
 
560
This option can be used to specify the path to a workspace to be labeled.
561
 
562
If not provided then the utility will use the current directory to determine
563
the root of the workspace.
564
 
565
=item B<packagebase=path>
566
 
567
This option can be used to specify the path to a package within a repository.
568
 
569
If the 'label' contains a package base, then it will be extracted and used.
570
 
571
If not provided and the utility is within a workspace, then the package base will
572
be taken to be that of the package in the workspace.
573
 
574
=item B<-branch>
575
 
576
This option modifies all commands. It causes the labeling operations to be
1341 dpurdie 577
performed on a packages 'branches' area instead of the default 'tags'
267 dpurdie 578
area.
579
 
385 dpurdie 580
=item -author=name
581
 
582
This option will force the author of changes as recorded in the repository.
583
The repository must be configured to allow such changes.
584
 
585
This option may not work for non-admin users.
586
 
587
=item -date=dateString
588
 
589
This option will force the date of the changes as recorded in the repository.
590
The repository must be configured to allow such changes.
591
The dateString is in a restricted ISO 8601 format: ie 2009-02-12T00:44:04.921324Z
592
 
593
This option may not work for non-admin users.
594
 
595
=item -allowLocalMods
596
 
597
This option modifies the checking that is done when the workspace is labeled.
598
The default is to 'not' allow local modifications. All modifications must be
599
committed before the label is created.
600
 
601
If local modifications are allowed, then the utility will warn about local
602
modifications, but the labelling process will continue. This allows
603
for 'complex' tagging. The modified files will be transferred to the repository
604
and will form a part of the tag.
605
 
606
This mode of operation should NOT be used for normal labeling. It is useful for
607
the preservation of 'Mixed Workspaces'.
608
 
267 dpurdie 609
=back
610
 
611
=head1 DESCRIPTION
612
 
613
This program provides a number of useful Subversion labeling operations. These
614
are:
615
 
616
=over 8
617
 
361 dpurdie 618
=item   *
267 dpurdie 619
 
385 dpurdie 620
check - check existence of a label
267 dpurdie 621
 
361 dpurdie 622
=item   *
267 dpurdie 623
 
385 dpurdie 624
available - check non-existence of a label
267 dpurdie 625
 
361 dpurdie 626
=item   *
267 dpurdie 627
 
375 dpurdie 628
list - list the labels on a package
267 dpurdie 629
 
361 dpurdie 630
=item   *
267 dpurdie 631
 
361 dpurdie 632
rename - rename a label
633
 
634
=item   *
635
 
636
label - label a workspace
637
 
638
=item   *
639
 
640
delete - delete a label
641
 
642
=item   *
643
 
644
clone - duplicate a label
645
 
267 dpurdie 646
=back
647
 
648
The various operations may be mixed in the one command. The order of the
649
operations is: check, available, list, rename, label, delete and clone
650
 
651
=head2 LABEL format
652
 
653
A 'label' as used by JATS within a Subversion repository, may have four elements.
654
These are:
655
 
656
=over
657
 
658
=item   * Package Path
659
 
385 dpurdie 660
Any text proceeding a / will be taken to be a package path. This identifies the
267 dpurdie 661
root of the package within the repository.
662
 
663
=item   * Label Type
664
 
665
This will be one of 'trunk', 'branches' or 'tags'.
666
 
667
Normally labels are placed on the 'tags' subdirectory of a package.
668
 
669
=item   * Simple Label
670
 
341 dpurdie 671
The label tag. It can only contain Alphanumerics and the characters :-_.
267 dpurdie 672
In practice this can be a simple version number as the labels are held the
673
context of a package.
674
 
383 dpurdie 675
A simple label of TIMESTAMP will be treated in special manner. The name will be
676
replaced with a unique name based on the users name and the current date time.
677
 
267 dpurdie 678
=item   * Peg
679
 
680
A peg consists of a '@' and a number string at the end of the label.
681
 
682
=back
683
 
684
An example of a full label is: repo/package/component/tags/label_text@1234
685
 
686
Not all operation support the full label syntax. The 'peg' is not allowed in
687
a label that will be used as a target of a repository copy operation, nor
688
is the 'Package Path'.
689
 
690
Full labels can be used in operations that specify the source of a
691
copy operation, such as a delete, rename or clone operation.
692
 
693
All operations report a 'Full Label' that can be used to reference the
341 dpurdie 694
repository at any time in the future. This is the 'tag' that needs to be
267 dpurdie 695
provided to 'Release Manager in order to reproduce the package.
696
 
697
=head1 EXAMPLE
698
 
699
jats svnlabel -label daf_br_23.0.0.syd
700
 
701
=cut
702