Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
311 dpurdie 1
########################################################################
2
# Copyright (C) 1998-2008 ERG Limited, All rights reserved
3
#
4
# Module name   : jats_svn.pl
5
# Module type   : Jats Utility
6
# Compiler(s)   : Perl
7
# Environment(s): Jats
8
#
9
# Description   : A script to perform a number of SVN utility functions
10
#                 The script will:
11
#                   Delete a package
12
#                   Create a package
13
#                   Import source to a package
14
#
15
#
16
#......................................................................#
17
 
18
require 5.006_001;
19
use strict;
20
use warnings;
21
use JatsError;
22
use JatsSvn qw(:All);
23
use JatsLocateFiles;
379 dpurdie 24
use JatsProperties;
311 dpurdie 25
 
379 dpurdie 26
 
311 dpurdie 27
use Pod::Usage;                                 # required for help support
28
use Getopt::Long qw(:config require_order);     # Stop on non-option
29
use Cwd;
30
use File::Path;
31
use File::Copy;
32
use File::Basename;
33
use File::Compare;
34
 
35
my $VERSION = "1.0.0";                          # Update this
36
 
37
#
38
#   Options
39
#
40
my $opt_debug   = $ENV{'GBE_DEBUG'};            # Allow global debug
41
my $opt_verbose = $ENV{'GBE_VERBOSE'};          # Allow global verbose
42
my $opt_help = 0;
43
 
44
#
45
#   Globals
46
#
47
my $opr_done;                                   # User has done something
48
 
49
#-------------------------------------------------------------------------------
50
# Function        : Mainline Entry Point
51
#
52
# Description     :
53
#
54
# Inputs          :
55
#
56
my $result = GetOptions (
57
                "help:+"        => \$opt_help,              # flag, multiple use allowed
58
                "manual:3"      => \$opt_help,              # flag
59
                "verbose:+"     => \$opt_verbose,           # flag, multiple use allowed
60
 
61
                );
62
 
63
                #
64
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
65
                #
66
 
67
#
68
#   Process help and manual options
69
#
70
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
71
pod2usage(-verbose => 1) if ($opt_help == 2 );
72
pod2usage(-verbose => 2) if ($opt_help > 2);
73
 
74
#
75
#   Configure the error reporting process now that we have the user options
76
#
77
ErrorConfig( 'name'    =>'SVN',
78
             'verbose' => $opt_verbose,
79
            );
80
 
81
#
369 dpurdie 82
#   Reconfigure the options parser to allow subcommands to parse options
311 dpurdie 83
#
84
Getopt::Long::Configure('permute');
85
 
86
#
87
#   Process command
88
#   First command line argument is a subversion command
89
#
90
my $cmd = shift @ARGV || "help";
91
CreatePackage()                        if ( $cmd =~ m/^create/ );
92
DeletePackage()                        if ( $cmd =~ m/^delete-package/ );
93
ImportPackage()                        if ( $cmd =~ m/^import/ );
94
SvnRepoCmd($cmd, @ARGV)                if ( $cmd eq 'ls' );
363 dpurdie 95
TestSvn()                              if ($cmd eq 'test');
369 dpurdie 96
ShowPaths()                            if ( $cmd =~ m/^path/ );
97
ShowTag()                              if ( $cmd =~ m/^tag/ );
98
ShowUrl()                              if ( $cmd =~ m/^url/ );
311 dpurdie 99
 
100
pod2usage(-verbose => 0, -message => "No valid operations specified") unless ( $opr_done );
101
exit 0;
102
 
