1/*
2 * list-cmd.c -- list a URL
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 "svn_cmdline.h"
25#include "svn_client.h"
26#include "svn_error.h"
27#include "svn_pools.h"
28#include "svn_time.h"
29#include "svn_xml.h"
30#include "svn_dirent_uri.h"
31#include "svn_path.h"
32#include "svn_utf.h"
33#include "svn_opt.h"
34
35#include "cl.h"
36
37#include "svn_private_config.h"
38#include "private/svn_string_private.h"
39
40
41
42/* Baton used when printing directory entries. */
43struct print_baton {
44  svn_boolean_t verbose;
45  apr_int64_t directories;
46  apr_int64_t files;
47  apr_int64_t locks;
48  svn_client_ctx_t *ctx;
49};
50
51/* This implements the svn_client_list_func2_t API, printing a single
52   directory entry in text format. */
53static svn_error_t *
54print_dirent(void *baton,
55             const char *path,
56             const svn_dirent_t *dirent,
57             const svn_lock_t *lock,
58             const char *abs_path,
59             const char *external_parent_url,
60             const char *external_target,
61             apr_pool_t *pool)
62{
63  struct print_baton *pb = baton;
64
65  if (pb->ctx->cancel_func)
66    SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
67
68  if (dirent->kind == svn_node_dir)
69    pb->directories++;
70  if (dirent->kind == svn_node_file)
71    pb->files++;
72  if (lock)
73    pb->locks++;
74
75  return SVN_NO_ERROR;
76}
77
78
79/* This implements the `svn_opt_subcommand_t' interface. */
80svn_error_t *
81svn_cl__null_list(apr_getopt_t *os,
82                  void *baton,
83                  apr_pool_t *pool)
84{
85  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
86  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
87  apr_array_header_t *targets;
88  int i;
89  apr_pool_t *subpool = svn_pool_create(pool);
90  apr_uint32_t dirent_fields;
91  struct print_baton pb = { FALSE };
92  svn_boolean_t seen_nonexistent_target = FALSE;
93  svn_error_t *err;
94
95  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
96                                                      opt_state->targets,
97                                                      ctx, FALSE, pool));
98
99  /* Add "." if user passed 0 arguments */
100  svn_opt_push_implicit_dot_target(targets, pool);
101
102  if (opt_state->verbose)
103    dirent_fields = SVN_DIRENT_ALL;
104  else
105    dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */
106
107  pb.ctx = ctx;
108  pb.verbose = opt_state->verbose;
109
110  if (opt_state->depth == svn_depth_unknown)
111    opt_state->depth = svn_depth_immediates;
112
113  /* For each target, try to list it. */
114  for (i = 0; i < targets->nelts; i++)
115    {
116      const char *target = APR_ARRAY_IDX(targets, i, const char *);
117      const char *truepath;
118      svn_opt_revision_t peg_revision;
119
120      svn_pool_clear(subpool);
121
122      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
123
124      /* Get peg revisions. */
125      SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
126                                 subpool));
127
128      err = svn_client_list3(truepath, &peg_revision,
129                             &(opt_state->start_revision),
130                             opt_state->depth,
131                             dirent_fields,
132                             opt_state->verbose,
133                             FALSE, /* include externals */
134                             print_dirent,
135                             &pb, ctx, subpool);
136
137      if (err)
138        {
139          /* If one of the targets is a non-existent URL or wc-entry,
140             don't bail out.  Just warn and move on to the next target. */
141          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
142              err->apr_err == SVN_ERR_FS_NOT_FOUND)
143              svn_handle_warning2(stderr, err, "svnbench: ");
144          else
145              return svn_error_trace(err);
146
147          svn_error_clear(err);
148          err = NULL;
149          seen_nonexistent_target = TRUE;
150        }
151      else if (!opt_state->quiet)
152        SVN_ERR(svn_cmdline_printf(pool,
153                                   _("%15s directories\n"
154                                     "%15s files\n"
155                                     "%15s locks\n"),
156                                   svn__ui64toa_sep(pb.directories, ',', pool),
157                                   svn__ui64toa_sep(pb.files, ',', pool),
158                                   svn__ui64toa_sep(pb.locks, ',', pool)));
159    }
160
161  svn_pool_destroy(subpool);
162
163  if (seen_nonexistent_target)
164    return svn_error_create(
165      SVN_ERR_ILLEGAL_TARGET, NULL,
166      _("Could not list all targets because some targets don't exist"));
167  else
168    return SVN_NO_ERROR;
169}
170