line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SVN::Deploy::Utils;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
19
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
40
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
59
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.11';
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
4
|
use Carp;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
100
|
|
9
|
1
|
|
|
1
|
|
543
|
use SVN::Client;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Cwd;
|
12
|
|
|
|
|
|
|
use Digest::MD5;
|
13
|
|
|
|
|
|
|
use File::Spec::Functions qw/:ALL/;
|
14
|
|
|
|
|
|
|
use File::Copy;
|
15
|
|
|
|
|
|
|
use File::Temp qw/tempdir/;
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use Data::Dumper;
|
18
|
|
|
|
|
|
|
$Data::Dumper::Indent=1;
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our $Cleanup = 1;
|
22
|
|
|
|
|
|
|
our $Verbose = 0;
|
23
|
|
|
|
|
|
|
our $LastErr = '';
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my %arg_check = (
|
27
|
|
|
|
|
|
|
connect_cached => {qw/username o password o pwd_sub o/},
|
28
|
|
|
|
|
|
|
import_synch => {qw/
|
29
|
|
|
|
|
|
|
dir m url m log o
|
30
|
|
|
|
|
|
|
checkout o ctx o
|
31
|
|
|
|
|
|
|
/},
|
32
|
|
|
|
|
|
|
);
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub _vlog($@) { print join(' ', @_), "\n" if $Verbose; };
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub _getargs {
|
39
|
|
|
|
|
|
|
my $caller = (caller(1))[3];
|
40
|
|
|
|
|
|
|
croak "odd number of arguments for $caller()"
|
41
|
|
|
|
|
|
|
unless @_ % 2 == 0;
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
$caller =~ s/.*::(\w+)$/$1/;
|
44
|
|
|
|
|
|
|
my %tmp = @_;
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
for my $arg ( keys( %{ $arg_check{$caller} } ) ) {
|
47
|
|
|
|
|
|
|
next if $arg_check{$caller}{$arg} ne 'm';
|
48
|
|
|
|
|
|
|
croak "$caller: mandatory parameter '$arg' missing or empty"
|
49
|
|
|
|
|
|
|
unless $tmp{$arg};
|
50
|
|
|
|
|
|
|
}
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
for my $arg ( keys( %tmp ) ) {
|
53
|
|
|
|
|
|
|
croak "$caller: unknown parameter '$arg'"
|
54
|
|
|
|
|
|
|
unless exists($arg_check{$caller}{$arg});
|
55
|
|
|
|
|
|
|
}
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
return(@_);
|
58
|
|
|
|
|
|
|
}
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub _getmd5 {
|
62
|
|
|
|
|
|
|
my($fn) = @_;
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
open(my $fh, '<', $fn)
|
65
|
|
|
|
|
|
|
or croak "couldn't read '$fn', $!";
|
66
|
|
|
|
|
|
|
binmode($fh);
|
67
|
|
|
|
|
|
|
my $md5 = Digest::MD5->new()->addfile($fh)->hexdigest();
|
68
|
|
|
|
|
|
|
close($fh);
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
return($md5);
|
71
|
|
|
|
|
|
|
}
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub _svn {
|
75
|
|
|
|
|
|
|
my $ctx = shift;
|
76
|
|
|
|
|
|
|
my $call = shift;
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my @ret = $ctx->$call(@_);
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
if ( ref($ret[0]) eq '_p_svn_error_t' ) {
|
81
|
|
|
|
|
|
|
$LastErr = "svn call $call(" . join(', ', @_) . ') failed, '
|
82
|
|
|
|
|
|
|
. $ret[0]->expanded_message();
|
83
|
|
|
|
|
|
|
return;
|
84
|
|
|
|
|
|
|
}
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
return(wantarray ? @ret : ($ret[0] || 1) );
|
87
|
|
|
|
|
|
|
};
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub _simple_prompt {
|
91
|
|
|
|
|
|
|
my($realm) = @_;
|
92
|
|
|
|
|
|
|
my %cred;
|
93
|
|
|
|
|
|
|
print "Logon information for $realm\n";
|
94
|
|
|
|
|
|
|
for my $par ( qw/username password/ ) {
|
95
|
|
|
|
|
|
|
print ucfirst($par), ": ";
|
96
|
|
|
|
|
|
|
$cred{$par} = ;
|
97
|
|
|
|
|
|
|
chomp($cred{$par});
|
98
|
|
|
|
|
|
|
}
|
99
|
|
|
|
|
|
|
return(@cred{qw/username password/});
|
100
|
|
|
|
|
|
|
}
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub connect_cached {
|
104
|
|
|
|
|
|
|
my %args = _getargs(@_);
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $ctx = SVN::Client->new(
|
107
|
|
|
|
|
|
|
auth => [
|
108
|
|
|
|
|
|
|
SVN::Client::get_simple_provider(),
|
109
|
|
|
|
|
|
|
SVN::Client::get_simple_prompt_provider(sub {
|
110
|
|
|
|
|
|
|
unless ( $args{username} and $args{password} ) {
|
111
|
|
|
|
|
|
|
my $subref = ref($args{pwd_sub}) eq 'CODE'
|
112
|
|
|
|
|
|
|
? $args{pwd_sub}
|
113
|
|
|
|
|
|
|
: \&_simple_prompt;
|
114
|
|
|
|
|
|
|
@args{qw/username password/} = $subref->($_[1]);
|
115
|
|
|
|
|
|
|
}
|
116
|
|
|
|
|
|
|
$_[0]->username($args{username});
|
117
|
|
|
|
|
|
|
$_[0]->password($args{password});
|
118
|
|
|
|
|
|
|
$_[0]->may_save(1);
|
119
|
|
|
|
|
|
|
}, 2),
|
120
|
|
|
|
|
|
|
SVN::Client::get_username_provider()
|
121
|
|
|
|
|
|
|
],
|
122
|
|
|
|
|
|
|
);
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
return($ctx);
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub import_synch {
|
129
|
|
|
|
|
|
|
my %args = _getargs(@_);
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
my $ctx = $args{ctx} || connect_cached();
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
$args{dir} = rel2abs($args{dir});
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
my $tempdir = tempdir(
|
136
|
|
|
|
|
|
|
'SVN-Deploy-Utils-XXXXXX',
|
137
|
|
|
|
|
|
|
CLEANUP => $Cleanup,
|
138
|
|
|
|
|
|
|
TMPDIR => 1,
|
139
|
|
|
|
|
|
|
);
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $origdir = getcwd();
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
if ( $args{log} ) {
|
144
|
|
|
|
|
|
|
_svn($ctx, 'log_msg', sub { ${$_[0]} = $args{log}; })
|
145
|
|
|
|
|
|
|
or return;
|
146
|
|
|
|
|
|
|
}
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# iterating over svn dir
|
149
|
|
|
|
|
|
|
# - locally missing -> delete in svn
|
150
|
|
|
|
|
|
|
# - locally name matches, type differs -> delete in svn
|
151
|
|
|
|
|
|
|
_vlog "pass 1: check for deleted items";
|
152
|
|
|
|
|
|
|
my @dstack;
|
153
|
|
|
|
|
|
|
my %todo;
|
154
|
|
|
|
|
|
|
my %ent_cache;
|
155
|
|
|
|
|
|
|
my $last_commit_revnum = -1;
|
156
|
|
|
|
|
|
|
do {{
|
157
|
|
|
|
|
|
|
my $suburl = join('/', @dstack);
|
158
|
|
|
|
|
|
|
$suburl = ' ' unless length($suburl);
|
159
|
|
|
|
|
|
|
my $url = join('/', $args{url}, @dstack);
|
160
|
|
|
|
|
|
|
my $subdir = catdir(@dstack);
|
161
|
|
|
|
|
|
|
my $dir = catdir($args{dir}, $subdir);
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# get entries for $url unless already done
|
164
|
|
|
|
|
|
|
unless ( $todo{$suburl} ) {
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
_vlog "getting entries for $url";
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
my $entries_href = _svn($ctx, 'ls', $url, 'HEAD', 0)
|
169
|
|
|
|
|
|
|
or return;
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
_vlog Dumper($entries_href);
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
$todo{$suburl} = [
|
174
|
|
|
|
|
|
|
map { {
|
175
|
|
|
|
|
|
|
name => $_,
|
176
|
|
|
|
|
|
|
kind => $entries_href->{$_}->kind,
|
177
|
|
|
|
|
|
|
time => $entries_href->{$_}->time,
|
178
|
|
|
|
|
|
|
size => $entries_href->{$_}->size,
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
} } keys(%$entries_href)
|
181
|
|
|
|
|
|
|
];
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# cache entries for later
|
184
|
|
|
|
|
|
|
$ent_cache{ join('/', $url, $_) }
|
185
|
|
|
|
|
|
|
= $entries_href->{$_} for keys(%$entries_href);
|
186
|
|
|
|
|
|
|
}
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $node = shift(@{$todo{$suburl}});
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# all nodes processed -> one up
|
191
|
|
|
|
|
|
|
unless ( defined($node) ) {
|
192
|
|
|
|
|
|
|
_vlog " --> no more nodes in $suburl, going back";
|
193
|
|
|
|
|
|
|
pop(@dstack);
|
194
|
|
|
|
|
|
|
delete($todo{$suburl}) unless $suburl eq ' ';
|
195
|
|
|
|
|
|
|
next;
|
196
|
|
|
|
|
|
|
}
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
my $locfile = catfile($dir, $node->{name});
|
199
|
|
|
|
|
|
|
my $svnfile = join('/', $url, $node->{name});
|
200
|
|
|
|
|
|
|
my $svnshort = join('/', @dstack, $node->{name});
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
_vlog " --> processing node '$svnshort'";
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# process node
|
205
|
|
|
|
|
|
|
if ( $node->{kind} == $SVN::Node::dir ) {
|
206
|
|
|
|
|
|
|
if ( -d $locfile ) {
|
207
|
|
|
|
|
|
|
_vlog " --> dir: pushing on stack";
|
208
|
|
|
|
|
|
|
push(@dstack, $node->{name});
|
209
|
|
|
|
|
|
|
} else {
|
210
|
|
|
|
|
|
|
_vlog " --> locally deleted or type changed -> deleting";
|
211
|
|
|
|
|
|
|
my $info = _svn($ctx, 'delete', $svnfile, 1)
|
212
|
|
|
|
|
|
|
or return;
|
213
|
|
|
|
|
|
|
$last_commit_revnum = $info->revision;
|
214
|
|
|
|
|
|
|
delete($ent_cache{$svnfile});
|
215
|
|
|
|
|
|
|
}
|
216
|
|
|
|
|
|
|
} else {
|
217
|
|
|
|
|
|
|
next if -e $locfile and !-d $locfile;
|
218
|
|
|
|
|
|
|
_vlog " --> locally deleted or type changed -> deleting";
|
219
|
|
|
|
|
|
|
my $info = _svn($ctx, 'delete', $svnfile, 1)
|
220
|
|
|
|
|
|
|
or return;
|
221
|
|
|
|
|
|
|
$last_commit_revnum = $info->revision;
|
222
|
|
|
|
|
|
|
delete($ent_cache{$svnfile});
|
223
|
|
|
|
|
|
|
}
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
}} while @dstack or @{$todo{' '}};
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# iterating over external dir
|
229
|
|
|
|
|
|
|
# - new dirs -> mkdir in repo
|
230
|
|
|
|
|
|
|
# - new files -> add to repo, add MD5 property
|
231
|
|
|
|
|
|
|
# - external file time > repo file time
|
232
|
|
|
|
|
|
|
# or external file size != repo file size
|
233
|
|
|
|
|
|
|
# or external file MD5 != MD5 property
|
234
|
|
|
|
|
|
|
# -> commit, set md5 property
|
235
|
|
|
|
|
|
|
_vlog "pass 2: check for new or changed items";
|
236
|
|
|
|
|
|
|
@dstack = ();
|
237
|
|
|
|
|
|
|
%todo = ();
|
238
|
|
|
|
|
|
|
my %to_commit;
|
239
|
|
|
|
|
|
|
do {{
|
240
|
|
|
|
|
|
|
my $suburl = join('/', @dstack);
|
241
|
|
|
|
|
|
|
my $url = join('/', $args{url}, @dstack);
|
242
|
|
|
|
|
|
|
my $subdir = catdir(@dstack);
|
243
|
|
|
|
|
|
|
$subdir = ' ' unless length($subdir);
|
244
|
|
|
|
|
|
|
my $dir = catdir($args{dir}, @dstack);
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# get entries for $dir unless already done
|
247
|
|
|
|
|
|
|
unless ( $todo{$subdir} ) {
|
248
|
|
|
|
|
|
|
opendir(my $dh, $dir)
|
249
|
|
|
|
|
|
|
or croak "couldn't open dir '$dir', $!";
|
250
|
|
|
|
|
|
|
$todo{$subdir} = [grep {not /^\.{1,2}$/} readdir($dh)];
|
251
|
|
|
|
|
|
|
}
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
my $node = shift(@{$todo{$subdir}});
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# all nodes processed -> one up
|
256
|
|
|
|
|
|
|
unless ( defined($node) ) {
|
257
|
|
|
|
|
|
|
_vlog " --> no more nodes in $subdir, going back";
|
258
|
|
|
|
|
|
|
pop(@dstack);
|
259
|
|
|
|
|
|
|
delete($todo{$subdir}) unless $subdir eq ' ';
|
260
|
|
|
|
|
|
|
next;
|
261
|
|
|
|
|
|
|
}
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
my $locfile = catfile($dir, $node);
|
264
|
|
|
|
|
|
|
my $svnfile = join('/', $url, $node);
|
265
|
|
|
|
|
|
|
my $locshort = catfile(@dstack, $node);
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
_vlog " --> processing node '$locshort'";
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# process node
|
270
|
|
|
|
|
|
|
my $svnent = $ent_cache{$svnfile};
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
if ( -d $locfile ) {
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
unless ( defined($svnent) ) {
|
275
|
|
|
|
|
|
|
_vlog " --> dir: creating in svn";
|
276
|
|
|
|
|
|
|
_svn($ctx, 'mkdir', $svnfile) or return;
|
277
|
|
|
|
|
|
|
}
|
278
|
|
|
|
|
|
|
_vlog " --> dir: pushing on stack";
|
279
|
|
|
|
|
|
|
push(@dstack, $node);
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
} else {
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
my($svn_md5, $loc_md5);
|
284
|
|
|
|
|
|
|
my $state = 'new';
|
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
if ( defined($svnent) ) {
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# exists in svn -> compare
|
289
|
|
|
|
|
|
|
my $svn_time = $svnent->time;
|
290
|
|
|
|
|
|
|
my $svn_size = $svnent->size;
|
291
|
|
|
|
|
|
|
$svn_md5
|
292
|
|
|
|
|
|
|
= _svn($ctx, 'propget', 'md5', $svnfile, 'HEAD', 0);
|
293
|
|
|
|
|
|
|
$svn_md5 = ($svn_md5 && $svn_md5->{$svnfile})
|
294
|
|
|
|
|
|
|
? $svn_md5->{$svnfile}
|
295
|
|
|
|
|
|
|
: '';
|
296
|
|
|
|
|
|
|
substr($svn_time, -6) = '';
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
my $loc_time = (stat($locfile))[9];
|
299
|
|
|
|
|
|
|
my $loc_size = -s $locfile;
|
300
|
|
|
|
|
|
|
$loc_md5 = _getmd5($locfile);
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
next if $loc_size == 0 and $svn_size == 0;
|
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
my $changed
|
305
|
|
|
|
|
|
|
= (
|
306
|
|
|
|
|
|
|
$loc_size != $svn_size
|
307
|
|
|
|
|
|
|
or $loc_time > $svn_time
|
308
|
|
|
|
|
|
|
or $loc_md5 ne $svn_md5
|
309
|
|
|
|
|
|
|
);
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
if ( $changed ) {
|
312
|
|
|
|
|
|
|
$state = 'changed';
|
313
|
|
|
|
|
|
|
} else {
|
314
|
|
|
|
|
|
|
next;
|
315
|
|
|
|
|
|
|
}
|
316
|
|
|
|
|
|
|
} else {
|
317
|
|
|
|
|
|
|
$loc_md5 = _getmd5($locfile);
|
318
|
|
|
|
|
|
|
}
|
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
_vlog " --> $state file: adding to svn";
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# copying file to workdir
|
323
|
|
|
|
|
|
|
unless ( $to_commit{$subdir} and -d $to_commit{$subdir} ) {
|
324
|
|
|
|
|
|
|
my $tempsub = catdir($tempdir, join('-', @dstack) || 'root' );
|
325
|
|
|
|
|
|
|
_vlog " --> checkout '$url' to '$tempsub'";
|
326
|
|
|
|
|
|
|
_svn($ctx, 'checkout', $url, $tempsub, 'HEAD', 0)
|
327
|
|
|
|
|
|
|
or return;
|
328
|
|
|
|
|
|
|
$to_commit{$subdir} = $tempsub;
|
329
|
|
|
|
|
|
|
}
|
330
|
|
|
|
|
|
|
my $workfile = catfile($to_commit{$subdir}, $node);
|
331
|
|
|
|
|
|
|
copy($locfile, $workfile)
|
332
|
|
|
|
|
|
|
or croak "couldn't copy '$locfile' to '$workfile', $!";
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
chdir($to_commit{$subdir});
|
335
|
|
|
|
|
|
|
if ( $state eq 'new' ) {
|
336
|
|
|
|
|
|
|
_svn($ctx, 'add', $node, 0)
|
337
|
|
|
|
|
|
|
or return;
|
338
|
|
|
|
|
|
|
}
|
339
|
|
|
|
|
|
|
_svn($ctx, 'propset', 'md5', $loc_md5, $node, 0)
|
340
|
|
|
|
|
|
|
or return;
|
341
|
|
|
|
|
|
|
}
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
}} while @dstack or @{$todo{' '}};
|
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
for my $v ( values(%to_commit) ) {
|
346
|
|
|
|
|
|
|
my $info = _svn($ctx, 'commit', $v, 0)
|
347
|
|
|
|
|
|
|
or return;
|
348
|
|
|
|
|
|
|
$last_commit_revnum = $info->revision
|
349
|
|
|
|
|
|
|
if $info->revision != $SVN::Core::INVALID_REVNUM;
|
350
|
|
|
|
|
|
|
}
|
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
chdir($origdir);
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
return($last_commit_revnum);
|
355
|
|
|
|
|
|
|
}
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
1;
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
## POD
|
361
|
|
|
|
|
|
|
=head1 NAME
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
SVN::Deploy::Utils - utility functions for SVN::Deploy
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
use SVN::Deploy::Utils;
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
my $rev = import_synch(
|
370
|
|
|
|
|
|
|
dir => '/my/local/dir',
|
371
|
|
|
|
|
|
|
url => 'svn://myrepo/trunk/mypath',
|
372
|
|
|
|
|
|
|
log => 'my import logmessage',
|
373
|
|
|
|
|
|
|
) or die $SVN::Deploy::Utils::LastErr;
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
SVN::Deploy::Utils provides two high level utility functions
|
378
|
|
|
|
|
|
|
encapsuling SVN::Client methods.
|
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=head1 FUNCTIONS
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
All functions return undef on error. $SVN::Deploy::Utils::LastErr will
|
383
|
|
|
|
|
|
|
contain a printable error message.
|
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head2 connect_cached
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
my $ctx = connect_cached(
|
388
|
|
|
|
|
|
|
[username => ,]
|
389
|
|
|
|
|
|
|
[password => ,]
|
390
|
|
|
|
|
|
|
[pwd_sub => ,]
|
391
|
|
|
|
|
|
|
);
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Returns an SVN::Client context object caching the authorization
|
394
|
|
|
|
|
|
|
information for later use. pwd_sub must reference a sub returning
|
395
|
|
|
|
|
|
|
username and password for e.g. user interaction.
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head2 import_synch
|
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
my $rev = import_synch(
|
400
|
|
|
|
|
|
|
dir => ,
|
401
|
|
|
|
|
|
|
url => ,
|
402
|
|
|
|
|
|
|
[log => ,]
|
403
|
|
|
|
|
|
|
[ctx => ,]
|
404
|
|
|
|
|
|
|
)
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Imports a local directory into a subversion repository. Adds or
|
407
|
|
|
|
|
|
|
deletes files and directories when neccessary, so that repeating calls
|
408
|
|
|
|
|
|
|
after changes in the local unversioned directory will result in
|
409
|
|
|
|
|
|
|
corresponding changes in the repository path.
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
If ctx is specified import_synch will use this context, otherwise it
|
412
|
|
|
|
|
|
|
will call connect_cached() without parameters.
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=head1 AUTHOR
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Thomas Kratz Etomk@cpan.orgE
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
Copyright (c) 2008 Thomas Kratz. All rights reserved.
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
421
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.8 or,
|
422
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available.
|
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=cut
|