2 * editor.c: compatibility editors
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 #include <apr_pools.h>
26 #include "svn_error.h"
27 #include "svn_pools.h"
29 #include "svn_delta.h"
30 #include "svn_dirent_uri.h"
32 #include "private/svn_ra_private.h"
33 #include "private/svn_delta_private.h"
34 #include "private/svn_editor.h"
36 #include "ra_loader.h"
37 #include "svn_private_config.h"
41 svn_ra__provide_props_cb_t provide_props_cb;
46 svn_ra__provide_base_cb_t provide_base_cb;
50 /* The shims currently want a callback that provides props for a given
51 REPOS_RELPATH at a given BASE_REVISION. However, the RA Ev2 interface
52 has a callback that provides properties for the REPOS_RELPATH from any
53 revision, which is returned along with the properties.
55 This is a little shim to map between the prototypes. The base revision
56 for the properties is discarded, and the requested revision (from the
57 shim code) is ignored.
59 The shim code needs to be updated to allow for an RA-style callback
60 to fetch properties. */
62 fetch_props(apr_hash_t **props,
64 const char *repos_relpath,
65 svn_revnum_t base_revision,
66 apr_pool_t *result_pool,
67 apr_pool_t *scratch_pool)
69 struct fp_baton *fpb = baton;
70 svn_revnum_t unused_revision;
72 /* Ignored: BASE_REVISION. */
74 return svn_error_trace(fpb->provide_props_cb(props, &unused_revision,
77 result_pool, scratch_pool));
80 /* See note above regarding BASE_REVISION.
81 This also pulls down the entire contents of the file stream from the
82 RA layer and stores them in a local file, returning the path.
85 fetch_base(const char **filename,
87 const char *repos_relpath,
88 svn_revnum_t base_revision,
89 apr_pool_t *result_pool,
90 apr_pool_t *scratch_pool)
92 struct fb_baton *fbb = baton;
93 svn_revnum_t unused_revision;
94 svn_stream_t *contents;
95 svn_stream_t *file_stream;
96 const char *tmp_filename;
98 /* Ignored: BASE_REVISION. */
100 SVN_ERR(fbb->provide_base_cb(&contents, &unused_revision, fbb->cb_baton,
101 repos_relpath, result_pool, scratch_pool));
103 SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL,
104 svn_io_file_del_on_pool_cleanup,
105 scratch_pool, scratch_pool));
106 SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool));
108 *filename = apr_pstrdup(result_pool, tmp_filename);
118 svn_ra__use_commit_shim(svn_editor_t **editor,
119 svn_ra_session_t *session,
120 apr_hash_t *revprop_table,
121 svn_commit_callback2_t commit_callback,
123 apr_hash_t *lock_tokens,
124 svn_boolean_t keep_locks,
125 svn_ra__provide_base_cb_t provide_base_cb,
126 svn_ra__provide_props_cb_t provide_props_cb,
127 svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
129 svn_cancel_func_t cancel_func,
131 apr_pool_t *result_pool,
132 apr_pool_t *scratch_pool)
134 const svn_delta_editor_t *deditor;
136 struct svn_delta__extra_baton *exb;
137 svn_delta__unlock_func_t unlock_func;
139 const char *repos_root;
140 const char *session_url;
141 const char *base_relpath;
142 svn_boolean_t *found_abs_paths;
143 struct fp_baton *fpb;
145 /* NOTE: PROVIDE_BASE_CB is currently unused by this shim. In the future,
146 we can pass it to the underlying Ev2/Ev1 shim to produce better
147 apply_txdelta drives (ie. against a base rather than <empty>). */
149 /* Fetch the RA provider's Ev1 commit editor. */
150 SVN_ERR(session->vtable->get_commit_editor(session, &deditor, &dedit_baton,
152 commit_callback, commit_baton,
153 lock_tokens, keep_locks,
156 /* Get or calculate the appropriate repos root and base relpath. */
157 SVN_ERR(svn_ra_get_repos_root2(session, &repos_root, scratch_pool));
158 SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool));
159 base_relpath = svn_uri_skip_ancestor(repos_root, session_url, scratch_pool);
161 /* We will assume that when the underlying Ev1 editor is finally driven
162 by the shim, that we will not need to prepend "/" to the paths. Place
163 this on the heap because it is examined much later. Set to FALSE. */
164 found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths));
166 /* The PROVIDE_PROPS_CB callback does not match what the shims want.
167 Let's jigger things around a little bit here. */
168 fpb = apr_palloc(result_pool, sizeof(*fpb));
169 fpb->provide_props_cb = provide_props_cb;
170 fpb->cb_baton = cb_baton;
172 /* Create the Ev2 editor from the Ev1 editor provided by the RA layer.
174 Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the
175 shim's FETCH_KIND_FUNC parameter. */
176 SVN_ERR(svn_delta__editor_from_delta(editor, &exb,
177 &unlock_func, &unlock_baton,
178 deditor, dedit_baton,
180 repos_root, base_relpath,
181 cancel_func, cancel_baton,
182 get_copysrc_kind_cb, cb_baton,
184 result_pool, scratch_pool));
186 /* Note: UNLOCK_FUNC and UNLOCK_BATON are unused during commit drives.
187 We can safely drop them on the floor. */
189 /* Since we're (currently) just wrapping an existing Ev1 editor, we have
190 to call any start_edit handler it may provide (the shim uses this to
191 invoke Ev1's open_root callback). We've got a couple of options to do
192 so: Implement a wrapper editor and call the start_edit callback upon
193 the first invocation of any of the underlying editor's functions; or,
194 just assume our consumer is going to eventually use the editor it is
195 asking for, and call the start edit callback now. For simplicity's
196 sake, we do the latter. */
199 /* Most commit drives pass SVN_INVALID_REVNUM for the revision.
200 All calls to svn_delta_path_driver() pass SVN_INVALID_REVNUM,
201 so this is fine for any commits done via that function.
203 Notably, the PROPSET command passes a specific revision. Before
204 PROPSET can use the RA Ev2 interface, we may need to make this
205 revision a parameter.
206 ### what are the exact semantics? what is the meaning of the
207 ### revision passed to the Ev1->open_root() callback? */
208 SVN_ERR(exb->start_edit(exb->baton, SVN_INVALID_REVNUM));
211 /* Note: EXB also contains a TARGET_REVISION function, but that is not
212 used during commit operations. We can safely ignore it. (ie. it is
213 in EXB for use by paired-shims) */
219 struct wrapped_replay_baton_t {
220 svn_ra__replay_revstart_ev2_callback_t revstart_func;
221 svn_ra__replay_revfinish_ev2_callback_t revfinish_func;
224 svn_ra_session_t *session;
226 svn_ra__provide_base_cb_t provide_base_cb;
227 svn_ra__provide_props_cb_t provide_props_cb;
230 /* This will be populated by the revstart wrapper. */
231 svn_editor_t *editor;
235 revstart_func_wrapper(svn_revnum_t revision,
237 const svn_delta_editor_t **deditor,
239 apr_hash_t *rev_props,
240 apr_pool_t *result_pool)
242 struct wrapped_replay_baton_t *wrb = replay_baton;
243 const char *repos_root;
244 const char *session_url;
245 const char *base_relpath;
246 svn_boolean_t *found_abs_paths;
247 struct fp_baton *fpb;
248 struct svn_delta__extra_baton *exb;
250 /* Get the Ev2 editor from the original revstart func. */
251 SVN_ERR(wrb->revstart_func(revision, wrb->replay_baton, &wrb->editor,
252 rev_props, result_pool));
254 /* Get or calculate the appropriate repos root and base relpath. */
255 SVN_ERR(svn_ra_get_repos_root2(wrb->session, &repos_root, result_pool));
256 SVN_ERR(svn_ra_get_session_url(wrb->session, &session_url, result_pool));
257 base_relpath = svn_uri_skip_ancestor(repos_root, session_url, result_pool);
259 /* We will assume that when the underlying Ev1 editor is finally driven
260 by the shim, that we will not need to prepend "/" to the paths. Place
261 this on the heap because it is examined much later. Set to FALSE. */
262 found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths));
264 /* The PROVIDE_PROPS_CB callback does not match what the shims want.
265 Let's jigger things around a little bit here. */
266 fpb = apr_palloc(result_pool, sizeof(*fpb));
267 fpb->provide_props_cb = wrb->provide_props_cb;
268 fpb->cb_baton = wrb->cb_baton;
270 /* Create the extra baton. */
271 exb = apr_pcalloc(result_pool, sizeof(*exb));
273 /* Create the Ev1 editor from the Ev2 editor provided by the RA layer.
275 Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the
276 shim's FETCH_KIND_FUNC parameter. */
277 SVN_ERR(svn_delta__delta_from_editor(deditor, dedit_baton, wrb->editor,
280 repos_root, base_relpath,
281 fetch_props, wrb->cb_baton,
282 fetch_base, wrb->cb_baton,
289 revfinish_func_wrapper(svn_revnum_t revision,
291 const svn_delta_editor_t *editor,
293 apr_hash_t *rev_props,
296 struct wrapped_replay_baton_t *wrb = replay_baton;
298 SVN_ERR(wrb->revfinish_func(revision, replay_baton, wrb->editor, rev_props,
305 svn_ra__use_replay_range_shim(svn_ra_session_t *session,
306 svn_revnum_t start_revision,
307 svn_revnum_t end_revision,
308 svn_revnum_t low_water_mark,
309 svn_boolean_t send_deltas,
310 svn_ra__replay_revstart_ev2_callback_t revstart_func,
311 svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
313 svn_ra__provide_base_cb_t provide_base_cb,
314 svn_ra__provide_props_cb_t provide_props_cb,
316 apr_pool_t *scratch_pool)
318 /* The basic strategy here is to wrap the callback start and finish
319 functions to appropriately return an Ev1 editor which is itself wrapped
320 from the Ev2 one the provided callbacks will give us. */
322 struct wrapped_replay_baton_t *wrb = apr_pcalloc(scratch_pool, sizeof(*wrb));
324 wrb->revstart_func = revstart_func;
325 wrb->revfinish_func = revfinish_func;
326 wrb->replay_baton = replay_baton;
327 wrb->session = session;
329 wrb->provide_base_cb = provide_base_cb;
330 wrb->provide_props_cb = provide_props_cb;
331 wrb->cb_baton = cb_baton;
333 return svn_error_trace(svn_ra_replay_range(session, start_revision,
334 end_revision, low_water_mark,
336 revstart_func_wrapper,
337 revfinish_func_wrapper,