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
,
95 callbacks
? callbacks
->auth_baton
: NULL
,
96 config
, sesspool
, sesspool
));
98 if (strcmp(repos_URL
, session_url
) != 0)
100 svn_pool_destroy(sesspool
);
101 return svn_error_createf(SVN_ERR_RA_SESSION_URL_MISMATCH
, NULL
,
102 _("Session URL '%s' does not match requested "
103 " URL '%s', and redirection was disallowed."),
104 session_url
, repos_URL
);
107 *session_baton
= sess
;
111 static svn_error_t
*compat_get_latest_revnum(void *session_baton
,
112 svn_revnum_t
*latest_revnum
,
115 return VTBL
.get_latest_revnum(session_baton
, latest_revnum
, pool
);
118 static svn_error_t
*compat_get_dated_revision(void *session_baton
,
119 svn_revnum_t
*revision
,
123 return VTBL
.get_dated_revision(session_baton
, revision
, tm
, pool
);
126 static svn_error_t
*compat_change_rev_prop(void *session_baton
,
128 const char *propname
,
129 const svn_string_t
*value
,
132 return VTBL
.change_rev_prop(session_baton
, rev
, propname
, NULL
, value
, pool
);
135 static svn_error_t
*compat_rev_proplist(void *session_baton
,
140 return VTBL
.rev_proplist(session_baton
, rev
, props
, pool
);
143 static svn_error_t
*compat_rev_prop(void *session_baton
,
145 const char *propname
,
146 svn_string_t
**value
,
149 return VTBL
.rev_prop(session_baton
, rev
, propname
, value
, pool
);
152 static svn_error_t
*compat_get_commit_editor(void *session_baton
,
153 const svn_delta_editor_t
157 svn_commit_callback_t callback
,
158 void *callback_baton
,
161 svn_commit_callback2_t callback2
;
162 void *callback2_baton
;
163 apr_hash_t
*revprop_table
= apr_hash_make(pool
);
165 svn_compat_wrap_commit_callback(&callback2
, &callback2_baton
,
166 callback
, callback_baton
,
168 apr_hash_set(revprop_table
, SVN_PROP_REVISION_LOG
, APR_HASH_KEY_STRING
,
169 svn_string_create(log_msg
, pool
));
170 return VTBL
.get_commit_editor(session_baton
, editor
, edit_baton
,
171 revprop_table
, callback2
, callback2_baton
,
175 static svn_error_t
*compat_get_file(void *session_baton
,
177 svn_revnum_t revision
,
178 svn_stream_t
*stream
,
179 svn_revnum_t
*fetched_rev
,
183 return VTBL
.get_file(session_baton
, path
, revision
, stream
, fetched_rev
,
187 static svn_error_t
*compat_get_dir(void *session_baton
,
189 svn_revnum_t revision
,
190 apr_hash_t
**dirents
,
191 svn_revnum_t
*fetched_rev
,
195 return VTBL
.get_dir(session_baton
, dirents
, fetched_rev
, props
,
196 path
, revision
, SVN_DIRENT_ALL
, pool
);
199 /** Reporter compat code. **/
201 struct compat_report_baton
{
202 const svn_ra_reporter3_t
*reporter
;
206 static svn_error_t
*compat_set_path(void *report_baton
,
208 svn_revnum_t revision
,
209 svn_boolean_t start_empty
,
212 struct compat_report_baton
*crb
= report_baton
;
214 return crb
->reporter
->set_path(crb
->baton
, path
, revision
,
215 svn_depth_infinity
, start_empty
,
219 static svn_error_t
*compat_delete_path(void *report_baton
,
223 struct compat_report_baton
*crb
= report_baton
;
225 return crb
->reporter
->delete_path(crb
->baton
, path
, pool
);
228 static svn_error_t
*compat_link_path(void *report_baton
,
231 svn_revnum_t revision
,
232 svn_boolean_t start_empty
,
235 struct compat_report_baton
*crb
= report_baton
;
237 return crb
->reporter
->link_path(crb
->baton
, path
, url
, revision
,
238 svn_depth_infinity
, start_empty
,
242 static svn_error_t
*compat_finish_report(void *report_baton
,
245 struct compat_report_baton
*crb
= report_baton
;
247 return crb
->reporter
->finish_report(crb
->baton
, pool
);
250 static svn_error_t
*compat_abort_report(void *report_baton
,
253 struct compat_report_baton
*crb
= report_baton
;
255 return crb
->reporter
->abort_report(crb
->baton
, pool
);
258 static const svn_ra_reporter_t compat_reporter
= {
262 compat_finish_report
,
266 static void compat_wrap_reporter(const svn_ra_reporter_t
**reporter
,
268 const svn_ra_reporter3_t
*wrapped
,
272 struct compat_report_baton
*crb
= apr_palloc(pool
, sizeof(*crb
));
273 crb
->reporter
= wrapped
;
274 crb
->baton
= wrapped_baton
;
276 *reporter
= &compat_reporter
;
280 static svn_error_t
*compat_do_update(void *session_baton
,
281 const svn_ra_reporter_t
**reporter
,
283 svn_revnum_t revision_to_update_to
,
284 const char *update_target
,
285 svn_boolean_t recurse
,
286 const svn_delta_editor_t
*editor
,
290 const svn_ra_reporter3_t
*reporter3
;
292 svn_depth_t depth
= SVN_DEPTH_INFINITY_OR_FILES(recurse
);
294 SVN_ERR(VTBL
.do_update(session_baton
, &reporter3
, &baton3
,
295 revision_to_update_to
, update_target
, depth
,
296 FALSE
/* send_copyfrom_args */,
297 FALSE
/* ignore_ancestry */,
298 editor
, update_baton
,
300 compat_wrap_reporter(reporter
, report_baton
, reporter3
, baton3
, pool
);
305 static svn_error_t
*compat_do_switch(void *session_baton
,
306 const svn_ra_reporter_t
**reporter
,
308 svn_revnum_t revision_to_switch_to
,
309 const char *switch_target
,
310 svn_boolean_t recurse
,
311 const char *switch_url
,
312 const svn_delta_editor_t
*editor
,
316 const svn_ra_reporter3_t
*reporter3
;
318 svn_depth_t depth
= SVN_DEPTH_INFINITY_OR_FILES(recurse
);
320 SVN_ERR(VTBL
.do_switch(session_baton
, &reporter3
, &baton3
,
321 revision_to_switch_to
, switch_target
, depth
,
323 FALSE
/* send_copyfrom_args */,
324 TRUE
/* ignore_ancestry */,
325 editor
, switch_baton
,
326 pool
/* result_pool */, pool
/* scratch_pool */));
328 compat_wrap_reporter(reporter
, report_baton
, reporter3
, baton3
, pool
);
333 static svn_error_t
*compat_do_status(void *session_baton
,
334 const svn_ra_reporter_t
**reporter
,
336 const char *status_target
,
337 svn_revnum_t revision
,
338 svn_boolean_t recurse
,
339 const svn_delta_editor_t
*editor
,
343 const svn_ra_reporter3_t
*reporter3
;
345 svn_depth_t depth
= SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse
);
347 SVN_ERR(VTBL
.do_status(session_baton
, &reporter3
, &baton3
, status_target
,
348 revision
, depth
, editor
, status_baton
, pool
));
350 compat_wrap_reporter(reporter
, report_baton
, reporter3
, baton3
, pool
);
355 static svn_error_t
*compat_do_diff(void *session_baton
,
356 const svn_ra_reporter_t
**reporter
,
358 svn_revnum_t revision
,
359 const char *diff_target
,
360 svn_boolean_t recurse
,
361 svn_boolean_t ignore_ancestry
,
362 const char *versus_url
,
363 const svn_delta_editor_t
*diff_editor
,
367 const svn_ra_reporter3_t
*reporter3
;
369 svn_depth_t depth
= SVN_DEPTH_INFINITY_OR_FILES(recurse
);
371 SVN_ERR(VTBL
.do_diff(session_baton
, &reporter3
, &baton3
, revision
,
372 diff_target
, depth
, ignore_ancestry
, TRUE
,
373 versus_url
, diff_editor
, diff_baton
, pool
));
375 compat_wrap_reporter(reporter
, report_baton
, reporter3
, baton3
, pool
);
380 static svn_error_t
*compat_get_log(void *session_baton
,
381 const apr_array_header_t
*paths
,
384 svn_boolean_t discover_changed_paths
,
385 svn_boolean_t strict_node_history
,
386 svn_log_message_receiver_t receiver
,
387 void *receiver_baton
,
390 svn_log_entry_receiver_t receiver2
;
391 void *receiver2_baton
;
393 svn_compat_wrap_log_receiver(&receiver2
, &receiver2_baton
,
394 receiver
, receiver_baton
,
397 return VTBL
.get_log(session_baton
, paths
, start
, end
, 0, /* limit */
398 discover_changed_paths
, strict_node_history
,
399 FALSE
, /* include_merged_revisions */
400 svn_compat_log_revprops_in(pool
), /* revprops */
401 receiver2
, receiver2_baton
, pool
);
404 static svn_error_t
*compat_check_path(void *session_baton
,
406 svn_revnum_t revision
,
407 svn_node_kind_t
*kind
,
410 return VTBL
.check_path(session_baton
, path
, revision
, kind
, pool
);
413 static svn_error_t
*compat_get_uuid(void *session_baton
,
417 return VTBL
.get_uuid(session_baton
, uuid
, pool
);
420 static svn_error_t
*compat_get_repos_root(void *session_baton
,
424 return VTBL
.get_repos_root(session_baton
, url
, pool
);
427 static svn_error_t
*compat_get_locations(void *session_baton
,
428 apr_hash_t
**locations
,
430 svn_revnum_t peg_revision
,
431 apr_array_header_t
*location_revs
,
434 return VTBL
.get_locations(session_baton
, locations
, path
, peg_revision
,
435 location_revs
, pool
);
438 static svn_error_t
*compat_get_file_revs(void *session_baton
,
442 svn_ra_file_rev_handler_t handler
,
446 svn_file_rev_handler_t handler2
;
447 void *handler2_baton
;
449 svn_compat_wrap_file_rev_handler(&handler2
, &handler2_baton
,
450 handler
, handler_baton
,
453 return VTBL
.get_file_revs(session_baton
, path
, start
, end
,
454 FALSE
, /* include merged revisions */
455 handler2
, handler2_baton
, pool
);
458 static const svn_version_t
*compat_get_version(void)
460 return VTBL
.get_version();
464 static const svn_ra_plugin_t compat_plugin
= {
468 compat_get_latest_revnum
,
469 compat_get_dated_revision
,
470 compat_change_rev_prop
,
473 compat_get_commit_editor
,
483 compat_get_repos_root
,
484 compat_get_locations
,
485 compat_get_file_revs
,
490 COMPAT_INITFUNC(int abi_version
,
494 const svn_ra__vtable_t
*vtable
;
495 const char * const * schemes
;
498 || abi_version
> SVN_RA_ABI_VERSION
)
499 return svn_error_createf(SVN_ERR_RA_UNSUPPORTED_ABI_VERSION
, NULL
,
500 _("Unsupported RA plugin ABI version (%d) "
501 "for %s"), abi_version
, NAME
);
503 /* We call the new init function so it can check library dependencies or
504 do other initialization things. We fake the loader version, since we
505 rely on the ABI version check instead. */
506 SVN_ERR(INITFUNC(VTBL
.get_version(), &vtable
, pool
));
508 schemes
= VTBL
.get_schemes(pool
);
510 for (; *schemes
!= NULL
; ++schemes
)
511 apr_hash_set(hash
, *schemes
, APR_HASH_KEY_STRING
, &compat_plugin
);