103
#-------------------------------------------------------------------------------
369 dpurdie 104
# Function        : ShowPaths
105
#
106
# Description     : Show PATHS
107
#
108
# Inputs          : 
109
#
110
# Returns         : 
111
#
112
sub ShowPaths
113
{
114
    #
115
    #   Parse more options
116
    #
117
    GetOptions (
118
                "help:+"        => \$opt_help,
119
                "manual:3"      => \$opt_help,
120
                ) || Error ("Invalid command line" );
121
 
122
    #
123
    #   Subcommand specific help
124
    #
125
    SubCommandHelp( $opt_help, "Subversion Paths") if ($opt_help || $#ARGV >= 0);
126
 
127
    #
128
    #   Display known PATHS
129
    #
130
    my ( $pSVN_URLS, $pSVN_URLS_LIST) = SvnPaths();
131
    print ("Configured SubVersion Repository Paths\n");
132
    print sprintf("    %-20s %s\n", 'Tag', 'URL Prefix');
133
 
134
    foreach my $key ( @{$pSVN_URLS_LIST} )
135
    {
136
        print sprintf("    %-20s %s\n", $key || 'Default', $pSVN_URLS->{$key} );
137
    }
138
 
139
    $opr_done = 1;
140
}
141
 
142
#-------------------------------------------------------------------------------
143
# Function        : ShowTag
144
#
145
# Description     : Convert a URL into a TAG
146
#                   Convert the current workspace info into a TAG
147
#
148
# Inputs          : url                     - Url to convert (optional)
149
#                   Options
150
#                       -help[=n]           - Show help
151
#                       -man                - Show manual
152
#                       -url=url            - Convert URL
153
#                       -path=path          - Convert Workspace
154
#
155
# Returns         : Nothing
156
#
157
sub ShowTag
158
{
159
    my $opt_path;
160
    my $opt_url;
161
 
162
    #
163
    #   Parse more options
164
    #
165
    GetOptions (
166
                "help:+"        => \$opt_help,
167
                "manual:3"      => \$opt_help,
168
                "path:s"        => \$opt_path,
169
                "url:s"         => \$opt_url,
170
                ) || Error ("Invalid command line" );
171
 
172
    #
173
    #   Subcommand specific help
174
    #
175
    SubCommandHelp( $opt_help, "Url to Tag") if ($opt_help);
176
 
177
    #
178
    #   Bare argument is a URL
179
    #   If no arguments provided assume a path of the current directory
180
    #
181
    $opt_url = shift (@ARGV) if ( $#ARGV == 0 );
182
    $opt_path = '.' unless ( defined $opt_path || defined $opt_url );
183
 
184
    #
185
    #   Sanity Tests
186
    #
187
    Error ("Cannot specify both a URL and a PATH")
188
            if ( defined $opt_url && defined $opt_path );
189
    Warning ("Too many arguments") if ( $#ARGV >= 0 );
190
 
191
    #   Do all the hard work
192
    #
193
    my $uref;
194
    if ( $opt_url )
195
    {
196
        $uref = NewSessionByUrl ( $opt_url );
197
        $uref->CalcRmReference($uref->Full());
198
    }
199
    else
200
    {
201
        $uref = NewSessionByWS($opt_path, 0, 1);
202
        my $ws_root = $uref->SvnLocateWsRoot(1);
203
        $uref->CalcRmReference($uref->FullWs());
204
    }
205
 
206
    Message ("Tag is: " . $uref->RmRef() );
207
    $opr_done = 1;
208
}
209
#-------------------------------------------------------------------------------
210
# Function        : ShowUrl
211
#
212
# Description     : Convert a TAG into a URL
213
#                   Show the current workspace URL
214
#
215
# Inputs          : tag                     - Tag to convert (optional)
216
#                   Options
217
#                       -help[=n]           - Show help
218
#                       -man                - Show manual
219
#                       -tag=tag            - Convert TAG
220
#                       -path=path          - Convert Workspace
221
#
222
# Returns         : Nothing
223
#
224
sub ShowUrl
225
{
226
    my $opt_path;
227
    my $opt_tag;
228
 
229
    #
230
    #   Parse more options
231
    #
232
    GetOptions (
233
                "help:+"        => \$opt_help,
234
                "manual:3"      => \$opt_help,
235
                "path:s"        => \$opt_path,
236
                "tag:s"         => \$opt_tag,
237
                ) || Error ("Invalid command line" );
238
 
239
    #
240
    #   Subcommand specific help
241
    #
242
    SubCommandHelp( $opt_help, "Tag to Url") if ($opt_help);
243
 
244
    #
245
    #   Bare argument is a TAG
246
    #   If no arguments provided assume a path of the current directory
247
    #
248
    $opt_tag = shift (@ARGV) if ( $#ARGV == 0 );
249
    $opt_path = '.' unless ( defined $opt_path || defined $opt_tag );
250
 
251
    #
252
    #   Sanity Tests
253
    #
254
    Error ("Cannot specify both a TAG and a PATH")
255
            if ( defined $opt_tag && defined $opt_path );
256
    Warning ("Too many arguments") if ( $#ARGV >= 0 );
257
 
258
    #   Do all the hard work
259
    #
260
    my $uref;
261
    my $url;
262
    if ( $opt_tag )
263
    {
264
        $url = SvnPath2Url($opt_tag);
265
    }
266
    else
267
    {
268
        $uref = NewSessionByWS($opt_path, 0, 1);
269
        my $ws_root = $uref->SvnLocateWsRoot(1);
270
        $url = $uref->FullWsRev();
271
    }
272
 
273
    Message ("Url: $url");
274
    $opr_done = 1;
275
}
276
 
277
#-------------------------------------------------------------------------------
363 dpurdie 278
# Function        : TestSvn
279
#
280
# Description     : Test access to subversion
281
#
282
# Inputs          : None
283
#
284
# Returns         :
285
#
286
sub TestSvn
287
{
288
    #
289
    #   Parse more options
290
    #
291
    GetOptions (
292
                "help:+"        => \$opt_help,
293
                "manual:3"      => \$opt_help,
294
                ) || Error ("Invalid command line" );
295
 
296
    #
297
    #   Subcommand specific help
298
    #
299
    SubCommandHelp( $opt_help, "Test Subversion") if ($opt_help || $#ARGV >= 0);
300
 
301
    SvnUserCmd( '--version');
302
    $opr_done = 1;
303
}
304
 
305
 
306
#-------------------------------------------------------------------------------
311 dpurdie 307
# Function        : SvnRepoCmd
308
#
309
# Description     : Execute a SVN command, where the first argument
310
#                   is a repository specifier
311
#
312
# Inputs          : $cmd
313
#                   $repo_url
314
#                   @opts
315
#
316
# Returns         : 
317
#
318
sub SvnRepoCmd
319
{
320
    my ( $cmd, $repo_url, @opts ) = @_;
321
    my $uref = NewSessionByUrl ( $repo_url );
322
 
323
    SvnUserCmd( $cmd,
324
            $uref->Full,
325
            @opts,
326
            { 'credentials' => 1 });
327
 
328
    $opr_done = 1;
329
}
330
 
331
#-------------------------------------------------------------------------------
332
# Function        : DeletePackage
333
#
334
# Description     : Delete a Package structure within a Repository
335
#                   Intended for test usage
336
#
337
# Inputs          : URL                 - Url to Repo + Package Base
338
#
339
# Returns         : 
340
#
341
sub DeletePackage
342
{
379 dpurdie 343
    my $opt_error = 0;
311 dpurdie 344
    #
345
    #   Parse more options
346
    #
347
    GetOptions (
348
                "help:+"        => \$opt_help,
349
                "manual:3"      => \$opt_help,
379 dpurdie 350
                "error!"       => \$opt_error,
311 dpurdie 351
                ) || Error ("Invalid command line" );
352
 
353
    #
354
    #   Subcommand specific help
355
    #
356
    SubCommandHelp( $opt_help, "Delete a Package") if ($opt_help || $#ARGV < 0);
357
 
358
    #
359
    #   Sanity Tests
360
    #
361
    Message ("Delete Entire Package Tree" );
362
    Warning ("Too many arguments: @ARGV") if ( $#ARGV >= 1 );
363
 
364
    #
365
    #   Do all the hard work
366
    #       Create
367
    #       Import
368
    #       Label
369
    #
370
    my $uref = NewSessionByUrl ( $ARGV[0] );
379 dpurdie 371
    $uref->SvnValidatePackageRoot(!$opt_error);
311 dpurdie 372
    $uref->SvnDelete (
373
                      'target'      => $uref->Full,
379 dpurdie 374
                      'comment'   => [$uref->Path().": Delete Pakage",'Deleted by user command','jats svn delete-package'],
375
                      'noerror'   => !$opt_error,
311 dpurdie 376
                      );
377
    $opr_done = 1;
378
}
379
 
380
#-------------------------------------------------------------------------------
381
# Function        : CreatePackage
382
#
383
# Description     : Create a Package structure within a Repository
384
#                   Optionally Import Data
385
#                   Optionally Tag the import
386
#                   Optionally Tag the import on a branch
387
#
388
# Inputs          : URL                 - Url to Repo + Package Base
389
#                   Options             - Command modifiers
390
#                       -import=path    - Import named directory
391
#                       -label=name     - Label the result
392
#                       -tag=name       - Import to Tag Only
393
#                       -branch=name    - Import to Branch only
394
#                       -new            - Must be new package
395
#                       -replace        - Replace existing
396
#
397
# Returns         : 
398
#
399
sub CreatePackage
400
{
401
    my $opt_import;
402
    my $opt_tag;
403
    my $opt_branch;
404
    my $opt_trunk;
405
    my $opt_new;
406
    my $opt_label;
407
    my $opt_replace;
408
    my $pname;
409
    my $type;
410
 
411
 
412
    Message ("Create New Package Version" );
413
 
414
    #
415
    #   Parse more options
416
    #
417
    GetOptions (
418
                "help:+"        => \$opt_help,
419
                "manual:3"      => \$opt_help,
420
                "verbose:+"     => \$opt_verbose,
421
                "import=s"      => \$opt_import,
422
                "new"           => \$opt_new,
423
                "branch=s"      => \$opt_branch,
424
                "trunk"         => \$opt_trunk,
425
                "tag=s"         => \$opt_tag,
426
                "label=s"       => \$opt_label,
427
                "replace"       => \$opt_replace,
428
 
429
                ) || Error ("Invalid command line" );
430
 
431
    #
432
    #   Subcommand specific help
433
    #
434
    SubCommandHelp( $opt_help, "Create a Package Version") if ($opt_help || $#ARGV < 0);
435
 
436
    #
369 dpurdie 437
    #   Alter the error reporting parameters
311 dpurdie 438
    #
439
    ErrorConfig( 'verbose' => $opt_verbose );
440
 
441
    #
442
    #   Sanity Tests
443
    #
444
    my $count = 0;
445
    $count++ if ( $opt_trunk );
446
    $count++ if ( $opt_branch );
447
    $count++ if ( $opt_tag );
448
    Error ("Conflicting options: -trunk, -tag, -branch") if ( $count > 1 );
449
    Error ("Nothing imported to be labeled") if ( $count && !$opt_import );
450
    Error ("Import path does not exist: $opt_import") if ( $opt_import && ! -d $opt_import );
451
    Error ("Conflicting options: new and replace") if ( $opt_new && $opt_replace );
452
 
453
    ($type, $opt_label) = ('tags', $opt_tag)            if ( $opt_tag);
454
    ($type, $opt_label) = ('branches', $opt_branch)     if ( $opt_branch );
455
    ($type, $opt_label) = ('trunk', $opt_label)         if ( $opt_trunk);
456
 
457
    #
458
    #   Do all the hard work
459
    #       Create
460
    #       Import
461
    #       Label
462
    #
463
    my $uref = NewSessionByUrl ( $ARGV[0] );
464
    $uref->SvnCreatePackage (
465
                      'import'  => $opt_import,
466
                      'label'   => $opt_label,
467
                      'type'    => $type,
468
                      'new'     => $opt_new,
469
                      'replace' => $opt_replace,
470
                      );
471
    Message ("Repository Ref: " . $uref->RmRef);
472
    $opr_done = 1;
473
}
474
 
475
#-------------------------------------------------------------------------------
476
# Function        : ImportPackage
477
#
478
# Description     : Import a new version of a package
479
#                   Take great care to reuse file-versions that are already in
480
#                   the  package
481
#
369 dpurdie 482
#                   Intended to allow the importation of multiple
311 dpurdie 483
#                   versions of a package
484
#
485
# Inputs          : 
486
#
487
# Returns         : 
488
#
489
sub ImportPackage
490
{
491
    Message ("Import Package Version" );
492
 
493
    #
494
    #   Options
495
    #
496
    my $opt_package;
497
    my $opt_dir;
498
    my $opt_label;
499
    my $opt_replace = 0;
500
    my $opt_reuse;
501
    my $opt_workdir = "SvnImportDir";
502
    my $opt_delete = 1;
379 dpurdie 503
    my $opt_author;
504
    my $opt_date;
505
    my $opt_log = '';
506
    my $opt_branch;
507
    my $opt_datafile;
311 dpurdie 508
 
509
    #
510
    #   Other globals
511
    #
512
    my $url_label;
379 dpurdie 513
    my $url_branch;
311 dpurdie 514
 
515
    #
516
    #   Configuration options
517
    #
518
    my $result = GetOptions (
379 dpurdie 519
                    'help:+'        => \$opt_help,
520
                    'manual:3'      => \$opt_help,
521
                    'verbose:+'     => \$opt_verbose,
522
                    'package=s'     => \$opt_package,
523
                    'dir=s'         => \$opt_dir,
524
                    'label=s'       => \$opt_label,
525
                    'branch=s'      => \$opt_branch,
526
                    'replace'       => \$opt_replace,
527
                    'reuse'         => \$opt_reuse,
528
                    'workspace=s'   => \$opt_workdir,
529
                    'delete!'       => \$opt_delete,
530
                    'author=s'      => \$opt_author,
531
                    'date=s'        => \$opt_date,
532
                    'log=s'         => \$opt_log,
533
                    'datafile=s'    => \$opt_datafile,
311 dpurdie 534
 
535
                    #
536
                    #   Update documentation at the end of the file
537
                    #
538
                    ) || Error ("Invalid command line" );
539
 
540
    #
541
    #   Insert defaults
341 dpurdie 542
    #   User can specify base package via -package or a non-options argument
311 dpurdie 543
    #
544
    $opt_package = $ARGV[0] unless ( $opt_package );
379 dpurdie 545
    unlink $opt_datafile if ( defined $opt_datafile );
311 dpurdie 546
 
547
    #
548
    #   Subcommand specific help
549
    #
550
    SubCommandHelp( $opt_help, "Import directory to a Package")
551
        if ($opt_help || ! $opt_package );
552
 
553
    #
369 dpurdie 554
    #   Alter the error reporting parameters
311 dpurdie 555
    #
556
    ErrorConfig( 'verbose' => $opt_verbose );
557
 
558
    #
559
    #   Configure the error reporting process now that we have the user options
560
    #
561
    Error ("No package URL specified") unless ( $opt_package );
562
    Error ("No base directory specified") unless ( $opt_dir );
563
    Error ("Invalid base directory: $opt_dir") unless ( -d $opt_dir );
564
 
565
    #
566
    #   Create an SVN session
567
    #
568
    my $svn = NewSessionByUrl ( $opt_package );
569
 
570
    #
571
    #   Ensure that the required label is available
572
    #
573
    if ( $opt_label )
574
    {
575
        $opt_label = SvnIsaSimpleLabel ($opt_label);
576
        $url_label = $svn->BranchName( $opt_label, 'tags' );
577
        $svn->SvnValidateTarget (
578
                        'target' => $url_label,
579
                        'available' => 1,
580
                        ) unless ( $opt_replace );
581
    }
582
 
583
    #
379 dpurdie 584
    #   Validate the required branch
585
    #   It will be created if it doesn't exist
586
    #
587
    if ( $opt_branch )
588
    {
589
        $opt_branch = SvnIsaSimpleLabel($opt_branch);
590
        $url_branch = $svn->BranchName( $opt_branch, 'branches' );
591
        $svn->SvnValidateTarget (
592
                        'target' => $url_branch,
593
                        'create' => 1,
594
                        );
595
    }
596
 
597
    #
311 dpurdie 598
    #   Create a workspace based on the users package
599
    #   Allow the workspace to be reused to speed up multiple
600
    #   operations
601
    #
602
    unless ( $opt_reuse && -d $opt_workdir )
603
    {
604
        Message ("Creating Workspace");
605
        rmtree( $opt_workdir );
606
 
607
        $svn->SvnValidatePackageRoot ();
608
        #DebugDumpData( 'Svn', $svn );
609
        $svn->SvnValidateTarget (
610
                            'cmd'    => 'SvnImporter',
611
                            'target' => $svn->Full,
612
                            'require' => 1,
613
                            );
614
 
379 dpurdie 615
        my $url_co = $opt_branch ? $url_branch : $svn->Full . '/trunk';
616
        $svn->SvnCo ( $url_co, $opt_workdir );
311 dpurdie 617
        Error ("Cannot locate the created Workspace")
618
            unless ( -d $opt_workdir );
619
    }
620
    else
621
    {
622
        Message ("Reusing Workspace");
623
    }
624
 
625
    #
626
    #   Determine differences between the two folders
627
    #       Create structures for each directory
628
    #
629
    Message ("Determine Files in packages");
630
 
631
    my $search = JatsLocateFiles->new("--Recurse=1",
632
                                       "--DirsToo",
633
                                       "--FilterOutRe=/\.svn/",
634
                                       "--FilterOutRe=/\.svn\$",
635
                                       "--FilterOutRe=^/${opt_workdir}\$",
636
                                       "--FilterOutRe=^/${opt_workdir}/",
637
                                       );
638
    my @ws = $search->search($opt_workdir);
639
    my @dir = $search->search($opt_dir);
640
 
641
    #Information ("WS Results", @ws);
642
    #Information ("DIR Results", @dir);
643
 
644
    #
645
    #   Create a hash the Workspace and the User dir
646
    #   The key will be file names
647
    #
648
    my %ws;  map ( $ws{$_} = 1 , @ws );
649
    my %dir; map ( $dir{$_} = 1 , @dir );
650
 
651
    #
652
    #   Create a hash of common elements
653
    #   Removing then from the other two
654
    #
655
    my %common;
656
    foreach ( keys %ws )
657
    {
658
        next unless ( exists $dir{$_} );
659
        $common{$_} = 1;
660
        delete $ws{$_};
661
        delete $dir{$_};
662
    }
663
 
664
    #DebugDumpData( 'WS', \%ws );
665
    #DebugDumpData( 'DIR', \%dir );
666
    #DebugDumpData( 'COMMON', \%common );
667
 
668
    #
379 dpurdie 669
    #   Need to consider the case where a file has been replaced with a directory
670
    #   and visa-versa. Delete files and directories first.
671
    #
672
    #
673
    #   Remove files
674
    #   Sort in reverse. This will ensure that we process directory
675
    #   contents before directories
676
    #
677
    my @rm_files = reverse sort keys %ws;
678
    if ( @rm_files )
679
    {
680
        foreach my $file ( @rm_files  )
681
        {
682
            Verbose ("Removing $file");
683
            unlink "$opt_workdir/$file";
684
        }
685
 
686
        #
687
        #   Inform Subversion about the removed files
688
        #
689
        my $base = 0;
690
        my $num = $#rm_files;
691
        Message ("Update the workspace: Removed " . ($num + 1) . " Files");
692
 
693
        while ( $base <= $num )
694
        {
695
            my $end = $base + 200;
696
            $end = $num if ( $end > $num );
697
 
698
            $svn->SvnCmd ( 'delete', map ("$opt_workdir/$_@", @rm_files[$base .. $end] ),
699
                            { 'error' => 'Deleting files from workspace' } );
700
 
701
            $base = $end + 1;
702
        }
703
    }
704
 
705
    #
311 dpurdie 706
    #   Add New Files
707
    #   Won't add empty directories at this point
708
    #
709
    #   Process by sorted list
710
    #   This will ensure we process parent directories first
711
    #
712
    my @added = sort keys %dir;
713
    if ( @added )
714
    {
715
        foreach my $file ( @added  )
716
        {
717
            my $src = "$opt_dir/$file";
718
            my $target = "$opt_workdir/$file";
719
 
720
            if ( -d $src )
721
            {
379 dpurdie 722
                Verbose ("Adding directory: $file");
311 dpurdie 723
                mkdir ( $target ) unless (-d $target);
724
            }
725
            else
726
            {
727
 
728
                my $path = dirname ( $target);
729
                mkdir ( $path ) unless (-d $path);
730
 
731
                Verbose ("Adding $file");
732
                unless (File::Copy::copy( $src, $target ))
733
                {
734
                    Error("Failed to transfer file [$file]: $!");
735
                }
736
            }
737
        }
738
 
739
        #
740
        #   Inform Subversion about the added files
741
        #   The command line does have a finite length, so add them 200 at a
742
        #   time.
743
        #
744
 
745
        my $base = 0;
746
        my $num = $#added;
379 dpurdie 747
        Message ("Update the workspace: Added " . (1 + $num) . " files");
311 dpurdie 748
 
749
        while ( $base <= $num )
750
        {
751
            my $end = $base + 200;
752
            $end = $num if ( $end > $num );
753
 
754
            $svn->SvnCmd ( 'add'
755
                            , '--depth=empty'
756
                            , '--parents'
379 dpurdie 757
                            , map ("$opt_workdir/$_@", @added[$base .. $end] ),
311 dpurdie 758
                            { 'error' => 'Adding files to workspace' } );
759
 
760
            $base = $end + 1;
761
        }
762
    }
763
 
764
    #
765
    #   The common files may have changed
766
    #   Simply copy them all in and let subversion figure it out
767
    #
768
    foreach my $file ( sort keys %common  )
769
    {
770
        my $src = "$opt_dir/$file";
771
        my $target = "$opt_workdir/$file";
772
 
773
        next if ( -d $src );
774
        if ( File::Compare::compare ($src, $target) )
775
        {
776
            Verbose ("Transfer $file");
777
            unlink $target;
778
            unless (File::Copy::copy( $src, $target ))
779
            {
780
                Error("Failed to transfer file [$file]: $!",
781
                      "Src: $src",
782
                      "Tgt: $target");
783
            }
784
        }
785
    }
786
 
787
    #
788
    #   Commit the workspace
789
    #   This will go back onto the trunk
790
    #
791
    $svn = NewSessionByWS( $opt_workdir );
379 dpurdie 792
    my $pkgPath = $svn->Path();
793
    my $ciComment = "$pkgPath: Checkin by Svn Import";
794
    $ciComment .= "\n" . $opt_log if ( $opt_log );
795
    $ciComment =~ s~\r\n~\n~g;
796
    $svn->SvnCi ('comment' => $ciComment, 'allowSame' => 1 );
381 dpurdie 797
    Message ("Repository Ref: " . $svn->RmRef) unless( $opt_label );
379 dpurdie 798
    $svn->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));
799
    $svn->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));
311 dpurdie 800
 
801
    #
802
    #   Label the result
803
    #   The workspace will have been updated, so we can use it as the base for
804
    #   the labeling process
805
    #
806
    if ( $opt_label )
807
    {
808
        $svn->SvnCopyWs (
809
                       target => $url_label,
810
                       'noswitch' => 1,
811
                       'replace' => $opt_replace,
379 dpurdie 812
                       'comment' => "$pkgPath: Tagged by Jats Svn Import",
311 dpurdie 813
                       );
814
        Message ("Repository Ref: " . $svn->RmRef);
379 dpurdie 815
        $svn->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));
816
        $svn->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));
311 dpurdie 817
    }
818
 
819
    #
820
    #   Clean up
821
    #
822
    if ( $opt_delete && ! $opt_reuse )
823
    {
824
        Message ("Delete Workspace");
825
        rmtree( $opt_workdir );
826
    }
379 dpurdie 827
 
828
    #
829
    #   Automation data transfer
830
    #
831
    if ( defined $opt_datafile )
832
    {
833
        my $data = JatsProperties::New();
834
 
835
        $data->setProperty('Command'        , 'ImportPackage');
836
        $data->setProperty('Label'          , $opt_label);
837
        $data->setProperty('subversion.tag' , $svn->RmRef);
838
 
839
        $data->Dump('InfoFile') if ($opt_verbose);
840
        $data->store( $opt_datafile );
841
    }
842
 
311 dpurdie 843
    $opr_done = 1;
844
}
845
 
846
#-------------------------------------------------------------------------------
847
# Function        : SubCommandHelp
848
#
849
# Description     : Provide help on a subcommand
850
#
851
# Inputs          : $help_level             - Help Level 1,2,3
852
#                   $topic                  - Topic Name
853
#
854
# Returns         : This function does not return
855
#
856
sub SubCommandHelp
857
{
858
    my ($help_level, $topic) = @_;
859
    my @sections;
860
    #
861
    #   Spell out the section we want to display
862
    #
863
    #   Note:
864
    #   Due to bug in pod2usage can't use 'head1' by itself
865
    #   Each one needs a subsection.
866
    #
867
    push @sections, qw( NAME SYNOPSIS ) ;
868
    push @sections, qw( ARGUMENTS OPTIONS ) if ( $help_level > 1 );
869
    push @sections, qw( DESCRIPTION )       if ( $help_level > 2 );
870
 
871
    #
872
    #   Extract section from the POD
873
    #
874
    pod2usage({-verbose => 99,
875
               -noperldoc => 1,
876
               -sections => $topic . '/' . join('|', @sections) } );
877
}
878
 
879
 
880
 
881
#-------------------------------------------------------------------------------
882
#   Documentation
883
#   NOTE
884
#
885
#   Each subcommand MUST have
886
#   head1 section as used by the subcommand
887
#       This should be empty, as the contents will NOT be displayed
888
#   head2 sections called
889
#       NAME SYNOPSIS ARGUMENTS OPTIONS DESCRIPTION
890
#
891
#=head1 xxxxxx
892
#=head2 NAME
893
#=head2 SYNOPSIS
894
#=head2 ARGUMENTS
895
#=head2 OPTIONS
896
#=head2 DESCRIPTION
897
#
898
 
899
=pod
900
 
361 dpurdie 901
=for htmltoc    GENERAL::Subversion::
902
 
311 dpurdie 903
=head1 NAME
904
 
905
jats svn - Miscellaneous SubVersion Operations
906
 
907
=head1 SYNOPSIS
908
 
909
jats svn [options] command [command options]
910
 
911
 Options:
912
    -help[=n]              - Help message, [n=1,2,3]
913
    -man                   - Full documentation [-help=3]
914
    -verbose[=n]           - Verbose command operation
915
 
916
 Common Command Options:
917
    All command support suboptions to provide command specific help
918
 
919
    -help[=n]              - Help message, [n=1,2,3]
920
    -man                   - Full documentation [-help=3]
921
 
922
 Commands are:
363 dpurdie 923
    test                   - Test access to subversion
369 dpurdie 924
    paths                  - Display Subversion tag to URL conversions
311 dpurdie 925
    ls URL                 - List Repo contents for URL
369 dpurdie 926
    tag [URL]              - Convert URL or Path to a Release Manager Tag
927
    url [TAG]              - Convert TAG or Path to a Subversion URL
311 dpurdie 928
    delete-package URL     - Delete Package Subtree
929
    create URL             - Create a new package at URL
930
    import URL             - Import files to package at URL
931
 
932
 Use the command
933
    jats svn command -h
934
 for command specific help
935
 
936
 
937
=head1 OPTIONS
938
 
939
=over
940
 
941
=item B<-help[=n]>
942
 
943
Print a help message and exit. The level of help may be either 1, 2 or
944
3 for a full manual.
945
 
946
This option may be specified multiple times to increment the help level, or
947
the help level may be directly specified as a number.
948
 
949
=item B<-man>
950
 
951
This is the same as '-help=3'.
952
The complete help is produced in a man page format.
953
 
954
=item B<--verbose[=n]>
955
 
956
This option will increase the level of verbosity of the commands.
957
 
958
If an argument is provided, then it will be used to set the level, otherwise the
959
existing level will be incremented. This option may be specified multiple times.
960
 
961
=back
962
 
963
=head1 DESCRIPTION
964
 
965
This program provides a number of useful Subversion based operations.
966
 
363 dpurdie 967
=head1 Test Subversion
968
 
969
=head2 NAME
970
 
971
Test Subversion
972
 
973
=head2 SYNOPSIS
974
 
975
    jats svn test
976
 
977
=head2 DESCRIPTION
978
 
979
This command will ensure that the subversion command line utility can be
980
located. The command will report the version of the svn client found.
981
 
369 dpurdie 982
=head1 Subversion Paths
983
 
984
=head2 NAME
985
 
986
Subversion Paths
987
 
988
=head2 SYNOPSIS
989
 
990
    jats svn paths
991
 
992
=head2 DESCRIPTION
993
 
994
This command will display the base Tags and associated URLs that are used by
995
JATS to convert a 'Subversion Tag' into a full URLs that will be used to access
996
a physical repository.
997
 
998
The 'Tags' configuration is site-specific.
999
 
311 dpurdie 1000
=head1 List Repository
1001
 
363 dpurdie 1002
=head2 NAME
1003
 
1004
List Repository
1005
 
1006
=head2 SYNOPSIS
1007
 
1008
    jats svn ls <URL>
1009
 
1010
=head2 DESCRIPTION
1011
 
311 dpurdie 1012
This command will take a URL and perform a 'svn' list operation. The URL will
1013
be expanded to include the site specific repository.
1014
 
369 dpurdie 1015
=head1 Url to Tag
1016
 
1017
=head2 NAME
1018
 
1019
Url to Tag
1020
 
1021
=head2 SYNOPSIS
1022
 
1023
    jats svn tag [Option] [tag]
1024
 
1025
 Options:
1026
    -help[=n]              - Help message, [n=1,2,3]
1027
    -man                   - Full documentation [-help=3]
1028
    -path=path             - Convert specified path
1029
    -url=url               - Convert specified URL
1030
 
1031
=head2 DESCRIPTION
1032
 
1033
This command will convert a URL or a PATH to a Subversion Tag that can
1034
be used within the remainder of the build system. If no PATH or URL is provided,
1035
then the command uses a path of the current directory.
1036
 
1037
The command will convert either a PATH or a URL. It will not do both.
1038
 
1039
The command will use the configured Subversion URL prefixes to create the Tag.
1040
 
1041
If a PATH is to be converted, then the PATH must address a Subversion workspace.
1042
The conversion will return a Tag to the root of the Workspace and Peg it to
1043
the last committed version. The command will not determine if the workspace
1044
contains modified files.
1045
 
1046
If a URL is to be converted, then the resultant value should be used with
1047
caution. The result is only as good as the provided URL and may not address
1048
the root of a package.
1049
 
1050
=head1 Tag to Url
1051
 
1052
=head2 NAME
1053
 
1054
Tag to Url
1055
 
1056
=head2 SYNOPSIS
1057
 
1058
    jats svn url [Option] [url]
1059
 
1060
 Options:
1061
    -help[=n]              - Help message, [n=1,2,3]
1062
    -man                   - Full documentation [-help=3]
1063
    -path=path             - Convert specified path
1064
    -url=url               - Convert specified URL
1065
 
1066
=head2 DESCRIPTION
1067
 
1068
This command will convert a TAG or a PATH to a full URL that can be used
1069
directly by Subversion. If no PATH or TAG is provided, then the command uses a
1070
path of the current directory.
1071
 
1072
The command will convert either a TAG or a URL. It will not do both.
1073
 
1074
The command will use the configured Subversion URL prefixes to expand the TAG.
1075
 
1076
If a PATH is to be converted, then the PATH must address a Subversion workspace.
1077
The conversion will return a URL to the root of the Workspace and Peg it to
1078
the last committed version. The command will not determine if the workspace
1079
contains modified files.
1080
 
1081
If a TAG is to be converted, then the resultant value should be used with
1082
caution. The result is only as good as the provided URL and may not address
1083
the root of a package.
1084
 
311 dpurdie 1085
=head1 Delete a Package
1086
 
1087
=head2 NAME
1088
 
1089
Delete a Package
1090
 
1091
=head2 SYNOPSIS
1092
 
1093
jats svn delete-package URL [options]
1094
 
1095
 Options:
1096
    -help[=n]              - Help message, [n=1,2,3]
1097
    -man                   - Full documentation [-help=3]
1098
    -verbose[=n]           - Verbose command operation
1099
 
1100
=head2 ARGUMENTS
1101
 
1102
The command takes one argument: The URL of the desired package.
1103
This may be be:
1104
 
1105
=over
1106
 
1107
=item * A full URL
1108
 
1109
Complete with protocol and path information.
1110
 
1111
=item * A simple URL
1112
 
1113
JATS will prepend the site-specific repository location to the user provided URL
1114
 
1115
=back
1116
 
1117
=head2 OPTIONS
1118
 
1119
This command has no significant options, other than the general help options.
1120
 
1121
=head2 DESCRIPTION
1122
 
1123
This command will delete a package from the repository. It will ensure
1124
that the package is a valid package, before it is deleted.
1125
 
1126
The command is intended to be used by test scripts, rather than users.
1127
 
1128
=head1 Create a Package Version
1129
 
1130
=head2 NAME
1131
 
1132
Create a Package Version
1133
 
1134
=head2 SYNOPSIS
1135
 
1136
jats svn [options] create URL [command options]
1137
 
1138
 Options:
1139
    -help[=n]               - Help message, [n=1,2,3]
1140
    -man                    - Full documentation [-help=3]
1141
    -verbose[=n]            - Verbose command operation
1142
 
1143
 Command Options
1144
    -help[=n]               - Provide command specific help
1145
    -import=nnn             - Import directory tree
1146
    -label=nnn              - Label it (trunk import only)
1147
    -new                    - Package must not exist
1148
    -replace                - Replace any existing versions
1149
    -trunk                  - Import to trunk
1150
    -tags=nnn               - Import to tags
1151
    -branch=nnn             - Import to branches
1152
 
1153
=head2 ARGUMENTS
1154
 
1155
The command takes one argument: The URL of the desired package.
1156
This may be be:
1157
 
1158
=over
1159
 
1160
=item * A full URL
1161
 
1162
Complete with protocol and path information.
1163
 
1164
=item * A simple URL
1165
 
1166
JATS will prepend the site-specific repository location to the user provided URL
1167
 
1168
=back
1169
 
1170
=head2 OPTIONS
1171
 
1172
=over
1173
 
1174
=item -help[=n]
1175
 
1176
Print a help message and exit. The level of help may be either 1, 2 or 3.
1177
 
1178
This option may be specified multiple times to increment the help level, or
1179
the help level may be directly specified as a number.
1180
 
1181
=item -import=nnn
1182
 
1183
This option specifies the path of a subdirectory tree to import into the newly
1184
created package. In not provided, then only a package skeleton will be created.
1185
 
1186
=item -label=nnn
1187
 
1188
This option specifies a label to place the imported source, if the source is
1189
being imported to the 'trunk' of the package.
1190
 
1191
=item -new
1192
 
1193
This option specifies that the named package MUST not exist at all.
1194
 
1195
=item -replace
1196
 
1197
This option allows the program to replace any existing versions of the
1198
imported source. It will allow the deletion of any existing trunk, tags or
1199
branches.
1200
 
1201
=item -trunk
1202
 
1203
This option specifies that imported source will be placed on the trunk of the
1204
package. This is the default mode of import.
1205
 
1206
The options -trunk, -tags and -branch are mutually exclusive.
1207
 
1208
=item -tags=nnn
1209
 
1210
This option specifies that imported source will be placed directly on the
1211
named tag of the package.
1212
 
1213
The options -trunk, -tags and -branch are mutually exclusive.
1214
 
1215
=item -branch=nnn
1216
 
1217
This option specifies that imported source will be placed directly on the
1218
named branch of the package.
1219
 
1220
The options -trunk, -tags and -branch are mutually exclusive.
1221
 
1222
=back
1223
 
1224
=head2 DESCRIPTION
1225
 
1226
This command will create a new package within a repository. It will ensure
1227
that the package contains the three required subdirectories: trunk, tags and
1228
branches.
1229
 
1230
The command will also ensure that packages are not placed at inappropriate
1231
locations within the repository. It is not correct to place a package within
1232
another package.
1233
 
1234
The command will, optionally, import a directory tree into the repository and,
1235
optionally, label the package.
1236
 
1237
The package body may be imported to the 'trunk' or to a branch or a tag.
1238
By default the data will be imported to the trunk and may be labeled (tagged).
1239
 
1240
Options allow the targets to be deleted if they exist or to ensure that they
1241
are not present.
1242
 
1243
The command does not attempt to merge file versions within the repository. It
1244
may result in multiple instances of a file within the repository. Use only for
341 dpurdie 1245
simple imports. Use the 'import' command for more sophisticated import requirements.
311 dpurdie 1246
 
1247
=head1 Import directory to a Package
1248
 
1249
=head2 NAME
1250
 
1251
Import directory to a Package
1252
 
1253
=head2 SYNOPSIS
1254
 
1255
jats svn [options] import URL [command options]
1256
 
1257
 Options:
1258
    -help[=n]               - Help message, [n=1,2,3]
1259
    -man                    - Full documentation [-help=3]
1260
    -verbose[=n]            - Verbose command operation
1261
 
1262
 Command Options
1263
    -help[=n]               - Command specific help, [n=1,2,3]
1264
    -verbose[=n]            - Verbose operation
1265
    -package=name           - Name of source package
1266
    -dir=path               - Path to new version
379 dpurdie 1267
    -label=label            - Label the result
1268
    -branch=branchName      - Base import on a branch
311 dpurdie 1269
    -replace                - Allow the label to be replaced
1270
    -reuse                  - Reuse the import directory
1271
    -workspace=path         - Path and name of alternate workspace
1272
    -[no]delete             - Deletes workspace after use. Default:yes
379 dpurdie 1273
    -author=name            - Force author of changes
1274
    -date=dateString        - Force date of changes
1275
    -log=text               - Append text to the commit message
1276
    -datafile=path          - Export tag data for automation
311 dpurdie 1277
 
379 dpurdie 1278
 
311 dpurdie 1279
=head2 ARGUMENTS
1280
 
1281
The command takes one argument: The URL of the desired package.
1282
This may be be:
1283
 
1284
=over
1285
 
1286
=item * A full URL
1287
 
1288
Complete with protocol and path information.
1289
 
1290
=item * A simple URL
1291
 
1292
JATS will prepend the site-specific repository location to the user provided URL
1293
 
1294
=back
1295
 
1296
=head2 OPTIONS
1297
 
1298
=over
1299
 
1300
=item -help[=n]
1301
 
1302
Print a help message and exit. The level of help may be either 1, 2 or 3.
1303
 
1304
This option may be specified multiple times to increment the help level, or
1305
the help level may be directly specified as a number.
1306
 
1307
=item -verbose[=n]
1308
 
1309
This option will increase the level of verbosity of the utility.
1310
 
1311
If an argument is provided, then it will be used to set the level, otherwise the
1312
existing level will be incremented. This option may be specified multiple times.
1313
 
1314
 
1315
=item -package=name
1316
 
1317
Either this option or a bare URL on the command line must be provided. It
1318
specifies the repository and package to be used as a basis for the work.
1319
 
1320
=item -dir=path
1321
 
1322
This option is mandatory. It specifies the path to a local directory that
1323
contains a version of the software to be checked in.
1324
 
1325
=item -label=name
1326
 
1327
The resulting software version will be labeled with this tag, if it is provided.
1328
 
383 dpurdie 1329
A label name of TIMESTAMP will be treated in special manner. The name will be
1330
replaced with a unique name based on the users name and the current date time.
1331
 
379 dpurdie 1332
=item -branch=branchName
1333
 
1334
This option will cause the importation to be referenced to the named branch.
1335
If the branch does not exist it will be created. If it does exist then it will
1336
be used.
1337
 
1338
If this option is not specified, then the importation will be based on the 'trunk'.
1339
 
1340
If the Workspace is provided, then it will be used independently of this option.
1341
 
383 dpurdie 1342
A branchName of TIMESTAMP will be treated in special manner. The name will be
1343
replaced with a unique name based on the users name and the current date time.
1344
 
311 dpurdie 1345
=item -replace
1346
 
1347
This option, if provided, allows the label to be replaced.
1348
 
1349
=item -reuse
1350
 
1351
This option can be used to speed the creation of multiple versions in a scripted
1352
environment. The option allows the utility to reuse the workspace if it exists.
1353
 
1354
=item -workspace=path
1355
 
1356
This option specifies an alternate workspace directory to create and use. The
1357
default directory is "SvnImportDir" within the users current directory.
1358
 
1359
=item [no]delete
1360
 
341 dpurdie 1361
This option control the deletion of the workspace directory. By default the
311 dpurdie 1362
directory will be deleted, unless re-use is also used.
1363
 
379 dpurdie 1364
=item -author=name
1365
 
1366
This option will force the author of changes as recorded in the repository.
1367
The repoistory must be configured to allow such changes.
1368
 
1369
This option may not work for non-admin users.
1370
 
1371
=item -date=dateString
1372
 
1373
This option will force the date of the changes as recorded in the repository.
1374
The repoistory must be configured to allow such changes.
1375
The dateString is in a restricted ISO 8601 format: ie 2009-02-12T00:44:04.921324Z
1376
 
1377
This option may not work for non-admin users.
1378
 
1379
=item -log=text
1380
 
1381
This option will append the specified text to the commit message.
1382
The first line of the commit message is fixed by the import tool.
1383
 
1384
=item -datafile=path
1385
 
1386
This option will cause the utility to create a data file to record the import
1387
tag. It is used for automation of the import process.
1388
 
311 dpurdie 1389
=back
1390
 
1391
=head2 DESCRIPTION
1392
 
1393
Import a new version of a package to the trunk of the package. The utility
1394
will only import changed files so that file history is preserved within the
1395
repository.
1396
 
1397
This utility is used import software from another version control system
1398
The utility will:
1399
 
1400
=over
1401
 
361 dpurdie 1402
=item *
311 dpurdie 1403
 
361 dpurdie 1404
Create a Work Space based on the current package version
1405
 
379 dpurdie 1406
The 'trunk' of the named package will be used as the base for the workspace,
1407
unless modified with the -branch option.
311 dpurdie 1408
 
361 dpurdie 1409
=item *
311 dpurdie 1410
 
361 dpurdie 1411
Update files and directories
1412
 
311 dpurdie 1413
Determines the files and directories that have been added and deleted and
1414
update the Workspace to reflect the new structure.
1415
 
361 dpurdie 1416
=item *
311 dpurdie 1417
 
361 dpurdie 1418
Check in the new version
311 dpurdie 1419
 
361 dpurdie 1420
=item *
1421
 
1422
Label the new version
1423
 
311 dpurdie 1424
=back
1425
 
1426
=cut
1427