]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_ra/editor.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_ra / editor.c
1 /*
2  * editor.c:  compatibility editors
3  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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
20  *    under the License.
21  * ====================================================================
22  */
23
24 #include <apr_pools.h>
25
26 #include "svn_error.h"
27 #include "svn_pools.h"
28 #include "svn_ra.h"
29 #include "svn_delta.h"
30 #include "svn_dirent_uri.h"
31
32 #include "private/svn_ra_private.h"
33 #include "private/svn_delta_private.h"
34 #include "private/svn_editor.h"
35
36 #include "ra_loader.h"
37 #include "svn_private_config.h"
38
39
40 struct fp_baton {
41   svn_ra__provide_props_cb_t provide_props_cb;
42   void *cb_baton;
43 };
44
45 struct fb_baton {
46   svn_ra__provide_base_cb_t provide_base_cb;
47   void *cb_baton;
48 };
49
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.
54
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.
58
59    The shim code needs to be updated to allow for an RA-style callback
60    to fetch properties.  */
61 static svn_error_t *
62 fetch_props(apr_hash_t **props,
63             void *baton,
64             const char *repos_relpath,
65             svn_revnum_t base_revision,
66             apr_pool_t *result_pool,
67             apr_pool_t *scratch_pool)
68 {
69   struct fp_baton *fpb = baton;
70   svn_revnum_t unused_revision;
71
72   /* Ignored: BASE_REVISION.  */
73
74   return svn_error_trace(fpb->provide_props_cb(props, &unused_revision,
75                                                fpb->cb_baton,
76                                                repos_relpath,
77                                                result_pool, scratch_pool));
78 }
79
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.
83 */
84 static svn_error_t *
85 fetch_base(const char **filename,
86            void *baton,
87            const char *repos_relpath,
88            svn_revnum_t base_revision,
89            apr_pool_t *result_pool,
90            apr_pool_t *scratch_pool)
91 {
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;
97
98   /* Ignored: BASE_REVISION.  */
99
100   SVN_ERR(fbb->provide_base_cb(&contents, &unused_revision, fbb->cb_baton,
101                                repos_relpath, result_pool, scratch_pool));
102
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));
107
108   *filename = apr_pstrdup(result_pool, tmp_filename);
109
110
111
112   return SVN_NO_ERROR;
113 }
114
115
116
117 svn_error_t *
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,
122                         void *commit_baton,
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,
128                         void *cb_baton,
129                         svn_cancel_func_t cancel_func,
130                         void *cancel_baton,
131                         apr_pool_t *result_pool,
132                         apr_pool_t *scratch_pool)
133 {
134   const svn_delta_editor_t *deditor;
135   void *dedit_baton;
136   struct svn_delta__extra_baton *exb;
137   svn_delta__unlock_func_t unlock_func;
138   void *unlock_baton;
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;
144
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>).  */
148
149   /* Fetch the RA provider's Ev1 commit editor.  */
150   SVN_ERR(session->vtable->get_commit_editor(session, &deditor, &dedit_baton,
151                                              revprop_table,
152                                              commit_callback, commit_baton,
153                                              lock_tokens, keep_locks,
154                                              result_pool));
155
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);
160
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));
165
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;
171
172   /* Create the Ev2 editor from the Ev1 editor provided by the RA layer.
173
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,
179                                        found_abs_paths,
180                                        repos_root, base_relpath,
181                                        cancel_func, cancel_baton,
182                                        get_copysrc_kind_cb, cb_baton,
183                                        fetch_props, fpb,
184                                        result_pool, scratch_pool));
185
186   /* Note: UNLOCK_FUNC and UNLOCK_BATON are unused during commit drives.
187      We can safely drop them on the floor.  */
188
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.  */
197   if (exb->start_edit)
198     {
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.
202
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));
209     }
210
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)  */
214
215   return SVN_NO_ERROR;
216 }
217
218
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;
222   void *replay_baton;
223
224   svn_ra_session_t *session;
225
226   svn_ra__provide_base_cb_t provide_base_cb;
227   svn_ra__provide_props_cb_t provide_props_cb;
228   void *cb_baton;
229
230   /* This will be populated by the revstart wrapper. */
231   svn_editor_t *editor;
232 };
233
234 static svn_error_t *
235 revstart_func_wrapper(svn_revnum_t revision,
236                       void *replay_baton,
237                       const svn_delta_editor_t **deditor,
238                       void **dedit_baton,
239                       apr_hash_t *rev_props,
240                       apr_pool_t *result_pool)
241 {
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;
249
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));
253
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);
258
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));
263
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;
269
270   /* Create the extra baton. */
271   exb = apr_pcalloc(result_pool, sizeof(*exb));
272
273   /* Create the Ev1 editor from the Ev2 editor provided by the RA layer.
274
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,
278                                        NULL, NULL,
279                                        found_abs_paths,
280                                        repos_root, base_relpath,
281                                        fetch_props, wrb->cb_baton,
282                                        fetch_base, wrb->cb_baton,
283                                        exb, result_pool));
284
285   return SVN_NO_ERROR;
286 }
287
288 static svn_error_t *
289 revfinish_func_wrapper(svn_revnum_t revision,
290                        void *replay_baton,
291                        const svn_delta_editor_t *editor,
292                        void *edit_baton,
293                        apr_hash_t *rev_props,
294                        apr_pool_t *pool)
295 {
296   struct wrapped_replay_baton_t *wrb = replay_baton;
297
298   SVN_ERR(wrb->revfinish_func(revision, replay_baton, wrb->editor, rev_props,
299                               pool));
300
301   return SVN_NO_ERROR;
302 }
303
304 svn_error_t *
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,
312                               void *replay_baton,
313                               svn_ra__provide_base_cb_t provide_base_cb,
314                               svn_ra__provide_props_cb_t provide_props_cb,
315                               void *cb_baton,
316                               apr_pool_t *scratch_pool)
317 {
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. */
321
322   struct wrapped_replay_baton_t *wrb = apr_pcalloc(scratch_pool, sizeof(*wrb));
323
324   wrb->revstart_func = revstart_func;
325   wrb->revfinish_func = revfinish_func;
326   wrb->replay_baton = replay_baton;
327   wrb->session = session;
328
329   wrb->provide_base_cb = provide_base_cb;
330   wrb->provide_props_cb = provide_props_cb;
331   wrb->cb_baton = cb_baton;
332
333   return svn_error_trace(svn_ra_replay_range(session, start_revision,
334                                              end_revision, low_water_mark,
335                                              send_deltas,
336                                              revstart_func_wrapper,
337                                              revfinish_func_wrapper,
338                                              wrb, scratch_pool));
339 }