#include "svn_string.h"
#include "svn_cmdline.h"
#include "svn_wc.h"
#include "svn_pools.h"
#include "svn_error_codes.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_time.h"
#include "svn_xml.h"
#include "cl.h"
#include "svn_private_config.h"
#include "tree-conflicts.h"
static svn_error_t *
svn_cl__info_print_time(apr_time_t atime,
const char *desc,
apr_pool_t *pool)
{
const char *time_utf8;
time_utf8 = svn_time_to_human_cstring(atime, pool);
return svn_cmdline_printf(pool, "%s: %s\n", desc, time_utf8);
}
static const char *
schedule_str(svn_wc_schedule_t schedule)
{
switch (schedule)
{
case svn_wc_schedule_normal:
return "normal";
case svn_wc_schedule_add:
return "add";
case svn_wc_schedule_delete:
return "delete";
case svn_wc_schedule_replace:
return "replace";
default:
return "none";
}
}
static svn_error_t *
print_info_xml(void *baton,
const char *target,
const svn_client_info2_t *info,
apr_pool_t *pool)
{
svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
const char *rev_str;
const char *path_prefix = baton;
if (SVN_IS_VALID_REVNUM(info->rev))
rev_str = apr_psprintf(pool, "%ld", info->rev);
else
rev_str = apr_pstrdup(pool, _("Resource is not under version control."));
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"path", svn_cl__local_style_skip_ancestor(
path_prefix, target, pool),
"kind", svn_cl__node_kind_str_xml(info->kind),
"revision", rev_str,
NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "url", info->URL);
if (info->repos_root_URL || info->repos_UUID)
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repository", NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "root", info->repos_root_URL);
svn_cl__xml_tagged_cdata(&sb, pool, "uuid", info->repos_UUID);
svn_xml_make_close_tag(&sb, pool, "repository");
}
if (info->wc_info)
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info", NULL);
if (info->wc_info->wcroot_abspath)
svn_cl__xml_tagged_cdata(&sb, pool, "wcroot-abspath",
info->wc_info->wcroot_abspath);
svn_cl__xml_tagged_cdata(&sb, pool, "schedule",
schedule_str(info->wc_info->schedule));
{
svn_depth_t depth = info->wc_info->depth;
if (depth == svn_depth_unknown && info->kind == svn_node_file)
depth = svn_depth_infinity;
svn_cl__xml_tagged_cdata(&sb, pool, "depth", svn_depth_to_word(depth));
}
svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-url",
info->wc_info->copyfrom_url);
if (SVN_IS_VALID_REVNUM(info->wc_info->copyfrom_rev))
svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-rev",
apr_psprintf(pool, "%ld",
info->wc_info->copyfrom_rev));
if (info->wc_info->recorded_time)
svn_cl__xml_tagged_cdata(&sb, pool, "text-updated",
svn_time_to_cstring(
info->wc_info->recorded_time,
pool));
svn_cl__xml_tagged_cdata(&sb, pool, "checksum",
svn_checksum_to_cstring(info->wc_info->checksum,
pool));
if (info->wc_info->changelist)
svn_cl__xml_tagged_cdata(&sb, pool, "changelist",
info->wc_info->changelist);
svn_xml_make_close_tag(&sb, pool, "wc-info");
}
if (info->last_changed_author
|| SVN_IS_VALID_REVNUM(info->last_changed_rev)
|| info->last_changed_date)
{
svn_cl__print_xml_commit(&sb, info->last_changed_rev,
info->last_changed_author,
svn_time_to_cstring(info->last_changed_date,
pool),
pool);
}
if (info->wc_info && info->wc_info->conflicts)
{
int i;
for (i = 0; i < info->wc_info->conflicts->nelts; i++)
{
const svn_wc_conflict_description2_t *conflict =
APR_ARRAY_IDX(info->wc_info->conflicts, i,
const svn_wc_conflict_description2_t *);
switch (conflict->kind)
{
case svn_wc_conflict_kind_text:
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "conflict",
NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "prev-base-file",
conflict->base_abspath);
svn_cl__xml_tagged_cdata(&sb, pool, "prev-wc-file",
conflict->my_abspath);
svn_cl__xml_tagged_cdata(&sb, pool, "cur-base-file",
conflict->their_abspath);
svn_xml_make_close_tag(&sb, pool, "conflict");
break;
case svn_wc_conflict_kind_property:
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "conflict",
NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "prop-file",
conflict->their_abspath);
svn_xml_make_close_tag(&sb, pool, "conflict");
break;
case svn_wc_conflict_kind_tree:
SVN_ERR(svn_cl__append_tree_conflict_info_xml(sb, conflict,
pool));
break;
}
}
}
if (info->lock)
svn_cl__print_xml_lock(&sb, info->lock, pool);
svn_xml_make_close_tag(&sb, pool, "entry");
return svn_cl__error_checked_fputs(sb->data, stdout);
}
static svn_error_t *
print_info(void *baton,
const char *target,
const svn_client_info2_t *info,
apr_pool_t *pool)
{
const char *path_prefix = baton;
SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"),
svn_cl__local_style_skip_ancestor(
path_prefix, target, pool)));
if (info->kind != svn_node_dir)
SVN_ERR(svn_cmdline_printf(pool, _("Name: %s\n"),
svn_dirent_basename(target, pool)));
if (info->wc_info && info->wc_info->wcroot_abspath)
SVN_ERR(svn_cmdline_printf(pool, _("Working Copy Root Path: %s\n"),
svn_dirent_local_style(
info->wc_info->wcroot_abspath,
pool)));
if (info->URL)
SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL));
if (info->repos_root_URL)
SVN_ERR(svn_cmdline_printf(pool, _("Repository Root: %s\n"),
info->repos_root_URL));
if (info->repos_UUID)
SVN_ERR(svn_cmdline_printf(pool, _("Repository UUID: %s\n"),
info->repos_UUID));
if (SVN_IS_VALID_REVNUM(info->rev))
SVN_ERR(svn_cmdline_printf(pool, _("Revision: %ld\n"), info->rev));
switch (info->kind)
{
case svn_node_file:
SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: file\n")));
break;
case svn_node_dir:
SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: directory\n")));
break;
case svn_node_none:
SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: none\n")));
break;
case svn_node_unknown:
default:
SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: unknown\n")));
break;
}
if (info->wc_info)
{
switch (info->wc_info->schedule)
{
case svn_wc_schedule_normal:
SVN_ERR(svn_cmdline_printf(pool, _("Schedule: normal\n")));
break;
case svn_wc_schedule_add:
SVN_ERR(svn_cmdline_printf(pool, _("Schedule: add\n")));
break;
case svn_wc_schedule_delete:
SVN_ERR(svn_cmdline_printf(pool, _("Schedule: delete\n")));
break;
case svn_wc_schedule_replace:
SVN_ERR(svn_cmdline_printf(pool, _("Schedule: replace\n")));
break;
default:
break;
}
switch (info->wc_info->depth)
{
case svn_depth_unknown:
break;
case svn_depth_empty:
SVN_ERR(svn_cmdline_printf(pool, _("Depth: empty\n")));
break;
case svn_depth_files:
SVN_ERR(svn_cmdline_printf(pool, _("Depth: files\n")));
break;
case svn_depth_immediates:
SVN_ERR(svn_cmdline_printf(pool, _("Depth: immediates\n")));
break;
case svn_depth_exclude:
SVN_ERR(svn_cmdline_printf(pool, _("Depth: exclude\n")));
break;
case svn_depth_infinity:
break;
default:
SVN_ERR(svn_cmdline_printf(pool, _("Depth: INVALID\n")));
}
if (info->wc_info->copyfrom_url)
SVN_ERR(svn_cmdline_printf(pool, _("Copied From URL: %s\n"),
info->wc_info->copyfrom_url));
if (SVN_IS_VALID_REVNUM(info->wc_info->copyfrom_rev))
SVN_ERR(svn_cmdline_printf(pool, _("Copied From Rev: %ld\n"),
info->wc_info->copyfrom_rev));
}
if (info->last_changed_author)
SVN_ERR(svn_cmdline_printf(pool, _("Last Changed Author: %s\n"),
info->last_changed_author));
if (SVN_IS_VALID_REVNUM(info->last_changed_rev))
SVN_ERR(svn_cmdline_printf(pool, _("Last Changed Rev: %ld\n"),
info->last_changed_rev));
if (info->last_changed_date)
SVN_ERR(svn_cl__info_print_time(info->last_changed_date,
_("Last Changed Date"), pool));
if (info->wc_info)
{
if (info->wc_info->recorded_time)
SVN_ERR(svn_cl__info_print_time(info->wc_info->recorded_time,
_("Text Last Updated"), pool));
if (info->wc_info->checksum)
SVN_ERR(svn_cmdline_printf(pool, _("Checksum: %s\n"),
svn_checksum_to_cstring(
info->wc_info->checksum, pool)));
if (info->wc_info->conflicts)
{
int i;
for (i = 0; i < info->wc_info->conflicts->nelts; i++)
{
const svn_wc_conflict_description2_t *conflict =
APR_ARRAY_IDX(info->wc_info->conflicts, i,
const svn_wc_conflict_description2_t *);
const char *desc;
const char *src_left_version;
const char *src_right_version;
switch (conflict->kind)
{
case svn_wc_conflict_kind_text:
if (conflict->base_abspath)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Previous Base File: %s\n"),
svn_cl__local_style_skip_ancestor(
path_prefix, conflict->base_abspath,
pool)));
if (conflict->my_abspath)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Previous Working File: %s\n"),
svn_cl__local_style_skip_ancestor(
path_prefix, conflict->my_abspath,
pool)));
if (conflict->their_abspath)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Current Base File: %s\n"),
svn_cl__local_style_skip_ancestor(
path_prefix, conflict->their_abspath,
pool)));
break;
case svn_wc_conflict_kind_property:
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Properties File: %s\n"),
svn_dirent_local_style(conflict->their_abspath,
pool)));
break;
case svn_wc_conflict_kind_tree:
SVN_ERR(
svn_cl__get_human_readable_tree_conflict_description(
&desc, conflict, pool));
src_left_version =
svn_cl__node_description(conflict->src_left_version,
info->repos_root_URL, pool);
src_right_version =
svn_cl__node_description(conflict->src_right_version,
info->repos_root_URL, pool);
SVN_ERR(svn_cmdline_printf(pool, "%s: %s\n",
_("Tree conflict"), desc));
if (src_left_version)
SVN_ERR(svn_cmdline_printf(pool, " %s: %s\n",
_("Source left"),
src_left_version));
if (src_right_version)
SVN_ERR(svn_cmdline_printf(pool, " %s: %s\n",
_("Source right"),
src_right_version));
break;
}
}
}
}
if (info->lock)
{
if (info->lock->token)
SVN_ERR(svn_cmdline_printf(pool, _("Lock Token: %s\n"),
info->lock->token));
if (info->lock->owner)
SVN_ERR(svn_cmdline_printf(pool, _("Lock Owner: %s\n"),
info->lock->owner));
if (info->lock->creation_date)
SVN_ERR(svn_cl__info_print_time(info->lock->creation_date,
_("Lock Created"), pool));
if (info->lock->expiration_date)
SVN_ERR(svn_cl__info_print_time(info->lock->expiration_date,
_("Lock Expires"), pool));
if (info->lock->comment)
{
int comment_lines;
comment_lines = svn_cstring_count_newlines(info->lock->comment) + 1;
SVN_ERR(svn_cmdline_printf(pool,
Q_("Lock Comment (%i line):\n%s\n",
"Lock Comment (%i lines):\n%s\n",
comment_lines),
comment_lines,
info->lock->comment));
}
}
if (info->wc_info && info->wc_info->changelist)
SVN_ERR(svn_cmdline_printf(pool, _("Changelist: %s\n"),
info->wc_info->changelist));
return svn_cmdline_printf(pool, "\n");
}
svn_error_t *
svn_cl__info(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;
apr_array_header_t *targets = NULL;
apr_pool_t *subpool = svn_pool_create(pool);
int i;
svn_error_t *err;
svn_boolean_t seen_nonexistent_target = FALSE;
svn_opt_revision_t peg_revision;
svn_client_info_receiver2_t receiver;
const char *path_prefix;
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);
if (opt_state->xml)
{
receiver = print_info_xml;
if (! opt_state->incremental)
SVN_ERR(svn_cl__xml_print_header("info", pool));
}
else
{
receiver = print_info;
if (opt_state->incremental)
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("'incremental' option only valid in XML "
"mode"));
}
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_empty;
SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
for (i = 0; i < targets->nelts; i++)
{
const char *truepath;
const char *target = APR_ARRAY_IDX(targets, i, const char *);
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))
{
if (peg_revision.kind == svn_opt_revision_unspecified)
peg_revision.kind = svn_opt_revision_head;
}
else
{
SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
}
err = svn_client_info3(truepath,
&peg_revision, &(opt_state->start_revision),
opt_state->depth, TRUE, TRUE,
opt_state->changelists,
receiver, (void *) path_prefix,
ctx, subpool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
{
svn_handle_warning2(stderr, err, "svn: ");
svn_error_clear(svn_cmdline_fprintf(stderr, subpool, "\n"));
}
else
{
return svn_error_trace(err);
}
svn_error_clear(err);
err = NULL;
seen_nonexistent_target = TRUE;
}
}
svn_pool_destroy(subpool);
if (opt_state->xml && (! opt_state->incremental))
SVN_ERR(svn_cl__xml_print_footer("info", pool));
if (seen_nonexistent_target)
return svn_error_create(
SVN_ERR_ILLEGAL_TARGET, NULL,
_("Could not display info for all targets because some "
"targets don't exist"));
else
return SVN_NO_ERROR;
}