Subversion Repositories DevTools

Rev

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