]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/svnbench/null-info-cmd.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / svnbench / null-info-cmd.c
1 /*
2  * info-cmd.c -- Display information about a resource
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_string.h"
31 #include "svn_cmdline.h"
32 #include "svn_wc.h"
33 #include "svn_pools.h"
34 #include "svn_error_codes.h"
35 #include "svn_error.h"
36 #include "svn_dirent_uri.h"
37 #include "svn_path.h"
38 #include "svn_time.h"
39 #include "svn_xml.h"
40 #include "cl.h"
41
42 #include "svn_private_config.h"
43 #include "private/svn_client_private.h"
44
45 \f
46 /*** Code. ***/
47
48 /* The dirent fields we care about for our calls to svn_ra_get_dir2. */
49 #define DIRENT_FIELDS (SVN_DIRENT_KIND        | \
50                        SVN_DIRENT_CREATED_REV | \
51                        SVN_DIRENT_TIME        | \
52                        SVN_DIRENT_LAST_AUTHOR)
53
54 /* Helper func for recursively fetching svn_dirent_t's from a remote
55    directory and pushing them at an info-receiver callback.
56
57    DEPTH is the depth starting at DIR, even though RECEIVER is never
58    invoked on DIR: if DEPTH is svn_depth_immediates, then increment
59    *COUNTER on all children of DIR, but none of their children; if
60    svn_depth_files, then increment *COUNTER on file children of DIR but
61    not on subdirectories; if svn_depth_infinity, recurse fully.
62    DIR is a relpath, relative to the root of RA_SESSION.
63 */
64 static svn_error_t *
65 push_dir_info(svn_ra_session_t *ra_session,
66               const svn_client__pathrev_t *pathrev,
67               const char *dir,
68               int *counter,
69               svn_depth_t depth,
70               svn_client_ctx_t *ctx,
71               apr_pool_t *pool)
72 {
73   apr_hash_t *tmpdirents;
74   apr_hash_index_t *hi;
75   apr_pool_t *subpool = svn_pool_create(pool);
76
77   SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
78                           dir, pathrev->rev, DIRENT_FIELDS, pool));
79
80   for (hi = apr_hash_first(pool, tmpdirents); hi; hi = apr_hash_next(hi))
81     {
82       const char *path;
83       const char *name = apr_hash_this_key(hi);
84       svn_dirent_t *the_ent = apr_hash_this_val(hi);
85       svn_client__pathrev_t *child_pathrev;
86
87       svn_pool_clear(subpool);
88
89       if (ctx->cancel_func)
90         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
91
92       path = svn_relpath_join(dir, name, subpool);
93       child_pathrev = svn_client__pathrev_join_relpath(pathrev, name, subpool);
94
95       if (depth >= svn_depth_immediates
96           || (depth == svn_depth_files && the_ent->kind == svn_node_file))
97         ++(*counter);
98
99       if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
100         SVN_ERR(push_dir_info(ra_session, child_pathrev, path,
101                               counter, depth, ctx, subpool));
102     }
103
104   svn_pool_destroy(subpool);
105
106   return SVN_NO_ERROR;
107 }
108
109 /* Stripped-down version of svn_client_info3 */
110 static svn_error_t *
111 client_info(const char *abspath_or_url,
112             const svn_opt_revision_t *peg_revision,
113             const svn_opt_revision_t *revision,
114             svn_depth_t depth,
115             svn_boolean_t fetch_excluded,
116             svn_boolean_t fetch_actual_only,
117             const apr_array_header_t *changelists,
118             int *counter,
119             svn_client_ctx_t *ctx,
120             apr_pool_t *pool)
121 {
122   svn_ra_session_t *ra_session;
123   svn_client__pathrev_t *pathrev;
124   svn_lock_t *lock;
125   const char *base_name;
126   svn_dirent_t *the_ent;
127   svn_error_t *err;
128
129   if (depth == svn_depth_unknown)
130     depth = svn_depth_empty;
131
132   /* Go repository digging instead. */
133
134   /* Trace rename history (starting at path_or_url@peg_revision) and
135      return RA session to the possibly-renamed URL as it exists in REVISION.
136      The ra_session returned will be anchored on this "final" URL. */
137   SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev,
138                                             abspath_or_url, NULL, peg_revision,
139                                             revision, ctx, pool));
140
141   svn_uri_split(NULL, &base_name, pathrev->url, pool);
142
143   /* Get the dirent for the URL itself. */
144   SVN_ERR(svn_ra_stat(ra_session, "", pathrev->rev, &the_ent, pool));
145
146   if (! the_ent)
147     return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
148                              _("URL '%s' non-existent in revision %ld"),
149                              pathrev->url, pathrev->rev);
150
151   /* check for locks */
152   err = svn_ra_get_lock(ra_session, &lock, "", pool);
153
154   /* An old mod_dav_svn will always work; there's nothing wrong with
155       doing a PROPFIND for a property named "DAV:supportedlock". But
156       an old svnserve will error. */
157   if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
158     {
159       svn_error_clear(err);
160       lock = NULL;
161     }
162   else if (err)
163     return svn_error_trace(err);
164
165   /* Push the URL's dirent (and lock) at the callback.*/
166   ++(*counter);
167
168   /* Possibly recurse, using the original RA session. */
169   if (depth > svn_depth_empty && (the_ent->kind == svn_node_dir))
170     {
171       apr_hash_t *locks;
172
173       if (peg_revision->kind == svn_opt_revision_head)
174         {
175           err = svn_ra_get_locks2(ra_session, &locks, "", depth, pool);
176
177           /* Catch specific errors thrown by old mod_dav_svn or svnserve. */
178           if (err &&
179               (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED
180                || err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
181             svn_error_clear(err);
182           else if (err)
183             return svn_error_trace(err);
184         }
185
186       SVN_ERR(push_dir_info(ra_session, pathrev, "",
187                             counter, depth, ctx, pool));
188     }
189
190   return SVN_NO_ERROR;
191 }
192
193
194 /* This implements the `svn_opt_subcommand_t' interface. */
195 svn_error_t *
196 svn_cl__null_info(apr_getopt_t *os,
197                   void *baton,
198                   apr_pool_t *pool)
199 {
200   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
201   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
202   apr_array_header_t *targets = NULL;
203   apr_pool_t *subpool = svn_pool_create(pool);
204   int i;
205   svn_error_t *err;
206   svn_boolean_t seen_nonexistent_target = FALSE;
207   svn_opt_revision_t peg_revision;
208   const char *path_prefix;
209
210   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
211                                                       opt_state->targets,
212                                                       ctx, FALSE, pool));
213
214   /* Add "." if user passed 0 arguments. */
215   svn_opt_push_implicit_dot_target(targets, pool);
216
217   if (opt_state->depth == svn_depth_unknown)
218     opt_state->depth = svn_depth_empty;
219
220   SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
221
222   for (i = 0; i < targets->nelts; i++)
223     {
224       const char *truepath;
225       const char *target = APR_ARRAY_IDX(targets, i, const char *);
226       int received_count = 0;
227
228       svn_pool_clear(subpool);
229       SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
230
231       /* Get peg revisions. */
232       SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool));
233
234       /* If no peg-rev was attached to a URL target, then assume HEAD. */
235       if (svn_path_is_url(truepath))
236         {
237           if (peg_revision.kind == svn_opt_revision_unspecified)
238             peg_revision.kind = svn_opt_revision_head;
239         }
240       else
241         {
242           SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
243         }
244
245       err = client_info(truepath,
246                         &peg_revision, &(opt_state->start_revision),
247                         opt_state->depth, TRUE, TRUE,
248                         NULL,
249                         &received_count,
250                         ctx, subpool);
251
252       if (err)
253         {
254           /* If one of the targets is a non-existent URL or wc-entry,
255              don't bail out.  Just warn and move on to the next target. */
256           if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
257               err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
258             {
259               svn_handle_warning2(stderr, err, "svnbench: ");
260               svn_error_clear(svn_cmdline_fprintf(stderr, subpool, "\n"));
261             }
262           else
263             {
264               return svn_error_trace(err);
265             }
266
267           svn_error_clear(err);
268           err = NULL;
269           seen_nonexistent_target = TRUE;
270         }
271       else
272         {
273           SVN_ERR(svn_cmdline_printf(pool, _("Number of status notifications "
274                                              "received: %d\n"),
275                                      received_count));
276         }
277     }
278   svn_pool_destroy(subpool);
279
280   if (seen_nonexistent_target)
281     return svn_error_create(
282       SVN_ERR_ILLEGAL_TARGET, NULL,
283       _("Could not display info for all targets because some "
284         "targets don't exist"));
285   else
286     return SVN_NO_ERROR;
287 }