#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_pools.h"
#include "svn_client.h"
#include "svn_string.h"
#include "svn_error_codes.h"
#include "svn_error.h"
#include "svn_utf.h"
#include "svn_sorts.h"
#include "svn_subst.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_props.h"
#include "svn_xml.h"
#include "cl.h"
#include "private/svn_cmdline_private.h"
#include "private/svn_opt_private.h"
#include "private/svn_sorts_private.h"
#include "svn_private_config.h"
static svn_error_t *
stream_write(svn_stream_t *out,
const char *data,
apr_size_t len)
{
apr_size_t write_len = len;
SVN_ERR(svn_stream_write(out, data, &write_len));
if (write_len != len)
return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
_("Error writing to stream"));
return SVN_NO_ERROR;
}
static svn_error_t *
print_properties_xml(const char *pname,
apr_hash_t *props,
apr_array_header_t *inherited_props,
apr_pool_t *pool)
{
apr_array_header_t *sorted_props;
int i;
apr_pool_t *iterpool = NULL;
svn_stringbuf_t *sb;
if (inherited_props && inherited_props->nelts)
{
iterpool = svn_pool_create(pool);
for (i = 0; i < inherited_props->nelts; i++)
{
const char *name_local;
svn_prop_inherited_item_t *iprop =
APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
svn_string_t *propval = apr_hash_this_val(
apr_hash_first(pool, iprop->prop_hash));
sb = NULL;
svn_pool_clear(iterpool);
if (svn_path_is_url(iprop->path_or_url))
name_local = iprop->path_or_url;
else
name_local = svn_dirent_local_style(iprop->path_or_url, iterpool);
svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
"path", name_local, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname, propval, TRUE, iterpool);
svn_xml_make_close_tag(&sb, iterpool, "target");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
}
if (iterpool == NULL)
iterpool = svn_pool_create(iterpool);
sorted_props = svn_sort__hash(props, svn_sort_compare_items_as_paths, pool);
for (i = 0; i < sorted_props->nelts; i++)
{
svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
const char *filename = item.key;
svn_string_t *propval = item.value;
sb = NULL;
svn_pool_clear(iterpool);
svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
"path", filename, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname, propval, FALSE, iterpool);
svn_xml_make_close_tag(&sb, iterpool, "target");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
if (iterpool)
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
print_single_prop(svn_string_t *propval,
const char *target_abspath_or_url,
const char *abspath_or_URL,
const char *wc_path_prefix,
svn_stream_t *out,
const char *pname_utf8,
svn_boolean_t print_filenames,
svn_boolean_t omit_newline,
svn_boolean_t like_proplist,
svn_boolean_t inherited_property,
apr_pool_t *scratch_pool)
{
if (print_filenames)
{
const char *header;
if (! svn_path_is_url(abspath_or_URL))
abspath_or_URL = svn_cl__local_style_skip_ancestor(wc_path_prefix,
abspath_or_URL,
scratch_pool);
if (inherited_property)
{
if (like_proplist)
{
if (! svn_path_is_url(target_abspath_or_url))
target_abspath_or_url =
svn_cl__local_style_skip_ancestor(wc_path_prefix,
target_abspath_or_url,
scratch_pool);
header = apr_psprintf(
scratch_pool,
_("Inherited properties on '%s',\nfrom '%s':\n"),
target_abspath_or_url, abspath_or_URL);
}
else
{
header = apr_psprintf(scratch_pool, "%s - ", abspath_or_URL);
}
}
else
header = apr_psprintf(scratch_pool, like_proplist
? _("Properties on '%s':\n")
: "%s - ", abspath_or_URL);
SVN_ERR(svn_cmdline_cstring_from_utf8(&header, header, scratch_pool));
SVN_ERR(svn_subst_translate_cstring2(header, &header,
APR_EOL_STR,
FALSE,
NULL,
FALSE,
scratch_pool));
SVN_ERR(stream_write(out, header, strlen(header)));
}
if (like_proplist)
{
apr_hash_t *hash = apr_hash_make(scratch_pool);
svn_hash_sets(hash, pname_utf8, propval);
SVN_ERR(svn_cmdline__print_prop_hash(out, hash, FALSE, scratch_pool));
}
else
{
if (svn_prop_needs_translation(pname_utf8))
SVN_ERR(svn_subst_detranslate_string(&propval, propval,
TRUE, scratch_pool));
SVN_ERR(stream_write(out, propval->data, propval->len));
if (! omit_newline)
SVN_ERR(stream_write(out, APR_EOL_STR,
strlen(APR_EOL_STR)));
}
return SVN_NO_ERROR;
}
static svn_error_t *
print_properties(svn_stream_t *out,
const char *target_abspath_or_url,
const char *pname_utf8,
apr_hash_t *props,
apr_array_header_t *inherited_props,
svn_boolean_t print_filenames,
svn_boolean_t omit_newline,
svn_boolean_t like_proplist,
apr_pool_t *pool)
{
apr_array_header_t *sorted_props;
int i;
apr_pool_t *iterpool = svn_pool_create(pool);
const char *path_prefix;
SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
if (inherited_props)
{
svn_pool_clear(iterpool);
for (i = 0; i < inherited_props->nelts; i++)
{
svn_prop_inherited_item_t *iprop =
APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
svn_string_t *propval = apr_hash_this_val(apr_hash_first(pool,
iprop->prop_hash));
SVN_ERR(print_single_prop(propval, target_abspath_or_url,
iprop->path_or_url,
path_prefix, out, pname_utf8,
print_filenames, omit_newline,
like_proplist, TRUE, iterpool));
}
}
sorted_props = svn_sort__hash(props, svn_sort_compare_items_as_paths, pool);
for (i = 0; i < sorted_props->nelts; i++)
{
svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
const char *filename = item.key;
svn_string_t *propval = item.value;
svn_pool_clear(iterpool);
SVN_ERR(print_single_prop(propval, target_abspath_or_url, filename,
path_prefix, out, pname_utf8, print_filenames,
omit_newline, like_proplist, FALSE,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_cl__propget(apr_getopt_t *os,
void *baton,
apr_pool_t *pool)
{
svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
const char *pname, *pname_utf8;
apr_array_header_t *args, *targets;
svn_stream_t *out;
svn_boolean_t warned = FALSE;
if (opt_state->verbose && (opt_state->revprop || opt_state->no_newline
|| opt_state->xml))
return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
_("--verbose cannot be used with --revprop or "
"--no-newline or --xml"));
SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool));
pname = APR_ARRAY_IDX(args, 0, const char *);
SVN_ERR(svn_utf_cstring_to_utf8(&pname_utf8, pname, pool));
if (! svn_prop_name_is_valid(pname_utf8))
return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("'%s' is not a valid Subversion property name"),
pname_utf8);
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
ctx, FALSE, pool));
svn_opt_push_implicit_dot_target(targets, pool);
SVN_ERR(svn_stream_for_stdout(&out, pool));
if (opt_state->revprop)
{
svn_revnum_t rev;
const char *URL;
svn_string_t *propval;
if (opt_state->show_inherited_props)
return svn_error_create(
SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("--show-inherited-props can't be used with --revprop"));
SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
&URL, ctx, pool));
SVN_ERR(svn_client_revprop_get(pname_utf8, &propval,
URL, &(opt_state->start_revision),
&rev, ctx, pool));
if (propval == NULL)
{
return svn_error_createf(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
_("Property '%s' not found on "
"revision %s"),
pname_utf8,
svn_opt__revision_to_string(
&opt_state->start_revision,
pool));
}
else
{
if (opt_state->xml)
{
svn_stringbuf_t *sb = NULL;
char *revstr = apr_psprintf(pool, "%ld", rev);
SVN_ERR(svn_cl__xml_print_header("properties", pool));
svn_xml_make_open_tag(&sb, pool, svn_xml_normal,
"revprops",
"rev", revstr, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname_utf8, propval, FALSE,
pool);
svn_xml_make_close_tag(&sb, pool, "revprops");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
SVN_ERR(svn_cl__xml_print_footer("properties", pool));
}
else
{
svn_string_t *printable_val = propval;
if (svn_prop_needs_translation(pname_utf8))
SVN_ERR(svn_subst_detranslate_string(&printable_val, propval,
TRUE, pool));
SVN_ERR(stream_write(out, printable_val->data,
printable_val->len));
if (! opt_state->no_newline)
SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR)));
}
}
}
else
{
apr_pool_t *subpool = svn_pool_create(pool);
int i;
if (opt_state->xml)
SVN_ERR(svn_cl__xml_print_header("properties", subpool));
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_empty;
if (opt_state->no_newline
&& ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty)
|| (opt_state->show_inherited_props)))
return svn_error_create
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("--no-newline is only available for single-target,"
" non-recursive propget operations"));
for (i = 0; i < targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(targets, i, const char *);
apr_hash_t *props;
svn_boolean_t print_filenames;
svn_boolean_t omit_newline;
svn_boolean_t like_proplist;
const char *truepath;
svn_opt_revision_t peg_revision;
apr_array_header_t *inherited_props;
svn_pool_clear(subpool);
SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
subpool));
if (!svn_path_is_url(truepath))
SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
SVN_ERR(svn_client_propget5(
&props,
opt_state->show_inherited_props ? &inherited_props : NULL,
pname_utf8, truepath,
&peg_revision,
&(opt_state->start_revision),
NULL, opt_state->depth,
opt_state->changelists, ctx, subpool,
subpool));
print_filenames = ((opt_state->depth > svn_depth_empty
|| targets->nelts > 1
|| apr_hash_count(props) > 1
|| opt_state->verbose
|| opt_state->show_inherited_props)
&& (! opt_state->no_newline));
omit_newline = opt_state->no_newline;
like_proplist = opt_state->verbose && !opt_state->no_newline;
if (opt_state->depth == svn_depth_empty
&& !opt_state->show_inherited_props
&& apr_hash_count(props) == 0)
{
svn_error_t *err;
err = svn_error_createf(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
_("Property '%s' not found on '%s'"),
pname_utf8, target);
svn_handle_warning2(stderr, err, "svn: ");
svn_error_clear(err);
warned = TRUE;
}
if (opt_state->xml)
SVN_ERR(print_properties_xml(
pname_utf8, props,
opt_state->show_inherited_props ? inherited_props : NULL,
subpool));
else
SVN_ERR(print_properties(
out, truepath, pname_utf8,
props,
opt_state->show_inherited_props ? inherited_props : NULL,
print_filenames,
omit_newline, like_proplist, subpool));
}
if (opt_state->xml)
SVN_ERR(svn_cl__xml_print_footer("properties", subpool));
svn_pool_destroy(subpool);
}
if (warned)
return svn_error_create(SVN_ERR_BASE, NULL, NULL);
return SVN_NO_ERROR;
}