proplist-cmd.c revision 299742
1/*
2 * proplist-cmd.c -- List properties of files/dirs
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
28/*** Includes. ***/
29
30#include "svn_cmdline.h"
31#include "svn_pools.h"
32#include "svn_client.h"
33#include "svn_error_codes.h"
34#include "svn_error.h"
35#include "svn_dirent_uri.h"
36#include "svn_path.h"
37#include "svn_xml.h"
38#include "svn_props.h"
39#include "cl.h"
40
41#include "private/svn_cmdline_private.h"
42
43#include "svn_private_config.h"
44
45typedef struct proplist_baton_t
46{
47  svn_cl__opt_state_t *opt_state;
48  svn_boolean_t is_url;
49} proplist_baton_t;
50
51
52/*** Code. ***/
53
54/* This implements the svn_proplist_receiver2_t interface, printing XML to
55   stdout. */
56static svn_error_t *
57proplist_receiver_xml(void *baton,
58                      const char *path,
59                      apr_hash_t *prop_hash,
60                      apr_array_header_t *inherited_props,
61                      apr_pool_t *pool)
62{
63  svn_cl__opt_state_t *opt_state = ((proplist_baton_t *)baton)->opt_state;
64  svn_boolean_t is_url = ((proplist_baton_t *)baton)->is_url;
65  svn_stringbuf_t *sb;
66  const char *name_local;
67
68  if (inherited_props && inherited_props->nelts)
69    {
70      int i;
71      apr_pool_t *iterpool = svn_pool_create(pool);
72
73      for (i = 0; i < inherited_props->nelts; i++)
74        {
75          svn_prop_inherited_item_t *iprop =
76            APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
77
78          sb = NULL;
79
80          if (svn_path_is_url(iprop->path_or_url))
81            name_local = iprop->path_or_url;
82          else
83            name_local = svn_dirent_local_style(iprop->path_or_url, iterpool);
84
85          svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
86                            "path", name_local, SVN_VA_NULL);
87          SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, iprop->prop_hash,
88                                                   (! opt_state->verbose),
89                                                   TRUE, iterpool));
90          svn_xml_make_close_tag(&sb, iterpool, "target");
91          SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
92        }
93      svn_pool_destroy(iterpool);
94    }
95
96  if (! is_url)
97    name_local = svn_dirent_local_style(path, pool);
98  else
99    name_local = path;
100
101  sb = NULL;
102
103
104  if (prop_hash)
105    {
106      /* "<target ...>" */
107        svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "target",
108                              "path", name_local, SVN_VA_NULL);
109
110        SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, prop_hash,
111                                                 (! opt_state->verbose),
112                                                 FALSE, pool));
113
114        /* "</target>" */
115        svn_xml_make_close_tag(&sb, pool, "target");
116        SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
117    }
118
119  return SVN_NO_ERROR;
120}
121
122
123/* This implements the svn_proplist_receiver2_t interface. */
124static svn_error_t *
125proplist_receiver(void *baton,
126                  const char *path,
127                  apr_hash_t *prop_hash,
128                  apr_array_header_t *inherited_props,
129                  apr_pool_t *pool)
130{
131  svn_cl__opt_state_t *opt_state = ((proplist_baton_t *)baton)->opt_state;
132  svn_boolean_t is_url = ((proplist_baton_t *)baton)->is_url;
133  const char *name_local;
134
135  if (! is_url)
136    name_local = svn_dirent_local_style(path, pool);
137  else
138    name_local = path;
139
140  if (inherited_props)
141    {
142      int i;
143      apr_pool_t *iterpool = svn_pool_create(pool);
144
145      for (i = 0; i < inherited_props->nelts; i++)
146        {
147          svn_prop_inherited_item_t *iprop =
148            APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
149
150          svn_pool_clear(iterpool);
151
152          if (!opt_state->quiet)
153            {
154              if (svn_path_is_url(iprop->path_or_url))
155                SVN_ERR(svn_cmdline_printf(
156                  iterpool, _("Inherited properties on '%s',\nfrom '%s':\n"),
157                  name_local, iprop->path_or_url));
158              else
159                SVN_ERR(svn_cmdline_printf(
160                  iterpool, _("Inherited properties on '%s',\nfrom '%s':\n"),
161                  name_local, svn_dirent_local_style(iprop->path_or_url,
162                                                     iterpool)));
163            }
164
165          SVN_ERR(svn_cmdline__print_prop_hash(NULL, iprop->prop_hash,
166                                               (! opt_state->verbose),
167                                               iterpool));
168        }
169      svn_pool_destroy(iterpool);
170    }
171
172  if (prop_hash && apr_hash_count(prop_hash))
173    {
174      if (!opt_state->quiet)
175        SVN_ERR(svn_cmdline_printf(pool, _("Properties on '%s':\n"),
176                                   name_local));
177      SVN_ERR(svn_cmdline__print_prop_hash(NULL, prop_hash,
178                                           (! opt_state->verbose), pool));
179    }
180
181  return SVN_NO_ERROR;
182}
183
184
185/* This implements the `svn_opt_subcommand_t' interface. */
186svn_error_t *
187svn_cl__proplist(apr_getopt_t *os,
188                 void *baton,
189                 apr_pool_t *scratch_pool)
190{
191  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
192  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
193  apr_array_header_t *targets;
194  apr_array_header_t *errors = apr_array_make(scratch_pool, 0,
195                                              sizeof(apr_status_t));
196
197  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
198                                                      opt_state->targets,
199                                                      ctx, FALSE,
200                                                      scratch_pool));
201
202  /* Add "." if user passed 0 file arguments */
203  svn_opt_push_implicit_dot_target(targets, scratch_pool);
204
205  if (opt_state->revprop)  /* operate on revprops */
206    {
207      svn_revnum_t rev;
208      const char *URL;
209      apr_hash_t *proplist;
210
211      if (opt_state->show_inherited_props)
212        return svn_error_create(
213          SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
214          _("--show-inherited-props can't be used with --revprop"));
215
216      SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
217                                      &URL, ctx, scratch_pool));
218
219      /* Let libsvn_client do the real work. */
220      SVN_ERR(svn_client_revprop_list(&proplist,
221                                      URL, &(opt_state->start_revision),
222                                      &rev, ctx, scratch_pool));
223
224      if (opt_state->xml)
225        {
226          svn_stringbuf_t *sb = NULL;
227          char *revstr = apr_psprintf(scratch_pool, "%ld", rev);
228
229          SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool));
230
231          svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal,
232                                "revprops",
233                                "rev", revstr, SVN_VA_NULL);
234          SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, proplist,
235                                                   (! opt_state->verbose),
236                                                   FALSE, scratch_pool));
237          svn_xml_make_close_tag(&sb, scratch_pool, "revprops");
238
239          SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
240          SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool));
241        }
242      else
243        {
244          SVN_ERR
245            (svn_cmdline_printf(scratch_pool,
246                                _("Unversioned properties on revision %ld:\n"),
247                                rev));
248
249          SVN_ERR(svn_cmdline__print_prop_hash(NULL, proplist,
250                                               (! opt_state->verbose),
251                                               scratch_pool));
252        }
253    }
254  else  /* operate on normal, versioned properties (not revprops) */
255    {
256      int i;
257      apr_pool_t *iterpool;
258      svn_proplist_receiver2_t pl_receiver;
259
260      if (opt_state->xml)
261        {
262          SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool));
263          pl_receiver = proplist_receiver_xml;
264        }
265      else
266        {
267          pl_receiver = proplist_receiver;
268        }
269
270      if (opt_state->depth == svn_depth_unknown)
271        opt_state->depth = svn_depth_empty;
272
273      iterpool = svn_pool_create(scratch_pool);
274      for (i = 0; i < targets->nelts; i++)
275        {
276          const char *target = APR_ARRAY_IDX(targets, i, const char *);
277          proplist_baton_t pl_baton;
278          const char *truepath;
279          svn_opt_revision_t peg_revision;
280
281          svn_pool_clear(iterpool);
282          SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
283
284          pl_baton.is_url = svn_path_is_url(target);
285          pl_baton.opt_state = opt_state;
286
287          /* Check for a peg revision. */
288          SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
289                                     iterpool));
290
291          SVN_ERR(svn_cl__try(
292                   svn_client_proplist4(truepath, &peg_revision,
293                                        &(opt_state->start_revision),
294                                        opt_state->depth,
295                                        opt_state->changelists,
296                                        opt_state->show_inherited_props,
297                                        pl_receiver, &pl_baton,
298                                        ctx, iterpool),
299                   errors, opt_state->quiet,
300                   SVN_ERR_UNVERSIONED_RESOURCE,
301                   SVN_ERR_ENTRY_NOT_FOUND,
302                   0));
303        }
304      svn_pool_destroy(iterpool);
305
306      if (opt_state->xml)
307        SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool));
308
309      /* Error out *after* we closed the XML element */
310      if (errors->nelts > 0)
311        {
312          svn_error_t *err;
313
314          err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
315          for (i = 0; i < errors->nelts; i++)
316            {
317              apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
318
319              if (status == SVN_ERR_ENTRY_NOT_FOUND)
320                err = svn_error_quick_wrap(err,
321                                           _("Could not display properties "
322                                             "of all targets because some "
323                                             "targets don't exist"));
324              else if (status == SVN_ERR_UNVERSIONED_RESOURCE)
325                err = svn_error_quick_wrap(err,
326                                           _("Could not display properties "
327                                             "of all targets because some "
328                                             "targets are not versioned"));
329            }
330
331          return svn_error_trace(err);
332        }
333    }
334
335  return SVN_NO_ERROR;
336}
337