]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/svnbench/null-export-cmd.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / svnbench / null-export-cmd.c
1 /*
2  * export-cmd.c -- Subversion export command
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 /* ==================================================================== */
25
26
27 \f
28 /*** Includes. ***/
29
30 #include "svn_client.h"
31 #include "svn_error.h"
32 #include "svn_dirent_uri.h"
33 #include "svn_path.h"
34 #include "svn_cmdline.h"
35 #include "cl.h"
36
37 #include "svn_private_config.h"
38 #include "private/svn_string_private.h"
39 #include "private/svn_client_private.h"
40
41 /*** The export editor code. ***/
42
43 /* ---------------------------------------------------------------------- */
44
45 /*** A dedicated 'export' editor, which does no .svn/ accounting.  ***/
46
47 typedef struct edit_baton_t
48 {
49   apr_int64_t file_count;
50   apr_int64_t dir_count;
51   apr_int64_t byte_count;
52   apr_int64_t prop_count;
53   apr_int64_t prop_byte_count;
54 } edit_baton_t;
55
56 static svn_error_t *
57 set_target_revision(void *edit_baton,
58                     svn_revnum_t target_revision,
59                     apr_pool_t *pool)
60 {
61   return SVN_NO_ERROR;
62 }
63
64
65 /* Just ensure that the main export directory exists. */
66 static svn_error_t *
67 open_root(void *edit_baton,
68           svn_revnum_t base_revision,
69           apr_pool_t *pool,
70           void **root_baton)
71 {
72   *root_baton = edit_baton;
73   return SVN_NO_ERROR;
74 }
75
76
77 /* Ensure the directory exists, and send feedback. */
78 static svn_error_t *
79 add_directory(const char *path,
80               void *parent_baton,
81               const char *copyfrom_path,
82               svn_revnum_t copyfrom_revision,
83               apr_pool_t *pool,
84               void **baton)
85 {
86   edit_baton_t *eb = parent_baton;
87   eb->dir_count++;
88
89   *baton = parent_baton;
90   return SVN_NO_ERROR;
91 }
92
93
94 /* Build a file baton. */
95 static svn_error_t *
96 add_file(const char *path,
97           void *parent_baton,
98           const char *copyfrom_path,
99           svn_revnum_t copyfrom_revision,
100           apr_pool_t *pool,
101           void **baton)
102 {
103   edit_baton_t *eb = parent_baton;
104   eb->file_count++;
105
106   *baton = parent_baton;
107   return SVN_NO_ERROR;
108 }
109
110 static svn_error_t *
111 window_handler(svn_txdelta_window_t *window, void *baton)
112 {
113   edit_baton_t *eb = baton;
114   if (window != NULL)
115     eb->byte_count += window->tview_len;
116
117   return SVN_NO_ERROR;
118 }
119
120 /* Write incoming data into the tmpfile stream */
121
122 static svn_error_t *
123 apply_textdelta(void *file_baton,
124                 const char *base_checksum,
125                 apr_pool_t *pool,
126                 svn_txdelta_window_handler_t *handler,
127                 void **handler_baton)
128 {
129   *handler_baton = file_baton;
130   *handler = window_handler;
131
132   return SVN_NO_ERROR;
133 }
134
135 static svn_error_t *
136 change_file_prop(void *file_baton,
137                  const char *name,
138                  const svn_string_t *value,
139                  apr_pool_t *pool)
140 {
141   edit_baton_t *eb = file_baton;
142   eb->prop_count++;
143   eb->prop_byte_count += value->len;
144
145   return SVN_NO_ERROR;
146 }
147
148 static svn_error_t *
149 change_dir_prop(void *dir_baton,
150                 const char *name,
151                 const svn_string_t *value,
152                 apr_pool_t *pool)
153 {
154   edit_baton_t *eb = dir_baton;
155   eb->prop_count++;
156
157   return SVN_NO_ERROR;
158 }
159
160 static svn_error_t *
161 close_file(void *file_baton,
162            const char *text_checksum,
163            apr_pool_t *pool)
164 {
165   return SVN_NO_ERROR;
166 }
167
168
169 /*** Public Interfaces ***/
170
171 static svn_error_t *
172 bench_null_export(svn_revnum_t *result_rev,
173                   const char *from_path_or_url,
174                   svn_opt_revision_t *peg_revision,
175                   svn_opt_revision_t *revision,
176                   svn_depth_t depth,
177                   void *baton,
178                   svn_client_ctx_t *ctx,
179                   svn_boolean_t quiet,
180                   apr_pool_t *pool)
181 {
182   svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
183   svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
184
185   SVN_ERR_ASSERT(peg_revision != NULL);
186   SVN_ERR_ASSERT(revision != NULL);
187
188   if (peg_revision->kind == svn_opt_revision_unspecified)
189     peg_revision->kind = svn_path_is_url(from_path_or_url)
190                        ? svn_opt_revision_head
191                        : svn_opt_revision_working;
192
193   if (revision->kind == svn_opt_revision_unspecified)
194     revision = peg_revision;
195
196   if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
197     {
198       svn_client__pathrev_t *loc;
199       svn_ra_session_t *ra_session;
200       svn_node_kind_t kind;
201
202       /* Get the RA connection. */
203       SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
204                                                 from_path_or_url, NULL,
205                                                 peg_revision,
206                                                 revision, ctx, pool));
207
208       SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
209
210       if (kind == svn_node_file)
211         {
212           apr_hash_t *props;
213
214           /* Since you cannot actually root an editor at a file, we
215            * manually drive a few functions of our editor. */
216
217           /* Step outside the editor-likeness for a moment, to actually talk
218            * to the repository. */
219           /* ### note: the stream will not be closed */
220           SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
221                                   svn_stream_empty(pool),
222                                   NULL, &props, pool));
223         }
224       else if (kind == svn_node_dir)
225         {
226           void *edit_baton = NULL;
227           const svn_delta_editor_t *export_editor = NULL;
228           const svn_ra_reporter3_t *reporter;
229           void *report_baton;
230
231           svn_delta_editor_t *editor = svn_delta_default_editor(pool);
232
233           editor->set_target_revision = set_target_revision;
234           editor->open_root = open_root;
235           editor->add_directory = add_directory;
236           editor->add_file = add_file;
237           editor->apply_textdelta = apply_textdelta;
238           editor->close_file = close_file;
239           editor->change_file_prop = change_file_prop;
240           editor->change_dir_prop = change_dir_prop;
241
242           /* for ra_svn, we don't need an editior in quiet mode */
243           if (!quiet || strncmp(loc->repos_root_url, "svn:", 4))
244             SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
245                                                       ctx->cancel_baton,
246                                                       editor,
247                                                       baton,
248                                                       &export_editor,
249                                                       &edit_baton,
250                                                       pool));
251
252           /* Manufacture a basic 'report' to the update reporter. */
253           SVN_ERR(svn_ra_do_update3(ra_session,
254                                     &reporter, &report_baton,
255                                     loc->rev,
256                                     "", /* no sub-target */
257                                     depth,
258                                     FALSE, /* don't want copyfrom-args */
259                                     FALSE, /* don't want ignore_ancestry */
260                                     export_editor, edit_baton,
261                                     pool, pool));
262
263           SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
264                                      /* Depth is irrelevant, as we're
265                                         passing start_empty=TRUE anyway. */
266                                      svn_depth_infinity,
267                                      TRUE, /* "help, my dir is empty!" */
268                                      NULL, pool));
269
270           SVN_ERR(reporter->finish_report(report_baton, pool));
271         }
272       else if (kind == svn_node_none)
273         {
274           return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
275                                    _("URL '%s' doesn't exist"),
276                                    from_path_or_url);
277         }
278       /* kind == svn_node_unknown not handled */
279     }
280
281
282   if (result_rev)
283     *result_rev = edit_revision;
284
285   return SVN_NO_ERROR;
286 }
287
288 \f
289 /*** Code. ***/
290
291 /* This implements the `svn_opt_subcommand_t' interface. */
292 svn_error_t *
293 svn_cl__null_export(apr_getopt_t *os,
294                     void *baton,
295                     apr_pool_t *pool)
296 {
297   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
298   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
299   const char *from;
300   apr_array_header_t *targets;
301   svn_error_t *err;
302   svn_opt_revision_t peg_revision;
303   const char *truefrom;
304   edit_baton_t eb = { 0 };
305
306   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
307                                                       opt_state->targets,
308                                                       ctx, FALSE, pool));
309
310   /* We want exactly 1 or 2 targets for this subcommand. */
311   if (targets->nelts < 1)
312     return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
313   if (targets->nelts > 2)
314     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
315
316   /* The first target is the `from' path. */
317   from = APR_ARRAY_IDX(targets, 0, const char *);
318
319   /* Get the peg revision if present. */
320   SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool));
321
322   if (opt_state->depth == svn_depth_unknown)
323     opt_state->depth = svn_depth_infinity;
324
325   /* Do the export. */
326   err = bench_null_export(NULL, truefrom, &peg_revision,
327                           &(opt_state->start_revision),
328                           opt_state->depth,
329                           &eb,
330                           ctx, opt_state->quiet, pool);
331
332   if (!opt_state->quiet)
333     SVN_ERR(svn_cmdline_printf(pool,
334                                _("%15s directories\n"
335                                  "%15s files\n"
336                                  "%15s bytes in files\n"
337                                  "%15s properties\n"
338                                  "%15s bytes in properties\n"),
339                                svn__ui64toa_sep(eb.dir_count, ',', pool),
340                                svn__ui64toa_sep(eb.file_count, ',', pool),
341                                svn__ui64toa_sep(eb.byte_count, ',', pool),
342                                svn__ui64toa_sep(eb.prop_count, ',', pool),
343                                svn__ui64toa_sep(eb.prop_byte_count, ',', pool)));
344
345   return svn_error_trace(err);
346 }