svn-transform 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +101 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/examples/example_helper.rb +31 -0
- data/examples/fixtures/dir_props.rb +29 -0
- data/examples/fixtures/original.rb +86 -0
- data/examples/fixtures/result.rb +105 -0
- data/examples/svn-transform/dir_example.rb +56 -0
- data/examples/svn-transform/file_example.rb +71 -0
- data/examples/svn-transform/transform/extension_example.rb +48 -0
- data/examples/svn-transform/transform/newline_example.rb +51 -0
- data/examples/svn-transform/transform/noop_example.rb +15 -0
- data/examples/svn-transform/transform/props_to_yaml_example.rb +137 -0
- data/examples/svn-transform_example.rb +148 -0
- data/lib/svn-transform.rb +264 -0
- data/lib/svn-transform/dir.rb +65 -0
- data/lib/svn-transform/file.rb +79 -0
- data/lib/svn-transform/session.rb +62 -0
- data/lib/svn-transform/transform/extension.rb +41 -0
- data/lib/svn-transform/transform/newline.rb +50 -0
- data/lib/svn-transform/transform/noop.rb +28 -0
- data/lib/svn-transform/transform/props_to_yaml.rb +134 -0
- metadata +115 -0
@@ -0,0 +1,264 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'svn-fixture'
|
3
|
+
|
4
|
+
class SvnTransform
|
5
|
+
VERSION = '0.1.0'
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Use diff to compare two repositories (on local file system)
|
9
|
+
# Where reasonable, this (or something like it) should be run to verify
|
10
|
+
# expected results. I recommend trying a direct copy first to ensure your
|
11
|
+
# original repo doesn't have any featurs that SvnPropsToYaml won't
|
12
|
+
# understand.
|
13
|
+
#
|
14
|
+
# http://www.coderetard.com/2009/02/17/compare-directories-and-file-content-in-linux-without-dircmp/
|
15
|
+
#
|
16
|
+
# ==== Gotchas
|
17
|
+
# svn:entry fields aren't directly copied, but seem to match.
|
18
|
+
# repo uuid is different, but not relevant, so that file is ignored.
|
19
|
+
# other differences may also exist if the in_repo is an older format.
|
20
|
+
#
|
21
|
+
# ==== Parameters
|
22
|
+
# old_dir<String>:: FS Path to original (in) repository.
|
23
|
+
# new_dir<String>:: FS Path to generated (out) repository.
|
24
|
+
#
|
25
|
+
# Note that these are filesystem paths, not Subversion URI's
|
26
|
+
#
|
27
|
+
# ==== Returns
|
28
|
+
# True, False::
|
29
|
+
# Whether the directories are the same (except db/uuid file)
|
30
|
+
# If False, puts the result of running the diff command.
|
31
|
+
def compare(old_dir, new_dir)
|
32
|
+
ret = `diff --brief --exclude=uuid -r "#{old_dir}" "#{new_dir}"`
|
33
|
+
if ret.empty?
|
34
|
+
return true
|
35
|
+
else
|
36
|
+
puts ret
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Setup and SvnTransform with in (existing) repository URI, a name for the
|
43
|
+
# out (transformed) repository, and options.
|
44
|
+
#
|
45
|
+
# ==== Parameters
|
46
|
+
# in_repo_uri<String>::
|
47
|
+
# URI of existing repository(e.g. file:///home/jm81/repo,
|
48
|
+
# svn://localhost/repo)
|
49
|
+
# out_repo_name<String>::
|
50
|
+
# Name only of out repository (e.g. "out"). See options[:out_repos_path]
|
51
|
+
# for specifying full path (on local filesystem only)
|
52
|
+
#
|
53
|
+
# ==== Options
|
54
|
+
# :username<String>:: Username for in (existing) repository
|
55
|
+
# :password<String>:: Password for in (existing) repository
|
56
|
+
# :out_repos_path<String>::
|
57
|
+
# Full path for out repository (defaults to
|
58
|
+
# "#{SvnFixture.config[:base_path]}/repo_#{out_repo_name}")
|
59
|
+
# :out_wc_path<String>::
|
60
|
+
# Full path for out working copy (used by SvnFixture; defaults to
|
61
|
+
# "#{SvnFixture.config[:base_path]}/wc_#{out_repo_name}")
|
62
|
+
def initialize(in_repo_uri, out_repo_name = nil, options = {})
|
63
|
+
@in_username = options[:username]
|
64
|
+
@in_password = options[:password]
|
65
|
+
@in_repo_uri = in_repo_uri
|
66
|
+
@out_repo_name = out_repo_name
|
67
|
+
@out_repos_path = options[:out_repos_path]
|
68
|
+
@out_wc_path = options[:out_wc_path]
|
69
|
+
@file_transforms = []
|
70
|
+
@dir_transforms = []
|
71
|
+
end
|
72
|
+
|
73
|
+
# Add a transform to be run on files. This can either be a class or a block
|
74
|
+
# (see Parameters). Each file at revision is given as an SvnTransform::File
|
75
|
+
# to each transform, which can alter the basename, body and/or properties
|
76
|
+
# of the file prior to its being committed to the new Repository.
|
77
|
+
#
|
78
|
+
# ==== Parameters
|
79
|
+
# klass<Class>::
|
80
|
+
# A class whose #initialize method accepts a SvnTransform::File as the first
|
81
|
+
# argument and which responds to #run.
|
82
|
+
# args<Array>::
|
83
|
+
# Additional arguments to pass to klass#initialize
|
84
|
+
# block<Proc>::
|
85
|
+
# A block that accepts one argument (a SvnTransform::File). If a klass is
|
86
|
+
# also given, the block is ignored
|
87
|
+
#
|
88
|
+
# ==== Returns
|
89
|
+
# Array:: The current @file_transforms Array
|
90
|
+
#
|
91
|
+
# ==== Raises
|
92
|
+
# ArgumentError:: Neither a Class nor a block was given.
|
93
|
+
def file_transform(klass = nil, *args, &block)
|
94
|
+
if klass
|
95
|
+
@file_transforms << [klass, args]
|
96
|
+
elsif block_given?
|
97
|
+
@file_transforms << block
|
98
|
+
else
|
99
|
+
raise(ArgumentError, "Class or Block required")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Add a transform to be run on directories. See +file_transform+
|
104
|
+
def dir_transform(klass = nil, *args, &block)
|
105
|
+
if klass
|
106
|
+
@dir_transforms << [klass, args]
|
107
|
+
elsif block_given?
|
108
|
+
@dir_transforms << block
|
109
|
+
else
|
110
|
+
raise(ArgumentError, "Class or Block required")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Run the conversion. This method sets up the connection to the existing
|
115
|
+
# repo and the SvnFixture that will generate the final transformed repo, then
|
116
|
+
# calls +changesets+ to do the actual work. Finally, commit the SvnFixture
|
117
|
+
# (out repo) and update its rev 0 date to match the in repo
|
118
|
+
def convert
|
119
|
+
in_repo_session = Session.new(@in_repo_uri, @in_username, @out_username)
|
120
|
+
@in_repo = in_repo_session.session
|
121
|
+
@ctx = in_repo_session.context
|
122
|
+
@out_repo = SvnFixture.repo(@out_repo_name, @out_repos_path, @out_wc_path)
|
123
|
+
|
124
|
+
# Process changesets and commit
|
125
|
+
changesets
|
126
|
+
@out_repo.commit
|
127
|
+
|
128
|
+
# Update rev 0 date
|
129
|
+
r0_date = @ctx.revprop_list(@in_repo_uri, 0)[0]['svn:date']
|
130
|
+
@out_repo.repos.fs.set_prop('svn:date', SvnFixture.svn_time(r0_date), 0)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Process the existing changesets and generate a SvnFixture::Revision for
|
134
|
+
# each.
|
135
|
+
#
|
136
|
+
# TODO This is a massive mess. It works, at least for my purposes. But it is
|
137
|
+
# a mess. Ideally, it should be multiple methods. Part of this is due to how
|
138
|
+
# I set up the SvnFixture::Revision class, which accepts a block at initialize
|
139
|
+
# that is process only when its #commit method is called.
|
140
|
+
def changesets
|
141
|
+
args = ['', 1, @in_repo.latest_revnum, 0, true, nil]
|
142
|
+
path_renames = {}
|
143
|
+
|
144
|
+
@in_repo.log(*args) do |changes, rev_num, author, date, msg|
|
145
|
+
# Sort so that files are processed first (for benefit of PropsToYaml),
|
146
|
+
# and deletes are last
|
147
|
+
changes = changes.sort { |a,b| sort_for(a, rev_num) <=> sort_for(b, rev_num) }
|
148
|
+
# Get revision properties
|
149
|
+
rev_props = @ctx.revprop_list(@in_repo_uri, rev_num)[0]
|
150
|
+
# Create Revision, including all revprops. Note that svn:author and
|
151
|
+
# svn:date are revprops. SvnFixture::Revision allows these without the
|
152
|
+
# svn: prefix (as Symbol), but revprops are written last, and so this
|
153
|
+
# should be completely accurate.
|
154
|
+
in_repo = @in_repo
|
155
|
+
out_wc_path = @out_repo.wc_path
|
156
|
+
svn_transform = self
|
157
|
+
@out_repo.revision(rev_num, msg, rev_props) do
|
158
|
+
# Now go through all the changes. Setup directorie structure for each
|
159
|
+
# node. This is easier to understand, in my opinion.
|
160
|
+
|
161
|
+
changes.each do |full_path, change|
|
162
|
+
full_path = Pathname.new(full_path.sub(/\A\//, ''))
|
163
|
+
# Descend to parent directory
|
164
|
+
parent_dir = self
|
165
|
+
full_path.dirname.descend do |path|
|
166
|
+
unless path.basename == '.'
|
167
|
+
parent_dir = parent_dir.dir(path.basename.to_s)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# TODO Replaces
|
172
|
+
|
173
|
+
if change.action == 'D'
|
174
|
+
del_path = path_renames['/' + full_path.to_s] || full_path.to_s
|
175
|
+
@ctx.delete(::File.join(out_wc_path, del_path))
|
176
|
+
elsif in_repo.stat(full_path.to_s, rev_num).file?
|
177
|
+
data = in_repo.file(full_path.to_s, rev_num)
|
178
|
+
transform_file = ::SvnTransform::File.new(full_path, data, rev_num, rev_props)
|
179
|
+
original_path = transform_file.path
|
180
|
+
svn_transform.__send__(:process_file_transforms, transform_file)
|
181
|
+
|
182
|
+
if change.copyfrom_path
|
183
|
+
from_path = path_renames[change.copyfrom_path] || change.copyfrom_path
|
184
|
+
@ctx.cp(
|
185
|
+
::File.join(out_wc_path, from_path),
|
186
|
+
::File.join(out_wc_path, transform_file.path.to_s)
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
unless transform_file.skip?
|
191
|
+
parent_dir.file(transform_file.basename) do
|
192
|
+
body(transform_file.body)
|
193
|
+
transform_file.properties.each_pair do |prop_k, prop_v|
|
194
|
+
prop(prop_k, prop_v) unless prop_k =~ /\Asvn:entry/
|
195
|
+
end
|
196
|
+
end
|
197
|
+
# For benefit of copies
|
198
|
+
if original_path != transform_file.path
|
199
|
+
path_renames['/' + original_path] = '/' + transform_file.path.to_s
|
200
|
+
end
|
201
|
+
end
|
202
|
+
else # directory
|
203
|
+
parent_dir.dir(full_path.basename.to_s) do
|
204
|
+
data = in_repo.dir(full_path.to_s, rev_num)
|
205
|
+
transform_dir = ::SvnTransform::Dir.new(full_path, data, rev_num, rev_props, in_repo, self)
|
206
|
+
svn_transform.__send__(:process_dir_transforms, transform_dir)
|
207
|
+
transform_dir.properties.each_pair do |prop_k, prop_v|
|
208
|
+
prop(prop_k, prop_v) unless prop_k =~ /\Asvn:entry/
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
# Process @file_transforms against the given File
|
220
|
+
#
|
221
|
+
# ==== Parameters
|
222
|
+
# file<SvnTransform::File>:: A file in the original repo at a given revision
|
223
|
+
def process_file_transforms(file)
|
224
|
+
@file_transforms.each do |transform|
|
225
|
+
if transform.is_a?(Proc)
|
226
|
+
transform.call(file)
|
227
|
+
else
|
228
|
+
transform[0].new(file, *transform[1]).run
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Process @dir_transforms against the given Dir
|
234
|
+
#
|
235
|
+
# ==== Parameters
|
236
|
+
# dir<SvnTransform::Dir>:: A directory in the original repo at a given revision
|
237
|
+
def process_dir_transforms(dir)
|
238
|
+
@dir_transforms.each do |transform|
|
239
|
+
if transform.is_a?(Proc)
|
240
|
+
transform.call(dir)
|
241
|
+
else
|
242
|
+
transform[0].new(dir, *transform[1]).run
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Return an Integer such that file changes are first, directories second
|
248
|
+
# and deleted nodes last (to minimize the chance of a Transformation being
|
249
|
+
# overridden.
|
250
|
+
def sort_for(change, rev_num)
|
251
|
+
return 2 if change[1].action == 'D'
|
252
|
+
return 0 if @in_repo.stat(change[0].sub(/\A\//, ''), rev_num).file?
|
253
|
+
return 1
|
254
|
+
end
|
255
|
+
end # SvnTransform
|
256
|
+
|
257
|
+
require 'svn-transform/session'
|
258
|
+
require 'svn-transform/file'
|
259
|
+
require 'svn-transform/dir'
|
260
|
+
|
261
|
+
# Require predefined transforms
|
262
|
+
%w{extension newline noop props_to_yaml}.each do |filename|
|
263
|
+
require 'svn-transform/transform/' + filename
|
264
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class SvnTransform
|
2
|
+
# A directory in original Subversion Repository, at a given changeset.
|
3
|
+
# Instances are initialized by SvnTransform#changesets.
|
4
|
+
#
|
5
|
+
# An instance for each file in the original repo at each revision will be
|
6
|
+
# passed to any directory transform blocks (TODO more info)
|
7
|
+
#
|
8
|
+
# Although more could theoretically be done (see #initialize fixture_dir
|
9
|
+
# param), the main thing intended to be alterable are the properties.
|
10
|
+
class Dir
|
11
|
+
# Initialize Dir instance using data passed by SvnTransform#changesets.
|
12
|
+
# This is data that will be available to Transformation blocks. It's
|
13
|
+
# relevant to remember that all this happens within a block given to an
|
14
|
+
# SvnFixture::Revision.
|
15
|
+
#
|
16
|
+
# ==== Parameters
|
17
|
+
# path<Pathname>::
|
18
|
+
# Full path within original Repository
|
19
|
+
# node_data<Array[String, Hash]>::
|
20
|
+
# Array returned by SWIG::TYPE_p_svn_ra_session_t#dir. First element is
|
21
|
+
# a Hash of directory entries, second is Hash of properties.
|
22
|
+
# rev_num<Integer>::
|
23
|
+
# Number of current revision
|
24
|
+
# rev_props<Hash>::
|
25
|
+
# Properties for current revision
|
26
|
+
# repos<Svn::Ra::Session>::
|
27
|
+
# Repo session (made available for PropsToYaml)
|
28
|
+
# fixture_dir<SvnFixture::Directory>::
|
29
|
+
# The SvnFixture::Directory representing this directory. This could be
|
30
|
+
# used to add, delete files, subdirs, etc, but doing much of that is
|
31
|
+
# likely to lead to weird results. I certainly don't intend to test this
|
32
|
+
# outside of one use case (PropsToYaml)
|
33
|
+
def initialize(path, node_data, rev_num, rev_props, repos, fixture_dir)
|
34
|
+
@path = path.kind_of?(Pathname) ? path : Pathname.new(path)
|
35
|
+
@entries = node_data[0]
|
36
|
+
@properties = node_data[1]
|
37
|
+
@rev_num = rev_num
|
38
|
+
@rev_props = rev_props
|
39
|
+
@repos = repos
|
40
|
+
@fixture_dir = fixture_dir
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader :path, :entries, :properties, :rev_num, :rev_props, :repos, :fixture_dir
|
44
|
+
|
45
|
+
# Assign a new properties Hash to the node
|
46
|
+
#
|
47
|
+
# ==== Parameters
|
48
|
+
# hsh<~each_pair>::
|
49
|
+
# A Hash (or other object) responding to #each_pair, where keys are
|
50
|
+
# svn property keys, and values are the corresponding property values.
|
51
|
+
# This method does not verify that keys are "human-readable"
|
52
|
+
# (See http://svnbook.red-bean.com/en/1.0/ch07s02.html)
|
53
|
+
def properties=(hsh)
|
54
|
+
unless hsh.respond_to?(:each_pair)
|
55
|
+
raise ArgumentError, "Argument must respond to #each_pair, such as a Hash"
|
56
|
+
end
|
57
|
+
@properties = hsh
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the base of the File
|
61
|
+
def basename
|
62
|
+
@path.basename.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class SvnTransform
|
2
|
+
# A file in original Subversion Repository, at a given changeset. Instances
|
3
|
+
# are initialized by SvnTransform#changesets.
|
4
|
+
#
|
5
|
+
# An instance for each file in the original repo at each revision will be
|
6
|
+
# passed to any file transform blocks (TODO more info)
|
7
|
+
class File
|
8
|
+
# Initialize File instance using data passed by SvnTransform#changesets.
|
9
|
+
# This is data that will be available to Transformation blocks. It's
|
10
|
+
# relevant to remember that all this happens within a block given to an
|
11
|
+
# SvnFixture::Revision
|
12
|
+
#
|
13
|
+
# ==== Parameters
|
14
|
+
# path<Pathname>::
|
15
|
+
# Full path within original Repository
|
16
|
+
# node_data<Array[String, Hash]>::
|
17
|
+
# Array returned by SWIG::TYPE_p_svn_ra_session_t#file. First element is
|
18
|
+
# node body, second is hash of properties.
|
19
|
+
# rev_num<Integer>::
|
20
|
+
# Number of current revision
|
21
|
+
# rev_props<Hash>::
|
22
|
+
# Properties for current revision
|
23
|
+
def initialize(path, node_data, rev_num, rev_props)
|
24
|
+
@path = path.kind_of?(Pathname) ? path : Pathname.new(path)
|
25
|
+
@body = node_data[0]
|
26
|
+
@properties = node_data[1]
|
27
|
+
@rev_num = rev_num
|
28
|
+
@rev_props = rev_props
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :path, :body, :properties, :rev_num, :rev_props
|
32
|
+
|
33
|
+
# Change the body of the node. The new body will be placed in the new
|
34
|
+
# repository.
|
35
|
+
#
|
36
|
+
# ==== Parameters
|
37
|
+
# value<String>:: New body
|
38
|
+
attr_writer :body
|
39
|
+
|
40
|
+
# Assign a new properties Hash to the node
|
41
|
+
#
|
42
|
+
# ==== Parameters
|
43
|
+
# hsh<~each_pair>::
|
44
|
+
# A Hash (or other object) responding to #each_pair, where keys are
|
45
|
+
# svn property keys, and values are the corresponding property values.
|
46
|
+
# This method does not verify that keys are "human-readable"
|
47
|
+
# (See http://svnbook.red-bean.com/en/1.0/ch07s02.html)
|
48
|
+
def properties=(hsh)
|
49
|
+
unless hsh.respond_to?(:each_pair)
|
50
|
+
raise ArgumentError, "Argument must respond to #each_pair, such as a Hash"
|
51
|
+
end
|
52
|
+
@properties = hsh
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get the base of the File
|
56
|
+
def basename
|
57
|
+
@path.basename.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
# Change the basename of the File. Alters the #path
|
61
|
+
#
|
62
|
+
# ==== Parameters
|
63
|
+
# val<String>:: New basename
|
64
|
+
def basename=(val)
|
65
|
+
@path = @path.dirname + val
|
66
|
+
end
|
67
|
+
|
68
|
+
# Skip this file at this revision (that is, don't commit it to new repo).
|
69
|
+
def skip!
|
70
|
+
@skip = true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Whether this file should be skipped (not committed to new repo at this
|
74
|
+
# revision)
|
75
|
+
def skip?
|
76
|
+
@skip == true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class SvnTransform
|
2
|
+
# A simplistic wrapper for Svn::Ra::Session. This takes care of setting up
|
3
|
+
# the context and callbacks as well as making the actual connection.
|
4
|
+
class Session
|
5
|
+
# Setup repository information
|
6
|
+
#
|
7
|
+
# ==== Parameters
|
8
|
+
# uri<String>:: URI of the repository (e.g. svn://example.com/repo)
|
9
|
+
# username<String>:: Username, if needed
|
10
|
+
# password<String>:: Password, if needed
|
11
|
+
def initialize(uri, username = nil, password = nil)
|
12
|
+
@uri = uri
|
13
|
+
@username = username
|
14
|
+
@password = password
|
15
|
+
end
|
16
|
+
|
17
|
+
# Open and return the actual Svn::Ra::Session
|
18
|
+
#
|
19
|
+
# ==== Returns
|
20
|
+
# Svn::Ra::Session:: A remote access session to a repository.
|
21
|
+
def session
|
22
|
+
# This will raise some error if connection fails for whatever reason.
|
23
|
+
# I don't currently see a reason to handle connection errors here, as I
|
24
|
+
# assume the best handling would be to raise another error.
|
25
|
+
@session ||= ::Svn::Ra::Session.open(@uri, {}, self.callbacks)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Setup, if needed, and return the working context (I don't really
|
29
|
+
# understand all this, but it's required to work with the working copy).
|
30
|
+
#
|
31
|
+
# ==== Returns
|
32
|
+
# Svn::Client::Context:: Context for working with working copy
|
33
|
+
def context
|
34
|
+
@context || begin
|
35
|
+
# Client::Context, which paticularly holds an auth_baton.
|
36
|
+
@context = ::Svn::Client::Context.new
|
37
|
+
if @username && @password
|
38
|
+
# TODO: What if another provider type is needed? Is this plausible?
|
39
|
+
@context.add_simple_prompt_provider(0) do |cred, realm, username, may_save|
|
40
|
+
cred.username = @username
|
41
|
+
cred.password = @password
|
42
|
+
end
|
43
|
+
elsif URI.parse(@uri).scheme == "file"
|
44
|
+
@context.add_username_prompt_provider(0) do |cred, realm, username, may_save|
|
45
|
+
cred.username = @username || "ANON"
|
46
|
+
end
|
47
|
+
else
|
48
|
+
@context.auth_baton = ::Svn::Core::AuthBaton.new()
|
49
|
+
end
|
50
|
+
@context
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Setup callbacks for Svn::Ra::Session.open.
|
55
|
+
#
|
56
|
+
# ==== Returns
|
57
|
+
# Svn::Ra::Callbacks
|
58
|
+
def callbacks
|
59
|
+
::Svn::Ra::Callbacks.new(context.auth_baton)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|