Subversion Repositories DevTools

Rev

Rev 379 | Rev 385 | 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) 2008 ERG Limited, All rights reserved
3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : JATS Subversion Interface Functions
10
#
11
#                 Requires a subversion client to be present on the machine
12
#                 Does require at least SubVersion 1.5
13
#                 Uses features not available in 1.4
14
#
15
#                 The package currently implements a set of functions
16
#                 There are some intentional limitations:
17
#                   1) Non recursive
18
#                   2) Errors terminate operation
19
#
20
#                 This package contains experimental argument passing
21
#                 processes. Sometimes use a hash of arguments
22
#
23
#......................................................................#
24
 
25
require 5.008_002;
26
use strict;
27
use warnings;
341 dpurdie 28
our $USER;
267 dpurdie 29
use JatsEnv;
30
 
31
package JatsSvn;
32
 
33
use JatsError;
34
use JatsSystem;
35
use JatsSvnCore qw(:All);
36
 
37
use File::Path;             # Instead of FileUtils
38
use File::Basename;
39
use Cwd;
40
 
41
 
42
# automatically export what we need into namespace of caller.
43
use Exporter();
44
our (@ISA, @EXPORT, %EXPORT_TAGS, @EXPORT_OK);
45
@ISA         = qw(Exporter JatsSvnCore);
46
 
47
@EXPORT      = qw(
48
                    NewSession
49
                    NewSessionByWS
50
                    NewSessionByUrl
51
 
52
                    SvnRmView
53
                    SvnIsaSimpleLabel
54
                    SvnComment
55
 
56
                    SvnUserCmd
361 dpurdie 57
 
58
                    SvnPath2Url
369 dpurdie 59
                    SvnPaths
267 dpurdie 60
                );
61
@EXPORT_OK =  qw(
62
                );
63
 
64
%EXPORT_TAGS = (All => [@EXPORT, @EXPORT_OK]);
65
 
66
#
67
#   Global Variables
68
#
69
 
70
#-------------------------------------------------------------------------------
71
# Function        : SvnCo
72
#
73
# Description     : Create a workspace
74
#                   Can be used to extract files, without creating the
75
#                   subversion control files.
76
#
77
# Inputs          : $self               - Instance data
78
#                   $RepoPath           - Within the repository
79
#                   $Path               - Local path
80
#                   Options             - Options
81
#                           --Export    - Export Only
82
#
83
# Returns         : Nothing
84
#
85
sub SvnCo
86
{
87
    my ($self, $RepoPath, $path, @opts) = @_;
88
    my $export = grep (/^--Export/, @opts );
341 dpurdie 89
    Debug ("SvnCo", $RepoPath, $path);
267 dpurdie 90
 
91
    #
92
    #   Ensure that the output path does not exist
93
    #   Do not allow the user to create a local work space
94
    #   where one already exists
95
    #
96
    Error ("SvnCo: No PATH specified" ) unless ( $path );
97
    Error ("SvnCo: Target path already exists", "Path: " . $path ) if ( -e $path );
98
 
99
    #
100
    #   Build up the command line
101
    #
102
    my @args = $export ? 'export' : 'checkout';
103
    push @args, qw( --ignore-externals );
104
    push @args, $RepoPath, $path;
105
 
106
    my @co_list;
107
    if ( $self->SvnCmd ( @args,
108
                            {
109
                                'process' => \&ProcessCo,
110
                                'data' => \@co_list,
111
                                'credentials' => 1,
112
                                'nosavedata' => 1,
113
                            }
114
                       ) || @co_list )
115
    {
116
        #
117
        #   We have a checkout limitation
118
        #   Delete the workspace and then report the error
119
        #
120
        Verbose2 ("Remove WorkSpace: $path");
121
        rmtree( $path, IsVerbose(3) );
122
        Error ("Checking out Workspace", @{$self->{ERROR_LIST}}, @co_list );
123
    }
124
    return;
125
 
126
    #
127
    #   Internal routine to scan each the checkout
128
    #
129
    #   Due to the structure of a SubVersion repository it would be
130
    #   possible for a user to extract the entire repository. This is
131
    #   not good as the repo could be very very large
132
    #
133
    #   Assume that the structure of the repo is such that our
134
    #   user is not allowed to extract a directory tree that contains
135
    #   key paths - such as /tags/ as this would indicate that they are
136
    #   attempting to extract something that is not a package
137
    #
138
    #
139
    sub ProcessCo
140
    {
141
        my $self = shift;
142
        if (  m~((/)(tags|branches|trunk)(/|$))~ )
143
        {
144
            my $bad_dir = $1;
145
            push @{$self->{ERROR_LIST}}, "Checkout does not describe the root of a package. Contains: $bad_dir";
146
            return 1;
147
        }
148
 
149
        ##
150
        ##   Limit the size of the WorkSpace
151
        ##   This limit is a bit artificial, but does attempt to
152
        ##   limit views that encompass too much.
153
        ##
154
        #if ( $#{$self->{RESULT_LIST}} > 100 )
155
        #{
156
        #    Warning ("View is too large - DEBUG USE ONLY. WILL BE REMOVED" );
157
        #    push @{$self->{ERROR_LIST}}, "View too large";
158
        #    return 1;
159
        #}
160
    }
161
}
162
 
163
#-------------------------------------------------------------------------------
164
# Function        : SvnCi
165
#
166
# Description     : Check in the specified WorkSpace
167
#
168
# Inputs          : $self           - Instance data
169
#                   A hash of named arguments
170
#                       comment     - Commit comment
379 dpurdie 171
#                       allowSame   - Allow no change to the workspace
267 dpurdie 172
#
173
# Returns         : Tag of the checkin
174
#
175
sub SvnCi
176
{
177
    my $self = shift;
178
    my %opt = @_;
179
    my $status_url;
379 dpurdie 180
    my $ws_rev;
267 dpurdie 181
 
182
    Debug ("SvnCi");
183
    Error ("SvnCi: Odd number of args") unless ((@_ % 2) == 0);
184
 
185
    #
186
    #   Validate the source path
187
    #   Note: populates @{$self->{RESULT_LIST}} with 'info' commands
188
    #
189
    my $path = SvnValidateWs ($self, 'SvnCi');
190
 
191
    #
192
    #   Scan the @{$self->{RESULT_LIST}}, which has the results of an 'info'
193
    #   command the locate the URL.
194
    #
195
    #   This contains the target view space
196
    #   Sanity test. Don't allow Checkin to a /tags/ area
197
    #
198
    foreach ( @{$self->{RESULT_LIST}})
199
    {
379 dpurdie 200
        if ( m~^URL:\s+(.+)~ ) {
267 dpurdie 201
            $status_url = $1;
379 dpurdie 202
        } elsif ( m~^Revision:\s+(\d+)~ ) {
203
            $ws_rev = $1;
267 dpurdie 204
        }
379 dpurdie 205
 
206
        last if ( defined $status_url && defined $ws_rev );
267 dpurdie 207
    }
208
 
209
    Error ("SvnCi: Cannot determine Repositoty URL")
210
        unless ( $status_url );
211
 
212
    Error ("SvnCi: Not allowed to commit to a 'tags' area", "URL: $status_url")
213
        if ( $status_url =~ m~/tags(/|$)~ );
214
 
215
    #
216
    #   Commit
217
    #
218
    $self->SvnCmd ( 'commit', $path
219
                    , '-m', SvnComment( $opt{'comment'}, 'Created by SvnCi' ),
220
                    , { 'credentials' => 1,
221
                        'process' => \&ProcessRevNo,
379 dpurdie 222
                        'error' => "SvnCi: Copy Error",
223
                         }
267 dpurdie 224
                        );
379 dpurdie 225
 
226
    #
227
    #   No error and no commit
228
    #   Workspace was not changed, may be allowed
229
    #
230
    if ( ! $self->{REVNO} && $opt{allowSame} )
231
    {
232
        Warning ("SvnCi: Workspace matches Repository. No commit");
233
        $self->{REVNO} = $ws_rev;
234
    }
235
 
267 dpurdie 236
    Error ("SvnCi: Cannot determine Revision Number", @{$self->{RESULT_LIST}})
237
        unless ( $self->{REVNO} );
238
 
239
    #
240
    #   Update the view
241
    #   Doing this so that the local view contains an up to date
242
    #   revision number. If not done, and a 'copy' is done based
243
    #   on this view then the branch information will indicate that
244
    #   the copy is based on an incorrect version.
245
    #   This can be confusing!
246
    #
247
    $self->SvnCmd ( 'update'   , $path
248
                        , '--ignore-externals'
249
                        , { 'credentials' => 1,
250
                            'error' => "SvnCi: Updating WorkSpace" }
251
                        );
252
    #
253
    #   Pass the updated revision number back to the user
254
    #
255
    $self->CalcRmReference($status_url);
379 dpurdie 256
    Message ("Commit Tag is: " . $self->{RMREF} );
267 dpurdie 257
    return $self->{RMREF} ;
258
}
259
 
