| 267 |
dpurdie |
1 |
########################################################################
|
|
|
2 |
# Copyright (C) 2008 ERG Limited, All rights reserved
|
|
|
3 |
#
|
|
|
4 |
# Module name : JatsSvnCore.pm
|
|
|
5 |
# Module type : Jats Support Module
|
|
|
6 |
# Compiler(s) : Perl
|
|
|
7 |
# Environment(s): jats
|
|
|
8 |
#
|
|
|
9 |
# Description : JATS LowLevel 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;
|
|
|
28 |
use JatsEnv;
|
|
|
29 |
|
|
|
30 |
#
|
|
|
31 |
# Global Variables
|
|
|
32 |
# Configuration variables imported from environment
|
|
|
33 |
# Must be 'our' to work with EnvImport
|
|
|
34 |
#
|
|
|
35 |
our $GBE_SVN_PATH; # Optional: SVN bin directory
|
|
|
36 |
our $GBE_SVN_USERNAME; # Optional: User name
|
|
|
37 |
our $GBE_SVN_PASSWORD; # Optional: User passwrd
|
| 363 |
dpurdie |
38 |
our $USER;
|
| 267 |
dpurdie |
39 |
|
|
|
40 |
package JatsSvnCore;
|
|
|
41 |
|
|
|
42 |
use JatsError;
|
|
|
43 |
use JatsSystem;
|
|
|
44 |
use IPC::Open3;
|
|
|
45 |
|
|
|
46 |
|
|
|
47 |
use File::Path; # Instead of FileUtils
|
|
|
48 |
use File::Basename;
|
|
|
49 |
use Cwd;
|
|
|
50 |
|
|
|
51 |
|
|
|
52 |
# automatically export what we need into namespace of caller.
|
|
|
53 |
use Exporter();
|
|
|
54 |
our (@ISA, @EXPORT, %EXPORT_TAGS, @EXPORT_OK);
|
|
|
55 |
@ISA = qw(Exporter);
|
|
|
56 |
@EXPORT = qw(
|
|
|
57 |
SvnSession
|
|
|
58 |
SvnUserCmd
|
|
|
59 |
SvnComment
|
|
|
60 |
|
|
|
61 |
);
|
|
|
62 |
@EXPORT_OK = qw(
|
|
|
63 |
ProcessRevNo
|
| 353 |
dpurdie |
64 |
%SVN_URLS
|
|
|
65 |
@SVN_URLS_LIST
|
|
|
66 |
|
| 267 |
dpurdie |
67 |
);
|
|
|
68 |
|
|
|
69 |
%EXPORT_TAGS = (All => [@EXPORT, @EXPORT_OK]);
|
|
|
70 |
|
|
|
71 |
|
|
|
72 |
#
|
|
|
73 |
# Package Global
|
|
|
74 |
#
|
| 353 |
dpurdie |
75 |
my $svn; # Abs path to 'svn' utility
|
|
|
76 |
my $stdmux; # Abs path to stdmux utlity
|
|
|
77 |
our %SVN_URLS; # Exported repository URLs
|
|
|
78 |
our @SVN_URLS_LIST; # Exported repository URLs scan order
|
| 267 |
dpurdie |
79 |
|
|
|
80 |
#-------------------------------------------------------------------------------
|
|
|
81 |
# Function : BEGIN
|
|
|
82 |
#
|
|
|
83 |
# Description : Module Initialization
|
|
|
84 |
# Invoked by Perl as soon as possible
|
|
|
85 |
# Setup environment variables
|
|
|
86 |
# Calculate globals
|
|
|
87 |
#
|
|
|
88 |
# Inputs : None
|
|
|
89 |
#
|
|
|
90 |
# Returns : Nothing
|
|
|
91 |
#
|
|
|
92 |
sub BEGIN
|
|
|
93 |
{
|
|
|
94 |
#
|
|
|
95 |
# Determine authentication information
|
|
|
96 |
# If not present then assume that the user is already athenticated
|
|
|
97 |
#
|
| 363 |
dpurdie |
98 |
::EnvImportOptional('USER');
|
| 267 |
dpurdie |
99 |
::EnvImportOptional('GBE_SVN_USERNAME');
|
|
|
100 |
::EnvImportOptional('GBE_SVN_PASSWORD');
|
|
|
101 |
|
|
|
102 |
#
|
|
|
103 |
# User can provide a path to the svn utility
|
|
|
104 |
# It will be used if its present
|
|
|
105 |
#
|
|
|
106 |
::EnvImportOptional('GBE_SVN_PATH', '');
|
|
|
107 |
|
| 297 |
dpurdie |
108 |
#
|
|
|
109 |
# For some reason thats not clear these EnvVars must be used in this function
|
|
|
110 |
# for them to be available elsewhere.
|
|
|
111 |
#
|
|
|
112 |
# No it doesn't make sence to me either
|
|
|
113 |
# Problem seen on Linx. Not investigated on others
|
|
|
114 |
#
|
|
|
115 |
Debug ("GBE_SVN_USERNAME", $::GBE_SVN_USERNAME);
|
|
|
116 |
Debug ("GBE_SVN_PASSWORD", $::GBE_SVN_PASSWORD);
|
|
|
117 |
Debug ("GBE_SVN_PATH", $::GBE_SVN_PATH);
|
|
|
118 |
|
| 271 |
dpurdie |
119 |
$stdmux = LocateProgInPath ( 'stdmux');
|
| 311 |
dpurdie |
120 |
$svn = LocateProgInPath ( 'svn', '--All', '--Path=' . $::GBE_SVN_PATH );
|
| 353 |
dpurdie |
121 |
|
|
|
122 |
#
|
| 365 |
dpurdie |
123 |
# Don't report errors in not finding svn and stdmux
|
|
|
124 |
# Need to allow the help system to work.
|
|
|
125 |
#
|
|
|
126 |
|
|
|
127 |
#
|
| 353 |
dpurdie |
128 |
# Extract GBE_SVN_XXXX_URL information from the environment
|
|
|
129 |
# XXXX is the first element of the repository path and will
|
|
|
130 |
# be globally (ERG) unique
|
|
|
131 |
# The value will be the URL to access this named repository path
|
|
|
132 |
# It will normally include the repository path
|
|
|
133 |
# The saved URL will be terminated with a single '/' to simplify usage
|
|
|
134 |
#
|
|
|
135 |
foreach ( sort keys %ENV )
|
|
|
136 |
{
|
|
|
137 |
if ( m ~^GBE_SVN_URL_*(.*)~ )
|
|
|
138 |
{
|
|
|
139 |
my $url = $ENV{$_};
|
|
|
140 |
my $key = $1;
|
|
|
141 |
$url =~ s~/*$~/~;
|
|
|
142 |
$SVN_URLS{$key} = $url;
|
|
|
143 |
|
|
|
144 |
#
|
|
|
145 |
# Ensure that it is in valid format
|
|
|
146 |
# Four forms are supported, although not all should be used
|
|
|
147 |
#
|
|
|
148 |
if ( $url =~ m{^svn://[^/]+} ) {
|
|
|
149 |
#
|
|
|
150 |
# Type is SVN server
|
|
|
151 |
# Protocol + server name
|
|
|
152 |
#
|
|
|
153 |
} elsif ( $url =~ m{^https{0,1}://.+} ) {
|
|
|
154 |
#
|
|
|
155 |
# Type is HTTP server
|
|
|
156 |
# Protocol + server name + path on server
|
|
|
157 |
#
|
|
|
158 |
} elsif ( $url =~ m{^file:///+[A-Z]:/} ) {
|
|
|
159 |
#
|
|
|
160 |
# Type is local Repo (file)
|
|
|
161 |
# Windows absolute pathname
|
|
|
162 |
# file:///I:/path/...
|
|
|
163 |
#
|
|
|
164 |
} elsif ( $url =~ m{^file:///+[^/]} ) {
|
|
|
165 |
#
|
|
|
166 |
# Type is local Repo (file)
|
|
|
167 |
# Unix absolute pathname
|
|
|
168 |
# file:///path/...
|
|
|
169 |
#
|
|
|
170 |
} else {
|
|
|
171 |
ReportError ("GBE_SVN_URL format not understood","$key: $url");
|
|
|
172 |
}
|
|
|
173 |
|
|
|
174 |
}
|
|
|
175 |
}
|
|
|
176 |
@SVN_URLS_LIST = reverse sort keys %SVN_URLS;
|
|
|
177 |
ErrorDoExit();
|
|
|
178 |
#DebugDumpData("%SVN_URLS", \%SVN_URLS, \@SVN_URLS_LIST);
|
| 267 |
dpurdie |
179 |
}
|
|
|
180 |
|
|
|
181 |
#-------------------------------------------------------------------------------
|
|
|
182 |
# Function : SvnSession
|
|
|
183 |
#
|
|
|
184 |
# Description : Create a new SvnSession
|
|
|
185 |
# Simply used to contain information about the operations
|
|
|
186 |
#
|
|
|
187 |
# Inputs : Nothing
|
|
|
188 |
#
|
|
|
189 |
# Returns : A blessed ref
|
|
|
190 |
#
|
|
|
191 |
sub SvnSession
|
|
|
192 |
{
|
|
|
193 |
my $self = {};
|
|
|
194 |
|
|
|
195 |
#
|
| 311 |
dpurdie |
196 |
# Delayed error reporting
|
|
|
197 |
# Allows the the package to be used when SVN is not installed
|
|
|
198 |
# as long as we don't want to use any of the features
|
|
|
199 |
#
|
|
|
200 |
# Think of 'help' when svn is not yet installed
|
|
|
201 |
#
|
|
|
202 |
Error ("The JATS stdmux utility cannot be found" ) unless ( $stdmux );
|
|
|
203 |
Error ("The svn utility cannot be found", "Configured Path: $::GBE_SVN_PATH") unless ( $svn );
|
|
|
204 |
|
|
|
205 |
#
|
| 267 |
dpurdie |
206 |
# Documented instance variables
|
|
|
207 |
#
|
|
|
208 |
$self->{REVNO} = undef; # Revision of last Repository operation
|
|
|
209 |
$self->{ERROR_LIST} = []; # Last SVN operation errors
|
|
|
210 |
$self->{RESULT_LIST} = []; # Last SVN operation results
|
|
|
211 |
$self->{PRINTDATA} = 0; # Global control of ProcessRevNo
|
|
|
212 |
|
|
|
213 |
bless ($self, __PACKAGE__);
|
|
|
214 |
}
|
|
|
215 |
|
|
|
216 |
#-------------------------------------------------------------------------------
|
|
|
217 |
# Function : SvnDelete
|
|
|
218 |
#
|
|
|
219 |
# Description : Delete a directory within a repostory
|
|
|
220 |
# Intended to be used to remove tags and branches
|
|
|
221 |
#
|
|
|
222 |
# Inputs : $self - Instance data
|
|
|
223 |
# A hash of named arguments
|
|
|
224 |
# target - Path to remove
|
|
|
225 |
# comment - User comment
|
|
|
226 |
# noerror - Don't panic on failure
|
|
|
227 |
#
|
|
|
228 |
#
|
|
|
229 |
# Returns : True - delete failed and 'noerror' was present
|
|
|
230 |
#
|
|
|
231 |
sub SvnDelete
|
|
|
232 |
{
|
|
|
233 |
my $self = shift;
|
|
|
234 |
my %opt = @_;
|
|
|
235 |
Debug ("SvnDelete");
|
|
|
236 |
Error ("Odd number of args to SvnDelete") unless ((@_ % 2) == 0);
|
|
|
237 |
Error ("SvnDelete: No target specified" ) unless ( $opt{'target'} );
|
|
|
238 |
|
|
|
239 |
my $error = $opt{'noerror'} ? '' : "SvnDelete: Target not deleted";
|
|
|
240 |
|
|
|
241 |
my $rv = SvnCmd ($self, 'delete'
|
|
|
242 |
, $opt{'target'}
|
|
|
243 |
, '-m', SvnComment( $opt{'comment'}, 'Deleted by SvnDelete' ),
|
|
|
244 |
, { 'credentials' => 1,
|
|
|
245 |
'error' => $error } );
|
|
|
246 |
return $rv;
|
|
|
247 |
}
|
|
|
248 |
|
|
|
249 |
|
|
|
250 |
#-------------------------------------------------------------------------------
|
|
|
251 |
# Function : SvnRename
|
|
|
252 |
#
|
|
|
253 |
# Description : Rename something within a repository
|
|
|
254 |
# Intended to be used to rename tags and branches
|
|
|
255 |
#
|
|
|
256 |
# A few tricks
|
|
|
257 |
# - Rename is the same as a copy-delete
|
|
|
258 |
# but it doesn't work if the source is pegged
|
|
|
259 |
# so we just use a copy.
|
|
|
260 |
# - Need to ensure the target does not exist
|
|
|
261 |
# because if it does then we may create a subdir
|
|
|
262 |
# within it.
|
|
|
263 |
#
|
|
|
264 |
# Inputs : $self - Instance data
|
|
|
265 |
# A hash of named arguments
|
|
|
266 |
# old - Location within the repository to copy from
|
|
|
267 |
# new - Location within the repository to copy to
|
|
|
268 |
# comment - Commit comment
|
|
|
269 |
# revision - ref to returned revision tag
|
|
|
270 |
# tag - ref to URL of the Check In
|
|
|
271 |
# replace - True: Delete existing tag if present
|
|
|
272 |
#
|
|
|
273 |
# Returns : Revision of the copy
|
|
|
274 |
#
|
|
|
275 |
sub SvnRename
|
|
|
276 |
{
|
|
|
277 |
my $self = shift;
|
|
|
278 |
my %opt = @_;
|
|
|
279 |
Debug ("SvnRename");
|
|
|
280 |
Error ("Odd number of args to SvnRename") unless ((@_ % 2) == 0);
|
|
|
281 |
|
|
|
282 |
#
|
|
|
283 |
# Insert defaults
|
|
|
284 |
#
|
|
|
285 |
my $old = $opt{old} || Error ("SvnRename: Source not specified" );
|
|
|
286 |
my $new = $opt{new} || Error ("SvnRename: Target not specified" );
|
|
|
287 |
|
|
|
288 |
#
|
|
|
289 |
# Validate the source
|
|
|
290 |
# Must do this in case the target-delete fails
|
|
|
291 |
#
|
|
|
292 |
SvnValidateTarget ( $self,
|
|
|
293 |
'cmd' => 'SvnRename',
|
|
|
294 |
'target' => $old,
|
|
|
295 |
'require' => 1,
|
|
|
296 |
);
|
|
|
297 |
|
|
|
298 |
#
|
|
|
299 |
# Validate the target
|
|
|
300 |
# Repo needs to be valid, but we may be able
|
|
|
301 |
# to delete the target if it does exist
|
|
|
302 |
#
|
|
|
303 |
SvnValidateTarget ( $self,
|
|
|
304 |
'target' => $new,
|
|
|
305 |
'delete' => $opt{replace},
|
|
|
306 |
);
|
|
|
307 |
#
|
|
|
308 |
# The 'rename' command does not handle a pegged source
|
|
|
309 |
# Detect this and use a 'copy' command
|
|
|
310 |
# We don't need to delete the source - as its pegged.
|
|
|
311 |
#
|
|
|
312 |
my $cmd = ($old =~ m~@\d+$~) ? 'copy' : 'rename';
|
|
|
313 |
SvnCmd ($self, $cmd
|
|
|
314 |
, $old
|
|
|
315 |
, $new
|
|
|
316 |
, '-m', SvnComment($opt{'comment'},'Renamed by SvnRename'),
|
|
|
317 |
, { 'credentials' => 1,
|
|
|
318 |
'process' => \&ProcessRevNo
|
|
|
319 |
, 'error' => "SvnRename: Target not renamed" } );
|
|
|
320 |
|
|
|
321 |
|
|
|
322 |
CalcRmReference($self, $new );
|
|
|
323 |
Message ("Tag is: " . $self->{RMREF} );
|
|
|
324 |
return $self->{RMREF} ;
|
|
|
325 |
}
|
|
|
326 |
|
|
|
327 |
#-------------------------------------------------------------------------------
|
|
|
328 |
# Function : SvnCopy
|
|
|
329 |
#
|
|
|
330 |
# Description : Copy something within a repository
|
|
|
331 |
# Intended to be used to copy tags and branches
|
|
|
332 |
#
|
|
|
333 |
# A few tricks
|
|
|
334 |
# - Need to ensure the target does not exist
|
|
|
335 |
# because if it does then we may create a subdir
|
|
|
336 |
# within it.
|
|
|
337 |
#
|
|
|
338 |
# Inputs : $self - Instance data
|
|
|
339 |
# A hash of named arguments
|
|
|
340 |
# old - Location within the repository to copy from
|
|
|
341 |
# new - Location within the repository to copy to
|
|
|
342 |
# comment - Commit comment
|
|
|
343 |
# revision - ref to returned revision tag
|
|
|
344 |
# tag - ref to URL of the Check In
|
|
|
345 |
# replace - True: Delete existing tag if present
|
|
|
346 |
# cmd - Error Prefix
|
|
|
347 |
# validated - Locations already validated
|
|
|
348 |
#
|
|
|
349 |
# Returns : Revision of the copy
|
|
|
350 |
#
|
|
|
351 |
sub SvnCopy
|
|
|
352 |
{
|
|
|
353 |
my $self = shift;
|
|
|
354 |
my %opt = @_;
|
|
|
355 |
Debug ("SvnCopy");
|
|
|
356 |
Error ("Odd number of args to SvnCopy") unless ((@_ % 2) == 0);
|
|
|
357 |
|
|
|
358 |
#
|
|
|
359 |
# Insert defaults
|
|
|
360 |
#
|
|
|
361 |
my $cmd = $opt{'cmd'} || 'SvnCopy';
|
|
|
362 |
my $old = $opt{old} || Error ("$cmd: Source not specified" );
|
|
|
363 |
my $new = $opt{new} || Error ("$cmd: Target not specified" );
|
|
|
364 |
|
|
|
365 |
#
|
|
|
366 |
# Validate the source
|
|
|
367 |
# Must do this in case the target-delete fails
|
|
|
368 |
#
|
|
|
369 |
SvnValidateTarget ( $self,
|
|
|
370 |
'cmd' => $cmd,
|
|
|
371 |
'target' => $old,
|
|
|
372 |
'require' => 1,
|
|
|
373 |
);
|
|
|
374 |
|
|
|
375 |
#
|
|
|
376 |
# Validate the target
|
|
|
377 |
# Repo needs to be valid, but we may be able
|
|
|
378 |
# to delete the target if it does exist
|
|
|
379 |
#
|
|
|
380 |
SvnValidateTarget ( $self,
|
|
|
381 |
'cmd' => $cmd,
|
|
|
382 |
'target' => $new,
|
|
|
383 |
'delete' => $opt{replace},
|
|
|
384 |
);
|
|
|
385 |
#
|
|
|
386 |
# Copy the URLs
|
|
|
387 |
#
|
|
|
388 |
SvnCmd ($self , 'copy'
|
|
|
389 |
, $old
|
|
|
390 |
, $new
|
|
|
391 |
, '-m', SvnComment($opt{'comment'},"Copied by $cmd"),
|
|
|
392 |
, { 'credentials' => 1
|
|
|
393 |
, 'process' => \&ProcessRevNo
|
|
|
394 |
, 'error' => "$cmd: Source not copied" } );
|
|
|
395 |
|
|
|
396 |
CalcRmReference($self, $new );
|
|
|
397 |
Message ("Tag is: " . $self->{RMREF} );
|
|
|
398 |
return $self->{RMREF} ;
|
|
|
399 |
}
|
|
|
400 |
|
|
|
401 |
|
|
|
402 |
#-------------------------------------------------------------------------------
|
|
|
403 |
# Function : SvnValidateTarget
|
|
|
404 |
#
|
|
|
405 |
# Description : Validate a target within the repository
|
|
|
406 |
# Optional allow the target to be deleted
|
|
|
407 |
# Mostly used internally
|
|
|
408 |
#
|
|
|
409 |
# Inputs : $self - Instance data
|
|
|
410 |
# A hash of named arguments
|
|
|
411 |
# target - Location within the repository to test
|
|
|
412 |
# cmd - Name of command to use in messages
|
|
|
413 |
# delete - Delete if it exists
|
|
|
414 |
# require - Target must exist
|
|
|
415 |
# available - Target must NOT exist
|
|
|
416 |
# comment - Deletion comment
|
|
|
417 |
# test - Just test existance
|
| 379 |
dpurdie |
418 |
# create - Create if it doesn't exist
|
| 267 |
dpurdie |
419 |
#
|
|
|
420 |
# Returns : May not return
|
| 385 |
dpurdie |
421 |
# 2 : Exists and was created
|
|
|
422 |
# 1 : Exists
|
|
|
423 |
# 0 : Not exist (any more)
|
| 267 |
dpurdie |
424 |
#
|
|
|
425 |
sub SvnValidateTarget
|
|
|
426 |
{
|
|
|
427 |
my $self = shift;
|
|
|
428 |
my %opt = @_;
|
|
|
429 |
Debug ("SvnValidateTarget", $opt{target});
|
|
|
430 |
Error ("Odd number of args to SvnValidateTarget") unless ((@_ % 2) == 0);
|
|
|
431 |
|
|
|
432 |
#
|
|
|
433 |
# Validate options
|
|
|
434 |
#
|
|
|
435 |
Error ("SvnValidateTarget: No target specified") unless ( $opt{target} );
|
|
|
436 |
$opt{cmd} = "SvnValidateTarget" unless ( $opt{cmd} );
|
|
|
437 |
my $cmd = $opt{cmd};
|
|
|
438 |
|
|
|
439 |
#
|
|
|
440 |
# Ensure that the target path does not exist
|
|
|
441 |
# Cannot allow a 'copy'/'rename' to copy into an existing path as
|
|
|
442 |
# Two problems:
|
|
|
443 |
# 1) We end up copying the source into a subdir of
|
|
|
444 |
# target path, which is not what we want.
|
|
|
445 |
# 2) Should use update to do that sort of a job
|
|
|
446 |
#
|
|
|
447 |
unless ( SvnTestPath ( $self, $cmd, $opt{target} ))
|
|
|
448 |
{
|
|
|
449 |
#
|
|
|
450 |
# Target does not exist
|
|
|
451 |
#
|
|
|
452 |
return 0 if ( $opt{'test'} || $opt{'available'} );
|
|
|
453 |
|
| 379 |
dpurdie |
454 |
#
|
|
|
455 |
# Create target if required
|
|
|
456 |
#
|
|
|
457 |
if ( $opt{create} )
|
|
|
458 |
{
|
|
|
459 |
$self->SvnCmd ('mkdir', $opt{target}
|
| 385 |
dpurdie |
460 |
, '-m', $self->Path() . ': Created by ' . $cmd
|
| 379 |
dpurdie |
461 |
, '--parents'
|
| 385 |
dpurdie |
462 |
, { 'credentials' => 1
|
|
|
463 |
,'error' => "SvnCreateBranch"
|
|
|
464 |
,'process' => \&ProcessRevNo
|
|
|
465 |
} );
|
|
|
466 |
return 2;
|
| 379 |
dpurdie |
467 |
}
|
|
|
468 |
|
| 267 |
dpurdie |
469 |
Error ("$cmd: Element does not exist", "Element: $opt{target}")
|
|
|
470 |
if ( $opt{'require'} );
|
|
|
471 |
}
|
|
|
472 |
else
|
|
|
473 |
{
|
|
|
474 |
#
|
|
|
475 |
# Target DOES exist
|
|
|
476 |
# - Good if the user requires the target
|
|
|
477 |
# - Error unless the user is prepared to delete it
|
|
|
478 |
#
|
|
|
479 |
return 1
|
| 379 |
dpurdie |
480 |
if ( $opt{'require'} || $opt{'test'} || $opt{'create'} );
|
| 267 |
dpurdie |
481 |
|
|
|
482 |
Error ("$cmd: Element exists", "Element: $opt{target}")
|
|
|
483 |
unless ( $opt{'delete'} );
|
|
|
484 |
|
|
|
485 |
#
|
|
|
486 |
# The user has requested that an existing target be deleted
|
|
|
487 |
#
|
|
|
488 |
SvnCmd ($self, 'delete'
|
|
|
489 |
, $opt{target}
|
|
|
490 |
, '-m', SvnComment($opt{'comment'},"Deleted by $cmd"),
|
|
|
491 |
, { 'credentials' => 1,
|
|
|
492 |
'error' => "$cmd: Element not deleted" } );
|
|
|
493 |
}
|
|
|
494 |
return 0;
|
|
|
495 |
}
|
|
|
496 |
|
|
|
497 |
#-------------------------------------------------------------------------------
|
|
|
498 |
# Function : ProcessRevNo
|
|
|
499 |
#
|
|
|
500 |
# Description : Callback function for SvnCmd to Extract a revision number
|
|
|
501 |
# from the svn command output stream
|
|
|
502 |
#
|
|
|
503 |
# Inputs : $self - Instance data
|
|
|
504 |
# $line - Command output
|
|
|
505 |
#
|
|
|
506 |
# Globals:
|
|
|
507 |
#
|
|
|
508 |
# Returns : zero - we don't want to kill the command
|
|
|
509 |
#
|
|
|
510 |
sub ProcessRevNo
|
|
|
511 |
{
|
|
|
512 |
my ($self, $line ) = @_;
|
|
|
513 |
|
|
|
514 |
if ( $line =~ m~Committed revision\s+(\d+)\.~i )
|
|
|
515 |
{
|
|
|
516 |
$self->{REVNO} = $1;
|
|
|
517 |
} elsif ( $self->{PRINTDATA} ) {
|
|
|
518 |
Message ( $line ) if $line;
|
|
|
519 |
}
|
|
|
520 |
return 0;
|
|
|
521 |
}
|
|
|
522 |
|
|
|
523 |
#-------------------------------------------------------------------------------
|
| 1329 |
dpurdie |
524 |
# Function : SvnInfo
|
|
|
525 |
#
|
|
|
526 |
# Description : Determine Subversion Info for a specified target
|
|
|
527 |
#
|
|
|
528 |
# Inputs : $self - Instance Data
|
|
|
529 |
# $url - Path or URL to get Info on
|
|
|
530 |
# $tag - Name of tag within $self to store data
|
|
|
531 |
#
|
|
|
532 |
# Returns : Non Zero if errors detected
|
|
|
533 |
#
|
|
|
534 |
sub SvnInfo
|
|
|
535 |
{
|
|
|
536 |
my ($self, $url, $tag) = @_;
|
|
|
537 |
Error ("Internal: SvnInfo. No Tag provided") unless ( defined $tag );
|
|
|
538 |
Error ("Internal: SvnInfo. No URL provided") unless ( defined $url );
|
|
|
539 |
|
|
|
540 |
#
|
|
|
541 |
# Only call once
|
|
|
542 |
# Must simulate a good call
|
|
|
543 |
#
|
|
|
544 |
if ( exists $self->{$tag} )
|
|
|
545 |
{
|
|
|
546 |
#DebugDumpData("MeCache: $tag", $self );
|
|
|
547 |
$self->{ERROR_LIST} = [];
|
|
|
548 |
return 0;
|
|
|
549 |
}
|
|
|
550 |
|
|
|
551 |
#
|
|
|
552 |
# Get basic information on the target
|
|
|
553 |
#
|
|
|
554 |
$self->{'infoTag'} = $tag;
|
|
|
555 |
$self->{$tag}{SvnInfoPath} = $url;
|
|
|
556 |
my $rv = $self->SvnCmd ('info', $url, '--depth', 'empty'
|
|
|
557 |
, { 'credentials' => 1,
|
|
|
558 |
'nosavedata' => 1,
|
|
|
559 |
'process' => \&ProcessInfo
|
|
|
560 |
}
|
|
|
561 |
);
|
|
|
562 |
|
|
|
563 |
delete $self->{$tag} if ( @{$self->{ERROR_LIST}} );
|
|
|
564 |
delete $self->{'infoTag'};
|
|
|
565 |
#DebugDumpData("Me: $tag", $self );
|
|
|
566 |
return $rv;
|
|
|
567 |
}
|
|
|
568 |
|
|
|
569 |
#-------------------------------------------------------------------------------
|
|
|
570 |
# Function : ProcessInfo
|
|
|
571 |
#
|
|
|
572 |
# Description : Process info for SvnInfo
|
|
|
573 |
#
|
|
|
574 |
# Inputs : $self - Instance data
|
|
|
575 |
# $line - Command output
|
|
|
576 |
#
|
|
|
577 |
# Returns : zero - we don't want to kill the command
|
|
|
578 |
#
|
|
|
579 |
sub ProcessInfo
|
|
|
580 |
{
|
|
|
581 |
my ($self, $line ) = @_;
|
|
|
582 |
|
|
|
583 |
Message ( $line ) if $self->{PRINTDATA};
|
|
|
584 |
$line =~ m~(.*?):\s+(.*)~;
|
|
|
585 |
$self->{$self->{'infoTag'}}{$1} = $2;
|
|
|
586 |
return 0;
|
|
|
587 |
}
|
|
|
588 |
|
|
|
589 |
#-------------------------------------------------------------------------------
|
| 267 |
dpurdie |
590 |
# Function : SvnScanPath
|
|
|
591 |
#
|
|
|
592 |
# Description : Internal helper function
|
|
|
593 |
# Scan a directory and split contents into three groups
|
|
|
594 |
#
|
|
|
595 |
# Inputs : $self - Instance data
|
|
|
596 |
# $cmd - Command prefix for errros
|
|
|
597 |
# $path - Path to test
|
|
|
598 |
#
|
|
|
599 |
# Returns : $ref_files - Ref to array of files
|
|
|
600 |
# $ref_dirs - Ref to array of dirs
|
|
|
601 |
# $ref_svn - Ref to array of svn dirs
|
|
|
602 |
# $found - True: Path found
|
|
|
603 |
#
|
|
|
604 |
sub SvnScanPath
|
|
|
605 |
{
|
|
|
606 |
my $self = shift;
|
|
|
607 |
my ($cmd, $path) = @_;
|
|
|
608 |
my @files;
|
|
|
609 |
my @dirs;
|
|
|
610 |
my @svn;
|
|
|
611 |
|
|
|
612 |
Debug ("SvnScanPath");
|
|
|
613 |
Verbose2 ("SvnScanPath: $path");
|
|
|
614 |
#
|
|
|
615 |
# Read in the directory information
|
|
|
616 |
# Just one level. Gets files and dirs
|
|
|
617 |
#
|
|
|
618 |
if ( ! SvnTestPath( $self, $cmd, $path, 1 ) )
|
|
|
619 |
{
|
|
|
620 |
#
|
|
|
621 |
# Path does not exist
|
|
|
622 |
#
|
|
|
623 |
return \@files, \@dirs, \@svn, 0;
|
|
|
624 |
}
|
|
|
625 |
|
|
|
626 |
#
|
|
|
627 |
# Path exists
|
|
|
628 |
# Sort into three sets
|
|
|
629 |
# - Svn Directories
|
|
|
630 |
# - Other Directories
|
|
|
631 |
# - Files
|
|
|
632 |
#
|
|
|
633 |
foreach ( @{$self->{RESULT_LIST}} )
|
|
|
634 |
{
|
|
|
635 |
if ( $_ eq 'trunk/' || $_ eq 'tags/' || $_ eq 'branches/' ) {
|
|
|
636 |
push @svn, $_;
|
|
|
637 |
|
|
|
638 |
} elsif ( substr ($_, -1) eq '/' ) {
|
|
|
639 |
push @dirs, $_;
|
|
|
640 |
|
|
|
641 |
} else {
|
|
|
642 |
push @files, $_;
|
|
|
643 |
}
|
|
|
644 |
}
|
|
|
645 |
|
|
|
646 |
return \@files, \@dirs, \@svn, 1;
|
|
|
647 |
}
|
|
|
648 |
|
|
|
649 |
#-------------------------------------------------------------------------------
|
|
|
650 |
# Function : SvnTestPath
|
|
|
651 |
#
|
|
|
652 |
# Description : Internal helper function
|
|
|
653 |
# Test a path within the Repo for existance
|
|
|
654 |
# Optionally read in immediate directory data
|
|
|
655 |
#
|
|
|
656 |
# Inputs : $self - Instance data
|
|
|
657 |
# $cmd - Command prefix for errros
|
|
|
658 |
# $path - Path to test
|
|
|
659 |
# $mode - True: Read in immediate data
|
|
|
660 |
#
|
|
|
661 |
# Returns : True : Path found
|
|
|
662 |
# False : Path is non-existent in revision
|
|
|
663 |
#
|
|
|
664 |
# May populate @RESULT_LIST with 'immediate' data
|
|
|
665 |
#
|
|
|
666 |
sub SvnTestPath
|
|
|
667 |
{
|
|
|
668 |
my $self = shift;
|
|
|
669 |
my ($cmd, $path, $mode) = @_;
|
|
|
670 |
my $depth = $mode ? 'immediates' : 'empty';
|
|
|
671 |
Debug ("SvnTestPath", @_);
|
|
|
672 |
|
|
|
673 |
#
|
|
|
674 |
# Read in the directory information - but no data
|
|
|
675 |
#
|
|
|
676 |
if ( SvnCmd ( $self, 'list', $path
|
|
|
677 |
, '--depth', $depth
|
|
|
678 |
, {'credentials' => 1,}
|
|
|
679 |
))
|
|
|
680 |
{
|
|
|
681 |
#
|
|
|
682 |
# Error occurred
|
|
|
683 |
# If the path does not exist then this is an error that
|
| 369 |
dpurdie |
684 |
# we can handle. The path does not exist in the Repository
|
| 267 |
dpurdie |
685 |
#
|
|
|
686 |
return 0
|
|
|
687 |
if ( $self->{ERROR_LIST}[0] =~ m~' non-existent in that revision$~
|
| 369 |
dpurdie |
688 |
|| $self->{ERROR_LIST}[0] =~ m~' non-existent in revision ~
|
| 267 |
dpurdie |
689 |
|| $self->{ERROR_LIST}[0] =~ m~: No repository found in '~
|
|
|
690 |
|| $self->{ERROR_LIST}[0] =~ m~: Error resolving case of '~
|
|
|
691 |
);
|
|
|
692 |
|
|
|
693 |
Error ("$cmd: Unexpected error", @{$self->{ERROR_LIST}});
|
|
|
694 |
}
|
|
|
695 |
return 1;
|
|
|
696 |
}
|
|
|
697 |
|
|
|
698 |
#-------------------------------------------------------------------------------
|
|
|
699 |
# Function : CalcRmReference
|
|
|
700 |
#
|
|
|
701 |
# Description : Determine the Release Manager Reference for a SVN
|
|
|
702 |
# operation
|
|
|
703 |
#
|
|
|
704 |
# Inputs : $self - Instance data
|
|
|
705 |
# $target - target
|
|
|
706 |
# $self->{REVNO} - Revision number
|
|
|
707 |
#
|
|
|
708 |
# Returns : RMREF - String Reference
|
|
|
709 |
#
|
|
|
710 |
sub CalcRmReference
|
|
|
711 |
{
|
|
|
712 |
my ($self, $target) = @_;
|
|
|
713 |
Error ("CalcRmReference: No Target") unless ( $target );
|
| 353 |
dpurdie |
714 |
Debug ("CalcRmReference: $target");
|
| 267 |
dpurdie |
715 |
|
|
|
716 |
#
|
| 353 |
dpurdie |
717 |
# Insert any revision information to create a pegged URL
|
|
|
718 |
#
|
| 369 |
dpurdie |
719 |
my $peg = $self->{REVNO} || $self->{WSREVNO};
|
|
|
720 |
$target .= '@' . $peg if $peg;
|
| 353 |
dpurdie |
721 |
|
|
|
722 |
#
|
| 267 |
dpurdie |
723 |
# Take target and remove the reference to the local repository,
|
|
|
724 |
# if its present. This will provide a ref that we can use on any site
|
|
|
725 |
#
|
| 353 |
dpurdie |
726 |
# Note: %SVN_URLS values will have a trailing '/'
|
| 267 |
dpurdie |
727 |
#
|
| 353 |
dpurdie |
728 |
# Sort in reverse order to ensure that the default URL is found last
|
| 399 |
dpurdie |
729 |
# Do case-insensitive compare. Cut the system some slack.
|
| 353 |
dpurdie |
730 |
#
|
|
|
731 |
foreach my $tag ( @SVN_URLS_LIST )
|
|
|
732 |
{
|
| 399 |
dpurdie |
733 |
if ( $target =~ s~^\Q$SVN_URLS{$tag}\E~$tag/~i )
|
| 353 |
dpurdie |
734 |
{
|
|
|
735 |
$target =~ s~^/~~;
|
|
|
736 |
last;
|
|
|
737 |
}
|
|
|
738 |
}
|
| 267 |
dpurdie |
739 |
return $self->{RMREF} = $target;
|
|
|
740 |
}
|
|
|
741 |
|
|
|
742 |
#-------------------------------------------------------------------------------
|
|
|
743 |
# Function : SvnComment
|
|
|
744 |
#
|
|
|
745 |
# Description : Create a nice SVN comment from a string or an array
|
|
|
746 |
#
|
|
|
747 |
# Inputs : user - User comment
|
|
|
748 |
# default - Default comment
|
|
|
749 |
#
|
|
|
750 |
# Comments may be:
|
|
|
751 |
# 1) A string - Simple
|
|
|
752 |
# 2) An array
|
|
|
753 |
#
|
|
|
754 |
# Returns : A string comment
|
|
|
755 |
#
|
|
|
756 |
sub SvnComment
|
|
|
757 |
{
|
|
|
758 |
my ($user, $default) = @_;
|
|
|
759 |
|
|
|
760 |
$user = $default unless ( $user );
|
|
|
761 |
return '' unless ( $user );
|
|
|
762 |
|
|
|
763 |
my $type = ref $user;
|
|
|
764 |
if ( $type eq '' ) {
|
|
|
765 |
return $user;
|
|
|
766 |
|
|
|
767 |
} elsif ( $type eq 'ARRAY' ) {
|
|
|
768 |
return join ("\n", @{$user});
|
|
|
769 |
|
|
|
770 |
} else {
|
|
|
771 |
Error ("Unknown comment type: $type");
|
|
|
772 |
}
|
|
|
773 |
}
|
|
|
774 |
|
|
|
775 |
|
|
|
776 |
#-------------------------------------------------------------------------------
|
|
|
777 |
# Function : SvnCredentials
|
|
|
778 |
#
|
|
|
779 |
# Description : Return an array of login credentials
|
|
|
780 |
# Used to extend command lines where repository access
|
|
|
781 |
# is required.
|
|
|
782 |
#
|
|
|
783 |
# There are security implications in using EnvVars
|
|
|
784 |
# to contain passwords. Its best to avoid their use
|
|
|
785 |
# and to let cached authentication from a user-session
|
|
|
786 |
# handle the process.
|
|
|
787 |
#
|
|
|
788 |
# Inputs : None
|
|
|
789 |
#
|
|
|
790 |
# Returns : An array - may be empty
|
|
|
791 |
#
|
|
|
792 |
sub SvnCredentials
|
|
|
793 |
{
|
|
|
794 |
my @result;
|
| 363 |
dpurdie |
795 |
Verbose2 ("SvnCredentials: $::USER");
|
| 267 |
dpurdie |
796 |
if ( $::GBE_SVN_USERNAME )
|
|
|
797 |
{
|
| 363 |
dpurdie |
798 |
Verbose2 ("SvnCredentials: GBE_SVN_USERNAME : $::GBE_SVN_USERNAME");
|
|
|
799 |
Verbose2 ("SvnCredentials: GBE_SVN_PASSWORD : Defined" ) if ($::GBE_SVN_PASSWORD);
|
|
|
800 |
|
| 267 |
dpurdie |
801 |
push @result, '--no-auth-cache';
|
|
|
802 |
push @result, '--username', $::GBE_SVN_USERNAME;
|
|
|
803 |
push @result, '--password', $::GBE_SVN_PASSWORD if ($::GBE_SVN_PASSWORD);
|
|
|
804 |
}
|
|
|
805 |
|
|
|
806 |
return @result;
|
|
|
807 |
}
|
|
|
808 |
|
|
|
809 |
#-------------------------------------------------------------------------------
|
|
|
810 |
# Function : SvnCmd
|
|
|
811 |
#
|
|
|
812 |
# Description : Run a Subversion Command and capture/process the
|
|
|
813 |
# output
|
|
|
814 |
#
|
|
|
815 |
# See also SvnUserCmd
|
|
|
816 |
#
|
|
|
817 |
# Inputs : $self - Instance data
|
|
|
818 |
# Command arguments
|
|
|
819 |
# Last argument may be a hash of options.
|
|
|
820 |
# credentials - Add credentials
|
|
|
821 |
# nosavedata - Don't save the data
|
|
|
822 |
# process - Callback function
|
|
|
823 |
# error - Error Message
|
|
|
824 |
# Used as first line of an Error call
|
|
|
825 |
#
|
|
|
826 |
# Returns : non-zero on errors detected
|
|
|
827 |
#
|
|
|
828 |
sub SvnCmd
|
|
|
829 |
{
|
|
|
830 |
my $self = shift;
|
|
|
831 |
Debug ("SvnCmd");
|
|
|
832 |
|
|
|
833 |
#
|
|
|
834 |
# Extract arguments and options
|
|
|
835 |
# If last argument is a hesh, then its a hash of options
|
|
|
836 |
#
|
|
|
837 |
my $opt;
|
|
|
838 |
$opt = pop @_
|
|
|
839 |
if (@_ > 0 and UNIVERSAL::isa($_[-1],'HASH'));
|
|
|
840 |
|
|
|
841 |
#
|
|
|
842 |
# All commands are non-interactive, prepend argument
|
| 367 |
dpurdie |
843 |
# Accept serve certs. Only applies to https connections. VisualSvn
|
|
|
844 |
# perfers https and it uses self-signed certificates.
|
| 267 |
dpurdie |
845 |
#
|
| 367 |
dpurdie |
846 |
unshift @_, '--non-interactive', '--trust-server-cert';
|
| 267 |
dpurdie |
847 |
Verbose2 "SvnCmd $svn @_";
|
|
|
848 |
|
|
|
849 |
#
|
|
|
850 |
# Prepend credentials, but don't show to users
|
|
|
851 |
#
|
|
|
852 |
unshift @_, SvnCredentials() if ( $opt->{'credentials'} );
|
|
|
853 |
|
|
|
854 |
#
|
|
|
855 |
# Useful debugging
|
|
|
856 |
#
|
|
|
857 |
# $self->{LAST_CMD} = [$svn, @_];
|
|
|
858 |
|
|
|
859 |
#
|
|
|
860 |
# Reset command output data
|
|
|
861 |
#
|
|
|
862 |
$self->{ERROR_LIST} = [];
|
|
|
863 |
$self->{RESULT_LIST} = [];
|
|
|
864 |
|
|
|
865 |
#
|
| 271 |
dpurdie |
866 |
# Make use of a wrapper program to mux the STDERR and STDOUT into
|
|
|
867 |
# one stream (STDOUT). # This solves a lot of problems
|
|
|
868 |
#
|
| 267 |
dpurdie |
869 |
# Do not use IO redirection of STDERR because as this will cause a
|
|
|
870 |
# shell (sh or cmd.exe) to be invoked and this makes it much
|
| 271 |
dpurdie |
871 |
# harder to kill on all platforms.
|
| 267 |
dpurdie |
872 |
#
|
|
|
873 |
# Use open3 as it allows the arguments to be passed
|
|
|
874 |
# directly without escaping and without any shell in the way
|
|
|
875 |
#
|
| 271 |
dpurdie |
876 |
local (*CHLD_OUT, *CHLD_IN);
|
|
|
877 |
my $pid = open3( \*CHLD_IN, \*CHLD_OUT, '>&STDERR', $stdmux, $svn, @_);
|
| 267 |
dpurdie |
878 |
|
|
|
879 |
#
|
|
|
880 |
# Looks as though we always get a PID - even if the process dies
|
|
|
881 |
# straight away or can't be found. I suspect that open3 doesn't set
|
|
|
882 |
# $! anyway. I know it doesn't set $?
|
|
|
883 |
#
|
|
|
884 |
Debug ("Pid: $pid");
|
|
|
885 |
Error ("Can't run command: $!") unless $pid;
|
|
|
886 |
|
|
|
887 |
#
|
|
|
888 |
# Close the input handle
|
|
|
889 |
# We don't have anything to send to this program
|
|
|
890 |
#
|
|
|
891 |
close(CHLD_IN);
|
|
|
892 |
|
|
|
893 |
#
|
|
|
894 |
# Monitor the output from the utility
|
| 271 |
dpurdie |
895 |
# Have used stdmux to multiplex stdout and stderr
|
| 267 |
dpurdie |
896 |
#
|
|
|
897 |
# Note: IO::Select doesn't work on Windows :(
|
| 271 |
dpurdie |
898 |
# Note: Open3 will cause blocking unless both streams are read
|
|
|
899 |
# Can read both streams becsue IO::Select doesn't work
|
| 267 |
dpurdie |
900 |
#
|
|
|
901 |
# Observation:
|
|
|
902 |
# svn puts errors to STDERR
|
|
|
903 |
# svn puts status to STDOUT
|
|
|
904 |
#
|
|
|
905 |
while (<CHLD_OUT>)
|
|
|
906 |
{
|
|
|
907 |
s~\s+$~~;
|
|
|
908 |
tr~\\/~/~;
|
|
|
909 |
|
| 379 |
dpurdie |
910 |
|
| 271 |
dpurdie |
911 |
Verbose3 ( "SvnCmd:" . $_);
|
|
|
912 |
m~^STD(...):(.+)~;
|
|
|
913 |
my $data = $1 ? $2 : $_;
|
|
|
914 |
next unless ( $data );
|
|
|
915 |
|
|
|
916 |
if ( $1 && $1 eq 'ERR' )
|
| 267 |
dpurdie |
917 |
{
|
| 271 |
dpurdie |
918 |
#
|
|
|
919 |
# Process STDERR output
|
|
|
920 |
#
|
|
|
921 |
push @{$self->{ERROR_LIST}}, $data;
|
| 267 |
dpurdie |
922 |
}
|
| 271 |
dpurdie |
923 |
else
|
|
|
924 |
{
|
|
|
925 |
#
|
|
|
926 |
# Process STDOUT data
|
|
|
927 |
#
|
|
|
928 |
push @{$self->{RESULT_LIST}}, $data unless ($opt->{'nosavedata'});
|
|
|
929 |
|
|
|
930 |
#
|
|
|
931 |
# If the user has specified a processing function then pass each
|
|
|
932 |
# line to the specified function. A non-zero return will
|
|
|
933 |
# be taken as a signal to kill the command.
|
|
|
934 |
#
|
|
|
935 |
if ( exists ($opt->{'process'}) && $opt->{'process'}($self, $data) )
|
|
|
936 |
{
|
|
|
937 |
kill 9, $pid;
|
|
|
938 |
last;
|
|
|
939 |
}
|
|
|
940 |
}
|
| 267 |
dpurdie |
941 |
}
|
|
|
942 |
|
|
|
943 |
close(CHLD_OUT);
|
|
|
944 |
|
|
|
945 |
#
|
|
|
946 |
# MUST wait for the process
|
|
|
947 |
# Under Windows if this is not done then we eventually fill up some
|
|
|
948 |
# perl-internal structure and can't spawn anymore processes.
|
|
|
949 |
#
|
|
|
950 |
my $rv = waitpid ( $pid, 0);
|
|
|
951 |
|
|
|
952 |
#
|
|
|
953 |
# If an error condition was detected and the user has provided
|
|
|
954 |
# an error message, then display the error
|
|
|
955 |
#
|
|
|
956 |
# This simplifies the user error processing
|
|
|
957 |
#
|
|
|
958 |
if ( @{$self->{ERROR_LIST}} && $opt->{'error'} )
|
|
|
959 |
{
|
|
|
960 |
Error ( $opt->{'error'}, @{$self->{ERROR_LIST}} );
|
|
|
961 |
}
|
|
|
962 |
|
|
|
963 |
#
|
|
|
964 |
# Exit status has no meaning since open3 has been used
|
|
|
965 |
# This is because perl does not treat the opened process as a child
|
|
|
966 |
# Not too sure it makes any difference anyway
|
|
|
967 |
#
|
|
|
968 |
#
|
|
|
969 |
Debug ("Useless Exit Status: $rv");
|
|
|
970 |
my $result = @{$self->{ERROR_LIST}} ? 1 : 0;
|
|
|
971 |
Verbose3 ("Exit Code: $result");
|
|
|
972 |
|
|
|
973 |
return $result;
|
|
|
974 |
}
|
|
|
975 |
|
| 271 |
dpurdie |
976 |
|
| 267 |
dpurdie |
977 |
#-------------------------------------------------------------------------------
|
|
|
978 |
# Function : SvnUserCmd
|
|
|
979 |
#
|
|
|
980 |
# Description : Run a Subversion Command for interactive user
|
|
|
981 |
# Intended to be used interactive
|
|
|
982 |
# No data captured or processed
|
|
|
983 |
# See also SvnCmd
|
|
|
984 |
#
|
|
|
985 |
# Inputs : Command arguments
|
|
|
986 |
# Last argument may be a hash of options.
|
|
|
987 |
# credentials - Add credentials
|
|
|
988 |
#
|
|
|
989 |
# Returns : Result code of the SVN command
|
|
|
990 |
#
|
|
|
991 |
sub SvnUserCmd
|
|
|
992 |
{
|
|
|
993 |
#
|
|
|
994 |
# Extract arguments and options
|
|
|
995 |
# If last argument is a hesh, then its a hash of options
|
|
|
996 |
#
|
|
|
997 |
my $opt;
|
|
|
998 |
$opt = pop @_
|
|
|
999 |
if (@_ > 0 and UNIVERSAL::isa($_[-1],'HASH'));
|
|
|
1000 |
|
|
|
1001 |
Verbose2 "SvnUserCmd $svn @_";
|
| 365 |
dpurdie |
1002 |
|
| 267 |
dpurdie |
1003 |
#
|
| 365 |
dpurdie |
1004 |
# Delayed error reporting
|
|
|
1005 |
# Allows the the package to be used when SVN is not installed
|
|
|
1006 |
# as long as we don't want to use any of the features
|
|
|
1007 |
#
|
|
|
1008 |
# Think of 'help' when svn is not yet installed
|
|
|
1009 |
#
|
|
|
1010 |
Error ("The JATS stdmux utility cannot be found" ) unless ( $stdmux );
|
|
|
1011 |
Error ("The svn utility cannot be found", "Configured Path: $::GBE_SVN_PATH") unless ( $svn );
|
|
|
1012 |
|
|
|
1013 |
#
|
| 267 |
dpurdie |
1014 |
# Prepend credentials, but don't show to users
|
|
|
1015 |
#
|
|
|
1016 |
unshift @_, SvnCredentials() if ( $opt->{'credentials'} );
|
|
|
1017 |
|
|
|
1018 |
|
|
|
1019 |
#
|
|
|
1020 |
# Run the command
|
|
|
1021 |
#
|
|
|
1022 |
my $rv = system( $svn, @_ );
|
|
|
1023 |
Verbose2 "System Result Code: $rv";
|
|
|
1024 |
Verbose2 "System Result Code: $!" if ($rv);
|
|
|
1025 |
|
|
|
1026 |
return $rv / 256;
|
|
|
1027 |
}
|
|
|
1028 |
|
|
|
1029 |
#------------------------------------------------------------------------------
|
|
|
1030 |
1;
|
| 363 |
dpurdie |
1031 |
|