You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/01/27 17:18:37 UTC
svn commit: r1727113 - in /subversion/trunk/subversion: include/svn_client.h
libsvn_client/resolved.c svn/conflict-callbacks.c
Author: stsp
Date: Wed Jan 27 16:18:37 2016
New Revision: 1727113
URL: http://svn.apache.org/viewvc?rev=1727113&view=rev
Log:
Add new APIs which provide descriptions of conflicts, and use them in 'svn'.
No functional change.
* subversion/include/svn_client.h
(svn_client_conflict_prop_get_description,
svn_client_conflict_tree_get_description): Declare.
* subversion/libsvn_client/resolved.c
(svn_client_conflict_prop_get_description,
svn_client_conflict_tree_get_description): Implement. For now, return the
same results as svn_cl__get_human_readable_prop_conflict_description() and
svn_cl__get_human_readable_tree_conflict_description(). In the future these
functions may return enhanced descriptions based on additional information
which is not yet available.
(map_conflict_action, map_conflict_reason, local_reason_str,
incoming_action_str, operation_str): New helpers, from svn/cl-conflicts.c.
* subversion/svn/conflict-callbacks.c
(handle_prop_conflict, handle_tree_conflict): Use new APIs.
Modified:
subversion/trunk/subversion/include/svn_client.h
subversion/trunk/subversion/libsvn_client/resolved.c
subversion/trunk/subversion/svn/conflict-callbacks.c
Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1727113&r1=1727112&r2=1727113&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Wed Jan 27 16:18:37 2016
@@ -4470,6 +4470,40 @@ svn_client_conflict_get_conflicted(svn_b
apr_pool_t *scratch_pool);
/**
+ * Return a textual human-readable description of the property conflict
+ * described by @a conflict, allocated in @a result_pool. The description
+ * is encoded in UTF-8 and may contain multiple lines separated by
+ * @c APR_EOL_STR. The last line is not terminated by a newline.
+ *
+ * Additionally, the description may be localized to the language used
+ * by the current locale.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_prop_get_description(const char **description,
+ svn_client_conflict_t *conflict,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return a textual human-readable description of the tree conflict
+ * described by @a conflict, allocated in @a result_pool. The description
+ * is encoded in UTF-8 and may contain multiple lines separated by
+ * @c APR_EOL_STR. The last line is not terminated by a newline.
+ *
+ * Additionally, the description may be localized to the language used
+ * by the current locale.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_tree_get_description(const char **description,
+ svn_client_conflict_t *conflict,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
* Set @a *options to an array of pointers to svn_client_conflict_option_t
* objects applicable to text conflicts described by @a conflict.
*
Modified: subversion/trunk/subversion/libsvn_client/resolved.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/resolved.c?rev=1727113&r1=1727112&r2=1727113&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/resolved.c (original)
+++ subversion/trunk/subversion/libsvn_client/resolved.c Wed Jan 27 16:18:37 2016
@@ -38,6 +38,7 @@
#include "svn_sorts.h"
#include "client.h"
#include "private/svn_sorts_private.h"
+#include "private/svn_token.h"
#include "private/svn_wc_private.h"
#include "svn_private_config.h"
@@ -347,6 +348,321 @@ svn_client_conflict_from_wc_description2
result_pool, scratch_pool));
}
+/* A map for svn_wc_conflict_action_t values to strings */
+static const svn_token_map_t map_conflict_action[] =
+{
+ { "edit", svn_wc_conflict_action_edit },
+ { "delete", svn_wc_conflict_action_delete },
+ { "add", svn_wc_conflict_action_add },
+ { "replace", svn_wc_conflict_action_replace },
+ { NULL, 0 }
+};
+
+/* A map for svn_wc_conflict_reason_t values to strings */
+static const svn_token_map_t map_conflict_reason[] =
+{
+ { "edit", svn_wc_conflict_reason_edited },
+ { "delete", svn_wc_conflict_reason_deleted },
+ { "missing", svn_wc_conflict_reason_missing },
+ { "obstruction", svn_wc_conflict_reason_obstructed },
+ { "add", svn_wc_conflict_reason_added },
+ { "replace", svn_wc_conflict_reason_replaced },
+ { "unversioned", svn_wc_conflict_reason_unversioned },
+ { "moved-away", svn_wc_conflict_reason_moved_away },
+ { "moved-here", svn_wc_conflict_reason_moved_here },
+ { NULL, 0 }
+};
+
+/* Return a localised string representation of the local part of a conflict;
+ NULL for non-localised odd cases. */
+static const char *
+local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason,
+ svn_wc_operation_t operation)
+{
+ switch (kind)
+ {
+ case svn_node_file:
+ case svn_node_symlink:
+ switch (reason)
+ {
+ case svn_wc_conflict_reason_edited:
+ return _("local file edit");
+ case svn_wc_conflict_reason_obstructed:
+ return _("local file obstruction");
+ case svn_wc_conflict_reason_deleted:
+ return _("local file delete");
+ case svn_wc_conflict_reason_missing:
+ if (operation == svn_wc_operation_merge)
+ return _("local file missing or deleted or moved away");
+ else
+ return _("local file missing");
+ case svn_wc_conflict_reason_unversioned:
+ return _("local file unversioned");
+ case svn_wc_conflict_reason_added:
+ return _("local file add");
+ case svn_wc_conflict_reason_replaced:
+ return _("local file replace");
+ case svn_wc_conflict_reason_moved_away:
+ return _("local file moved away");
+ case svn_wc_conflict_reason_moved_here:
+ return _("local file moved here");
+ }
+ break;
+ case svn_node_dir:
+ switch (reason)
+ {
+ case svn_wc_conflict_reason_edited:
+ return _("local dir edit");
+ case svn_wc_conflict_reason_obstructed:
+ return _("local dir obstruction");
+ case svn_wc_conflict_reason_deleted:
+ return _("local dir delete");
+ case svn_wc_conflict_reason_missing:
+ if (operation == svn_wc_operation_merge)
+ return _("local dir missing or deleted or moved away");
+ else
+ return _("local dir missing");
+ case svn_wc_conflict_reason_unversioned:
+ return _("local dir unversioned");
+ case svn_wc_conflict_reason_added:
+ return _("local dir add");
+ case svn_wc_conflict_reason_replaced:
+ return _("local dir replace");
+ case svn_wc_conflict_reason_moved_away:
+ return _("local dir moved away");
+ case svn_wc_conflict_reason_moved_here:
+ return _("local dir moved here");
+ }
+ break;
+ case svn_node_none:
+ case svn_node_unknown:
+ switch (reason)
+ {
+ case svn_wc_conflict_reason_edited:
+ return _("local edit");
+ case svn_wc_conflict_reason_obstructed:
+ return _("local obstruction");
+ case svn_wc_conflict_reason_deleted:
+ return _("local delete");
+ case svn_wc_conflict_reason_missing:
+ if (operation == svn_wc_operation_merge)
+ return _("local missing or deleted or moved away");
+ else
+ return _("local missing");
+ case svn_wc_conflict_reason_unversioned:
+ return _("local unversioned");
+ case svn_wc_conflict_reason_added:
+ return _("local add");
+ case svn_wc_conflict_reason_replaced:
+ return _("local replace");
+ case svn_wc_conflict_reason_moved_away:
+ return _("local moved away");
+ case svn_wc_conflict_reason_moved_here:
+ return _("local moved here");
+ }
+ break;
+ }
+ return NULL;
+}
+
+/* Return a localised string representation of the incoming part of a
+ conflict; NULL for non-localised odd cases. */
+static const char *
+incoming_action_str(svn_node_kind_t kind, svn_wc_conflict_action_t action)
+{
+ switch (kind)
+ {
+ case svn_node_file:
+ case svn_node_symlink:
+ switch (action)
+ {
+ case svn_wc_conflict_action_edit:
+ return _("incoming file edit");
+ case svn_wc_conflict_action_add:
+ return _("incoming file add");
+ case svn_wc_conflict_action_delete:
+ return _("incoming file delete or move");
+ case svn_wc_conflict_action_replace:
+ return _("incoming replace with file");
+ }
+ break;
+ case svn_node_dir:
+ switch (action)
+ {
+ case svn_wc_conflict_action_edit:
+ return _("incoming dir edit");
+ case svn_wc_conflict_action_add:
+ return _("incoming dir add");
+ case svn_wc_conflict_action_delete:
+ return _("incoming dir delete or move");
+ case svn_wc_conflict_action_replace:
+ return _("incoming replace with dir");
+ }
+ break;
+ case svn_node_none:
+ case svn_node_unknown:
+ switch (action)
+ {
+ case svn_wc_conflict_action_edit:
+ return _("incoming edit");
+ case svn_wc_conflict_action_add:
+ return _("incoming add");
+ case svn_wc_conflict_action_delete:
+ return _("incoming delete or move");
+ case svn_wc_conflict_action_replace:
+ return _("incoming replace");
+ }
+ break;
+ }
+ return NULL;
+}
+
+/* Return a localised string representation of the operation part of a
+ conflict. */
+static const char *
+operation_str(svn_wc_operation_t operation)
+{
+ switch (operation)
+ {
+ case svn_wc_operation_update: return _("upon update");
+ case svn_wc_operation_switch: return _("upon switch");
+ case svn_wc_operation_merge: return _("upon merge");
+ case svn_wc_operation_none: return _("upon none");
+ }
+ SVN_ERR_MALFUNCTION_NO_RETURN();
+ return NULL;
+}
+
+svn_error_t *
+svn_client_conflict_prop_get_description(const char **description,
+ svn_client_conflict_t *conflict,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *reason_str, *action_str;
+
+ /* We provide separately translatable strings for the values that we
+ * know about, and a fall-back in case any other values occur. */
+ switch (svn_client_conflict_get_local_change(conflict))
+ {
+ case svn_wc_conflict_reason_edited:
+ reason_str = _("local edit");
+ break;
+ case svn_wc_conflict_reason_added:
+ reason_str = _("local add");
+ break;
+ case svn_wc_conflict_reason_deleted:
+ reason_str = _("local delete");
+ break;
+ case svn_wc_conflict_reason_obstructed:
+ reason_str = _("local obstruction");
+ break;
+ default:
+ reason_str = apr_psprintf(
+ scratch_pool, _("local %s"),
+ svn_token__to_word(
+ map_conflict_reason,
+ svn_client_conflict_get_local_change(conflict)));
+ break;
+ }
+ switch (svn_client_conflict_get_incoming_change(conflict))
+ {
+ case svn_wc_conflict_action_edit:
+ action_str = _("incoming edit");
+ break;
+ case svn_wc_conflict_action_add:
+ action_str = _("incoming add");
+ break;
+ case svn_wc_conflict_action_delete:
+ action_str = _("incoming delete");
+ break;
+ default:
+ action_str = apr_psprintf(
+ scratch_pool, _("incoming %s"),
+ svn_token__to_word(
+ map_conflict_action,
+ svn_client_conflict_get_incoming_change(conflict)));
+ break;
+ }
+ SVN_ERR_ASSERT(reason_str && action_str);
+
+ *description = apr_psprintf(result_pool, _("%s, %s %s"),
+ reason_str, action_str,
+ operation_str(
+ svn_client_conflict_get_operation(conflict)));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_tree_get_description(const char **description,
+ svn_client_conflict_t *conflict,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *action, *reason, *operation;
+ svn_node_kind_t incoming_kind;
+ svn_wc_conflict_action_t conflict_action;
+ svn_wc_conflict_reason_t conflict_reason;
+ svn_wc_operation_t conflict_operation;
+ svn_node_kind_t conflict_node_kind;
+
+ conflict_action = svn_client_conflict_get_incoming_change(conflict);
+ conflict_reason = svn_client_conflict_get_local_change(conflict);
+ conflict_operation = svn_client_conflict_get_operation(conflict);
+ conflict_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict);
+
+ /* Determine the node kind of the incoming change. */
+ incoming_kind = svn_node_unknown;
+ if (conflict_action == svn_wc_conflict_action_edit ||
+ conflict_action == svn_wc_conflict_action_delete)
+ {
+ /* Change is acting on 'src_left' version of the node. */
+ SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(
+ NULL, NULL, &incoming_kind, conflict, scratch_pool,
+ scratch_pool));
+ }
+ else if (conflict_action == svn_wc_conflict_action_add ||
+ conflict_action == svn_wc_conflict_action_replace)
+ {
+ /* Change is acting on 'src_right' version of the node.
+ *
+ * ### For 'replace', the node kind is ambiguous. However, src_left
+ * ### is NULL for replace, so we must use src_right. */
+ SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(
+ NULL, NULL, &incoming_kind, conflict, scratch_pool,
+ scratch_pool));
+ }
+
+ reason = local_reason_str(conflict_node_kind, conflict_reason,
+ conflict_operation);
+ action = incoming_action_str(incoming_kind, conflict_action);
+ operation = operation_str(conflict_operation);
+ SVN_ERR_ASSERT(operation);
+
+ if (action && reason)
+ {
+ *description = apr_psprintf(result_pool, _("%s, %s %s"),
+ reason, action, operation);
+ }
+ else
+ {
+ /* A catch-all message for very rare or nominally impossible cases.
+ It will not be pretty, but is closer to an internal error than
+ an ordinary user-facing string. */
+ *description = apr_psprintf(result_pool,
+ _("local: %s %s incoming: %s %s %s"),
+ svn_node_kind_to_word(conflict_node_kind),
+ svn_token__to_word(map_conflict_reason,
+ conflict_reason),
+ svn_node_kind_to_word(incoming_kind),
+ svn_token__to_word(map_conflict_action,
+ conflict_action),
+ operation);
+ }
+ return SVN_NO_ERROR;
+}
+
void
svn_client_conflict_option_set_merged_propval(
svn_client_conflict_option_t *option,
Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1727113&r1=1727112&r2=1727113&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Wed Jan 27 16:18:37 2016
@@ -1080,7 +1080,7 @@ handle_prop_conflict(svn_client_conflict
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
- const char *message;
+ const char *description;
const svn_string_t *merged_propval = NULL;
svn_boolean_t resolved_allowed = FALSE;
const svn_string_t *base_propval;
@@ -1100,11 +1100,9 @@ handle_prop_conflict(svn_client_conflict
path_prefix,
svn_client_conflict_get_local_abspath(conflict),
scratch_pool)));
-
- SVN_ERR(svn_cl__get_human_readable_prop_conflict_description(&message,
- conflict,
- scratch_pool));
- SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", message));
+ SVN_ERR(svn_client_conflict_prop_get_description(&description, conflict,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", description));
SVN_ERR(svn_client_conflict_prop_get_resolution_options(&default_options,
conflict,
@@ -1195,7 +1193,7 @@ handle_tree_conflict(svn_client_conflict
svn_cmdline_prompt_baton_t *pb,
apr_pool_t *scratch_pool)
{
- const char *readable_desc;
+ const char *description;
const char *src_left_version;
const char *src_right_version;
const char *repos_root_url;
@@ -1205,14 +1203,14 @@ handle_tree_conflict(svn_client_conflict
apr_array_header_t *default_options;
apr_pool_t *iterpool;
- SVN_ERR(svn_cl__get_human_readable_tree_conflict_description(
- &readable_desc, conflict, scratch_pool));
+ SVN_ERR(svn_client_conflict_tree_get_description(
+ &description, conflict, scratch_pool, scratch_pool));
SVN_ERR(svn_cmdline_fprintf(
stderr, scratch_pool,
_("Tree conflict on '%s'\n > %s\n"),
svn_cl__local_style_skip_ancestor(path_prefix,
svn_client_conflict_get_local_abspath(conflict), scratch_pool),
- readable_desc));
+ description));
SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict,
scratch_pool, scratch_pool));