2 * propget-cmd.c -- Print properties and values of files/dirs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* ==================================================================== */
31 #include "svn_cmdline.h"
32 #include "svn_pools.h"
33 #include "svn_client.h"
34 #include "svn_string.h"
35 #include "svn_error_codes.h"
36 #include "svn_error.h"
38 #include "svn_sorts.h"
39 #include "svn_subst.h"
40 #include "svn_dirent_uri.h"
42 #include "svn_props.h"
46 #include "private/svn_cmdline_private.h"
48 #include "svn_private_config.h"
54 stream_write(svn_stream_t *out,
58 apr_size_t write_len = len;
60 /* We're gonna bail on an incomplete write here only because we know
61 that this stream is really stdout, which should never be blocking
63 SVN_ERR(svn_stream_write(out, data, &write_len));
65 return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
66 _("Error writing to stream"));
72 print_properties_xml(const char *pname,
74 apr_array_header_t *inherited_props,
77 apr_array_header_t *sorted_props;
79 apr_pool_t *iterpool = NULL;
82 if (inherited_props && inherited_props->nelts)
84 iterpool = svn_pool_create(pool);
86 for (i = 0; i < inherited_props->nelts; i++)
88 const char *name_local;
89 svn_prop_inherited_item_t *iprop =
90 APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
91 svn_string_t *propval = svn__apr_hash_index_val(
92 apr_hash_first(pool, iprop->prop_hash));
95 svn_pool_clear(iterpool);
97 if (svn_path_is_url(iprop->path_or_url))
98 name_local = iprop->path_or_url;
100 name_local = svn_dirent_local_style(iprop->path_or_url, iterpool);
102 svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
103 "path", name_local, NULL);
105 svn_cmdline__print_xml_prop(&sb, pname, propval, TRUE, iterpool);
106 svn_xml_make_close_tag(&sb, iterpool, "target");
108 SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
112 if (iterpool == NULL)
113 iterpool = svn_pool_create(iterpool);
115 sorted_props = svn_sort__hash(props, svn_sort_compare_items_as_paths, pool);
116 for (i = 0; i < sorted_props->nelts; i++)
118 svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
119 const char *filename = item.key;
120 svn_string_t *propval = item.value;
123 svn_pool_clear(iterpool);
125 svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
126 "path", filename, NULL);
127 svn_cmdline__print_xml_prop(&sb, pname, propval, FALSE, iterpool);
128 svn_xml_make_close_tag(&sb, iterpool, "target");
130 SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
134 svn_pool_destroy(iterpool);
139 /* Print the property PNAME_UTF with the value PROPVAL set on ABSPATH_OR_URL
142 If INHERITED_PROPERTY is true then the property described is inherited,
143 otherwise it is explicit.
145 WC_PATH_PREFIX is the absolute path of the current working directory (and
146 is ignored if ABSPATH_OR_URL is a URL).
148 All other arguments are as per print_properties. */
150 print_single_prop(svn_string_t *propval,
151 const char *target_abspath_or_url,
152 const char *abspath_or_URL,
153 const char *wc_path_prefix,
155 const char *pname_utf8,
156 svn_boolean_t print_filenames,
157 svn_boolean_t omit_newline,
158 svn_boolean_t like_proplist,
159 svn_boolean_t inherited_property,
160 apr_pool_t *scratch_pool)
166 /* Print the file name. */
168 if (! svn_path_is_url(abspath_or_URL))
169 abspath_or_URL = svn_cl__local_style_skip_ancestor(wc_path_prefix,
173 /* In verbose mode, print exactly same as "proplist" does;
174 * otherwise, print a brief header. */
175 if (inherited_property)
179 if (! svn_path_is_url(target_abspath_or_url))
180 target_abspath_or_url =
181 svn_cl__local_style_skip_ancestor(wc_path_prefix,
182 target_abspath_or_url,
184 header = apr_psprintf(
186 _("Inherited properties on '%s',\nfrom '%s':\n"),
187 target_abspath_or_url, abspath_or_URL);
191 header = apr_psprintf(scratch_pool, "%s - ", abspath_or_URL);
195 header = apr_psprintf(scratch_pool, like_proplist
196 ? _("Properties on '%s':\n")
197 : "%s - ", abspath_or_URL);
198 SVN_ERR(svn_cmdline_cstring_from_utf8(&header, header, scratch_pool));
199 SVN_ERR(svn_subst_translate_cstring2(header, &header,
200 APR_EOL_STR, /* 'native' eol */
201 FALSE, /* no repair */
202 NULL, /* no keywords */
203 FALSE, /* no expansion */
205 SVN_ERR(stream_write(out, header, strlen(header)));
210 /* Print the property name and value just as "proplist -v" does */
211 apr_hash_t *hash = apr_hash_make(scratch_pool);
213 svn_hash_sets(hash, pname_utf8, propval);
214 SVN_ERR(svn_cmdline__print_prop_hash(out, hash, FALSE, scratch_pool));
218 /* If this is a special Subversion property, it is stored as
219 UTF8, so convert to the native format. */
220 if (svn_prop_needs_translation(pname_utf8))
221 SVN_ERR(svn_subst_detranslate_string(&propval, propval,
222 TRUE, scratch_pool));
224 SVN_ERR(stream_write(out, propval->data, propval->len));
227 SVN_ERR(stream_write(out, APR_EOL_STR,
228 strlen(APR_EOL_STR)));
233 /* Print the properties in PROPS and/or *INHERITED_PROPS to the stream OUT.
234 PROPS is a hash mapping (const char *) path to (svn_string_t) property
235 value. INHERITED_PROPS is a depth-first ordered array of
236 svn_prop_inherited_item_t * structures.
238 TARGET_ABSPATH_OR_URL is the path which inherits INHERITED_PROPS.
240 PROPS may be an empty hash, but is never null. INHERITED_PROPS may be
243 If IS_URL is true, all paths in PROPS are URLs, else all paths are local
246 PNAME_UTF8 is the property name of all the properties.
248 If PRINT_FILENAMES is true, print the item's path before each property.
250 If OMIT_NEWLINE is true, don't add a newline at the end of each property.
252 If LIKE_PROPLIST is true, print everything in a more verbose format
253 like "svn proplist -v" does. */
255 print_properties(svn_stream_t *out,
256 const char *target_abspath_or_url,
257 const char *pname_utf8,
259 apr_array_header_t *inherited_props,
260 svn_boolean_t print_filenames,
261 svn_boolean_t omit_newline,
262 svn_boolean_t like_proplist,
265 apr_array_header_t *sorted_props;
267 apr_pool_t *iterpool = svn_pool_create(pool);
268 const char *path_prefix;
270 SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
274 svn_pool_clear(iterpool);
276 for (i = 0; i < inherited_props->nelts; i++)
278 svn_prop_inherited_item_t *iprop =
279 APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
280 svn_string_t *propval = svn__apr_hash_index_val(apr_hash_first(pool,
282 SVN_ERR(print_single_prop(propval, target_abspath_or_url,
284 path_prefix, out, pname_utf8,
285 print_filenames, omit_newline,
286 like_proplist, TRUE, iterpool));
290 sorted_props = svn_sort__hash(props, svn_sort_compare_items_as_paths, pool);
291 for (i = 0; i < sorted_props->nelts; i++)
293 svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
294 const char *filename = item.key;
295 svn_string_t *propval = item.value;
297 svn_pool_clear(iterpool);
299 SVN_ERR(print_single_prop(propval, target_abspath_or_url, filename,
300 path_prefix, out, pname_utf8, print_filenames,
301 omit_newline, like_proplist, FALSE,
305 svn_pool_destroy(iterpool);
311 /* This implements the `svn_opt_subcommand_t' interface. */
313 svn_cl__propget(apr_getopt_t *os,
317 svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
318 svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
319 const char *pname, *pname_utf8;
320 apr_array_header_t *args, *targets;
323 if (opt_state->verbose && (opt_state->revprop || opt_state->strict
325 return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
326 _("--verbose cannot be used with --revprop or "
327 "--strict or --xml"));
329 /* PNAME is first argument (and PNAME_UTF8 will be a UTF-8 version
331 SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool));
332 pname = APR_ARRAY_IDX(args, 0, const char *);
333 SVN_ERR(svn_utf_cstring_to_utf8(&pname_utf8, pname, pool));
334 if (! svn_prop_name_is_valid(pname_utf8))
335 return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
336 _("'%s' is not a valid Subversion property name"),
339 SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
343 /* Add "." if user passed 0 file arguments */
344 svn_opt_push_implicit_dot_target(targets, pool);
346 /* Open a stream to stdout. */
347 SVN_ERR(svn_stream_for_stdout(&out, pool));
349 if (opt_state->revprop) /* operate on a revprop */
353 svn_string_t *propval;
355 if (opt_state->show_inherited_props)
356 return svn_error_create(
357 SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
358 _("--show-inherited-props can't be used with --revprop"));
360 SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
363 /* Let libsvn_client do the real work. */
364 SVN_ERR(svn_client_revprop_get(pname_utf8, &propval,
365 URL, &(opt_state->start_revision),
372 svn_stringbuf_t *sb = NULL;
373 char *revstr = apr_psprintf(pool, "%ld", rev);
375 SVN_ERR(svn_cl__xml_print_header("properties", pool));
377 svn_xml_make_open_tag(&sb, pool, svn_xml_normal,
379 "rev", revstr, NULL);
381 svn_cmdline__print_xml_prop(&sb, pname_utf8, propval, FALSE,
384 svn_xml_make_close_tag(&sb, pool, "revprops");
386 SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
387 SVN_ERR(svn_cl__xml_print_footer("properties", pool));
391 svn_string_t *printable_val = propval;
393 /* If this is a special Subversion property, it is stored as
394 UTF8 and LF, so convert to the native locale and eol-style. */
396 if (svn_prop_needs_translation(pname_utf8))
397 SVN_ERR(svn_subst_detranslate_string(&printable_val, propval,
400 SVN_ERR(stream_write(out, printable_val->data,
401 printable_val->len));
402 if (! opt_state->strict)
403 SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR)));
407 else /* operate on a normal, versioned property (not a revprop) */
409 apr_pool_t *subpool = svn_pool_create(pool);
413 SVN_ERR(svn_cl__xml_print_header("properties", subpool));
415 if (opt_state->depth == svn_depth_unknown)
416 opt_state->depth = svn_depth_empty;
418 /* Strict mode only makes sense for a single target. So make
419 sure we have only a single target, and that we're not being
420 asked to recurse on that target. */
421 if (opt_state->strict
422 && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty)))
423 return svn_error_create
424 (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
425 _("Strict output of property values only available for single-"
426 "target, non-recursive propget operations"));
428 for (i = 0; i < targets->nelts; i++)
430 const char *target = APR_ARRAY_IDX(targets, i, const char *);
432 svn_boolean_t print_filenames;
433 svn_boolean_t omit_newline;
434 svn_boolean_t like_proplist;
435 const char *truepath;
436 svn_opt_revision_t peg_revision;
437 apr_array_header_t *inherited_props;
439 svn_pool_clear(subpool);
440 SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
442 /* Check for a peg revision. */
443 SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
446 if (!svn_path_is_url(truepath))
447 SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
449 SVN_ERR(svn_client_propget5(
451 opt_state->show_inherited_props ? &inherited_props : NULL,
452 pname_utf8, truepath,
454 &(opt_state->start_revision),
455 NULL, opt_state->depth,
456 opt_state->changelists, ctx, subpool,
459 /* Any time there is more than one thing to print, or where
460 the path associated with a printed thing is not obvious,
461 we'll print filenames. That is, unless we've been told
462 not to do so with the --strict option. */
463 print_filenames = ((opt_state->depth > svn_depth_empty
464 || targets->nelts > 1
465 || apr_hash_count(props) > 1
466 || opt_state->verbose
467 || opt_state->show_inherited_props)
468 && (! opt_state->strict));
469 omit_newline = opt_state->strict;
470 like_proplist = opt_state->verbose && !opt_state->strict;
473 SVN_ERR(print_properties_xml(
475 opt_state->show_inherited_props ? inherited_props : NULL,
478 SVN_ERR(print_properties(
479 out, truepath, pname_utf8,
481 opt_state->show_inherited_props ? inherited_props : NULL,
483 omit_newline, like_proplist, subpool));
487 SVN_ERR(svn_cl__xml_print_footer("properties", subpool));
489 svn_pool_destroy(subpool);