[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[RFC] new svn_client_conflict API

From: Stefan Sperling <stsp_at_elego.de>
Date: Fri, 29 May 2015 13:16:02 +0200

I would like to start transitioning away from svn_wc_conflict_description2_t
in public APIs and introduce a higher-level API to eventually replace it.

My end goal is to use an opaque type with methods that make it possible
to implement conflict resolution in a way that is easier to use.
For example, the way tree conflict are currently presented to the user is
universally poor across all SVN clients and very poor in our command line
client in particular.

Another sore point is property conflicts. There's still no way in our API
to resolve individual property conflicts on the node, even though the
underlying WC storage can support this.

As a first step, I'd like to introduce new APIs that still use
svn_wc_conflict_description2_t for passing information around but treat it
as if it was an opaque type. This way we can gradually switch the command
line client over to these new APIs without changing existing behaviour.

Once that's done, a new opaque type can be introduced and we can
deprecate svn_wc_conflict_description2_t from the public API.
'svn resolve' would then stop using the conflict callback and instead
call into the client library, actively steering the resolution process.

Below is a sketch of an API I'd like to wrap around the
svn_wc_conflict_description2_t struct.

The API uses terminology that I'd like clients to mirror in their user
interfaces. It breaks with some naming conventions that are misleading
or insufficient to describe complex conflicts (e.g. "yours/mine/theirs").
It also tries to explain things in a way that prevents misunderstandings
of what the information returned by the API really means, so that SVN
client authors can make informed choices about how to present the information.

The intention is to later extend this API to produce detailed data about
tree conflicts and other complex scenarios so that users can make more
informed choices about how to resolve conflicts.
See http://mail-archives.apache.org/mod_mbox/subversion-users/201505.mbox/%3C20150520105235.GE4388%40jim.stsp.name%3E
for an example of what I'd eventually like to see at the conflict prompt.

Any comments on this?
I'm expecting people to point out that all switch functions are duplicates
of the update ones :-) At the API level I'd like to keep them seperate for
clarity even if they map to the same internal implementation.

Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 1682370)
+++ subversion/include/svn_client.h (working copy)
@@ -4356,6 +4356,400 @@ svn_client_revert(const apr_array_header_t *paths,
 /** @} */
 
 /**
+ * @defgroup Conflicts Dealing with conflicted paths.
+ *
+ * @{
+ */
+
+/**
+ * Return conflict information for the working copy node at @a local_abspath.
+ * Allocate @a *conflict @a result_pool.
+ *
+ * Use @a scratch_pool for temporary allocations.
+ *
+ * @since New in 1.10.
+ * ### Should return a new opaque type such as "svn_client_conflict_t"
+ * ### instead of svn_wc_conflict_description2_t. For now, we use the old
+ * ### type to allow for smooth API transition within Subversion, though
+ * ### some internal use of svn_wc_conflict_description2_t may remain.
+ */
+svn_error_t *
+svn_client_conflict_get(svn_wc_conflict_description2_t **conflict,
+ const char *local_abspath,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return conflict information for all conflicted paths at or beneath
+ * @a local_abspath within the specified @a depth.
+ *
+ * @a conflicts will be set to a hash keyed by a local absolute path.
+ * Hash table values are pointers to svn_wc_conflict_description2_t.
+ * Theh hash table and values are allocated in @a result_pool.
+ *
+ * Use @a scratch_pool for temporary allocations.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_get_multiple(apr_hash_t *conflicts,
+ const char *local_abspath,
+ svn_depth_t depth,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the absolute path to the conflicted working copy node described
+ * by @a conflict.
+ *
+ * @since New in 1.10.
+ */
+const char *
+svn_client_conflict_get_local_abspath(svn_wc_conflict_description2_t *conflict);
+
+/**
+ * Return the operation during which the conflict described by @a
+ * conflict was recorded.
+ *
+ * @since New in 1.10.
+ */
+svn_wc_operation_t
+svn_client_conflict_get_operation(svn_wc_conflict_description2_t *conflict);
+
+/**
+ * Return the action an update, switch, or merge operation attempted to
+ * perform on the working copy node described by @a conflict.
+ *
+ * @since New in 1.10.
+ */
+svn_wc_conflict_action_t
+svn_client_conflict_get_incoming_change(
+ svn_wc_conflict_description2_t *conflict);
+
+/**
+ * Return the reason why the attempted action performed by an update, switch,
+ * or merge operation conflicted with the state of the node in the working copy.
+ *
+ * During update and switch operations this local change is part of uncommitted
+ * modifications in the working copy. During merge operations it may
+ * additionally be part of the history of the merge target branch, anywhere
+ * between the common ancestor revision and the working copy revision.
+ *
+ * @since New in 1.10.
+ */
+svn_wc_conflict_reason_t
+svn_client_conflict_get_local_change(svn_wc_conflict_description2_t *conflict);
+
+/**
+ * Indicate the types of conflicts present on the working copy node
+ * described by @a conflict. Any output argument may be @c NULL if
+ * the caller is not interested in the status of a particular type.
+ *
+ * While multiple text and/or property changes may exist, only one
+ * tree conflict can be recorded on a node.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_get_types(svn_boolean_t *has_text_conflicts,
+ svn_boolean_t *has_prop_conflicts,
+ svn_boolean_t *has_tree_conflict,
+ svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the URLs and revisions of repository nodes involved in the
+ * merge operation which recorded @a conflict.
+ *
+ * Note that this does not provide any information about the actual
+ * changes which caused the conflict. These are merely the repository
+ * nodes involved in driving the merge operation. The conflicting changes
+ * are contained somewhere within the set of differences between these nodes
+ * and perhaps also the local modifications of the working copy.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_merge_get_versions(const char **url_source,
+ svn_revnum_t *rev_source,
+ const char **url_target,
+ svn_revnum_t *rev_target,
+ const char **url_common_ancestor,
+ svn_revnum_t *rev_common_ancestor,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+/**
+ * Return the URLs and revisions of repository nodes involved in the
+ * update operation which recorded @a conflict.
+ *
+ * Note that this does not provide any information about the actual
+ * changes which caused the conflict. These are merely the repository
+ * nodes involved in driving the update operation. The conflicting changes
+ * are contained somewhere within the set of differences between these nodes
+ * and the local modifications of the working copy.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_update_get_versions(
+ const char **url_before,
+ svn_revnum_t *rev_before,
+ const char **url_after,
+ svn_revnum_t *rev_after,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the URLs and revisions of repository nodes involved in the
+ * switch operation which recorded @a conflict.
+ *
+ * Note that this does not provide any information about the actual
+ * changes which caused the conflict. These are merely the repository
+ * nodes involved in driving the switch operation. The conflicting changes
+ * are contained somewhere within the set of differences between these nodes
+ * and the local modifications of the working copy.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_switch_get_versions(
+ const char **url_before,
+ svn_revnum_t *rev_before,
+ const char **url_after,
+ svn_revnum_t *rev_after,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+
+/**
+ * Return the kinds of nodes involved in a conflict recorded during
+ * a merge operation.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_merge_get_kinds(svn_node_kind_t **kind_source,
+ svn_node_kind_t **kind_target,
+ svn_node_kind_t **kind_common_ancestor,
+ svn_node_kind_t **kind_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the kinds of nodes involved in a conflict recorded during
+ * an update operation.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_update_get_kinds(svn_node_kind_t **kind_before,
+ svn_node_kind_t **kind_after,
+ svn_node_kind_t **kind_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the kinds of nodes involved in a conflict recorded during
+ * an switch operation.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_switch_get_kinds(svn_node_kind_t **kind_before,
+ svn_node_kind_t **kind_after,
+ svn_node_kind_t **kind_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+/**
+ * If @a conflict describes one or more property conflicts, return an array
+ * of const char * in @a *propnames, allocated in @a result_pool.
+ * If there is no property conflict set @a *propnames to NULL.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_get_propnames(apr_array_header **propnames,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return property values for the conflicted property @propname for which
+ * a conflict was recorded during a merge operation.
+ *
+ * Set @a *val_source to the merge target's property value as seen in the
+ * repository on the merge source branch at the merged-in revision.
+ *
+ * Set @a *val_target to the merge target's property value as seen in
+ * the repository at the merge target's revision. In other words, it is the
+ * value as seen in the merge target working copy's BASE revision and it is
+ * unaffected by any local modifications in the working copy.
+ *
+ * Set @a *val_common_ancestor to the value as seen in the repository at
+ * merge operation's common ancestor path and revision.
+ *
+ * Set @a *val_during to the value as seen in the working copy during the
+ * merge operation, including any local modifications. It may be identical to
+ * @a *val_target if no local modifications were present during the operation.
+ *
+ * These values do not contain conflict markers. A diff between versions can
+ * be generated with svn_diff_mem_string_output_unified3(). A merged version
+ * can be generated using svn_diff_mem_string_output_merge3().
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_merge_get_propvals(const svn_string_t **val_source,
+ const svn_string_t **val_target,
+ const svn_string_t **val_common_ancestor,
+ const svn_string_t **val_during,
+ const char *propname,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return property values for the conflicted property @propname for which
+ * a conflict was recorded during an update operation.
+ *
+ * Set @a *val_before to the pre-update value as seen in the
+ * repository at the former BASE revision of the working copy.
+ * It is unaffected by any local modifications in the working copy.
+ *
+ * Set @a *val_after to the post-update value as seen in the
+ * repository at the update target revision. In other words, it
+ * is the value the working copy has been updated to and it is also
+ * unaffected by any local modifications in the working copy.
+ *
+ * Set @a *val_during to the property value as seen in the
+ * working copy at the time the conflict was recorded, including
+ * local modifications, if any.
+ *
+ * These values do not contain conflict markers. A diff between versions can
+ * be generated with svn_diff_mem_string_output_unified3(). A merged version
+ * can be generated using svn_diff_mem_string_output_merge3().
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_update_get_propvals(
+ const svn_string_t **val_before,
+ const svn_string_t **val_after,
+ const svn_string_t **val_during,
+ const char *propname,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return property values for the conflicted property @propname for which
+ * a conflict was recorded during a switch operation.
+ *
+ * Set @a *val_before to the pre-switch value as seen in the
+ * repository at the former BASE revision and branch of the working copy.
+ * It is unaffected by any local modifications in the working copy.
+ *
+ * Set @a *val_after to the post-switch value as seen in the
+ * repository at the switch target branch and revision. In other words,
+ * it is the value the working copy has been switched to and it is also
+ * unaffected by any local modifications in the working copy.
+ *
+ * @a *val_during contains the property value as seen in the
+ * working copy at the time the conflict was recorded, including
+ * local modifications, if any.
+ *
+ * These values do not contain conflict markers. A diff between versions can
+ * be generated with svn_diff_mem_string_output_unified3(). A merged version
+ * can be generated using svn_diff_mem_string_output_merge3().
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_switch_get_propvals(
+ const svn_string_t **val_before,
+ const svn_string_t **val_after,
+ const svn_string_t **val_during,
+ const char *propname,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the content of the file versions involved in a text conflict
+ * recorded during a merge operation. The returned content does not
+ * contain conflict markers. A merged version can be generated using
+ * ### need to implement a diff3 function which accepts streams as input
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_update_get_file_contents(
+ svn_stream_t **content_source,
+ svn_stream_t **content_target,
+ svn_stream_t **content_common_ancestor,
+ svn_stream_t **content_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the content of the file versions involved in a text conflict
+ * recorded during an update operation. The returned content does not
+ * contain conflict markers. A merged version can be generated using
+ * ### need to implement a diff3 function which accepts streams as input
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_update_get_file_contents(
+ svn_stream_t **content_before,
+ svn_stream_t **content_after,
+ svn_stream_t **content_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Return the content of the file versions involved in a text conflict
+ * recorded during a switch operation. The returned content does not
+ * contain conflict markers. A merged version can be generated using
+ * ### need to implement a diff3 function which accepts streams as input
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_client_conflict_switch_get_file_contents(
+ svn_stream_t **content_before,
+ svn_stream_t **content_after,
+ svn_stream_t **content_during,
+ svn_wc_conflict_description2_t *conflict,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/** @} */
+
+/**
  * @defgroup Resolved Mark conflicted paths as resolved.
  *
  * @{
Received on 2015-05-29 13:17:02 CEST

This is an archived mail posted to the Subversion Dev mailing list.