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