summaryrefslogtreecommitdiffstats
path: root/subversion/svn/cl-conflicts.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svn/cl-conflicts.c')
-rw-r--r--subversion/svn/cl-conflicts.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/subversion/svn/cl-conflicts.c b/subversion/svn/cl-conflicts.c
new file mode 100644
index 0000000..440c9d7
--- /dev/null
+++ b/subversion/svn/cl-conflicts.c
@@ -0,0 +1,454 @@
+/*
+ * conflicts.c: Tree conflicts.
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include "cl-conflicts.h"
+#include "svn_hash.h"
+#include "svn_xml.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "private/svn_token.h"
+
+#include "cl.h"
+
+#include "svn_private_config.h"
+
+
+/* A map for svn_wc_conflict_action_t values to XML strings */
+static const svn_token_map_t map_conflict_action_xml[] =
+{
+ { "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 XML strings */
+static const svn_token_map_t map_conflict_reason_xml[] =
+{
+ { "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 }
+};
+
+static const svn_token_map_t map_conflict_kind_xml[] =
+{
+ { "text", svn_wc_conflict_kind_text },
+ { "property", svn_wc_conflict_kind_property },
+ { "tree", svn_wc_conflict_kind_tree },
+ { 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)
+{
+ switch (kind)
+ {
+ case svn_node_file:
+ 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:
+ 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:
+ 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_symlink:
+ case svn_node_none:
+ case svn_node_unknown:
+ 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:
+ 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");
+ case svn_wc_conflict_action_replace:
+ return _("incoming file replace");
+ }
+ 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");
+ case svn_wc_conflict_action_replace:
+ return _("incoming dir replace");
+ }
+ break;
+ case svn_node_symlink:
+ case svn_node_none:
+ case svn_node_unknown:
+ 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_cl__get_human_readable_prop_conflict_description(
+ const char **desc,
+ const svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *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 (conflict->reason)
+ {
+ 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(pool, _("local %s"),
+ svn_token__to_word(map_conflict_reason_xml,
+ conflict->reason));
+ break;
+ }
+ switch (conflict->action)
+ {
+ 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(pool, _("incoming %s"),
+ svn_token__to_word(map_conflict_action_xml,
+ conflict->action));
+ break;
+ }
+ SVN_ERR_ASSERT(reason_str && action_str);
+ *desc = apr_psprintf(pool, _("%s, %s %s"),
+ reason_str, action_str,
+ operation_str(conflict->operation));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_cl__get_human_readable_tree_conflict_description(
+ const char **desc,
+ const svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *pool)
+{
+ const char *action, *reason, *operation;
+ svn_node_kind_t incoming_kind;
+
+ /* 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. */
+ if (conflict->src_left_version)
+ incoming_kind = conflict->src_left_version->node_kind;
+ }
+ 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. */
+ if (conflict->src_right_version)
+ incoming_kind = conflict->src_right_version->node_kind;
+ }
+
+ reason = local_reason_str(conflict->node_kind, conflict->reason);
+ action = incoming_action_str(incoming_kind, conflict->action);
+ operation = operation_str(conflict->operation);
+ SVN_ERR_ASSERT(operation);
+
+ if (action && reason)
+ {
+ *desc = apr_psprintf(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. */
+ *desc = apr_psprintf(pool, _("local: %s %s incoming: %s %s %s"),
+ svn_node_kind_to_word(conflict->node_kind),
+ svn_token__to_word(map_conflict_reason_xml,
+ conflict->reason),
+ svn_node_kind_to_word(incoming_kind),
+ svn_token__to_word(map_conflict_action_xml,
+ conflict->action),
+ operation);
+ }
+ return SVN_NO_ERROR;
+}
+
+
+/* Helper for svn_cl__append_tree_conflict_info_xml().
+ * Appends the attributes of the given VERSION to ATT_HASH.
+ * SIDE is the content of the version tag's side="..." attribute,
+ * currently one of "source-left" or "source-right".*/
+static svn_error_t *
+add_conflict_version_xml(svn_stringbuf_t **pstr,
+ const char *side,
+ const svn_wc_conflict_version_t *version,
+ apr_pool_t *pool)
+{
+ apr_hash_t *att_hash = apr_hash_make(pool);
+
+
+ svn_hash_sets(att_hash, "side", side);
+
+ if (version->repos_url)
+ svn_hash_sets(att_hash, "repos-url", version->repos_url);
+
+ if (version->path_in_repos)
+ svn_hash_sets(att_hash, "path-in-repos", version->path_in_repos);
+
+ if (SVN_IS_VALID_REVNUM(version->peg_rev))
+ svn_hash_sets(att_hash, "revision", apr_ltoa(pool, version->peg_rev));
+
+ if (version->node_kind != svn_node_unknown)
+ svn_hash_sets(att_hash, "kind",
+ svn_cl__node_kind_str_xml(version->node_kind));
+
+ svn_xml_make_open_tag_hash(pstr, pool, svn_xml_self_closing,
+ "version", att_hash);
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+append_tree_conflict_info_xml(svn_stringbuf_t *str,
+ const svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *pool)
+{
+ apr_hash_t *att_hash = apr_hash_make(pool);
+ const char *tmp;
+
+ svn_hash_sets(att_hash, "victim",
+ svn_dirent_basename(conflict->local_abspath, pool));
+
+ svn_hash_sets(att_hash, "kind",
+ svn_cl__node_kind_str_xml(conflict->node_kind));
+
+ svn_hash_sets(att_hash, "operation",
+ svn_cl__operation_str_xml(conflict->operation, pool));
+
+ tmp = svn_token__to_word(map_conflict_action_xml, conflict->action);
+ svn_hash_sets(att_hash, "action", tmp);
+
+ tmp = svn_token__to_word(map_conflict_reason_xml, conflict->reason);
+ svn_hash_sets(att_hash, "reason", tmp);
+
+ /* Open the tree-conflict tag. */
+ svn_xml_make_open_tag_hash(&str, pool, svn_xml_normal,
+ "tree-conflict", att_hash);
+
+ /* Add child tags for OLDER_VERSION and THEIR_VERSION. */
+
+ if (conflict->src_left_version)
+ SVN_ERR(add_conflict_version_xml(&str,
+ "source-left",
+ conflict->src_left_version,
+ pool));
+
+ if (conflict->src_right_version)
+ SVN_ERR(add_conflict_version_xml(&str,
+ "source-right",
+ conflict->src_right_version,
+ pool));
+
+ svn_xml_make_close_tag(&str, pool, "tree-conflict");
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_cl__append_conflict_info_xml(svn_stringbuf_t *str,
+ const svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *att_hash;
+ const char *kind;
+ if (conflict->kind == svn_wc_conflict_kind_tree)
+ {
+ /* Uses other element type */
+ return svn_error_trace(
+ append_tree_conflict_info_xml(str, conflict, scratch_pool));
+ }
+
+ att_hash = apr_hash_make(scratch_pool);
+
+ svn_hash_sets(att_hash, "operation",
+ svn_cl__operation_str_xml(conflict->operation, scratch_pool));
+
+
+ kind = svn_token__to_word(map_conflict_kind_xml, conflict->kind);
+ svn_hash_sets(att_hash, "type", kind);
+
+ svn_hash_sets(att_hash, "operation",
+ svn_cl__operation_str_xml(conflict->operation, scratch_pool));
+
+
+ /* "<conflict>" */
+ svn_xml_make_open_tag_hash(&str, scratch_pool,
+ svn_xml_normal, "conflict", att_hash);
+
+ if (conflict->src_left_version)
+ SVN_ERR(add_conflict_version_xml(&str,
+ "source-left",
+ conflict->src_left_version,
+ scratch_pool));
+
+ if (conflict->src_right_version)
+ SVN_ERR(add_conflict_version_xml(&str,
+ "source-right",
+ conflict->src_right_version,
+ scratch_pool));
+
+ switch (conflict->kind)
+ {
+ case svn_wc_conflict_kind_text:
+ /* "<prev-base-file> xx </prev-base-file>" */
+ svn_cl__xml_tagged_cdata(&str, scratch_pool, "prev-base-file",
+ conflict->base_abspath);
+
+ /* "<prev-wc-file> xx </prev-wc-file>" */
+ svn_cl__xml_tagged_cdata(&str, scratch_pool, "prev-wc-file",
+ conflict->my_abspath);
+
+ /* "<cur-base-file> xx </cur-base-file>" */
+ svn_cl__xml_tagged_cdata(&str, scratch_pool, "cur-base-file",
+ conflict->their_abspath);
+
+ break;
+
+ case svn_wc_conflict_kind_property:
+ /* "<prop-file> xx </prop-file>" */
+ svn_cl__xml_tagged_cdata(&str, scratch_pool, "prop-file",
+ conflict->their_abspath);
+ break;
+
+ default:
+ case svn_wc_conflict_kind_tree:
+ SVN_ERR_MALFUNCTION(); /* Handled separately */
+ break;
+ }
+
+ /* "</conflict>" */
+ svn_xml_make_close_tag(&str, scratch_pool, "conflict");
+
+ return SVN_NO_ERROR;
+}
OpenPOWER on IntegriCloud