3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
20 * ====================================================================
24 #include <apr_pools.h>
28 #include "svn_types.h"
29 #include "svn_string.h"
30 #include "svn_props.h"
31 #include "svn_compat.h"
33 /* This file is a template for a compatibility wrapper for an RA library.
34 * It contains an svn_ra_plugin_t and wrappers for all of its functions,
35 * implemented in terms of svn_ra__vtable_t functions. It also contains
36 * the implementations of an svn_ra_FOO_init for the FOO RA library.
38 * A file in the RA library includes this file, providing the
39 * following macros before inclusion:
41 * NAME The library name, e.g. "ra_local".
42 * DESCRIPTION The short library description as a string constant.
43 * VTBL The name of an svn_ra_vtable_t object for the library.
44 * INITFUNC The init function for the library, e.g. svn_ra_local__init.
45 * COMPAT_INITFUNC The compatibility init function, e.g. svn_ra_local_init.
48 /* Check that all our "arguments" are defined. */
49 #if ! defined(NAME) || ! defined(DESCRIPTION) || ! defined(VTBL) \
50 || ! defined(INITFUNC) || ! defined(COMPAT_INITFUNC)
51 #error Missing define for RA compatibility wrapper.
55 static svn_error_t *compat_open(void **session_baton,
56 const char *repos_URL,
57 const svn_ra_callbacks_t *callbacks,
62 /* Here, we should be calling svn_ra_create_callbacks to initialize
63 * the svn_ra_callbacks2_t structure. However, doing that
64 * introduces a circular dependancy between libsvn_ra and
65 * libsvn_ra_{local,neon,serf,svn}, which include
66 * wrapper_template.h. In turn, circular dependancies break the
67 * build on win32 (and possibly other systems).
69 * In order to avoid this happening at all, the code of
70 * svn_ra_create_callbacks is duplicated here. This is evil, but
71 * the alternative (creating a new ra_util library) would be massive
72 * overkill for the time being. Just be sure to keep the following
73 * line and the code of svn_ra_create_callbacks in sync. */
74 apr_pool_t *sesspool = svn_pool_create(pool);
75 svn_ra_callbacks2_t *callbacks2 = apr_pcalloc(sesspool,
78 svn_ra_session_t *sess = apr_pcalloc(sesspool, sizeof(*sess));
79 const char *session_url;
82 sess->pool = sesspool;
84 callbacks2->open_tmp_file = callbacks->open_tmp_file;
85 callbacks2->auth_baton = callbacks->auth_baton;
86 callbacks2->get_wc_prop = callbacks->get_wc_prop;
87 callbacks2->set_wc_prop = callbacks->set_wc_prop;
88 callbacks2->push_wc_prop = callbacks->push_wc_prop;
89 callbacks2->invalidate_wc_props = callbacks->invalidate_wc_props;
90 callbacks2->progress_func = NULL;
91 callbacks2->progress_baton = NULL;
93 SVN_ERR(VTBL.open_session(sess, &session_url, repos_URL,
94 callbacks2, callback_baton, config, sesspool));
96 if (strcmp(repos_URL, session_url) != 0)
98 svn_pool_destroy(sesspool);
99 return svn_error_createf(SVN_ERR_RA_SESSION_URL_MISMATCH, NULL,
100 _("Session URL '%s' does not match requested "
101 " URL '%s', and redirection was disallowed."),
102 session_url, repos_URL);
105 *session_baton = sess;
109 static svn_error_t *compat_get_latest_revnum(void *session_baton,
110 svn_revnum_t *latest_revnum,
113 return VTBL.get_latest_revnum(session_baton, latest_revnum, pool);
116 static svn_error_t *compat_get_dated_revision(void *session_baton,
117 svn_revnum_t *revision,
121 return VTBL.get_dated_revision(session_baton, revision, tm, pool);
124 static svn_error_t *compat_change_rev_prop(void *session_baton,
126 const char *propname,
127 const svn_string_t *value,
130 return VTBL.change_rev_prop(session_baton, rev, propname, NULL, value, pool);
133 static svn_error_t *compat_rev_proplist(void *session_baton,
138 return VTBL.rev_proplist(session_baton, rev, props, pool);
141 static svn_error_t *compat_rev_prop(void *session_baton,
143 const char *propname,
144 svn_string_t **value,
147 return VTBL.rev_prop(session_baton, rev, propname, value, pool);
150 static svn_error_t *compat_get_commit_editor(void *session_baton,
151 const svn_delta_editor_t
155 svn_commit_callback_t callback,
156 void *callback_baton,
159 svn_commit_callback2_t callback2;
160 void *callback2_baton;
161 apr_hash_t *revprop_table = apr_hash_make(pool);
163 svn_compat_wrap_commit_callback(&callback2, &callback2_baton,
164 callback, callback_baton,
166 apr_hash_set(revprop_table, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
167 svn_string_create(log_msg, pool));
168 return VTBL.get_commit_editor(session_baton, editor, edit_baton,
169 revprop_table, callback2, callback2_baton,
173 static svn_error_t *compat_get_file(void *session_baton,
175 svn_revnum_t revision,
176 svn_stream_t *stream,
177 svn_revnum_t *fetched_rev,
181 return VTBL.get_file(session_baton, path, revision, stream, fetched_rev,
185 static svn_error_t *compat_get_dir(void *session_baton,
187 svn_revnum_t revision,
188 apr_hash_t **dirents,
189 svn_revnum_t *fetched_rev,
193 return VTBL.get_dir(session_baton, dirents, fetched_rev, props,
194 path, revision, SVN_DIRENT_ALL, pool);
197 /** Reporter compat code. **/
199 struct compat_report_baton {
200 const svn_ra_reporter3_t *reporter;
204 static svn_error_t *compat_set_path(void *report_baton,
206 svn_revnum_t revision,
207 svn_boolean_t start_empty,
210 struct compat_report_baton *crb = report_baton;
212 return crb->reporter->set_path(crb->baton, path, revision,
213 svn_depth_infinity, start_empty,
217 static svn_error_t *compat_delete_path(void *report_baton,
221 struct compat_report_baton *crb = report_baton;
223 return crb->reporter->delete_path(crb->baton, path, pool);
226 static svn_error_t *compat_link_path(void *report_baton,
229 svn_revnum_t revision,
230 svn_boolean_t start_empty,
233 struct compat_report_baton *crb = report_baton;
235 return crb->reporter->link_path(crb->baton, path, url, revision,
236 svn_depth_infinity, start_empty,
240 static svn_error_t *compat_finish_report(void *report_baton,
243 struct compat_report_baton *crb = report_baton;
245 return crb->reporter->finish_report(crb->baton, pool);
248 static svn_error_t *compat_abort_report(void *report_baton,
251 struct compat_report_baton *crb = report_baton;
253 return crb->reporter->abort_report(crb->baton, pool);
256 static const svn_ra_reporter_t compat_reporter = {
260 compat_finish_report,
264 static void compat_wrap_reporter(const svn_ra_reporter_t **reporter,
266 const svn_ra_reporter3_t *wrapped,
270 struct compat_report_baton *crb = apr_palloc(pool, sizeof(*crb));
271 crb->reporter = wrapped;
272 crb->baton = wrapped_baton;
274 *reporter = &compat_reporter;
278 static svn_error_t *compat_do_update(void *session_baton,
279 const svn_ra_reporter_t **reporter,
281 svn_revnum_t revision_to_update_to,
282 const char *update_target,
283 svn_boolean_t recurse,
284 const svn_delta_editor_t *editor,
288 const svn_ra_reporter3_t *reporter3;
290 svn_depth_t depth = SVN_DEPTH_INFINITY_OR_FILES(recurse);
292 SVN_ERR(VTBL.do_update(session_baton, &reporter3, &baton3,
293 revision_to_update_to, update_target, depth,
294 FALSE /* send_copyfrom_args */,
295 FALSE /* ignore_ancestry */,
296 editor, update_baton,
298 compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool);
303 static svn_error_t *compat_do_switch(void *session_baton,
304 const svn_ra_reporter_t **reporter,
306 svn_revnum_t revision_to_switch_to,
307 const char *switch_target,
308 svn_boolean_t recurse,
309 const char *switch_url,
310 const svn_delta_editor_t *editor,
314 const svn_ra_reporter3_t *reporter3;
316 svn_depth_t depth = SVN_DEPTH_INFINITY_OR_FILES(recurse);
318 SVN_ERR(VTBL.do_switch(session_baton, &reporter3, &baton3,
319 revision_to_switch_to, switch_target, depth,
321 FALSE /* send_copyfrom_args */,
322 TRUE /* ignore_ancestry */,
323 editor, switch_baton,
324 pool /* result_pool */, pool /* scratch_pool */));
326 compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool);
331 static svn_error_t *compat_do_status(void *session_baton,
332 const svn_ra_reporter_t **reporter,
334 const char *status_target,
335 svn_revnum_t revision,
336 svn_boolean_t recurse,
337 const svn_delta_editor_t *editor,
341 const svn_ra_reporter3_t *reporter3;
343 svn_depth_t depth = SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse);
345 SVN_ERR(VTBL.do_status(session_baton, &reporter3, &baton3, status_target,
346 revision, depth, editor, status_baton, pool));
348 compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool);
353 static svn_error_t *compat_do_diff(void *session_baton,
354 const svn_ra_reporter_t **reporter,
356 svn_revnum_t revision,
357 const char *diff_target,
358 svn_boolean_t recurse,
359 svn_boolean_t ignore_ancestry,
360 const char *versus_url,
361 const svn_delta_editor_t *diff_editor,
365 const svn_ra_reporter3_t *reporter3;
367 svn_depth_t depth = SVN_DEPTH_INFINITY_OR_FILES(recurse);
369 SVN_ERR(VTBL.do_diff(session_baton, &reporter3, &baton3, revision,
370 diff_target, depth, ignore_ancestry, TRUE,
371 versus_url, diff_editor, diff_baton, pool));
373 compat_wrap_reporter(reporter, report_baton, reporter3, baton3, pool);
378 static svn_error_t *compat_get_log(void *session_baton,
379 const apr_array_header_t *paths,
382 svn_boolean_t discover_changed_paths,
383 svn_boolean_t strict_node_history,
384 svn_log_message_receiver_t receiver,
385 void *receiver_baton,
388 svn_log_entry_receiver_t receiver2;
389 void *receiver2_baton;
391 svn_compat_wrap_log_receiver(&receiver2, &receiver2_baton,
392 receiver, receiver_baton,
395 return VTBL.get_log(session_baton, paths, start, end, 0, /* limit */
396 discover_changed_paths, strict_node_history,
397 FALSE, /* include_merged_revisions */
398 svn_compat_log_revprops_in(pool), /* revprops */
399 receiver2, receiver2_baton, pool);
402 static svn_error_t *compat_check_path(void *session_baton,
404 svn_revnum_t revision,
405 svn_node_kind_t *kind,
408 return VTBL.check_path(session_baton, path, revision, kind, pool);
411 static svn_error_t *compat_get_uuid(void *session_baton,
415 return VTBL.get_uuid(session_baton, uuid, pool);
418 static svn_error_t *compat_get_repos_root(void *session_baton,
422 return VTBL.get_repos_root(session_baton, url, pool);
425 static svn_error_t *compat_get_locations(void *session_baton,
426 apr_hash_t **locations,
428 svn_revnum_t peg_revision,
429 apr_array_header_t *location_revs,
432 return VTBL.get_locations(session_baton, locations, path, peg_revision,
433 location_revs, pool);
436 static svn_error_t *compat_get_file_revs(void *session_baton,
440 svn_ra_file_rev_handler_t handler,
444 svn_file_rev_handler_t handler2;
445 void *handler2_baton;
447 svn_compat_wrap_file_rev_handler(&handler2, &handler2_baton,
448 handler, handler_baton,
451 return VTBL.get_file_revs(session_baton, path, start, end,
452 FALSE, /* include merged revisions */
453 handler2, handler2_baton, pool);
456 static const svn_version_t *compat_get_version(void)
458 return VTBL.get_version();
462 static const svn_ra_plugin_t compat_plugin = {
466 compat_get_latest_revnum,
467 compat_get_dated_revision,
468 compat_change_rev_prop,
471 compat_get_commit_editor,
481 compat_get_repos_root,
482 compat_get_locations,
483 compat_get_file_revs,
488 COMPAT_INITFUNC(int abi_version,
492 const svn_ra__vtable_t *vtable;
493 const char * const * schemes;
496 || abi_version > SVN_RA_ABI_VERSION)
497 return svn_error_createf(SVN_ERR_RA_UNSUPPORTED_ABI_VERSION, NULL,
498 _("Unsupported RA plugin ABI version (%d) "
499 "for %s"), abi_version, NAME);
501 /* We call the new init function so it can check library dependencies or
502 do other initialization things. We fake the loader version, since we
503 rely on the ABI version check instead. */
504 SVN_ERR(INITFUNC(VTBL.get_version(), &vtable, pool));
506 schemes = VTBL.get_schemes(pool);
508 for (; *schemes != NULL; ++schemes)
509 apr_hash_set(hash, *schemes, APR_HASH_KEY_STRING, &compat_plugin);