260
#-------------------------------------------------------------------------------
261
# Function        : SvnCreatePackage
262
#
263
# Description     : Create a package and any associated files
264
#
265
# Inputs          : $self        - Instance data
266
#                   A hash of named arguments
267
#                       package  - Name of the package
268
#                                  May include subdirs
269
#                       new      - True: Must not already exist
270
#                       replace  - True: Replace targets
271
#                       import   - DirTree to import
272
#                       label    - Tag for imported DirTree
273
#                       type     - Import TTB target
274
#
275
# Returns         : Revision of the copy
276
#
277
sub SvnCreatePackage
278
{
279
    my $self = shift;
280
    my %opt = @_;
281
    my $target;
282
 
283
    Debug ("SvnCreatePackage", @_);
284
    Error ("Odd number of args to SvnCreatePackage") unless ((@_ % 2) == 0);
285
    my %dirs = ( 'trunk/'       => 0,
286
                 'tags/'        => 0,
287
                 'branches/'    => 0 );
288
 
289
    #
290
    #   Sanity Tests
291
    #
292
    my $package = $self->Full || Error ("SvnCreatePackage: No package name provided");
293
    Error ("SvnCreatePackage: Invalid import path") if ( $opt{'import'} && ! -d $opt{'import'} );
294
    Error ("SvnCreatePackage: Tag without Import") if ( $opt{'label'} && ! $opt{'import'} );
295
    $opt{'label'} = SvnIsaSimpleLabel( $opt{'label'} ) if (  $opt{'label'} );
296
 
297
    #
298
    #   Package path cannot contain any of the keyword paths tags,trunk,branches
299
    #   as this would place a package with a package
300
    #
301
    Error ("Package path contains a reserved word ($1)", "Path: $package")
302
        if (  $package =~ m~/(tags|branches|trunk)(/|$)~ );
303
 
304
    #
305
    #   Package path cannot be pegged, or look like one
306
    #
307
    Error ("Package name contains a Peg ($1)", "Path: $package")
308
        if ( $package =~ m~.*(@\d+)$~ );
309
 
310
    #
311
    #   Determine TTB target
312
    #
313
    $opt{'type'} = 'trunk' unless ( $opt{'type'} );
314
    Error ("Invalid TTB type") unless ( $opt{'type'} =~ m{^(tags|branches|trunk)$} );
315
    Error ("Import without label") if ( $opt{'type'} ne  'trunk'  && ! $opt{'label'} );
316
 
317
    #
318
    #   Before we import data we must ensure that the targets do not exist
319
    #   Determine the import target(s)
320
    #
321
    my $import_target;
322
    my $copy_target;
323
 
324
    if ( $opt{'import'} )
325
    {
326
        #
327
        #   Primary target
328
        #   trunk, branck or tag
329
        #
330
        $import_target = $package . '/' . $opt{'type'};
331
        $import_target .= '/' .$opt{'label'} if ( $opt{'type'} ne 'trunk');
332
 
333
        $self->SvnValidateTarget( 'target'    => $import_target,
334
                                  'delete'    => $opt{'replace'},
335
                                  'available' => 1 );
336
 
337
        #
338
        #   Secondary target
339
        #   If primary is a trunk and a label is provided
340
        #
341
        if ( $opt{'type'} eq 'trunk' && $opt{'label'} )
342
        {
343
            $copy_target = $package . '/tags/' . $opt{'label'};
344
            $self->SvnValidateTarget( 'target'    => $copy_target,
345
                                      'delete'    => $opt{'replace'},
346
                                      'available' => 1 );
347
        }
348
    }
349
 
350
    #
351
    #   Probe to see if the package exists
352
    #
353
    my ( $ref_files, $ref_dirs, $ref_svn, $found ) = $self->SvnScanPath ( 'SvnCreatePackage', $package );
379 dpurdie 354
 
267 dpurdie 355
    if ( @$ref_dirs )
356
    {
357
        Error ("SvnCreatePackage: Package directory exists",
358
               "Cannot create a package here. Unexpected subdirectories:", @$ref_dirs);
359
    }
360
 
361
    if ( @$ref_files )
362
    {
363
        Warning ("SvnCreatePackage: Unexpected files found",
364
               "Path: $package",
365
               "Unexpected files found: @$ref_files");
366
    }
367
 
368
    if ( @$ref_svn )
369
    {
370
        #
371
        #   Do we need a new one
372
        #
373
        Error ("SvnCreatePackage: Package exists: $package") if $opt{'new'};
374
 
375
        #
376
        #   Some subversion files have been found here
377
        #   Create the rest
378
        #   Assume that the directory tree is good
379
        #
380
        #
381
        #   Some, or all, of the required package subdirectories exist
382
        #   Determine the new ones to created so that it can be done
383
        #   in an atomic step
384
        #
385
        delete $dirs{$_} foreach  ( @$ref_svn );
386
        if ( keys %dirs )
387
        {
388
            Warning ("SvnCreatePackage: Not all package subdirs present",
389
                     "Remaining dirs will be created",
390
                     "Found: @$ref_svn") if @$ref_svn;
391
        }
392
        else
393
        {
394
            Warning ("SvnCreatePackage: Package already present");
395
        }
396
    }
397
 
398
    #
399
    #   Create package directories that have not been discovered
400
    #       trunk
401
    #       branches
402
    #       tags
403
    #
404
    my @dirs;
405
    push @dirs, $package . '/' . $_ foreach ( keys %dirs );
406
    $target = $package . '/trunk';
407
 
408
    #
409
    #   Create missing directories - if any
410
    #
411
    if ( @dirs )
412
    {
413
        $self->SvnCmd ('mkdir', @dirs
379 dpurdie 414
                       , '-m', $self->Path() . ': Created by SvnCreatePackage'
267 dpurdie 415
                       , '--parents'
416
                       , { 'credentials' => 1,
417
                           'error' => "SvnCreatePackage" } );
418
    }
419
 
420
    #
421
    #   Import data into the package if required
422
    #   Import data. Possible cases:
423
    #       - Import to trunk - and then tag it
424
    #       - Import to branches
425
    #       - Import to tags
426
    #
427
    if ( $import_target )
428
    {
429
        Verbose ("Importing directory into new package: $opt{'import'}");
430
 
431
        $target = $import_target;
432
        $self->{PRINTDATA} = 1;
433
        $self->SvnCmd ('import', $opt{'import'}
434
                        , $target
435
                        , '-m', 'Import by SvnCreatePackage'
436
                        , '--force'
437
                        , { 'credentials' => 1
438
                           ,'error' => "Import Incomplete"
439
                           ,'process' => \&ProcessRevNo
440
                          })
441
    }
442
 
443
    #
444
    #   If imported to the trunk AND a label is provided
445
    #   then tag the import as well.
446
    #   A simple URL copy
447
    #
448
    if ( $copy_target )
449
    {
450
        Verbose ("Labeling imported trunk: $opt{'label'} ");
451
        $target = $copy_target;
452
        $self->SvnCmd ('copy'  , $import_target
453
                        , $target
454
                        , '-m', 'Import tagged by SvnCreatePackage'
455
                        , { 'credentials' => 1
456
                          , 'process' => \&ProcessRevNo
457
                          , 'error' => "Import Incomplete" } );
458
    }
459
 
460
    #
461
    #   Pass the updated revision number back to the user
462
    #
463
    $self->CalcRmReference($target);
379 dpurdie 464
    Message ("Create Package Tag is: " . $self->{RMREF} );
267 dpurdie 465
    return $self->{RMREF} ;
466
}
467
 
