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