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));