468
#-------------------------------------------------------------------------------
469
# Function        : SvnRmView
470
#
471
# Description     : Remove a Subversion view
472
#                   Will run sanity checks and only remove the view if
473
#                   all is well
474
#
475
# Inputs          : A hash of named arguments
476
#                       path     - Path to local workspace
477
#                       modified - Array of files that are allowed to be modified
478
#                       force    - True: Force deletion
479
#
480
# Returns         :
481
#
482
sub SvnRmView
483
{
484
    my %opt = @_;
485
    Debug ("SvnRmView");
486
    Error ("Odd number of args to SvnRmView") unless ((@_ % 2) == 0);
487
 
488
    #
489
    #   Sanity test
490
    #
491
    my $path = $opt{'path'} || '';
492
    my $path_length = length ($path);
493
    Verbose2 ("Delete WorkSpace: $path");
494
 
495
    #
496
    #   If the path does not exist then assume that its already deleted
497
    #
498
    unless ( $path && -e $path )
499
    {
500
        Verbose2 ("SvnRmView: Path does not exist");
501
        return;
502
    }
503
 
504
    #
505
    #   Create information about the workspace
506
    #   This will also validate the path
507
    #
361 dpurdie 508
    my $session = NewSessionByWS ( $path, 0, 1 );
267 dpurdie 509
 
510
    #
511
    #   Validate the path
512
    #
513
    $session->SvnValidateWs ($path, 'SvnRmView');
514
 
515
    #
516
    #   Ask subversion if there are any files to be updated
517
    #   Prevent deletion of a view that has modified files
518
    #
519
    unless ( $opt{'force'} )
520
    {
521
        $session->SvnWsModified ( 'cmd' => 'SvnRmView', %opt );
522
    }
523
 
524
    #
525
    #   Now we can delete it
526
    #
527
    Verbose2 ("Remove WorkSpace: $path");
528
    rmtree( $path, IsVerbose(3) );
529
}
530
 
531
 
532
#-------------------------------------------------------------------------------
533
# Function        : SvnCopyWs
534
#
535
# Description     : Copy a workspace to a new place in the repository
536
#                   Effectively 'label' the workspace
537
#
538
#                   It would appear that the 'copy' command is very clever
539
#                   If a version-controlled file has been changed
540
#                   in the source workspace, then it will automatically be
541
#                   copied. This is a trap.
542
#
543
#                   Only allow a 'copy' if there are no modified
544
#                   files in the work space (unless overridden)
545
#
546
#
547
# Inputs          : $self        - Instance data
548
#                   A hash of named arguments
549
#                       path     - Path to local workspace
550
#                       target   - Location within the repository to copy to
551
#                       comment  - Commit comment
552
#                       modified - Array of files that are allowed to
553
#                                  be modified in the workspace.
554
#                       noswitch  - True: Don't switch to the new URL
555
#                       replace   - True: Delete existing tag if present
556
#
557
# Returns         : Revision of the copy
558
#
559
sub SvnCopyWs
560
{
561
    my $self = shift;
562
    my %opt = @_;
563
    Debug ("SvnCopyWs");
564
    Error ("Odd number of args to SvnCopyWs") unless ((@_ % 2) == 0);
565
    Error ("SvnCopyWs: No Workspace" ) unless ( $self->{WS} );
566
 
567
    #
568
    #   Insert defaults
569
    #
570
    my $target = $opt{target} || Error ("SvnCopyWs: Target not specified" );
571
 
572
    #
573
    #   Validate the source path
574
    #
575
    my $path = SvnValidateWs ($self, 'SvnCopyWs');
576
 
577
    #
578
    #   Validate the target
579
    #   Cannot have a 'peg'
580
    #
581
    Error ("SvnCopyWs: Target contains a Peg: ($1)", $target)
582
        if ( $target =~ m~(@\d+)\s*$~ );
583
 
584
    #
585
    #   Examine the workspace and ensure that there are no modified
586
    #   files - unless they are expected
587
    #
588
    $self->SvnWsModified ( 'cmd' => 'SvnCopyWs', %opt );
589
 
590
    #
591
    #   Validate the repository
592
    #   Ensure that the target does not exist
593
    #   The target may be deleted if it exists and allowed by the user
594
    #
595
    $self->SvnValidateTarget ( 'cmd'    => 'SvnCopyWs',
596
                        'target' => $target,
597
                        'delete' => $opt{replace},
598
                        'comment' => 'Deleted by SvnCopyWs'
599
                        );
369 dpurdie 600
 
267 dpurdie 601
    #
602
    #   Copy source to destination
603
    #   It would appear that even though the source is a WorkSpace, the copy
604
    #   does not transfer data from the WorkSpace. It appears as though its all
605
    #   done on the server. This is good - and fast.
606
    #
607
    #   More over files that are modified in the local workspace will
608
    #   be copied and checked into the target.
609
    #
610
    if ( $self->SvnCmd ( 'cp'  , $path
611
                        , $target
612
                        , '--parents'
613
                        , '-m', SvnComment( $opt{'comment'}, 'Created by SvnCopyWs' ),
614
                        , { 'process' => \&ProcessRevNo,
615
                            'credentials' => 1, }
616
                        ) )
617
    {
618
        #
619
        #   Error in copy
620
        #   Attempt to delete the target. Don't worry if we can't do that
621
        #
622
        my @err1 = @{$self->{ERROR_LIST}};
623
        $self->SvnCmd ( 'delete'
624
                    , $target
625
                    , '-m', 'Deleted by SvnCopyWs after creation failure'
626
                    , { 'credentials' => 1, }
627
               );
628
        Error ("SvnCopyWs: Copy Error", @err1);
629
    }
630
 
631
    Error ("SvnCopyWs: Cannot determine Revision Number", @{$self->{RESULT_LIST}})
632
        unless ( $self->{REVNO} );
633
 
634
    Verbose2 ("Copy committed as revision: " . $self->{REVNO} );
635
 
636
    unless ( $opt{'noswitch'} )
637
    {
638
        #
639
        #   Switch to the new URL
640
        #   This will link the Workspace with the copy that we have just made
641
        #
642
        $self->SvnCmd ( 'switch', $target
643
                         , $path
644
                         , { 'credentials' => 1,
645
                             'error' => "SvnCopyWs: Cannot switch to new URL" }
646
               );
647
    }
648
 
649
    #
650
    #   Pass the updated revision number back to the user
651
    #
652
    $self->CalcRmReference($target );
353 dpurdie 653
    #Message ("Tag is: " . $self->{RMREF} );
267 dpurdie 654
    return $self->{RMREF} ;
655
}
656
 
