1 | require "English" |
---|
2 | require "svn/error" |
---|
3 | require "svn/util" |
---|
4 | require "svn/core" |
---|
5 | require "svn/fs" |
---|
6 | require "svn/client" |
---|
7 | require "svn/ext/repos" |
---|
8 | |
---|
9 | module Svn |
---|
10 | module Repos |
---|
11 | Util.set_constants(Ext::Repos, self) |
---|
12 | Util.set_methods(Ext::Repos, self) |
---|
13 | |
---|
14 | |
---|
15 | @@alias_targets = %w(create hotcopy recover db_logfiles) |
---|
16 | class << self |
---|
17 | @@alias_targets.each do |target| |
---|
18 | alias_method "_#{target}", target |
---|
19 | end |
---|
20 | end |
---|
21 | @@alias_targets.each do |target| |
---|
22 | alias_method "_#{target}", target |
---|
23 | end |
---|
24 | @@alias_targets = nil |
---|
25 | |
---|
26 | module_function |
---|
27 | def create(path, config={}, fs_config={}, &block) |
---|
28 | _create(path, nil, nil, config, fs_config, &block) |
---|
29 | end |
---|
30 | |
---|
31 | def hotcopy(src, dest, clean_logs=true) |
---|
32 | _hotcopy(src, dest, clean_logs) |
---|
33 | end |
---|
34 | |
---|
35 | def recover(path, nonblocking=false, cancel_func=nil, &start_callback) |
---|
36 | recover3(path, nonblocking, start_callback, cancel_func) |
---|
37 | end |
---|
38 | |
---|
39 | def db_logfiles(path, only_unused=true) |
---|
40 | _db_logfiles(path, only_unused) |
---|
41 | end |
---|
42 | |
---|
43 | def read_authz(file, must_exist=true) |
---|
44 | Repos.authz_read(file, must_exist) |
---|
45 | end |
---|
46 | |
---|
47 | ReposCore = SWIG::TYPE_p_svn_repos_t |
---|
48 | class ReposCore |
---|
49 | class << self |
---|
50 | def def_simple_delegate(*ids) |
---|
51 | ids.each do |id| |
---|
52 | module_eval(<<-EOC, __FILE__, __LINE__) |
---|
53 | def #{id.to_s} |
---|
54 | Repos.#{id.to_s}(self) |
---|
55 | end |
---|
56 | EOC |
---|
57 | end |
---|
58 | end |
---|
59 | end |
---|
60 | |
---|
61 | def_simple_delegate :path, :db_env, :conf_dir |
---|
62 | def_simple_delegate :svnserve_conf, :lock_dir |
---|
63 | def_simple_delegate :db_lockfile, :db_logs_lockfile |
---|
64 | def_simple_delegate :hook_dir, :start_commit_hook |
---|
65 | def_simple_delegate :pre_commit_hook, :post_commit_hook |
---|
66 | def_simple_delegate :pre_revprop_change_hook, :post_revprop_change_hook |
---|
67 | def_simple_delegate :pre_lock_hook, :post_lock_hook |
---|
68 | def_simple_delegate :pre_unlock_hook, :post_unlock_hook |
---|
69 | |
---|
70 | attr_reader :authz_read_func |
---|
71 | |
---|
72 | def fs |
---|
73 | Repos.fs_wrapper(self) |
---|
74 | end |
---|
75 | |
---|
76 | def set_authz_read_func(&block) |
---|
77 | @authz_read_func = block |
---|
78 | end |
---|
79 | |
---|
80 | def report(rev, username, fs_base, target, tgt_path, |
---|
81 | editor, text_deltas=true, recurse=true, |
---|
82 | ignore_ancestry=false, authz_read_func=nil) |
---|
83 | authz_read_func ||= @authz_read_func |
---|
84 | args = [ |
---|
85 | rev, username, self, fs_base, target, tgt_path, |
---|
86 | text_deltas, recurse, ignore_ancestry, editor, |
---|
87 | authz_read_func, |
---|
88 | ] |
---|
89 | report_baton = Repos.begin_report(*args) |
---|
90 | setup_report_baton(report_baton) |
---|
91 | if block_given? |
---|
92 | report_baton.set_path("", rev) |
---|
93 | result = yield(report_baton) |
---|
94 | report_baton.finish_report unless report_baton.aborted? |
---|
95 | result |
---|
96 | else |
---|
97 | report_baton |
---|
98 | end |
---|
99 | end |
---|
100 | |
---|
101 | def report2(rev, fs_base, target, tgt_path, editor, text_deltas=true, |
---|
102 | ignore_ancestry=false, depth=nil, authz_read_func=nil, |
---|
103 | send_copyfrom_args=nil) |
---|
104 | authz_read_func ||= @authz_read_func |
---|
105 | args = [ |
---|
106 | rev, self, fs_base, target, tgt_path, text_deltas, |
---|
107 | depth, ignore_ancestry, send_copyfrom_args, editor, |
---|
108 | authz_read_func, |
---|
109 | ] |
---|
110 | report_baton = Repos.begin_report2(*args) |
---|
111 | setup_report_baton(report_baton) |
---|
112 | if block_given? |
---|
113 | report_baton.set_path("", rev, false, nil, depth) |
---|
114 | result = yield(report_baton) |
---|
115 | report_baton.finish_report unless report_baton.aborted? |
---|
116 | result |
---|
117 | else |
---|
118 | report_baton |
---|
119 | end |
---|
120 | end |
---|
121 | |
---|
122 | def commit_editor(repos_url, base_path, txn=nil, user=nil, |
---|
123 | log_msg=nil, commit_callback=nil, |
---|
124 | authz_callback=nil) |
---|
125 | editor, baton = Repos.get_commit_editor3(self, txn, repos_url, |
---|
126 | base_path, user, log_msg, |
---|
127 | commit_callback, |
---|
128 | authz_callback) |
---|
129 | editor.baton = baton |
---|
130 | editor |
---|
131 | end |
---|
132 | |
---|
133 | def commit_editor2(repos_url, base_path, txn=nil, user=nil, |
---|
134 | log_msg=nil, commit_callback=nil, |
---|
135 | authz_callback=nil) |
---|
136 | editor, baton = Repos.get_commit_editor4(self, txn, repos_url, |
---|
137 | base_path, user, log_msg, |
---|
138 | commit_callback, |
---|
139 | authz_callback) |
---|
140 | editor.baton = baton |
---|
141 | editor |
---|
142 | end |
---|
143 | |
---|
144 | def commit_editor3(repos_url, base_path, txn=nil, rev_props=nil, |
---|
145 | commit_callback=nil, authz_callback=nil) |
---|
146 | rev_props ||= {} |
---|
147 | editor, baton = Repos.get_commit_editor5(self, txn, repos_url, |
---|
148 | base_path, rev_props, |
---|
149 | commit_callback, |
---|
150 | authz_callback) |
---|
151 | editor.baton = baton |
---|
152 | editor |
---|
153 | end |
---|
154 | |
---|
155 | def youngest_revision |
---|
156 | fs.youngest_rev |
---|
157 | end |
---|
158 | alias_method :youngest_rev, :youngest_revision |
---|
159 | |
---|
160 | def dated_revision(date) |
---|
161 | Repos.dated_revision(self, date.to_apr_time) |
---|
162 | end |
---|
163 | |
---|
164 | def logs(paths, start_rev, end_rev, limit, |
---|
165 | discover_changed_paths=true, |
---|
166 | strict_node_history=false, |
---|
167 | authz_read_func=nil) |
---|
168 | authz_read_func ||= @authz_read_func |
---|
169 | paths = [paths] unless paths.is_a?(Array) |
---|
170 | infos = [] |
---|
171 | receiver = Proc.new do |changed_paths, revision, author, date, message| |
---|
172 | if block_given? |
---|
173 | yield(changed_paths, revision, author, date, message) |
---|
174 | end |
---|
175 | infos << [changed_paths, revision, author, date, message] |
---|
176 | end |
---|
177 | Repos.get_logs3(self, paths, start_rev, end_rev, |
---|
178 | limit, discover_changed_paths, |
---|
179 | strict_node_history, authz_read_func, |
---|
180 | receiver) |
---|
181 | infos |
---|
182 | end |
---|
183 | |
---|
184 | def file_revs(path, start_rev, end_rev, authz_read_func=nil) |
---|
185 | args = [path, start_rev, end_rev, authz_read_func] |
---|
186 | if block_given? |
---|
187 | revs = file_revs2(*args) do |path, rev, rev_props, prop_diffs| |
---|
188 | yield(path, rev, rev_props, Util.hash_to_prop_array(prop_diffs)) |
---|
189 | end |
---|
190 | else |
---|
191 | revs = file_revs2(*args) |
---|
192 | end |
---|
193 | revs.collect do |path, rev, rev_props, prop_diffs| |
---|
194 | [path, rev, rev_props, Util.hash_to_prop_array(prop_diffs)] |
---|
195 | end |
---|
196 | end |
---|
197 | |
---|
198 | def file_revs2(path, start_rev, end_rev, authz_read_func=nil) |
---|
199 | authz_read_func ||= @authz_read_func |
---|
200 | revs = [] |
---|
201 | handler = Proc.new do |path, rev, rev_props, prop_diffs| |
---|
202 | yield(path, rev, rev_props, prop_diffs) if block_given? |
---|
203 | revs << [path, rev, rev_props, prop_diffs] |
---|
204 | end |
---|
205 | Repos.get_file_revs(self, path, start_rev, end_rev, |
---|
206 | authz_read_func, handler) |
---|
207 | revs |
---|
208 | end |
---|
209 | |
---|
210 | def commit_txn(txn) |
---|
211 | Repos.fs_commit_txn(self, txn) |
---|
212 | end |
---|
213 | |
---|
214 | def transaction_for_commit(*args) |
---|
215 | if args.first.is_a?(Hash) |
---|
216 | props, rev = args |
---|
217 | else |
---|
218 | author, log, rev = args |
---|
219 | props = { |
---|
220 | Svn::Core::PROP_REVISION_AUTHOR => author, |
---|
221 | Svn::Core::PROP_REVISION_LOG => log, |
---|
222 | } |
---|
223 | end |
---|
224 | txn = Repos.fs_begin_txn_for_commit2(self, rev || youngest_rev, props) |
---|
225 | |
---|
226 | if block_given? |
---|
227 | yield(txn) |
---|
228 | commit(txn) if fs.transactions.include?(txn.name) |
---|
229 | else |
---|
230 | txn |
---|
231 | end |
---|
232 | end |
---|
233 | |
---|
234 | def transaction_for_update(author, rev=nil) |
---|
235 | txn = Repos.fs_begin_txn_for_update(self, rev || youngest_rev, author) |
---|
236 | |
---|
237 | if block_given? |
---|
238 | yield(txn) |
---|
239 | txn.abort if fs.transactions.include?(txn.name) |
---|
240 | else |
---|
241 | txn |
---|
242 | end |
---|
243 | end |
---|
244 | |
---|
245 | def commit(txn) |
---|
246 | Repos.fs_commit_txn(self, txn) |
---|
247 | end |
---|
248 | |
---|
249 | def lock(path, token=nil, comment=nil, dav_comment=true, |
---|
250 | expiration_date=nil, current_rev=nil, steal_lock=false) |
---|
251 | if expiration_date |
---|
252 | expiration_date = expiration_date.to_apr_time |
---|
253 | else |
---|
254 | expiration_date = 0 |
---|
255 | end |
---|
256 | current_rev ||= youngest_rev |
---|
257 | Repos.fs_lock(self, path, token, comment, |
---|
258 | dav_comment, expiration_date, |
---|
259 | current_rev, steal_lock) |
---|
260 | end |
---|
261 | |
---|
262 | def unlock(path, token, break_lock=false) |
---|
263 | Repos.fs_unlock(self, path, token, break_lock) |
---|
264 | end |
---|
265 | |
---|
266 | def get_locks(path, authz_read_func=nil) |
---|
267 | authz_read_func ||= @authz_read_func |
---|
268 | Repos.fs_get_locks(self, path, authz_read_func) |
---|
269 | end |
---|
270 | |
---|
271 | def set_prop(author, name, new_value, rev=nil, authz_read_func=nil, |
---|
272 | use_pre_revprop_change_hook=true, |
---|
273 | use_post_revprop_change_hook=true) |
---|
274 | authz_read_func ||= @authz_read_func |
---|
275 | rev ||= youngest_rev |
---|
276 | Repos.fs_change_rev_prop3(self, rev, author, name, new_value, |
---|
277 | use_pre_revprop_change_hook, |
---|
278 | use_post_revprop_change_hook, |
---|
279 | authz_read_func) |
---|
280 | end |
---|
281 | |
---|
282 | def prop(name, rev=nil, authz_read_func=nil) |
---|
283 | authz_read_func ||= @authz_read_func |
---|
284 | rev ||= youngest_rev |
---|
285 | value = Repos.fs_revision_prop(self, rev, name, authz_read_func) |
---|
286 | if name == Svn::Core::PROP_REVISION_DATE |
---|
287 | value = Time.from_svn_format(value) |
---|
288 | end |
---|
289 | value |
---|
290 | end |
---|
291 | |
---|
292 | def proplist(rev=nil, authz_read_func=nil) |
---|
293 | authz_read_func ||= @authz_read_func |
---|
294 | rev ||= youngest_rev |
---|
295 | props = Repos.fs_revision_proplist(self, rev, authz_read_func) |
---|
296 | if props.has_key?(Svn::Core::PROP_REVISION_DATE) |
---|
297 | props[Svn::Core::PROP_REVISION_DATE] = |
---|
298 | Time.from_svn_format(props[Svn::Core::PROP_REVISION_DATE]) |
---|
299 | end |
---|
300 | props |
---|
301 | end |
---|
302 | |
---|
303 | def node_editor(base_root, root) |
---|
304 | editor, baton = Repos.node_editor(self, base_root, root) |
---|
305 | def baton.node |
---|
306 | Repos.node_from_baton(self) |
---|
307 | end |
---|
308 | editor.baton = baton |
---|
309 | editor |
---|
310 | end |
---|
311 | |
---|
312 | def dump_fs(dumpstream, feedback_stream, start_rev, end_rev, |
---|
313 | incremental=true, use_deltas=true, &cancel_func) |
---|
314 | Repos.dump_fs2(self, dumpstream, feedback_stream, |
---|
315 | start_rev, end_rev, incremental, |
---|
316 | use_deltas, cancel_func) |
---|
317 | end |
---|
318 | |
---|
319 | def load_fs(dumpstream, feedback_stream=nil, uuid_action=nil, |
---|
320 | parent_dir=nil, use_pre_commit_hook=true, |
---|
321 | use_post_commit_hook=true, &cancel_func) |
---|
322 | uuid_action ||= Svn::Repos::LOAD_UUID_DEFAULT |
---|
323 | Repos.load_fs2(self, dumpstream, feedback_stream, |
---|
324 | uuid_action, parent_dir, |
---|
325 | use_pre_commit_hook, use_post_commit_hook, |
---|
326 | cancel_func) |
---|
327 | end |
---|
328 | |
---|
329 | def build_parser(uuid_action, parent_dir, |
---|
330 | use_history=true, outstream=nil) |
---|
331 | outstream ||= StringIO.new |
---|
332 | parser, baton = Repos.get_fs_build_parser2(use_history, |
---|
333 | uuid_action, |
---|
334 | outstream, |
---|
335 | parent_dir) |
---|
336 | def parser.parse_dumpstream(stream, &cancel_func) |
---|
337 | Repos.parse_dumpstream2(stream, self, @baton, cancel_func) |
---|
338 | end |
---|
339 | |
---|
340 | def parser.outstream=(new_stream) |
---|
341 | @outstream = new_stream |
---|
342 | end |
---|
343 | |
---|
344 | def parser.baton=(new_baton) |
---|
345 | @baton = new_baton |
---|
346 | end |
---|
347 | |
---|
348 | def parser.baton |
---|
349 | @baton |
---|
350 | end |
---|
351 | |
---|
352 | parser.outstream = outstream |
---|
353 | parser.baton = baton |
---|
354 | parser |
---|
355 | end |
---|
356 | |
---|
357 | def delta_tree(root, base_rev) |
---|
358 | base_root = fs.root(base_rev) |
---|
359 | editor = node_editor(base_root, root) |
---|
360 | root.replay(editor) |
---|
361 | editor.baton.node |
---|
362 | end |
---|
363 | |
---|
364 | def mergeinfo(paths, revision=nil, inherit=nil, |
---|
365 | include_descendants=false, &authz_read_func) |
---|
366 | path = nil |
---|
367 | unless paths.is_a?(Array) |
---|
368 | path = paths |
---|
369 | paths = [path] |
---|
370 | end |
---|
371 | revision ||= Svn::Core::INVALID_REVNUM |
---|
372 | results = Repos.fs_get_mergeinfo(self, paths, revision, |
---|
373 | inherit, include_descendants, |
---|
374 | authz_read_func) |
---|
375 | results = results[path] if path |
---|
376 | results |
---|
377 | end |
---|
378 | |
---|
379 | private |
---|
380 | def setup_report_baton(baton) |
---|
381 | baton.instance_variable_set("@aborted", false) |
---|
382 | |
---|
383 | def baton.aborted? |
---|
384 | @aborted |
---|
385 | end |
---|
386 | |
---|
387 | def baton.set_path(path, revision, start_empty=false, lock_token=nil, |
---|
388 | depth=nil) |
---|
389 | Repos.set_path3(self, path, revision, depth, start_empty, lock_token) |
---|
390 | end |
---|
391 | |
---|
392 | def baton.link_path(path, link_path, revision, start_empty=false, |
---|
393 | lock_token=nil, depth=nil) |
---|
394 | Repos.link_path3(self, path, link_path, revision, depth, |
---|
395 | start_empty, lock_token) |
---|
396 | end |
---|
397 | |
---|
398 | def baton.delete_path(path) |
---|
399 | Repos.delete_path(self, path) |
---|
400 | end |
---|
401 | |
---|
402 | def baton.finish_report |
---|
403 | Repos.finish_report(self) |
---|
404 | end |
---|
405 | |
---|
406 | def baton.abort_report |
---|
407 | Repos.abort_report(self) |
---|
408 | @aborted = true |
---|
409 | end |
---|
410 | |
---|
411 | end |
---|
412 | end |
---|
413 | |
---|
414 | |
---|
415 | class Node |
---|
416 | |
---|
417 | alias text_mod? text_mod |
---|
418 | alias prop_mod? prop_mod |
---|
419 | |
---|
420 | def copy? |
---|
421 | Util.copy?(copyfrom_path, copyfrom_rev) |
---|
422 | end |
---|
423 | |
---|
424 | def add? |
---|
425 | action == "A" |
---|
426 | end |
---|
427 | |
---|
428 | def delete? |
---|
429 | action == "D" |
---|
430 | end |
---|
431 | |
---|
432 | def replace? |
---|
433 | action == "R" |
---|
434 | end |
---|
435 | |
---|
436 | def file? |
---|
437 | kind == Core::NODE_FILE |
---|
438 | end |
---|
439 | |
---|
440 | def dir? |
---|
441 | kind == Core::NODE_DIR |
---|
442 | end |
---|
443 | |
---|
444 | def none? |
---|
445 | kind == Core::NODE_NONE |
---|
446 | end |
---|
447 | |
---|
448 | def unknown? |
---|
449 | kind == Core::NODE_UNKNOWN |
---|
450 | end |
---|
451 | |
---|
452 | end |
---|
453 | |
---|
454 | Authz = SWIG::TYPE_p_svn_authz_t |
---|
455 | class Authz |
---|
456 | |
---|
457 | class << self |
---|
458 | def read(file, must_exist=true) |
---|
459 | Repos.authz_read(file, must_exist) |
---|
460 | end |
---|
461 | end |
---|
462 | |
---|
463 | def can_access?(repos_name, path, user, required_access) |
---|
464 | Repos.authz_check_access(self, |
---|
465 | repos_name, |
---|
466 | path, |
---|
467 | user, |
---|
468 | required_access) |
---|
469 | end |
---|
470 | end |
---|
471 | end |
---|
472 | end |
---|