Modified: subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.h URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.h?rev=1425414&r1=1425413&r2=1425414&view=diff ============================================================================== --- subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.h (original) +++ subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.h Sun Dec 23 05:58:52 2012 @@ -49,24 +49,44 @@ extern "C" { #define SVN_WC__CONFLICT_KIND_REJECT "reject" #define SVN_WC__CONFLICT_KIND_OBSTRUCTED "obstructed" +#define SVN_WC__CONFLICT_SRC_SUBVERSION "subversion" +/* Return a new conflict skel, allocated in RESULT_POOL. -/* Return a new conflict skel, allocated in RESULT_POOL. */ + Typically creating a conflict starts with calling this function and then + collecting details via one or more calls to svn_wc__conflict_skel_add_*(). + + The caller can then (when necessary) add operation details via + svn_wc__conflict_skel_set_op_*() and store the resulting conflict together + with the result of its operation in the working copy database. +*/ svn_skel_t * -svn_wc__conflict_skel_new(apr_pool_t *result_pool); +svn_wc__conflict_skel_create(apr_pool_t *result_pool); + +/* Return a boolean in *COMPLETE indicating whether CONFLICT_SKEL contains + everything needed for installing in the working copy database. + + This typically checks if CONFLICT_SKEL contains at least one conflict + and an operation. + */ +svn_error_t * +svn_wc__conflict_skel_is_complete(svn_boolean_t *complete, + const svn_skel_t *conflict_skel); /* Set 'update' as the conflicting operation in CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. - BASE_REVISION is the revision the node was at before the update. - TARGET_REVISION is the revision being updated to. + ORIGINAL specifies the BASE node before updating. - Do temporary allocations in SCRATCH_POOL. */ + It is an error to set another operation to a conflict skel that + already has an operation. + + Do temporary allocations in SCRATCH_POOL. The new skel data is + completely stored in RESULT-POOL. */ svn_error_t * svn_wc__conflict_skel_set_op_update(svn_skel_t *conflict_skel, - svn_revnum_t base_revision, - svn_revnum_t target_revision, + const svn_wc_conflict_version_t *original, apr_pool_t *result_pool, apr_pool_t *scratch_pool); @@ -74,208 +94,247 @@ svn_wc__conflict_skel_set_op_update(svn_ /* Set 'switch' as the conflicting operation in CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. - BASE_REVISION is the revision the node was at before the switch. - TARGET_REVISION is the revision being switched to. - REPOS_RELPATH is the path being switched to, relative to the - repository root. + ORIGINAL specifies the BASE node before switching. + + It is an error to set another operation to a conflict skel that + already has an operation. Do temporary allocations in SCRATCH_POOL. */ svn_error_t * svn_wc__conflict_skel_set_op_switch(svn_skel_t *conflict_skel, - svn_revnum_t base_revision, - svn_revnum_t target_revision, - const char *repos_relpath, + const svn_wc_conflict_version_t *original, + apr_pool_t *result_pool, apr_pool_t *scratch_pool); /* Set 'merge' as conflicting operation in CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. - REPOS_UUID is the UUID of the repository accessed via REPOS_ROOT_URL. - - LEFT_REPOS_RELPATH and RIGHT_REPOS_RELPATH paths to the merge-left - and merge-right merge sources, relative to REPOS_URL + LEFT and RIGHT paths are the merge-left and merge-right merge + sources of the merge. - LEFT_REVISION is the merge-left revision. - RIGHT_REVISION is the merge-right revision. + It is an error to set another operation to a conflict skel that + already has an operation. Do temporary allocations in SCRATCH_POOL. */ svn_error_t * svn_wc__conflict_skel_set_op_merge(svn_skel_t *conflict_skel, - const char *repos_uuid, - const char *repos_root_url, - svn_revnum_t left_revision, - const char *left_repos_relpath, - svn_revnum_t right_revision, - const char *right_repos_relpath, + const svn_wc_conflict_version_t *left, + const svn_wc_conflict_version_t *right, apr_pool_t *result_pool, apr_pool_t *scratch_pool); -/* Set 'patch' as the conflicting operation in CONFLICT_SKEL. +/* Add a text conflict to CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. - PATCH_SOURCE_LABEL is a string identifying the patch source in - some way, for display purposes. It is usually the absolute path - to the patch file, or a token such as "<stdin>" if the patch source - is not a file. + The DB, WRI_ABSPATH pair specifies in which working copy the conflict + will be recorded. (Needed for making the paths relative). + + MINE_ABSPATH, THEIR_OLD_ABSPATH and THEIR_ABSPATH specify the marker + files for this text conflict. Each of these values can be NULL to specify + that the node doesn't exist in this case. + + ### It is expected that in a future version we will also want to store + ### the sha1 checksum of these files to allow reinstalling the conflict + ### markers from the pristine store. + + It is an error to add another text conflict to a conflict skel that + already contains a text conflict. Do temporary allocations in SCRATCH_POOL. */ svn_error_t * -svn_wc__conflict_skel_set_op_patch(svn_skel_t *conflict_skel, - const char *patch_source_label, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); +svn_wc__conflict_skel_add_text_conflict(svn_skel_t *conflict_skel, + svn_wc__db_t *db, + const char *wri_abspath, + const char *mine_abspath, + const char *their_old_abspath, + const char *their_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Add a text conflict to CONFLICT_SKEL. +/* Add property conflict details to CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. - All checksums passed should be suitable for retreiving conflicted - versions of the file from the pristine store. + The DB, WRI_ABSPATH pair specifies in which working copy the conflict + will be recorded. (Needed for making the paths relative). - ORIGINAL_CHECKSUM is the checksum of the BASE version of the conflicted - file (without local modifications). - MINE_CHECKSUM is the checksum of the WORKING version of the conflicted - file as of the time the conflicting operation was run (i.e. including - local modifications). - INCOMING_CHECKSUM is the checksum of the incoming file causing the - conflict. ### is this needed for update? what about merge? - - It is an error (### which one?) if no conflicting operation has been - set on CONFLICT_SKEL before calling this function. - It is an error (### which one?) if CONFLICT_SKEL already contains - a text conflict. + The MINE_PROPS, THEIR_OLD_PROPS and THEIR_PROPS are hashes mapping a + const char * property name to a const svn_string_t* value. - Do temporary allocations in SCRATCH_POOL. -*/ -svn_error_t * -svn_wc__conflict_skel_add_text_conflict( - svn_skel_t *conflict_skel, - const svn_checksum_t *original_checksum, - const svn_checksum_t *mine_checksum, - const svn_checksum_t *incoming_checksum, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - - -/* Add a property conflict to SKEL. - - PROP_NAME is the name of the conflicted property. - - ORIGINAL_VALUE is the property's value at the BASE revision. MINE_VALUE - is the property's value in WORKING (BASE + local modifications). - INCOMING_VALUE is the incoming property value brought in by the - operation. When merging, INCOMING_BASE_VALUE is the base value against - which INCOMING_VALUE ws being applied. For updates, INCOMING_BASE_VALUE - should be the same as ORIGINAL_VALUE. - - *_VALUE may be NULL, indicating no value was present. - - It is an error (### which one?) if no conflicting operation has been - set on CONFLICT_SKEL before calling this function. - It is an error (### which one?) if CONFLICT_SKEL already cotains - a propery conflict for PROP_NAME. + The CONFLICTED_PROP_NAMES is a const char * property name value mapping + to "", recording which properties aren't resolved yet in the current + property values. + ### Needed for creating the marker file from this conflict data. + ### Would also allow per property marking as resolved. + ### Maybe useful for calling (legacy) conflict resolvers that expect one + ### property conflict per invocation. - The conflict recorded in SKEL will be allocated from RESULT_POOL. Do - temporary allocations in SCRATCH_POOL. + It is an error to add another text conflict to a conflict skel that + already contains a text conflict. + + Do temporary allocations in SCRATCH_POOL. */ svn_error_t * -svn_wc__conflict_skel_add_prop_conflict( - svn_skel_t *skel, - const char *prop_name, - const svn_string_t *original_value, - const svn_string_t *mine_value, - const svn_string_t *incoming_value, - const svn_string_t *incoming_base_value, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); +svn_wc__conflict_skel_add_prop_conflict(svn_skel_t *conflict_skel, + svn_wc__db_t *db, + const char *wri_abspath, + const char *marker_abspath, + apr_hash_t *mine_props, + apr_hash_t *their_old_props, + apr_hash_t *their_props, + apr_hash_t *conflicted_prop_names, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Add a tree conflict to CONFLICT_SKEL. Allocate data stored in the skel in RESULT_POOL. LOCAL_CHANGE is the local tree change made to the node. - ORIGINAL_LOCAL_KIND is the kind of the local node in BASE. - If ORIGINAL_LOCAL_KIND is svn_node_file, ORIGINAL_CHECKSUM is the checksum - for the BASE of the file, for retrieval from the pristine store. - - MINE_LOCAL_KIND is the kind of the local node in WORKING at the - time the conflict was flagged. - If MINE_LOCAL_KIND is svn_node_file, ORIGINAL_CHECKSUM is the checksum - of the WORKING version of the file at the time the conflict was flagged, - for retrieval from the pristine store. - - INCOMING_KIND is the kind of the incoming node. - If INCOMING_KIND is svn_node_file, INCOMING_CHECKSUM is the checksum - of the INCOMING version of the file, for retrieval from the pristine store. - - It is an error (### which one?) if no conflicting operation has been - set on CONFLICT_SKEL before calling this function. - It is an error (### which one?) if CONFLICT_SKEL already contains - a tree conflict. + INCOMING_CHANGE is the incoming change made to the node. + + It is an error to add another tree conflict to a conflict skel that + already contains a tree conflict. + + ### Is it an error to add a tree conflict to any existing conflict? Do temporary allocations in SCRATCH_POOL. */ svn_error_t * -svn_wc__conflict_skel_add_tree_conflict( - svn_skel_t *skel, - svn_wc_conflict_reason_t local_change, - svn_kind_t original_local_kind, - const svn_checksum_t *original_checksum, - svn_kind_t mine_local_kind, - const svn_checksum_t *mine_checksum, - svn_wc_conflict_action_t incoming_change, - svn_kind_t incoming_kind, - const svn_checksum_t *incoming_checksum, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - - -/* Add a reject conflict to CONFLICT_SKEL. - Allocate data stored in the skel in RESULT_POOL. - - HUNK_ORIGINAL_OFFSET, HUNK_ORIGINAL_LENGTH, HUNK_MODIFIED_OFFSET, - and HUNK_MODIFIED_LENGTH is hunk-header data identifying the hunk - which was rejected. - - REJECT_DIFF_CHECKSUM is the checksum of the text of the rejected - diff, for retrieval from the pristine store. - - It is an error (### which one?) if no conflicting operation has been - set on CONFLICT_SKEL before calling this function. - It is an error (### which one?) if CONFLICT_SKEL already contains - a reject conflict for the hunk. +svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel, + svn_wc__db_t *db, + const char *wri_abspath, + svn_wc_conflict_reason_t local_change, + svn_wc_conflict_action_t incoming_change, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/* + * ----------------------------------------------------------- + * Reading conflict skels. Maybe this can be made private later + * ----------------------------------------------------------- + */ + +/* Read common information from CONFLICT_SKEL to determine the operation + * and merge origins. + * + * Output arguments can be NULL if the value is not necessary. + * + * TEXT_, PROP_ and TREE_CONFLICTED (when not NULL) will be set to TRUE + * when the conflict contains the specified kind of conflict, otherwise + * to false. + * + * Allocate the result in RESULT_POOL. Perform temporary allocations in + * SCRATCH_POOL. + */ +svn_error_t * +svn_wc__conflict_read_info(svn_wc_operation_t *operation, + const apr_array_header_t **locations, + svn_boolean_t *text_conflicted, + svn_boolean_t *prop_conflicted, + svn_boolean_t *tree_conflicted, + svn_wc__db_t *db, + const char *wri_abspath, + const svn_skel_t *conflict_skel, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Reads back the original data stored by svn_wc__conflict_add_text_conflict() + * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH. + * + * Values as documented for svn_wc__conflict_add_text_conflict(). + * + * Output arguments can be NULL if the value is not necessary. + * + * Allocate the result in RESULT_POOL. Perform temporary allocations in + * SCRATCH_POOL. + */ +svn_error_t * +svn_wc__conflict_read_text_conflict(const char **mine_abspath, + const char **their_old_abspath, + const char **their_abspath, + svn_wc__db_t *db, + const char *wri_abspath, + const svn_skel_t *conflict_skel, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); - Do temporary allocations in SCRATCH_POOL. -*/ +/* Reads back the original data stored by svn_wc__conflict_add_prop_conflict() + * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH. + * + * Values as documented for svn_wc__conflict_add_prop_conflict(). + * + * Output arguments can be NULL if the value is not necessary + * Allocate the result in RESULT_POOL. Perform temporary allocations in + * SCRATCH_POOL. + */ svn_error_t * -svn_wc__conflict_skel_add_reject_conflict( - svn_skel_t *conflict_skel, - svn_linenum_t hunk_original_offset, - svn_linenum_t hunk_original_length, - svn_linenum_t hunk_modified_offset, - svn_linenum_t hunk_modified_length, - const svn_checksum_t *reject_diff_checksum, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - - -/* Add an obstruction conflict to CONFLICT_SKEL. - Allocate data stored in the skel in RESULT_POOL. - - It is an error (### which one?) if no conflicting operation has been - set on CONFLICT_SKEL before calling this function. - It is an error (### which one?) if CONFLICT_SKEL already contains - an obstruction. +svn_wc__conflict_read_prop_conflict(const char **marker_abspath, + apr_hash_t **mine_props, + apr_hash_t **their_old_props, + apr_hash_t **their_props, + apr_hash_t **conflicted_prop_names, + svn_wc__db_t *db, + const char *wri_abspath, + const svn_skel_t *conflict_skel, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); - Do temporary allocations in SCRATCH_POOL. -*/ +/* Reads back the original data stored by svn_wc__conflict_add_tree_conflict() + * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH. + * + * Values as documented for svn_wc__conflict_add_tree_conflict(). + * + * Output arguments can be NULL if the value is not necessary + * Allocate the result in RESULT_POOL. Perform temporary allocations in + * SCRATCH_POOL. + */ +svn_error_t * +svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change, + svn_wc_conflict_action_t *incoming_change, + svn_wc__db_t *db, + const char *wri_abspath, + const svn_skel_t *conflict_skel, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Create the necessary marker files for the conflicts stored in + * CONFLICT_SKEL and return the work items to fill the markers from + * the work queue. + * + * Currently only used for property conflicts as text conflict markers + * are just in-wc files. + * + * Allocate the result in RESULT_POOL. Perform temporary allocations in + * SCRATCH_POOL. + */ +svn_error_t * +svn_wc__conflict_create_markers(svn_skel_t **work_item, + svn_wc__db_t *db, + const char *local_abspath, + svn_skel_t *conflict_skel, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Call the interactive conflict resolver RESOLVER_FUNC with RESOLVER_BATON to + allow resolving the conflicts on LOCAL_ABSPATH. + + CONFLICT_SKEL contains the details of the conflicts on LOCAL_ABSPATH. + Resolver actions are directly applied to the in-db state of LOCAL_ABSPATH, + so the conflict and the state in CONFLICT_SKEL must already be installed in + wc.db. */ svn_error_t * -svn_wc__conflict_skel_add_obstruction(svn_skel_t *conflict_skel, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); +svn_wc__conflict_invoke_resolver(svn_wc__db_t *db, + const char *local_abspath, + const svn_skel_t *conflict_skel, + const apr_array_header_t *merge_options, + svn_wc_conflict_resolver_func2_t resolver_func, + void *resolver_baton, + apr_pool_t *scratch_pool); /* Resolve text conflicts on the given node. */
Modified: subversion/branches/javahl-ra/subversion/libsvn_wc/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_wc/externals.c?rev=1425414&r1=1425413&r2=1425414&view=diff ============================================================================== --- subversion/branches/javahl-ra/subversion/libsvn_wc/externals.c (original) +++ subversion/branches/javahl-ra/subversion/libsvn_wc/externals.c Sun Dec 23 05:58:52 2012 @@ -600,10 +600,11 @@ close_file(void *file_baton, eb->new_pristine_abspath = NULL; } - /* ### TODO: Merge the changes */ + /* Merge the changes */ { svn_skel_t *all_work_items = NULL; + svn_skel_t *conflict_skel = NULL; svn_skel_t *work_item; apr_hash_t *base_props = NULL; apr_hash_t *actual_props = NULL; @@ -675,26 +676,20 @@ close_file(void *file_baton, if (regular_prop_changes->nelts > 0) { - SVN_ERR(svn_wc__merge_props(&work_item, &prop_state, + SVN_ERR(svn_wc__merge_props(&conflict_skel, + &prop_state, &new_pristine_props, &new_actual_props, eb->db, eb->local_abspath, svn_kind_file, - NULL, NULL, NULL /* server_baseprops*/, base_props, actual_props, regular_prop_changes, TRUE /* base_merge */, FALSE /* dry_run */, - eb->conflict_func, - eb->conflict_baton, eb->cancel_func, eb->cancel_baton, pool, pool)); - - if (work_item) - all_work_items = svn_wc__wq_merge(all_work_items, work_item, - pool); } else { @@ -740,6 +735,7 @@ close_file(void *file_baton, enum svn_wc_merge_outcome_t merge_outcome; /* Ok, we have to do some work to merge a local change */ SVN_ERR(svn_wc__perform_file_merge(&work_item, + &conflict_skel, &merge_outcome, eb->db, eb->local_abspath, @@ -752,8 +748,6 @@ close_file(void *file_baton, *eb->target_revision, eb->propchanges, eb->diff3cmd, - eb->conflict_func, - eb->conflict_baton, eb->cancel_func, eb->cancel_baton, pool, pool)); @@ -784,6 +778,29 @@ close_file(void *file_baton, /* ### Retranslate on magic property changes, etc. */ } + if (conflict_skel) + { + SVN_ERR(svn_wc__conflict_skel_set_op_switch( + conflict_skel, + svn_wc_conflict_version_create2( + eb->repos_root_url, + eb->repos_uuid, + repos_relpath, + eb->original_revision, + svn_node_file, + pool), + pool, pool)); + + + SVN_ERR(svn_wc__conflict_create_markers(&work_item, + eb->db, eb->local_abspath, + conflict_skel, + pool, pool)); + + all_work_items = svn_wc__wq_merge(all_work_items, work_item, + pool); + } + SVN_ERR(svn_wc__db_external_add_file( eb->db, eb->local_abspath, @@ -804,6 +821,7 @@ close_file(void *file_baton, eb->recorded_revision, TRUE, new_actual_props, FALSE /* keep_recorded_info */, + conflict_skel, all_work_items, pool)); Modified: subversion/branches/javahl-ra/subversion/libsvn_wc/merge.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_wc/merge.c?rev=1425414&r1=1425413&r2=1425414&view=diff ============================================================================== --- subversion/branches/javahl-ra/subversion/libsvn_wc/merge.c (original) +++ subversion/branches/javahl-ra/subversion/libsvn_wc/merge.c Sun Dec 23 05:58:52 2012 @@ -29,6 +29,7 @@ #include "wc.h" #include "adm_files.h" +#include "conflicts.h" #include "translate.h" #include "workqueue.h" @@ -450,198 +451,6 @@ do_text_merge_external(svn_boolean_t *co return SVN_NO_ERROR; } -/* Create a new file in the same directory as VERSIONED_ABSPATH, with the - same basename as VERSIONED_ABSPATH, with a ".edited" extension, and set - *WORK_ITEM to a new work item that will copy and translate from the file - SOURCE to that new file. It will be translated from repository-normal - form to working-copy form according to the versioned properties of - VERSIONED_ABSPATH that are current when the work item is executed. - - DB should have a write lock for the directory containing SOURCE. - - Allocate *WORK_ITEM in RESULT_POOL. */ -static svn_error_t* -save_merge_result(svn_skel_t **work_item, - const merge_target_t *mt, - const char *source, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *edited_copy_abspath; - const char *dir_abspath; - const char *filename; - - svn_dirent_split(&dir_abspath, &filename, mt->local_abspath, scratch_pool); - - /* ### Should use preserved-conflict-file-exts. */ - /* Create the .edited file within this file's DIR_ABSPATH */ - SVN_ERR(svn_io_open_uniquely_named(NULL, - &edited_copy_abspath, - dir_abspath, - filename, - ".edited", - svn_io_file_del_none, - scratch_pool, scratch_pool)); - SVN_ERR(svn_wc__wq_build_file_copy_translated(work_item, - mt->db, mt->local_abspath, - source, edited_copy_abspath, - result_pool, scratch_pool)); - - return SVN_NO_ERROR; -} - -/* Deal with the result of the conflict resolution callback, as indicated by - * CHOICE. - * - * Set *WORK_ITEMS to new work items that will ... - * Set *MERGE_OUTCOME to the result of the 3-way merge. - * - * LEFT_ABSPATH, RIGHT_ABSPATH, and TARGET_ABSPATH are the input files to - * the 3-way merge, and MERGED_FILE is the merged result as generated by the - * internal or external merge or by the conflict resolution callback. - * - * DETRANSLATED_TARGET is the detranslated version of TARGET_ABSPATH - * (see detranslate_wc_file() above). DIFF3_OPTIONS are passed to the - * diff3 implementation in case a 3-way merge has to be carried out. */ -static svn_error_t* -eval_conflict_func_result(svn_skel_t **work_items, - enum svn_wc_merge_outcome_t *merge_outcome, - svn_wc_conflict_choice_t choice, - const merge_target_t *mt, - const char *left_abspath, - const char *right_abspath, - const char *merged_file, - const char *detranslated_target, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *install_from = NULL; - svn_boolean_t remove_source = FALSE; - - *work_items = NULL; - - switch (choice) - { - /* If the callback wants to use one of the fulltexts - to resolve the conflict, so be it.*/ - case svn_wc_conflict_choose_base: - { - install_from = left_abspath; - *merge_outcome = svn_wc_merge_merged; - break; - } - case svn_wc_conflict_choose_theirs_full: - { - install_from = right_abspath; - *merge_outcome = svn_wc_merge_merged; - break; - } - case svn_wc_conflict_choose_mine_full: - { - /* Do nothing to merge_target, let it live untouched! */ - *merge_outcome = svn_wc_merge_merged; - return SVN_NO_ERROR; - } - case svn_wc_conflict_choose_theirs_conflict: - case svn_wc_conflict_choose_mine_conflict: - { - const char *chosen_path; - const char *temp_dir; - svn_stream_t *chosen_stream; - svn_diff_t *diff; - svn_diff_conflict_display_style_t style; - svn_diff_file_options_t *diff3_options; - - diff3_options = svn_diff_file_options_create(scratch_pool); - - if (mt->merge_options) - SVN_ERR(svn_diff_file_options_parse(diff3_options, - mt->merge_options, - scratch_pool)); - - style = choice == svn_wc_conflict_choose_theirs_conflict - ? svn_diff_conflict_display_latest - : svn_diff_conflict_display_modified; - - SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, mt->db, - mt->wri_abspath, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_open_unique(&chosen_stream, &chosen_path, - temp_dir, svn_io_file_del_none, - scratch_pool, scratch_pool)); - - SVN_ERR(svn_diff_file_diff3_2(&diff, - left_abspath, - detranslated_target, right_abspath, - diff3_options, scratch_pool)); - SVN_ERR(svn_diff_file_output_merge2(chosen_stream, diff, - left_abspath, - detranslated_target, - right_abspath, - /* markers ignored */ - NULL, NULL, - NULL, NULL, - style, - scratch_pool)); - SVN_ERR(svn_stream_close(chosen_stream)); - - install_from = chosen_path; - remove_source = TRUE; - *merge_outcome = svn_wc_merge_merged; - break; - } - - /* For the case of 3-way file merging, we don't - really distinguish between these return values; - if the callback claims to have "generally - resolved" the situation, we still interpret - that as "OK, we'll assume the merged version is - good to use". */ - case svn_wc_conflict_choose_merged: - { - install_from = merged_file; - *merge_outcome = svn_wc_merge_merged; - break; - } - case svn_wc_conflict_choose_postpone: - default: - { -#if 0 - /* ### what should this value be? no caller appears to initialize - ### it, so we really SHOULD be setting a value here. */ - *merge_outcome = svn_wc_merge_merged; -#endif - - /* Assume conflict remains. */ - return SVN_NO_ERROR; - } - } - - SVN_ERR_ASSERT(install_from != NULL); - - { - svn_skel_t *work_item; - - SVN_ERR(svn_wc__wq_build_file_install(&work_item, - mt->db, mt->local_abspath, - install_from, - FALSE /* use_commit_times */, - FALSE /* record_fileinfo */, - result_pool, scratch_pool)); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); - - if (remove_source) - { - SVN_ERR(svn_wc__wq_build_file_remove(&work_item, - mt->db, install_from, - result_pool, scratch_pool)); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); - } - } - - return SVN_NO_ERROR; -} - /* Preserve the three pre-merge files. Create three empty files, with unique names that each include the @@ -798,133 +607,6 @@ preserve_pre_merge_files(svn_skel_t **wo return SVN_NO_ERROR; } -/* Helper for maybe_resolve_conflicts() below. */ -static const svn_wc_conflict_description2_t * -setup_text_conflict_desc(const char *left_abspath, - const char *right_abspath, - const char *target_abspath, - const svn_wc_conflict_version_t *left_version, - const svn_wc_conflict_version_t *right_version, - const char *result_target, - const char *detranslated_target, - const svn_prop_t *mimeprop, - svn_boolean_t is_binary, - apr_pool_t *pool) -{ - svn_wc_conflict_description2_t *cdesc; - - cdesc = svn_wc_conflict_description_create_text2(target_abspath, pool); - cdesc->is_binary = is_binary; - cdesc->mime_type = (mimeprop && mimeprop->value) - ? mimeprop->value->data : NULL, - cdesc->base_abspath = left_abspath; - cdesc->their_abspath = right_abspath; - cdesc->my_abspath = detranslated_target; - cdesc->merged_file = result_target; - - cdesc->src_left_version = left_version; - cdesc->src_right_version = right_version; - - return cdesc; -} - -/* XXX Insane amount of parameters... */ -/* RESULT_TARGET is the path to the merged file produced by the internal or - external 3-way merge. */ -static svn_error_t* -maybe_resolve_conflicts(svn_skel_t **work_items, - const merge_target_t *mt, - const char *left_abspath, - const char *right_abspath, - const char *left_label, - const char *right_label, - const char *target_label, - enum svn_wc_merge_outcome_t *merge_outcome, - const svn_wc_conflict_version_t *left_version, - const svn_wc_conflict_version_t *right_version, - const char *result_target, - const char *detranslated_target, - svn_wc_conflict_resolver_func2_t conflict_func, - void *conflict_baton, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_wc_conflict_result_t *result; - svn_skel_t *work_item; - - *work_items = NULL; - - /* Give the conflict resolution callback a chance to clean - up the conflicts before we mark the file 'conflicted' */ - if (!conflict_func) - { - /* If there is no interactive conflict resolution then we are effectively - postponing conflict resolution. */ - result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, - NULL, result_pool); - } - else - { - const svn_wc_conflict_description2_t *cdesc; - - cdesc = setup_text_conflict_desc(left_abspath, - right_abspath, - mt->local_abspath, - left_version, - right_version, - result_target, - detranslated_target, - get_prop(mt, SVN_PROP_MIME_TYPE), - FALSE, - scratch_pool); - - SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool, - scratch_pool)); - if (result == NULL) - return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, - NULL, _("Conflict callback violated API:" - " returned no results")); - - if (result->save_merged) - { - SVN_ERR(save_merge_result(work_items, - mt, - /* Look for callback's own - merged-file first: */ - result->merged_file - ? result->merged_file - : result_target, - result_pool, scratch_pool)); - } - } - - SVN_ERR(eval_conflict_func_result(&work_item, - merge_outcome, - result->choice, - mt, - left_abspath, - right_abspath, - result->merged_file - ? result->merged_file - : result_target, - detranslated_target, - result_pool, scratch_pool)); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); - - if (result->choice != svn_wc_conflict_choose_postpone) - /* The conflicts have been dealt with, nothing else - * to do for us here. */ - return SVN_NO_ERROR; - - /* The conflicts have not been dealt with. */ - *merge_outcome = svn_wc_merge_conflict; - - return SVN_NO_ERROR; -} - - /* Attempt a trivial merge of LEFT_ABSPATH and RIGHT_ABSPATH to TARGET_ABSPATH. * The merge is trivial if the file at LEFT_ABSPATH equals the detranslated * form of the target at DETRANSLATED_TARGET_ABSPATH, because in this case @@ -1020,6 +702,7 @@ merge_file_trivial(svn_skel_t **work_ite /* XXX Insane amount of parameters... */ static svn_error_t* merge_text_file(svn_skel_t **work_items, + svn_skel_t **conflict_skel, enum svn_wc_merge_outcome_t *merge_outcome, const merge_target_t *mt, const char *left_abspath, @@ -1028,11 +711,7 @@ merge_text_file(svn_skel_t **work_items, const char *right_label, const char *target_label, svn_boolean_t dry_run, - const svn_wc_conflict_version_t *left_version, - const svn_wc_conflict_version_t *right_version, const char *detranslated_target_abspath, - svn_wc_conflict_resolver_func2_t conflict_func, - void *conflict_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, @@ -1088,22 +767,7 @@ merge_text_file(svn_skel_t **work_items, if (contains_conflicts && ! dry_run) { - SVN_ERR(maybe_resolve_conflicts(work_items, - mt, - left_abspath, - right_abspath, - left_label, - right_label, - target_label, - merge_outcome, - left_version, - right_version, - result_target, - detranslated_target_abspath, - conflict_func, conflict_baton, - cancel_func, cancel_baton, - result_pool, scratch_pool)); - + *merge_outcome = svn_wc_merge_conflict; if (*merge_outcome == svn_wc_merge_conflict) { const char *left_copy, *right_copy, *target_copy; @@ -1122,11 +786,17 @@ merge_text_file(svn_skel_t **work_items, /* Track the three conflict files in the metadata. * ### TODO WC-NG: Do this outside the work queue: see * svn_wc__wq_tmp_build_set_text_conflict_markers()'s doc string. */ - SVN_ERR(svn_wc__wq_tmp_build_set_text_conflict_markers( - &work_item, mt->db, mt->local_abspath, - left_copy, right_copy, target_copy, - result_pool, scratch_pool)); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); + + if (!*conflict_skel) + *conflict_skel = svn_wc__conflict_skel_create(result_pool); + + SVN_ERR(svn_wc__conflict_skel_add_text_conflict(*conflict_skel, + mt->db, mt->local_abspath, + target_copy, + left_copy, + right_copy, + result_pool, + scratch_pool)); } if (*merge_outcome == svn_wc_merge_merged) @@ -1178,10 +848,10 @@ done: return SVN_NO_ERROR; } - /* XXX Insane amount of parameters... */ static svn_error_t * merge_binary_file(svn_skel_t **work_items, + svn_skel_t **conflict_skel, enum svn_wc_merge_outcome_t *merge_outcome, const merge_target_t *mt, const char *left_abspath, @@ -1190,11 +860,7 @@ merge_binary_file(svn_skel_t **work_item const char *right_label, const char *target_label, svn_boolean_t dry_run, - const svn_wc_conflict_version_t *left_version, - const svn_wc_conflict_version_t *right_version, const char *detranslated_target_abspath, - svn_wc_conflict_resolver_func2_t conflict_func, - void *conflict_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -1204,7 +870,6 @@ merge_binary_file(svn_skel_t **work_item const char *left_copy, *right_copy; const char *merge_dirpath, *merge_filename; const char *conflict_wrk; - svn_skel_t *work_item; *work_items = NULL; @@ -1219,92 +884,6 @@ merge_binary_file(svn_skel_t **work_item return SVN_NO_ERROR; } - /* Give the conflict resolution callback a chance to clean - up the conflict before we mark the file 'conflicted' */ - if (conflict_func) - { - svn_wc_conflict_result_t *result = NULL; - const svn_wc_conflict_description2_t *cdesc; - const char *install_from = NULL; - - cdesc = setup_text_conflict_desc(left_abspath, right_abspath, - mt->local_abspath, - left_version, right_version, - NULL /* result_target */, - detranslated_target_abspath, - get_prop(mt, SVN_PROP_MIME_TYPE), - TRUE, pool); - - SVN_ERR(conflict_func(&result, cdesc, conflict_baton, pool, pool)); - if (result == NULL) - return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, - NULL, _("Conflict callback violated API:" - " returned no results")); - - switch (result->choice) - { - /* For a binary file, there's no merged file to look at, - unless the conflict-callback did the merging itself. */ - case svn_wc_conflict_choose_base: - { - install_from = left_abspath; - *merge_outcome = svn_wc_merge_merged; - break; - } - case svn_wc_conflict_choose_theirs_full: - { - install_from = right_abspath; - *merge_outcome = svn_wc_merge_merged; - break; - } - /* For a binary file, if the response is to use the - user's file, we do nothing. We also do nothing if - the response claims to have already resolved the - problem.*/ - case svn_wc_conflict_choose_mine_full: - { - *merge_outcome = svn_wc_merge_merged; - return SVN_NO_ERROR; - } - case svn_wc_conflict_choose_merged: - { - if (! result->merged_file) - { - /* Callback asked us to choose its own - merged file, but didn't provide one! */ - return svn_error_create - (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, - NULL, _("Conflict callback violated API:" - " returned no merged file")); - } - else - { - install_from = result->merged_file; - *merge_outcome = svn_wc_merge_merged; - break; - } - } - case svn_wc_conflict_choose_postpone: - default: - { - /* Assume conflict remains, fall through to code below. */ - } - } - - if (install_from != NULL) - { - SVN_ERR(svn_wc__wq_build_file_install(work_items, - mt->db, mt->local_abspath, - install_from, - FALSE /* use_commit_times */, - FALSE /* record_fileinfo */, - result_pool, scratch_pool)); - - /* A merge choice was made, so we're done here. */ - return SVN_NO_ERROR; - } - } - /* reserve names for backups of left and right fulltexts */ SVN_ERR(svn_io_open_uniquely_named(NULL, &left_copy, @@ -1350,16 +929,15 @@ merge_binary_file(svn_skel_t **work_item /* Mark target_abspath's entry as "Conflicted", and start tracking the backup files in the entry as well. */ - SVN_ERR(svn_wc__wq_tmp_build_set_text_conflict_markers(&work_item, - mt->db, - mt->local_abspath, - left_copy, - right_copy, - conflict_wrk, - result_pool, - scratch_pool)); + if (!*conflict_skel) + *conflict_skel = svn_wc__conflict_skel_create(result_pool); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); + SVN_ERR(svn_wc__conflict_skel_add_text_conflict(*conflict_skel, + mt->db, mt->local_abspath, + conflict_wrk, + left_copy, + right_copy, + result_pool, scratch_pool)); *merge_outcome = svn_wc_merge_conflict; /* a conflict happened */ @@ -1369,12 +947,11 @@ merge_binary_file(svn_skel_t **work_item /* XXX Insane amount of parameters... */ svn_error_t * svn_wc__internal_merge(svn_skel_t **work_items, + svn_skel_t **conflict_skel, enum svn_wc_merge_outcome_t *merge_outcome, svn_wc__db_t *db, const char *left_abspath, - const svn_wc_conflict_version_t *left_version, const char *right_abspath, - const svn_wc_conflict_version_t *right_version, const char *target_abspath, const char *wri_abspath, const char *left_label, @@ -1385,8 +962,6 @@ svn_wc__internal_merge(svn_skel_t **work const char *diff3_cmd, const apr_array_header_t *merge_options, const apr_array_header_t *prop_diff, - svn_wc_conflict_resolver_func2_t conflict_func, - void *conflict_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, @@ -1447,6 +1022,7 @@ svn_wc__internal_merge(svn_skel_t **work if (is_binary) { SVN_ERR(merge_binary_file(work_items, + conflict_skel, merge_outcome, &mt, left_abspath, @@ -1455,16 +1031,13 @@ svn_wc__internal_merge(svn_skel_t **work right_label, target_label, dry_run, - left_version, - right_version, detranslated_target_abspath, - conflict_func, - conflict_baton, result_pool, scratch_pool)); } else { SVN_ERR(merge_text_file(work_items, + conflict_skel, merge_outcome, &mt, left_abspath, @@ -1473,10 +1046,7 @@ svn_wc__internal_merge(svn_skel_t **work right_label, target_label, dry_run, - left_version, - right_version, detranslated_target_abspath, - conflict_func, conflict_baton, cancel_func, cancel_baton, result_pool, scratch_pool)); } @@ -1521,8 +1091,8 @@ svn_wc_merge5(enum svn_wc_merge_outcome_ apr_pool_t *scratch_pool) { const char *dir_abspath = svn_dirent_dirname(target_abspath, scratch_pool); - svn_skel_t *prop_items = NULL; svn_skel_t *work_items; + svn_skel_t *conflict_skel = NULL; apr_hash_t *pristine_props = NULL; apr_hash_t *actual_props = NULL; apr_hash_t *new_actual_props = NULL; @@ -1600,24 +1170,24 @@ svn_wc_merge5(enum svn_wc_merge_outcome_ scratch_pool)); } - SVN_ERR(svn_wc__merge_props(&prop_items, merge_props_outcome, + SVN_ERR(svn_wc__merge_props(&conflict_skel, + merge_props_outcome, &new_pristine_props, &new_actual_props, wc_ctx->db, target_abspath, svn_kind_file, - left_version, right_version, original_props, pristine_props, actual_props, prop_diff, FALSE /* base_merge */, dry_run, - conflict_func, conflict_baton, cancel_func, cancel_baton, scratch_pool, scratch_pool)); } /* Queue all the work. */ SVN_ERR(svn_wc__internal_merge(&work_items, + &conflict_skel, merge_content_outcome, wc_ctx->db, - left_abspath, left_version, - right_abspath, right_version, + left_abspath, + right_abspath, target_abspath, target_abspath, left_label, right_label, target_label, @@ -1626,26 +1196,54 @@ svn_wc_merge5(enum svn_wc_merge_outcome_ diff3_cmd, merge_options, prop_diff, - conflict_func, conflict_baton, cancel_func, cancel_baton, scratch_pool, scratch_pool)); - work_items = svn_wc__wq_merge(prop_items, work_items, scratch_pool); - /* If this isn't a dry run, then run the work! */ if (!dry_run) { + if (conflict_skel) + { + svn_skel_t *work_item; + + SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_skel, + left_version, + right_version, + scratch_pool, + scratch_pool)); + + SVN_ERR(svn_wc__conflict_create_markers(&work_item, + wc_ctx->db, target_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + } + if (new_actual_props) SVN_ERR(svn_wc__db_op_set_props(wc_ctx->db, target_abspath, new_actual_props, svn_wc__has_magic_property(prop_diff), - NULL, work_items, scratch_pool)); - else + conflict_skel, work_items, + scratch_pool)); + else if (conflict_skel) + SVN_ERR(svn_wc__db_op_mark_conflict(wc_ctx->db, target_abspath, + conflict_skel, work_items, + scratch_pool)); + else if (work_items) SVN_ERR(svn_wc__db_wq_add(wc_ctx->db, target_abspath, work_items, scratch_pool)); - SVN_ERR(svn_wc__wq_run(wc_ctx->db, target_abspath, - cancel_func, cancel_baton, - scratch_pool)); + + if (work_items) + SVN_ERR(svn_wc__wq_run(wc_ctx->db, target_abspath, + cancel_func, cancel_baton, + scratch_pool)); + + if (conflict_skel && conflict_func) + SVN_ERR(svn_wc__conflict_invoke_resolver(wc_ctx->db, target_abspath, + conflict_skel, merge_options, + conflict_func, conflict_baton, + scratch_pool)); } return SVN_NO_ERROR;