657
#-------------------------------------------------------------------------------
658
# Function        : SvnWsModified
659
#
660
# Description     : Test a Workspace for modified files
661
#                   Allow some files to be modified
662
#
663
# Inputs          : $self           - Instance data
664
#                   A hash of named arguments
665
#                       path        - Path to local workspace
666
#                       modified    - Files that are allowed to be modified
667
#                                     Relative to the 'path'
668
#                                     May be a single file or an array of files
669
#                       cmd         - Command name for error reporting
670
#
671
# Returns         :
672
#
673
sub SvnWsModified
674
{
675
    my $self = shift;
676
    my %opt = @_;
677
    Debug ("SvnWsModified");
678
    Error ("Odd number of args to SvnWsModified") unless ((@_ % 2) == 0);
679
 
680
    my $cmd = $opt{'cmd'} || 'SvnWsModified';
681
 
682
    #
683
    #   Validate the path
684
    #
685
    SvnValidateWs ($self, $cmd);
686
    my $path = $self->{WS};
687
    my $path_length = length ($path);
688
    Verbose2 ("Test Workspace for Modifications: $path");
689
 
690
    #
691
    #   Ask subversion if there are any files to be updated
692
    #
693
    $self->SvnCmd ('status', $path, {'error' => "Svn status command error"} );
694
 
695
    #
696
    #   Examine the list of modified files
697
    #
698
    if ( @{$self->{RESULT_LIST}} )
699
    {
700
        #
351 dpurdie 701
        #   Create a hash of files that are allowed to change
267 dpurdie 702
        #   These are files relative to the base of the view
703
        #
704
        #   The svn command has the 'path' prepended, so this
705
        #   will be removed as we process the commands
706
        #
707
        my %allowed;
708
        my @unexpected;
709
 
710
        if ( exists $opt{'modified'}  )
711
        {
712
            $allowed{'/' . $_} = 1 foreach ( ref ($opt{'modified'}) ? @{$opt{'modified'}} : $opt{'modified'}  );
713
        }
714
 
715
        #
716
        #   Process the list of modified files
717
        #   Do this even if we aren't allowed modified files as we
718
        #   still need to examine the status and kill off junk entries
719
        #   ie: ?, I, ! and ~
720
        #
721
        #    First column: Says if item was added, deleted, or otherwise changed
722
        #      ' ' no modifications
723
        #      'A' Added
724
        #      'C' Conflicted
725
        #      'D' Deleted
726
        #      'I' Ignored
727
        #      'M' Modified
728
        #      'R' Replaced
729
        #      'X' item is unversioned, but is used by an externals definition
730
        #      '?' item is not under version control
731
        #      '!' item is missing (removed by non-svn command) or incomplete
732
        #      '~' versioned item obstructed by some item of a different kind
733
        #
734
        foreach my $entry ( @{$self->{RESULT_LIST}} )
735
        {
736
            #
737
            #   Extract filename from line
351 dpurdie 738
            #       First 8 chars are status
267 dpurdie 739
            #       Remove WS path too
740
            #
351 dpurdie 741
            my $file = substr ( $entry, 8 + $path_length );
267 dpurdie 742
            next if ( $allowed{$file} );
743
 
744
            #
745
            #   Examine the first char and rule out funny things
746
            #
747
            my $f1 =  substr ($entry, 0,1 );
748
            next if ( $f1 =~ m{[?I!~]} );
749
            push @unexpected, $entry;
750
        }
751
        Error ("Workspace contains unexpected modified files", @unexpected)
752
            if ( @unexpected );
753
    }
754
}
755
 
756
#-------------------------------------------------------------------------------
757
# Function        : SvnListPackages
758
#
759
# Description     : Determine a list of packages within the repo
760
#                   This turns out to be a very slow process
761
#                   so don't use it unless you really really need to
762
#
763
# Inputs          : $repo       - Name of the repository
764
#
765
# Returns         : 
766
#
767
sub SvnListPackages
768
{
769
    my ($repo) = @_;
770
 
771
    my @path_list = $repo;
772
    my @list;
773
    my $scanned = 0;
774
    Debug ("SvnListPackages");
775
    while ( @path_list )
776
    {
777
        my $path = shift @path_list;
778
        $scanned++;
779
print "Reading: $path\n";
780
        my ( $ref_files, $ref_dirs, $ref_svn, $found ) = SvnScanPath ( 'Listing Packages', $path );
781
 
782
        #
783
        #   If there are Subversion dirs (ttb) in this directory
784
        #   then this is a package. Add to list
785
        #
786
        push @list, $path if ( @$ref_svn );
787
 
788
        #
789
        #   Add subdirs to the list of paths to explore
790
        #
791
        foreach  ( @$ref_dirs )
792
        {
793
            chop;                                 # Remove trailing '/'
794
            push @path_list, $path . '/' . $_;    # Extend the path
795
        }
796
    }
797
 
798
    Message ("Found:", @list );
799
    Message ("Dirs Scanned: $scanned");
800
    Message ("Packages Found: $#list");
801
}
802
 
803
#-------------------------------------------------------------------------------
804
# Function        : ListLabels
805
#
806
# Description     : List labels within a given package
807
#
808
# Inputs          : $self               - Instance data
809
#                   $path               - path to label source
810
#
811
# Returns         : Ref to an array
812
#
813
sub ListLabels
814
{
815
    my ($self, $path) = @_;
816
    Debug ("ListLabels");
817
 
818
    my ( $ref_files, $ref_dirs, $ref_svn, $found ) = $self->SvnScanPath ( 'Listing Versions', $path );
819
 
820
    Error ("List: Path not found: $path") unless ( $found );
821
 
822
    #
823
    #   Dont report files - just directories
824
    #
825
    return $ref_dirs;
826
}
827
 
828
 
829
#-------------------------------------------------------------------------------
830
# Function        : SvnLocateWsRoot
831
#
832
# Description     : Given a WorkSpace, determine the root of the work space
833
#                   This is not as simple as you might think
834
#
835
#                   Algorithm
836
#                       svn ls ..
837
#                       Am I in the parent directory
838
#                       Repeat
839
#
369 dpurdie 840
#                   Updates 'WS' and 'WSURL'
841
#
267 dpurdie 842
# Inputs          : $self               - Instance data
843
#                   $test               - True: Don't die on error
844
#
845
# Returns         : Root of workspace as an absolute address
846
#                   Will not return if there is an error
847
#
848
sub SvnLocateWsRoot
849
{
850
    my ($self, $test) = @_;
851
    my @path;
852
    my $path = $self->{WS};
853
 
854
    Debug ("SvnLocateWsRoot");
855
    Error ("SvnLocateWsRoot: No Workspace") unless ( $path  );
856
    Verbose2 ("SvnLocateWsRoot: Start in $path");
857
 
858
    #
859
    #   Validate the source path
860
    #
861
    if ( SvnValidateWs ($self, 'SvnLocateWsRoot', $test) )
862
    {
863
        return undef;
864
    }
865
 
866
    #
867
    #   Need to sanitize the users path to ensure that the following
868
    #   algorithm works. Need:
869
    #       1) Absolute Path
870
    #       2) Not ending in '/'
871
    #
872
 
873
    #
874
    #   If we have a relative path then prepend the current directory
875
    #   An absolute path is:
876
    #           /aaa/aa/aa
877
    #       or  c:/aaa/aa/aa
878
    #
879
    $path = getcwd() . '/' . $path
880
        unless ( $path =~ m~^/|\w:/~  );
881
 
882
    #
883
    #   Walk the bits and remove ".." directories
884
    #       Done by pushing non-.. elements and poping last entry for .. elements.
885
    #   Have a leading "/" which is good.
886
    #
887
    #   Create a array of directories in the path
888
    #   Split on one or more \ or / separators
889
    #
890
    foreach ( split /[\\\/]+/ , $path )
891
    {
892
        next if ( $_ eq '.' );
893
        unless ( $_ eq '..' )
894
        {
895
            push @path, $_;
896
        }
897
        else
898
        {
899
            Error ("SvnLocateWsRoot: Bad Pathname: $path")
900
                if ( $#path <= 0 );
901
            pop @path;
902
        }
903
    }
904
 
369 dpurdie 905
    #
906
    #   Need to adjust the WSURL too
907
    #   Break into parts and pop them off as we go
908
    #   Add a dummy one to allow for the first iteration
909
    #
910
    my @wsurl = (split (/[\\\/]+/ , $self->{WSURL}), 'Dummy');
911
 
267 dpurdie 912
    Verbose2 ("Clean absolute path elements: @path");
913
    PATH_LOOP:
914
    while ( @path )
915
    {
916
        #
917
        #   This directory element. Append / to assist in compare
918
        #   Determine parent path
919
        #
920
        my $name = pop (@path) . '/';
921
        my $parent = join ('/', @path );
369 dpurdie 922
        pop @wsurl;
267 dpurdie 923
 
924
        #
925
        #   Examine the parent directory
926
        #   Get a list of all elements in the parent
927
        #   Need to ensure that this directory is one of them
928
        #
929
        #   Ignore any errors - assume that they are because the
930
        #   parent is not a part of the work space. This will terminate the
931
        #   search.
932
        #
933
        $self->SvnCmd ('list', $parent, '--depth', 'immediates' );
934
        foreach my $entry ( @{$self->{RESULT_LIST}} )
935
        {
936
            next PATH_LOOP
937
                if ( $entry eq $name );
938
        }
939
 
940
        #
941
        #   Didn't find 'dir' in directory svn listing of parent
942
        #   This parent is not a part of the same WorkSpace as 'dir'
943
        #   We have a winner.
944
        #
945
        chop $name;                         #   Chop the '/' previously added
946
        $self->{WS} = $parent . '/' . $name;
369 dpurdie 947
 
948
        #
949
        #   Reform the WSURL. Elements have been removed as we tested up the
950
        #   path
951
        #
952
        $self->{WSURL} = join '/', @wsurl;
953
 
267 dpurdie 954
        return $self->{WS};
955
    }
956
 
957
    #
958
    #   Shouldn't get this far
959
    #
960
    Error ("SvnLocateWsRoot: Root not found");
961
}
962
 
963
#-------------------------------------------------------------------------------
964
# Function        : SvnValidateWs
965
#
966
# Description     : Validate the path to a working store
967
#
968
# Inputs          : $self           - Instance data
969
#                   $user           - Optional prefix for error messages
970
#                   $test           - True: Just test, Else Error
971
#
972
# Returns         : Will not return if not a workspace
973
#                   Returns the users path
974
#                   @{$self->{RESULT_LIST}} will be populated with info about the
975
#                   item requested as per an 'info' call
976
#
977
sub SvnValidateWs
978
{
979
    my ($self, $user, $test) = @_;
980
    Debug ("SvnValidateWs");
981
 
982
    $user = "Invalid Subversion Workspace" unless ( $user );
983
    my $path = $self->{WS} ;
984
 
985
    #
986
    #   Only validate it one
987
    #
988
    return $path if ( $self->{WS_VALIDATED} );
989
 
990
    #
991
    #   Validate the source path
992
    #   Must exist and must be a directory
993
    #
994
    if ( ! $path ) {
995
        @{$self->{ERROR_LIST}} = "$user: No path specified";
996
 
997
    } elsif ( ! -e $path ) {
998
        @{$self->{ERROR_LIST}} = "$user: Path does not exist: $path";
999
 
1000
    } elsif ( ! -d $path ) {
1001
        @{$self->{ERROR_LIST}} = "$user: Path is not a directory";
1002
    } else {
1003
        #
1004
        #   Determine the source path is an fact a view
1005
        #   The info command can do this. Use depth empty to limit the work done
1006
        #
1007
        $self->SvnCmd ('info', $path, '--depth', 'empty' );
1008
 
1009
        #
1010
        #   Error. Prepend nice message
1011
        #
1012
        unshift @{$self->{ERROR_LIST}}, "$user: Path is not a WorkSpace: $path"
1013
            if ( @{$self->{ERROR_LIST}} );
1014
    }
1015
 
1016
    #
1017
    #   Figure out what to do
1018
    #
1019
    if ( $test )
1020
    {
1021
        return @{$self->{ERROR_LIST}};
1022
    }
1023
    else
1024
    {
1025
        Error @{$self->{ERROR_LIST}} if @{$self->{ERROR_LIST}};
1026
        $self->{WS_VALIDATED} = 1;
1027
        return $path;
1028
    }
1029
}
1030
 
1031
#-------------------------------------------------------------------------------
1032
# Function        : SvnValidatePackageRoot
1033
#
1034
# Description     : Validate a package root
1035
#
1036
# Inputs          : $self           - Instance data
1037
#
1038
# Returns         : Will only return if valid
1039
#                   Returns a cleaned package root
1040
#
1041
sub SvnValidatePackageRoot
1042
{
379 dpurdie 1043
    my ($self, $warning_only) = @_;
267 dpurdie 1044
    Debug ("SvnValidatePackageRoot");
1045
    my $url = $self->Full || Error ("SvnValidatePackageRoot: No URL");
1046
 
1047
    Error ("Package path contains a reserved word ($self->{TAGTYPE})", "Path: $url")
1048
        if (  $self->{TAGTYPE} );
1049
 
1050
    Error ("Package name contains a Peg ($self->{PEG})", "Path: $url")
1051
        if ( $self->{PEG} );
1052
 
1053
    #
1054
    #   Ensure that the target path does exist
1055
    #   Moreover it needs to be a directory and it should have a
1056
    #   a ttb structure
1057
    #
1058
    my ( $ref_files, $ref_dirs, $ref_svn, $found ) = $self->SvnScanPath ( 'Package Base Test', $url );
1059
 
1060
    #
379 dpurdie 1061
    #   Only looking for package path
1062
    #
1063
    if ( !$found && $warning_only )
1064
    {
1065
        return $url;
1066
    }
1067
 
1068
    #
267 dpurdie 1069
    #   Examine the results to see if we have a valid package base
1070
    #
1071
    Error ("Package Base Test: Not a valid package") unless ( $found );
1072
 
1073
    #
1074
    #   Extra bits found
1075
    #   Its not the root of a package
1076
    #
1077
    if ( @$ref_files )
1078
    {
1079
        Warning ("Package Base Test: Files exists",
1080
               "Unexpected files found:", @$ref_files );
1081
    }
1082
 
1083
    #
1084
    #   Need a truck directory
1085
    #   If we don't have a truck we don't have a package
1086
    #
1087
    my $trunk_found = grep ( /trunk\//, @$ref_svn );
1088
    Error ("Invalid Package Base. Does not contain a 'trunk' directory")
1089
        unless ( $trunk_found );
1090
 
1091
    return $url;
1092
}
1093
 
1094
 
1095
#-------------------------------------------------------------------------------
1096
# Function        : SvnIsaSimpleLabel
1097
#
1098
# Description     : Check a label
1099
#                       Must not contain a PEG
1100
#                       Must not contain invalid characters (@ or /)
1101
#                       Must not contain a :: sequence (will confuse other tools)
1102
#                       Handle special label of TIMESTAMP
1103
#
1104
# Inputs          : $label          - to test
1105
#
1106
# Returns         : Will not return on error
1107
#                   Returns label on success
1108
#
1109
sub SvnIsaSimpleLabel
1110
{
1111
    my ($label) = @_;
1112
    Debug ("SvnIsaSimpleLabel, $label");
1113
 
1114
    Error ("No label provided") unless ( $label );
1115
    Error ("Invalid label. Peg (\@nnn) is not allowed: \"$label\"" ) if ( $label =~ m~@\d+$~ );
1116
    Error ("Invalid label. Package Path is not allowed: \"$label\"" ) if ( $label =~ m~/~ );
383 dpurdie 1117
    Error ("Invalid label. Invalid Start Character: \"$label\"" ) unless ( $label =~ m~^[0-9a-zA-Z]~ );
1118
    Error ("Invalid label. Invalid End Character: \"$label\"" ) unless ( $label =~ m~[0-9a-zA-Z]$~ );
267 dpurdie 1119
    Error ("Invalid label. Invalid Characters: \"$label\"" ) unless ( $label =~ m~^[-.:0-9a-zA-Z_]+$~ );
1120
    Error ("Invalid label. Double :: not allowed: \"$label\"" ) if ( $label =~m~::~ );
1121
 
1122
    #
1123
    #   Allow for a label of TIMESTAMP and have it expand
383 dpurdie 1124
    #   Create a label based on users name and a date-time that can be sorted
267 dpurdie 1125
    #
1126
    if ( $label eq 'TIMESTAMP' )
1127
    {
341 dpurdie 1128
        ::EnvImport ('USER' );
1129
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
1130
        $label = sprintf("%s_%4.4u.%2.2u.%2.2u.%2.2u%2.2u%2.2u",
1131
            $::USER, $year+1900, $mon+1, $mday, $hour, $min, $sec );
267 dpurdie 1132
    }
1133
    return $label;
1134
}
1135
 
1136
#-------------------------------------------------------------------------------
1137
# Function        : NewSession
1138
#
1139
# Description     : Create a new empty SvnSession Class
1140
#
1141
# Inputs          : None
1142
#
1143
# Returns         : Class
1144
#
1145
sub NewSession
1146
{
1147
    Debug ("NewSession");
1148
    my $self  = SvnSession();
1149
 
1150
    #
1151
    #   Document Class Variables
1152
    #
1153
    $self->{URL} = '';                  # Repo URL prefix
1154
    $self->{WS}  = '';                  # Users WorkSpace
1155
    $self->{PROTOCOL} = '';             # Named Access Protocol
1156
    $self->{PKGROOT} = '';              # Package root
1157
 
1158
    #
1159
    #   Create a class
1160
    #   Bless my self
1161
    #
1162
    bless ($self, __PACKAGE__);
1163
    return $self;
1164
}
1165
 
1166
#-------------------------------------------------------------------------------
1167
# Function        : NewSessionByWS
1168
#
1169
# Description     : Establish a new SVN Session based on a Workspace
1170
#                   Given a workspace path determine the SvnServer and other
1171
#                   relevent information.
1172
#
1173
#                   Requires some rules
1174
#                       * The package is rooted within a 'ttb'
1175
#
1176
# Inputs          : $path                   - Path to WorkSpace
1177
#                   $test                   - No Error on no WS
361 dpurdie 1178
#                   $slack                  - Less stringent
267 dpurdie 1179
#
1180
# Returns         : Ref to Session Information
1181
#
1182
sub NewSessionByWS
1183
{
361 dpurdie 1184
    my ($path, $test, $slack) = @_;
267 dpurdie 1185
    Debug ("NewSessionByWS", @_);
1186
 
1187
    #
1188
    #   Create a basic Session
1189
    #   Populate it with information that is known
1190
    #
1191
    my $self = NewSession();
1192
    $self->{WS} = $path;
1193
 
1194
    #
1195
    #   Validate the path provided
1196
    #   In the process populate the @{$self->{RESULT_LIST}} with information
1197
    #   about the workspace.
1198
    #
1199
    if ($self->SvnValidateWs ( undef, 1) )
1200
    {
1201
        return $self if ( $test );
1202
        Error ( @{$self->{ERROR_LIST}} );
1203
    }
1204
 
1205
    #
1206
    #   Extract useful info
1207
    #       URL: svn://auperaws996vm21/test/MixedView/trunk
1208
    #       Repository Root: svn://auperaws996vm21/test
1209
    #
1210
    my $url;
1211
    my $reporoot;
369 dpurdie 1212
    my $repoVersion;
267 dpurdie 1213
 
1214
    foreach ( @{$self->{RESULT_LIST}} )
1215
    {
1216
        $url = $1 if ( m~^URL:\s+(.+)~ );
1217
        $reporoot = $1 if ( m~^Repository Root:\s+(.+)~ );
369 dpurdie 1218
        $repoVersion = $1 if ( m~^Revision:\s+(.+)~ );
1219
        last if ( $url && $reporoot && $repoVersion);
267 dpurdie 1220
    }
1221
    Error ("JatsSvn Internal error. Can't parse info")
1222
        unless ( $url && $reporoot );
1223
 
1224
    #
1225
    #   Need the length of the path to the repository
1226
    #   but not the name of the repostory itself.
1227
    #
1228
    #   Remove that from the head of the URL to give a
1229
    #   path within the repository, that includes the repos name
1230
    #
1231
    $reporoot = (fileparse( $reporoot ))[1];
1232
    $url = substr ($url, length ($reporoot));
1233
    $self->{WSURL} = $url;
1234
    chop $reporoot;
1235
 
1236
    Verbose2 ("SvnLocatePackageRoot: $reporoot, $url" );
1237
 
1238
    #
1239
    #   Remove anything after a ttb ( truck, tags, branch ) element
1240
    #   This will be the root of the package within the repo
1241
    #
1242
    if (  $url =~ m~(.+)/((tags|branches|trunk)(/|$).*)~ )
1243
    {
1244
        $url = $1;
1245
        $self->{WSTYPE} = $3;
1246
    }
1247
    else
1248
    {
361 dpurdie 1249
        #
1250
        #   If we are being slack (ie deleting the workspace)
1251
        #   Then generate a warning, not an error
1252
        #
1253
        my $fnc = $slack ? \&Warning : \&Error;
1254
        $fnc->("SvnLocatePackageRoot. Non standard repository format",
1255
               "Url must contain 'tags' or 'branches' or 'trunk'",
267 dpurdie 1256
               "Url: $url");
361 dpurdie 1257
        $self->{WSTYPE} = 'trunk';
267 dpurdie 1258
    }
1259
 
1260
    #
1261
    #   Insert known information
1262
    #
1263
    $self->{URL} = $reporoot . '/';
1264
    $self->{PKGROOT} = $url;
369 dpurdie 1265
    $self->{WSREVNO} = $repoVersion;
267 dpurdie 1266
 
1267
    #
1268
    #   Create useful information
1269
    #
1270
    SplitPackageUrl($self);
1271
    return $self;
1272
}
1273
 
1274
#-------------------------------------------------------------------------------
1275
# Function        : NewSessionByUrl
1276
#
1277
# Description     : Establish a new SVN Session based on a user URL
1278
#
1279
# Inputs          : $uurl                   - Users URL
361 dpurdie 1280
#                   $ttb_test               - Test and warn for TTB structure
267 dpurdie 1281
#                   $session                - Optional: Existing session
1282
#
1283
# Returns         : Ref to Session Information
1284
#
1285
sub NewSessionByUrl
1286
{
361 dpurdie 1287
    my ($uurl, $ttb_test, $self ) = @_;
267 dpurdie 1288
    Debug ("NewSessionByUrl", @_);
1289
    Error ("No Repostory Path specified") unless ( $uurl );
1290
 
1291
    #
1292
    #   Create a basic Session
1293
    #   Populate it with information that is known
1294
    #
1295
    $self = NewSession() unless ( $self );
1296
 
1297
    #
369 dpurdie 1298
    #   Examine the URL and convert a Repository Path into a URL
353 dpurdie 1299
    #   as provided by configuration information within the environment
267 dpurdie 1300
    #
361 dpurdie 1301
    ($self->{URL}, $self->{PKGROOT} ) = SvnPath2Url ($uurl);
1302
 
1303
    #
1304
    #   Create useful information
1305
    #
1306
    SplitPackageUrl($self);
1307
 
1308
    #
1309
    #   Warn of non-standard URLs
1310
    #   These may create problems latter
1311
    #
1312
    if ( $ttb_test )
1313
    {
1314
        Warning("Non standard repository format",
1315
                 "Url should contain 'tags' or 'branches' or 'trunk'",
1316
                 "Url: $self->{PKGROOT}") unless $self->{TAGTYPE};
1317
    }
1318
 
1319
    return $self;
1320
}
1321
 
1322
#-------------------------------------------------------------------------------
1323
# Function        : SvnPath2Url
1324
#
1325
# Description     : Convert a repository path to a Full Url
1326
#                   Also handles Full Url
1327
#
1328
# Inputs          : $rpath             - Repository Path
1329
#                                        May be a full URL
1330
#
1331
# Returns         : List context
1332
#                   Two items that can be joined
1333
#                   URL                - URL
1334
#                   PKG_ROOT           - Package Root
1335
#
1336
#                   Scalar context: Joined URL and Package Root
1337
#                                   Fully formed URL
1338
#
1339
sub SvnPath2Url
1340
{
1341
    my ($rpath) = @_;
1342
    my $processed = 0;
1343
    my $url;
1344
    my $pkgroot;
1345
 
1346
    #
1347
    #   Examine the argument and convert a Repository Path into a URL
1348
    #   as provided by configuration information within the environment
1349
    #
1350
    $rpath =~ m~(.+?)/(.*)~;
1351
    my $fe = $1 || $rpath;
353 dpurdie 1352
    my $rest = $2 || '';
361 dpurdie 1353
 
353 dpurdie 1354
    if ( $SVN_URLS{$fe} )
267 dpurdie 1355
    {
361 dpurdie 1356
        $url = $SVN_URLS{$fe};
1357
        $pkgroot = $rest;
353 dpurdie 1358
        $processed = 1;
341 dpurdie 1359
    }
1360
 
353 dpurdie 1361
    if ( ! $processed )
341 dpurdie 1362
    {
267 dpurdie 1363
        #
353 dpurdie 1364
        #   Examine the URL and determine if we have a FULL Url or
1365
        #   a path within the 'default' server
1366
        #
1367
        foreach my $key ( @SVN_URLS_LIST )
1368
        {
361 dpurdie 1369
            if ( $rpath =~ m~^$SVN_URLS{$key}(.*)~ )
353 dpurdie 1370
            {
361 dpurdie 1371
                $url = $SVN_URLS{$key};
1372
                $pkgroot = $1;
353 dpurdie 1373
                $processed = 1;
1374
                last;
1375
            }
1376
        }
1377
    }
267 dpurdie 1378
 
353 dpurdie 1379
    #
1380
    #   Last attempt
1381
    #   Treat as a raw URL - some operations won't be allowed
1382
    #
1383
    if ( ! $processed )
267 dpurdie 1384
    {
361 dpurdie 1385
        if ( $rpath =~ m~^((file|http|https|svn):///?([^/]+)/)(.+)~ )
353 dpurdie 1386
        {
1387
            #       http://server/
1388
            #       https://server/
1389
            #       svn://server/
1390
            #       file://This/Isa/Bad/Guess
1391
            #
361 dpurdie 1392
            $url = $1;
1393
            $pkgroot = $4;
353 dpurdie 1394
        }
369 dpurdie 1395
        elsif ($SVN_URLS{''} )
353 dpurdie 1396
        {
361 dpurdie 1397
            $url = $SVN_URLS{''};
1398
            $pkgroot = $rpath;
353 dpurdie 1399
        }
1400
        else
1401
        {
1402
            #
1403
            #   User default (site configured) Repo Root
1404
            #
1405
            Error ("No site repository configured for : $fe",
1406
                   "Configure GBE_SVN_URL_" . uc($fe) );
1407
        }
267 dpurdie 1408
    }
1409
 
1410
    #
361 dpurdie 1411
    #   May want two elements, may want one
267 dpurdie 1412
    #
361 dpurdie 1413
    return $url, $pkgroot if ( wantarray );
1414
    return $url . $pkgroot;
267 dpurdie 1415
}
1416
 
369 dpurdie 1417
#-------------------------------------------------------------------------------
1418
# Function        : SvnPaths
1419
#
1420
# Description     : Extract SVN path conversion information
1421
#
1422
# Inputs          : Nothing
1423
#
1424
# Returns         : Two refs
1425
#                   Hash of SVN URLS
1426
#                   Array for search order
1427
#
1428
sub SvnPaths
1429
{
1430
    return \%SVN_URLS, \@SVN_URLS_LIST;
1431
}
361 dpurdie 1432
 
267 dpurdie 1433
#-------------------------------------------------------------------------------
1434
# Function        : SplitPackageUrl
1435
#
1436
# Description     : Slip the package URL into a few useful bits
1437
#
1438
# Inputs          : $self           - Instance data
1439
#
1440
# Returns         : Nothing
1441
#
1442
sub SplitPackageUrl
1443
{
1444
    my ($self) = @_;
353 dpurdie 1445
    Debug ("SplitPackageUrl", $self->{URL}, $self->{PKGROOT});
267 dpurdie 1446
 
1447
    #
1448
    #   Remove any protocol that may be present
1449
    #       http://server/
341 dpurdie 1450
    #       https://server/
267 dpurdie 1451
    #       svn://server/
1452
    #       file://This/Isa/Bad/Guess
1453
    #
341 dpurdie 1454
    if ( $self->{URL} =~ m~^(file|http|https|svn)://([^/]+)~ )
267 dpurdie 1455
    {
1456
        $self->{PROTOCOL} = $1;
1457
        $self->{SERVER} = $2;
1458
    }
1459
 
1460
    if ( $self->{PKGROOT} =~ m~(.*)(@\d+)$~ )
1461
    {
1462
        $self->{PEG} = $2;
1463
    }
1464
 
1465
    #
1466
    #   Determine TTB type
1467
    #   Need to handle
1468
    #       .../trunk
1469
    #       .../trunk@nnnnn
1470
    #       .../tags/version@nnnnn
1471
    #       .../branches/version@nnnnn
1472
    #
1473
    #
1474
    if (  $self->{PKGROOT} =~ m~/?(.*)/(tags|branches|trunk)(/|$|@)(.*)$~ )
1475
    {
1476
        $self->{PATH}         = $1;
1477
        $self->{TAGTYPE}      = $2;
1478
        $self->{VERSION}      = $4;
1479
    }
1480
    else
1481
    {
1482
        $self->{PATH} = $self->{PKGROOT};
1483
    }
1484
 
1485
    DebugDumpData ('SplitPackageUrl', $self ) if ( IsDebug(2) );
1486
}
1487
 
1488
#-------------------------------------------------------------------------------
1489
# Function        : Full
1490
#                   FullWs
1491
#                   Repo
1492
#                   Peg
1493
#                   Type
1494
#                   WsType
1495
#                   Path
1496
#                   Version
1497
#                   RmRef
1498
#
1499
# Description     : Accessor functions
1500
#
1501
# Inputs          : $self       - Instance data
1502
#                                 self (is $_[0])
1503
#
1504
# Returns         : Data Item
1505
#
369 dpurdie 1506
sub Full        { return $_[0]->{URL} . $_[0]->{PKGROOT} ; }
1507
sub FullWs      { return $_[0]->{URL} . $_[0]->{WSURL} ; }
1508
sub FullWsRev   { return $_[0]->{URL} . $_[0]->{WSURL} . '@' . $_[0]->{WSREVNO} ; }
1509
sub Peg         { return $_[0]->{PEG} ; }
1510
sub Type        { return $_[0]->{TAGTYPE} || '' ; }
1511
sub WsType      { return $_[0]->{WSTYPE}  || '' ; }
1512
sub Path        { return $_[0]->{PATH} ; }
1513
sub Version     { return $_[0]->{VERSION} ; }
1514
sub RmRef       { return $_[0]->{RMREF} ; }
267 dpurdie 1515
 
1516
#-------------------------------------------------------------------------------
1517
# Function        : Print
1518
#
1519
# Description     : Debug display the URL
1520
#
1521
# Inputs          : $self           - Instance data
1522
#                   $header
1523
#                   $indent
1524
#
1525
# Returns         : Nothing
1526
#
1527
sub Print
1528
{
1529
    my ($self, $header, $indent) = @_;
1530
    print "$header\n" if $header;
1531
    $indent = 4 unless ( defined $indent );
1532
    $indent = ' ' x $indent;
1533
 
1534
 
1535
    print $indent . "PROTOCOL:" . $self->{PROTOCOL} . "\n";
1536
    print $indent . "SERVER  :" . $self->{SERVER} . "\n";
1537
    print $indent . "URL     :" . $self->{URL} . "\n";
1538
    print $indent . "PKGROOT :" . $self->{PKGROOT} . "\n";
1539
    print $indent . "PATH    :" . $self->{PATH} . "\n";
353 dpurdie 1540
    print $indent . "TAGTYPE :" . ($self->{TAGTYPE} || '') . "\n";
1541
    print $indent . "VERSION :" . ($self->{VERSION} || '') . "\n";
1542
    print $indent . "PEG     :" . ($self->{PEG} || '') . "\n";
267 dpurdie 1543
    print $indent . "FULL    :" . $self->Full . "\n";
1544
}
1545
 
1546
#-------------------------------------------------------------------------------
1547
# Function        : BranchName
1548
#
1549
# Description     : Create a full URL to a branch or tag based on the
1550
#                   current entry
1551
#
1552
#                   URL must have a TTB format
1553
#
1554
# Inputs          : $self           - Instance data
1555
#                   $branch         - Name of the branch
1556
#                   $type           - Optional branch type
1557
#
1558
# Returns         : Full URL name to the new branch
1559
#
1560
sub BranchName
1561
{
1562
    my ($self, $branch, $type ) = @_;
1563
    Debug ( "BranchName", $branch );
1564
 
1565
    $type = 'branches' unless ( $type );
1566
    my $root = $self->{PKGROOT};
1567
 
1568
    $root =~ s~/(tags|branches|trunk)(/|$|@).*~~;
1569
 
1570
    return $self->{URL} . $root . '/' . $type . '/' . $branch;
1571
}
1572
 
379 dpurdie 1573
#-------------------------------------------------------------------------------
1574
# Function        : setRepoProperty
1575
#
1576
# Description     : Sets a Repository property
1577
#                   This may well fail unless the Repo is setup to allow such
1578
#                   chnages and the user is allowed to make such changes
1579
#
1580
# Inputs          : $name
1581
#                   $value
1582
#
1583
# Returns         : Will not return on error
1584
#
1585
sub setRepoProperty
1586
{
1587
    my ($self, $name, $value ) = @_;
1588
    Debug ( "setRepoProperty", $name, $value );
1589
    #
1590
    #   Ensure that the Repo version is known
1591
    #   This should be set by a previous operation
1592
    #
1593
    unless ( defined $self->{REVNO} )
1594
    {
1595
        Error ("setRepoProperty. Release Revision Number not known");
1596
    }
1597
 
1598
    #
1599
    #   Execute the command
1600
    #
1601
    if ( $self->SvnCmd ( 'propset' , $name, '--revprop', '-r',  $self->{REVNO}, $value, $self->Full,
1602
                            {
1603
                                'credentials' => 1,
1604
                                'nosavedata' => 1,
1605
                            }
1606
                       ) )
1607
    {
1608
        #
1609
        #   Property NOT set
1610
        #
1611
        Error ("setRepoProperty: $name - FAILED");
1612
    }
1613
}
1614
 
267 dpurdie 1615
#------------------------------------------------------------------------------
1616
1;