Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c Mon Jun 29 13:42:10 2015 @@ -1931,6 +1931,34 @@ pack_shard(struct pack_baton *baton, return SVN_NO_ERROR; } +/* Read the youngest rev and the first non-packed rev info for FS from disk. + Set *FULLY_PACKED when there is no completed unpacked shard. + Use SCRATCH_POOL for temporary allocations. + */ +static svn_error_t * +get_pack_status(svn_boolean_t *fully_packed, + svn_fs_t *fs, + apr_pool_t *scratch_pool) +{ + fs_fs_data_t *ffd = fs->fsap_data; + apr_int64_t completed_shards; + svn_revnum_t youngest; + + SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs, + scratch_pool)); + + SVN_ERR(svn_fs_fs__youngest_rev(&youngest, fs, scratch_pool)); + completed_shards = (youngest + 1) / ffd->max_files_per_dir; + + /* See if we've already completed all possible shards thus far. */ + if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir)) + *fully_packed = TRUE; + else + *fully_packed = FALSE; + + return SVN_NO_ERROR; +} + /* The work-horse for svn_fs_fs__pack, called with the FS write lock. This implements the svn_fs_fs__with_write_lock() 'body' callback type. BATON is a 'struct pack_baton *'. @@ -1952,30 +1980,16 @@ pack_body(void *baton, struct pack_baton *pb = baton; fs_fs_data_t *ffd = pb->fs->fsap_data; apr_int64_t completed_shards; - svn_revnum_t youngest; apr_pool_t *iterpool; + svn_boolean_t fully_packed; - /* If the repository isn't a new enough format, we don't support packing. - Return a friendly error to that effect. */ - if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT) - return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("FSFS format (%d) too old to pack; please upgrade the filesystem."), - ffd->format); - - /* If we aren't using sharding, we can't do any packing, so quit. */ - if (!ffd->max_files_per_dir) - return SVN_NO_ERROR; - - SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, pb->fs, - pool)); - - SVN_ERR(svn_fs_fs__youngest_rev(&youngest, pb->fs, pool)); - completed_shards = (youngest + 1) / ffd->max_files_per_dir; - - /* See if we've already completed all possible shards thus far. */ - if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir)) + /* Since another process might have already packed the repo, + we need to re-read the pack status. */ + SVN_ERR(get_pack_status(&fully_packed, pb->fs, pool)); + if (fully_packed) return SVN_NO_ERROR; + completed_shards = (ffd->youngest_rev_cache + 1) / ffd->max_files_per_dir; pb->revs_dir = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, pool); if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT) pb->revsprops_dir = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR, @@ -2009,7 +2023,25 @@ svn_fs_fs__pack(svn_fs_t *fs, struct pack_baton pb = { 0 }; fs_fs_data_t *ffd = fs->fsap_data; svn_error_t *err; + svn_boolean_t fully_packed; + + /* If the repository isn't a new enough format, we don't support packing. + Return a friendly error to that effect. */ + if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT) + return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("FSFS format (%d) too old to pack; please upgrade the filesystem."), + ffd->format); + + /* If we aren't using sharding, we can't do any packing, so quit. */ + if (!ffd->max_files_per_dir) + return SVN_NO_ERROR; + + /* Is there we even anything to do?. */ + SVN_ERR(get_pack_status(&fully_packed, fs, pool)); + if (fully_packed) + return SVN_NO_ERROR; + /* Lock the repo and start the pack process. */ pb.fs = fs; pb.notify_func = notify_func; pb.notify_baton = notify_baton;
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c Mon Jun 29 13:42:10 2015 @@ -89,15 +89,6 @@ path_txn_props(svn_fs_t *fs, } static APR_INLINE const char * -path_txn_props_final(svn_fs_t *fs, - const svn_fs_fs__id_part_t *txn_id, - apr_pool_t *pool) -{ - return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), - PATH_TXN_PROPS_FINAL, pool); -} - -static APR_INLINE const char * path_txn_next_ids(svn_fs_t *fs, const svn_fs_fs__id_part_t *txn_id, apr_pool_t *pool) @@ -1160,7 +1151,6 @@ static svn_error_t * set_txn_proplist(svn_fs_t *fs, const svn_fs_fs__id_part_t *txn_id, apr_hash_t *props, - svn_boolean_t final, apr_pool_t *pool) { svn_stringbuf_t *buf; @@ -1173,9 +1163,7 @@ set_txn_proplist(svn_fs_t *fs, SVN_ERR(svn_stream_close(stream)); /* Open the transaction properties file and write new contents to it. */ - SVN_ERR(svn_io_write_atomic((final - ? path_txn_props_final(fs, txn_id, pool) - : path_txn_props(fs, txn_id, pool)), + SVN_ERR(svn_io_write_atomic(path_txn_props(fs, txn_id, pool), buf->data, buf->len, NULL /* copy_perms_path */, pool)); return SVN_NO_ERROR; @@ -1232,7 +1220,7 @@ svn_fs_fs__change_txn_props(svn_fs_txn_t /* Create a new version of the file and write out the new props. */ /* Open the transaction properties file. */ - SVN_ERR(set_txn_proplist(txn->fs, &ftd->txn_id, txn_prop, FALSE, pool)); + SVN_ERR(set_txn_proplist(txn->fs, &ftd->txn_id, txn_prop, pool)); return SVN_NO_ERROR; } @@ -3337,41 +3325,31 @@ verify_locks(svn_fs_t *fs, return SVN_NO_ERROR; } -/* Return in *PATH the path to a file containing the properties that - make up the final revision properties file. This involves setting - svn:date and removing any temporary properties associated with the - commit flags. */ +/* Writes final revision properties to file PATH applying permissions + from file PERMS_REFERENCE. This involves setting svn:date and + removing any temporary properties associated with the commit flags. */ static svn_error_t * -write_final_revprop(const char **path, +write_final_revprop(const char *path, + const char *perms_reference, svn_fs_txn_t *txn, - const svn_fs_fs__id_part_t *txn_id, apr_pool_t *pool) { apr_hash_t *txnprops; - svn_boolean_t final_mods = FALSE; svn_string_t date; svn_string_t *client_date; + apr_file_t *revprop_file; + svn_stream_t *stream; SVN_ERR(svn_fs_fs__txn_proplist(&txnprops, txn, pool)); /* Remove any temporary txn props representing 'flags'. */ - if (svn_hash_gets(txnprops, SVN_FS__PROP_TXN_CHECK_OOD)) - { - svn_hash_sets(txnprops, SVN_FS__PROP_TXN_CHECK_OOD, NULL); - final_mods = TRUE; - } - - if (svn_hash_gets(txnprops, SVN_FS__PROP_TXN_CHECK_LOCKS)) - { - svn_hash_sets(txnprops, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL); - final_mods = TRUE; - } + svn_hash_sets(txnprops, SVN_FS__PROP_TXN_CHECK_OOD, NULL); + svn_hash_sets(txnprops, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL); client_date = svn_hash_gets(txnprops, SVN_FS__PROP_TXN_CLIENT_DATE); if (client_date) { svn_hash_sets(txnprops, SVN_FS__PROP_TXN_CLIENT_DATE, NULL); - final_mods = TRUE; } /* Update commit time to ensure that svn:date revprops remain ordered if @@ -3381,18 +3359,22 @@ write_final_revprop(const char **path, date.data = svn_time_to_cstring(apr_time_now(), pool); date.len = strlen(date.data); svn_hash_sets(txnprops, SVN_PROP_REVISION_DATE, &date); - final_mods = TRUE; } - if (final_mods) - { - SVN_ERR(set_txn_proplist(txn->fs, txn_id, txnprops, TRUE, pool)); - *path = path_txn_props_final(txn->fs, txn_id, pool); - } - else - { - *path = path_txn_props(txn->fs, txn_id, pool); - } + /* Create new revprops file. Tell OS to truncate existing file, + since file may already exists from failed transaction. */ + SVN_ERR(svn_io_file_open(&revprop_file, path, + APR_WRITE | APR_CREATE | APR_TRUNCATE + | APR_BUFFERED, APR_OS_DEFAULT, pool)); + + stream = svn_stream_from_aprfile2(revprop_file, TRUE, pool); + SVN_ERR(svn_hash_write2(txnprops, stream, SVN_HASH_TERMINATOR, pool)); + SVN_ERR(svn_stream_close(stream)); + + SVN_ERR(svn_io_file_flush_to_disk(revprop_file, pool)); + SVN_ERR(svn_io_file_close(revprop_file, pool)); + + SVN_ERR(svn_io_copy_perms(perms_reference, path, pool)); return SVN_NO_ERROR; } @@ -3457,7 +3439,7 @@ commit_body(void *baton, apr_pool_t *poo struct commit_baton *cb = baton; fs_fs_data_t *ffd = cb->fs->fsap_data; const char *old_rev_filename, *rev_filename, *proto_filename; - const char *revprop_filename, *final_revprop; + const char *revprop_filename; const svn_fs_id_t *root_id, *new_root_id; apr_uint64_t start_node_id; apr_uint64_t start_copy_id; @@ -3610,12 +3592,11 @@ commit_body(void *baton, apr_pool_t *poo remove the transaction directory later. */ SVN_ERR(unlock_proto_rev(cb->fs, txn_id, proto_file_lockcookie, pool)); - /* Move the revprops file into place. */ + /* Write final revprops file. */ SVN_ERR_ASSERT(! svn_fs_fs__is_packed_revprop(cb->fs, new_rev)); - SVN_ERR(write_final_revprop(&revprop_filename, cb->txn, txn_id, pool)); - final_revprop = svn_fs_fs__path_revprops(cb->fs, new_rev, pool); - SVN_ERR(svn_fs_fs__move_into_place(revprop_filename, final_revprop, - old_rev_filename, pool)); + revprop_filename = svn_fs_fs__path_revprops(cb->fs, new_rev, pool); + SVN_ERR(write_final_revprop(revprop_filename, old_rev_filename, + cb->txn, pool)); /* Update the 'current' file. */ SVN_ERR(verify_as_revision_before_current_plus_plus(cb->fs, new_rev, pool)); @@ -3919,6 +3900,5 @@ svn_fs_fs__begin_txn(svn_fs_txn_t **txn_ svn_string_create("0", pool)); ftd = (*txn_p)->fsap_data; - return svn_error_trace(set_txn_proplist(fs, &ftd->txn_id, props, FALSE, - pool)); + return svn_error_trace(set_txn_proplist(fs, &ftd->txn_id, props, pool)); } Modified: subversion/branches/move-tracking-2/subversion/libsvn_repos/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_repos/deprecated.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_repos/deprecated.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_repos/deprecated.c Mon Jun 29 13:42:10 2015 @@ -774,9 +774,9 @@ svn_repos_verify_fs2(svn_repos_t *repos, end_rev, FALSE, FALSE, - FALSE, notify_func, notify_baton, + NULL, NULL, cancel_func, cancel_baton, pool)); Modified: subversion/branches/move-tracking-2/subversion/libsvn_repos/dump.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_repos/dump.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_repos/dump.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_repos/dump.c Mon Jun 29 13:42:10 2015 @@ -2265,24 +2265,6 @@ verify_close_directory(void *dir_baton, return close_directory(dir_baton, pool); } -static void -notify_verification_error(svn_revnum_t rev, - svn_error_t *err, - svn_repos_notify_func_t notify_func, - void *notify_baton, - apr_pool_t *pool) -{ - svn_repos_notify_t *notify_failure; - - if (notify_func == NULL) - return; - - notify_failure = svn_repos_notify_create(svn_repos_notify_failure, pool); - notify_failure->err = err; - notify_failure->revision = rev; - notify_func(notify_baton, notify_failure, pool); -} - /* Verify revision REV in file system FS. */ static svn_error_t * verify_one_revision(svn_fs_t *fs, @@ -2359,15 +2341,42 @@ verify_fs_notify_func(svn_revnum_t revis notify_baton->notify, pool); } +static svn_error_t * +report_error(svn_revnum_t revision, + svn_error_t *verify_err, + svn_repos_verify_callback_t verify_callback, + void *verify_baton, + apr_pool_t *pool) +{ + if (verify_callback) + { + svn_error_t *cb_err; + + /* The caller provided us with a callback, so make him responsible + for what's going to happen with the error. */ + cb_err = verify_callback(verify_baton, revision, verify_err, pool); + svn_error_clear(verify_err); + SVN_ERR(cb_err); + + return SVN_NO_ERROR; + } + else + { + /* No callback -- no second guessing. Just return the error. */ + return svn_error_trace(verify_err); + } +} + svn_error_t * svn_repos_verify_fs3(svn_repos_t *repos, svn_revnum_t start_rev, svn_revnum_t end_rev, - svn_boolean_t keep_going, svn_boolean_t check_normalization, svn_boolean_t metadata_only, svn_repos_notify_func_t notify_func, void *notify_baton, + svn_repos_verify_callback_t verify_callback, + void *verify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -2380,8 +2389,6 @@ svn_repos_verify_fs3(svn_repos_t *repos, svn_fs_progress_notify_func_t verify_notify = NULL; struct verify_fs_notify_func_baton_t *verify_notify_baton = NULL; svn_error_t *err; - svn_boolean_t failed_metadata = FALSE; - svn_revnum_t failed_revisions = 0; /* Determine the current youngest revision of the filesystem. */ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool)); @@ -2430,20 +2437,8 @@ svn_repos_verify_fs3(svn_repos_t *repos, } else if (err) { - notify_verification_error(SVN_INVALID_REVNUM, err, notify_func, - notify_baton, iterpool); - - if (!keep_going) - { - /* Return the error, the caller doesn't want us to continue. */ - return svn_error_trace(err); - } - else - { - /* Clear the error and keep going. */ - failed_metadata = TRUE; - svn_error_clear(err); - } + SVN_ERR(report_error(SVN_INVALID_REVNUM, err, verify_callback, + verify_baton, iterpool)); } if (!metadata_only) @@ -2463,20 +2458,8 @@ svn_repos_verify_fs3(svn_repos_t *repos, } else if (err) { - notify_verification_error(rev, err, notify_func, notify_baton, - iterpool); - - if (!keep_going) - { - /* Return the error, the caller doesn't want us to continue. */ - return svn_error_trace(err); - } - else - { - /* Clear the error and keep going. */ - ++failed_revisions; - svn_error_clear(err); - } + SVN_ERR(report_error(rev, err, verify_callback, verify_baton, + iterpool)); } else if (notify_func) { @@ -2495,40 +2478,5 @@ svn_repos_verify_fs3(svn_repos_t *repos, svn_pool_destroy(iterpool); - /* Summarize the results. */ - if (failed_metadata || 0 != failed_revisions) - { - const char *const repos_path = - svn_dirent_local_style(svn_repos_path(repos, pool), pool); - - if (0 == failed_revisions) - { - return svn_error_createf( - SVN_ERR_REPOS_VERIFY_FAILED, NULL, - _("Metadata verification failed on repository '%s'"), - repos_path); - } - else - { - const char* format_string; - - if (failed_metadata) - format_string = apr_psprintf( - pool, _("Verification of metadata and" - " %%%s out of %%%s revisions" - " failed on repository '%%s'"), - SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT); - else - format_string = apr_psprintf( - pool, _("Verification of %%%s out of %%%s revisions" - " failed on repository '%%s'"), - SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT); - - return svn_error_createf( - SVN_ERR_REPOS_VERIFY_FAILED, NULL, format_string, - failed_revisions, end_rev - start_rev + 1, repos_path); - } - } - return SVN_NO_ERROR; } Modified: subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_repos/rev_hunt.c Mon Jun 29 13:42:10 2015 @@ -1336,6 +1336,7 @@ struct send_baton apr_hash_t *last_props; const char *last_path; svn_fs_root_t *last_root; + svn_boolean_t include_merged_revisions; }; /* Send PATH_REV to HANDLER and HANDLER_BATON, using information provided by @@ -1379,10 +1380,11 @@ send_path_revision(struct path_revision /* Special case: In the first revision, we always provide a delta. */ contents_changed = TRUE; } - else if (strcmp(sb->last_path, path_rev->path)) + else if (sb->include_merged_revisions + && strcmp(sb->last_path, path_rev->path)) { - /* This is a HACK!!! - * Blame, in older clients anyways, relies on getting a notification + /* ### This is a HACK!!! + * Blame -g, in older clients anyways, relies on getting a notification * whenever the path changes - even if there was no content change. * * TODO: A future release should take an extra parameter and depending @@ -1466,6 +1468,7 @@ get_file_revs_backwards(svn_repos_t *rep last_pool = svn_pool_create(scratch_pool); sb.iterpool = svn_pool_create(scratch_pool); sb.last_pool = svn_pool_create(scratch_pool); + sb.include_merged_revisions = FALSE; /* We want the first txdelta to be against the empty file. */ sb.last_root = NULL; @@ -1621,6 +1624,9 @@ svn_repos_get_file_revs2(svn_repos_t *re /* Create an empty hash table for the first property diff. */ sb.last_props = apr_hash_make(sb.last_pool); + /* Inform send_path_revision() whether workarounds / special behavior + * may be needed. */ + sb.include_merged_revisions = include_merged_revisions; /* Get the revisions we are interested in. */ duplicate_path_revs = apr_hash_make(scratch_pool); Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/cache-membuffer.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/cache-membuffer.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/cache-membuffer.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/cache-membuffer.c Mon Jun 29 13:42:10 2015 @@ -2233,7 +2233,7 @@ membuffer_cache_get_internal(svn_membuff /* Look for the *ITEM identified by KEY. If no item has been stored * for KEY, *ITEM will be NULL. Otherwise, the DESERIALIZER is called - * re-construct the proper object from the serialized data. + * to re-construct the proper object from the serialized data. * Allocations will be done in POOL. */ static svn_error_t * Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c Mon Jun 29 13:42:10 2015 @@ -55,6 +55,27 @@ struct cfg_section_t }; +/* States that a config option value can assume. */ +typedef enum option_state_t +{ + /* Value still needs to be expanded. + This is the initial state for *all* values. */ + option_state_needs_expanding, + + /* Value is currently being expanded. + This transitional state allows for detecting cyclic dependencies. */ + option_state_expanding, + + /* Expanded value is available. + Values that never needed expanding directly go into that state + skipping option_state_expanding. */ + option_state_expanded, + + /* The value expansion is cyclic which results in "undefined" behavior. + This is to return a defined value ("") in that case. */ + option_state_cyclic +} option_state_t; + /* Option table entries. */ typedef struct cfg_option_t cfg_option_t; struct cfg_option_t @@ -71,10 +92,10 @@ struct cfg_option_t /* The expanded option value. */ const char *x_value; - /* Expansion flag. If this is TRUE, this value has already been expanded. - In this case, if x_value is NULL, no expansions were necessary, - and value should be used directly. */ - svn_boolean_t expanded; + /* Expansion state. If this is option_state_expanded, VALUE has already + been expanded. In this case, if x_value is NULL, no expansions were + necessary, and value should be used directly. */ + option_state_t state; }; @@ -396,12 +417,13 @@ svn_config_merge(svn_config_t *cfg, cons static svn_boolean_t rmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option) { - /* Only clear the `expanded' flag if the value actually contains + /* Only reset the expansion state if the value actually contains variable expansions. */ - if (option->expanded && option->x_value != NULL) + if ( (option->state == option_state_expanded && option->x_value != NULL) + || option->state == option_state_cyclic) { option->x_value = NULL; - option->expanded = FALSE; + option->state = option_state_needs_expanding; } return FALSE; @@ -482,7 +504,7 @@ find_option(svn_config_t *cfg, const cha /* Has a bi-directional dependency with make_string_from_option(). */ -static void +static svn_boolean_t expand_option_value(svn_config_t *cfg, cfg_section_t *section, const char *opt_value, const char **opt_x_valuep, apr_pool_t *x_pool); @@ -496,7 +518,20 @@ make_string_from_option(const char **val apr_pool_t* x_pool) { /* Expand the option value if necessary. */ - if (!opt->expanded) + if ( opt->state == option_state_expanding + || opt->state == option_state_cyclic) + { + /* Recursion is not supported. Since we can't produce an error + * nor should we abort the process, the next best thing is to + * report the recursive part as an empty string. */ + *valuep = ""; + + /* Go into "value undefined" state. */ + opt->state = option_state_cyclic; + + return; + } + else if (opt->state == option_state_needs_expanding) { /* before attempting to expand an option, check for the placeholder. * If none is there, there is no point in calling expand_option_value. @@ -511,9 +546,16 @@ make_string_from_option(const char **val tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool)); - expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool); - opt->expanded = TRUE; + /* Expand the value. During that process, have the option marked + * as "expanding" to detect cycles. */ + opt->state = option_state_expanding; + if (expand_option_value(cfg, section, opt->value, &opt->x_value, + tmp_pool)) + opt->state = option_state_expanded; + else + opt->state = option_state_cyclic; + /* Ensure the expanded value is allocated in a permanent pool. */ if (x_pool != cfg->x_pool) { /* Grab the fully expanded value from tmp_pool before its @@ -527,7 +569,7 @@ make_string_from_option(const char **val } else { - opt->expanded = TRUE; + opt->state = option_state_expanded; } } @@ -549,8 +591,9 @@ make_string_from_option(const char **val /* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP. If no variable replacements are done, set *OPT_X_VALUEP to - NULL. Allocate from X_POOL. */ -static void + NULL. Return TRUE if the expanded value is defined and FALSE + for recursive definitions. Allocate from X_POOL. */ +static svn_boolean_t expand_option_value(svn_config_t *cfg, cfg_section_t *section, const char *opt_value, const char **opt_x_valuep, apr_pool_t *x_pool) @@ -587,6 +630,18 @@ expand_option_value(svn_config_t *cfg, c should terminate. */ make_string_from_option(&cstring, cfg, section, x_opt, x_pool); + /* Values depending on cyclic values must also be marked as + * "undefined" because they might themselves form cycles with + * the one cycle we just detected. Due to the early abort of + * the recursion, we won't follow and thus detect dependent + * cycles anymore. + */ + if (x_opt->state == option_state_cyclic) + { + *opt_x_valuep = ""; + return FALSE; + } + /* Append the plain text preceding the expansion. */ len = name_start - FMT_START_LEN - copy_from; if (buf == NULL) @@ -625,6 +680,9 @@ expand_option_value(svn_config_t *cfg, c } else *opt_x_valuep = NULL; + + /* Expansion has a well-defined answer. */ + return TRUE; } static cfg_section_t * @@ -664,7 +722,7 @@ svn_config_create_option(cfg_option_t ** o->value = apr_pstrdup(pool, value); o->x_value = NULL; - o->expanded = FALSE; + o->state = option_state_needs_expanding; *opt = o; } @@ -685,7 +743,8 @@ svn_config__is_expanded(svn_config_t *cf return FALSE; /* already expanded? */ - if (opt->expanded) + if ( opt->state == option_state_expanded + || opt->state == option_state_cyclic) return TRUE; /* needs expansion? */ @@ -719,8 +778,14 @@ svn_config_get(svn_config_t *cfg, const { apr_pool_t *tmp_pool = svn_pool_create(cfg->pool); const char *x_default; - expand_option_value(cfg, sec, default_value, &x_default, tmp_pool); - if (x_default) + if (!expand_option_value(cfg, sec, default_value, &x_default, + tmp_pool)) + { + /* Recursive definitions are not supported. + Normalize the answer in that case. */ + *valuep = ""; + } + else if (x_default) { svn_stringbuf_set(cfg->tmp_value, x_default); *valuep = cfg->tmp_value->data; @@ -758,7 +823,7 @@ svn_config_set(svn_config_t *cfg, { /* Replace the option's value. */ opt->value = apr_pstrdup(cfg->pool, value); - opt->expanded = FALSE; + opt->state = option_state_needs_expanding; return; } @@ -1171,7 +1236,7 @@ svn_config_dup(svn_config_t **cfgp, destopt->value = apr_pstrdup(pool, srcopt->value); destopt->x_value = apr_pstrdup(pool, srcopt->x_value); - destopt->expanded = srcopt->expanded; + destopt->state = srcopt->state; apr_hash_set(destsec->options, apr_pstrdup(pool, (const char*)optkey), optkeyLength, destopt); Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/io.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_subr/io.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_subr/io.c Mon Jun 29 13:42:10 2015 @@ -2301,6 +2301,14 @@ svn_error_t *svn_io_file_flush_to_disk(a apr_pool_t *pool) { apr_os_file_t filehand; + const char *fname; + apr_status_t apr_err; + + /* We need this only in case of an error but this is cheap to get - + * so we do it here for clarity. */ + apr_err = apr_file_name_get(&fname, file); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't get file name")); /* ### In apr 1.4+ we could delegate most of this function to apr_file_sync(). The only major difference is that this doesn't @@ -2318,7 +2326,8 @@ svn_error_t *svn_io_file_flush_to_disk(a if (! FlushFileBuffers(filehand)) return svn_error_wrap_apr(apr_get_os_error(), - _("Can't flush file to disk")); + _("Can't flush file '%s' to disk"), + try_utf8_from_internal_style(fname, pool)); #else int rv; @@ -2339,7 +2348,8 @@ svn_error_t *svn_io_file_flush_to_disk(a if (rv == -1) return svn_error_wrap_apr(apr_get_os_error(), - _("Can't flush file to disk")); + _("Can't flush file '%s' to disk"), + try_utf8_from_internal_style(fname, pool)); #endif } @@ -4014,6 +4024,24 @@ svn_io_stat(apr_finfo_t *finfo, const ch return SVN_NO_ERROR; } +#if defined(WIN32) +/* Platform specific implementation of apr_file_rename() to workaround + APR problems on Windows. */ +static apr_status_t +win32_file_rename(const WCHAR *from_path_w, + const WCHAR *to_path_w, + apr_pool_t *pool) +{ + /* APR calls MoveFileExW() with MOVEFILE_COPY_ALLOWED, while we rely + * that rename is atomic operation. Call MoveFileEx directly on Windows + * without MOVEFILE_COPY_ALLOWED flag to workaround it. + */ + if (!MoveFileExW(from_path_w, to_path_w, MOVEFILE_REPLACE_EXISTING)) + return apr_get_os_error(); + + return APR_SUCCESS; +} +#endif svn_error_t * svn_io_file_rename(const char *from_path, const char *to_path, @@ -4021,13 +4049,19 @@ svn_io_file_rename(const char *from_path { apr_status_t status = APR_SUCCESS; const char *from_path_apr, *to_path_apr; +#if defined(WIN32) + WCHAR *from_path_w; + WCHAR *to_path_w; +#endif SVN_ERR(cstring_from_utf8(&from_path_apr, from_path, pool)); SVN_ERR(cstring_from_utf8(&to_path_apr, to_path, pool)); - status = apr_file_rename(from_path_apr, to_path_apr, pool); +#if defined(WIN32) + SVN_ERR(svn_io__utf8_to_unicode_longpath(&from_path_w, from_path_apr, pool)); + SVN_ERR(svn_io__utf8_to_unicode_longpath(&to_path_w, to_path_apr, pool)); + status = win32_file_rename(from_path_w, to_path_w, pool); -#if defined(WIN32) || defined(__OS2__) /* If the target file is read only NTFS reports EACCESS and FAT/FAT32 reports EEXIST */ if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) @@ -4037,9 +4071,23 @@ svn_io_file_rename(const char *from_path allow renaming when from_path is read only. */ SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); + status = win32_file_rename(from_path_w, to_path_w, pool); + } + WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w, pool)); +#elif defined(__OS2__) + /* If the target file is read only NTFS reports EACCESS and + FAT/FAT32 reports EEXIST */ + if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) + { + /* Set the destination file writable because OS/2 will not + allow us to rename when to_path is read-only, but will + allow renaming when from_path is read only. */ + SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); + status = apr_file_rename(from_path_apr, to_path_apr, pool); } - WIN32_RETRY_LOOP(status, apr_file_rename(from_path_apr, to_path_apr, pool)); +#else + status = apr_file_rename(from_path_apr, to_path_apr, pool); #endif /* WIN32 || __OS2__ */ if (status) Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/conflicts.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_wc/conflicts.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_wc/conflicts.c Mon Jun 29 13:42:10 2015 @@ -2323,6 +2323,17 @@ svn_wc__read_conflicts(const apr_array_h return SVN_NO_ERROR; } +svn_error_t * +svn_wc__read_conflict_descriptions2_t(const apr_array_header_t **conflicts, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_wc__read_conflicts(conflicts, NULL, wc_ctx->db, local_abspath, + FALSE, FALSE, result_pool, scratch_pool); +} + /*** Resolving a conflict automatically ***/ Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c (original) +++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c Mon Jun 29 13:42:10 2015 @@ -746,7 +746,7 @@ request_body_to_string(svn_string_t **re int seen_eos; apr_status_t status; apr_off_t total_read = 0; - apr_off_t limit_req_body = ap_get_limit_req_body(r); + apr_off_t limit_req_body = ap_get_limit_xml_body(r); int result = HTTP_BAD_REQUEST; const char *content_length_str; char *endp; Modified: subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.c (original) +++ subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.c Mon Jun 29 13:42:10 2015 @@ -229,7 +229,7 @@ operation_str(svn_wc_operation_t operati svn_error_t * svn_cl__get_human_readable_prop_conflict_description( const char **desc, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool) { const char *reason_str, *action_str; @@ -288,7 +288,7 @@ svn_cl__get_human_readable_prop_conflict svn_error_t * svn_cl__get_human_readable_tree_conflict_description( const char **desc, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool) { const char *action, *reason, *operation; @@ -301,32 +301,26 @@ svn_cl__get_human_readable_tree_conflict 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_get_node_kind(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) { - const svn_wc_conflict_version_t *src_left_version; - /* Change is acting on 'src_left' version of the node. */ - src_left_version = svn_client_conflict_get_src_left_version(conflict); - if (src_left_version) - incoming_kind = src_left_version->node_kind; + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + NULL, NULL, &incoming_kind, conflict, pool, pool)); } else if (conflict_action == svn_wc_conflict_action_add || conflict_action == svn_wc_conflict_action_replace) { - const svn_wc_conflict_version_t *src_right_version; - /* 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. */ - src_right_version = svn_client_conflict_get_src_right_version(conflict); - if (src_right_version) - incoming_kind = src_right_version->node_kind; + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location( + NULL, NULL, &incoming_kind, conflict, pool, pool)); } reason = local_reason_str(conflict_node_kind, conflict_reason, @@ -380,13 +374,16 @@ svn_cl__get_human_readable_action_descri /* Helper for svn_cl__append_tree_conflict_info_xml(). - * Appends the attributes of the given VERSION to ATT_HASH. + * Appends the repository location of a conflicted node 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, + const char *repos_root_url, + const char *repos_relpath, + svn_revnum_t peg_rev, + svn_node_kind_t node_kind, apr_pool_t *pool) { apr_hash_t *att_hash = apr_hash_make(pool); @@ -394,18 +391,17 @@ add_conflict_version_xml(svn_stringbuf_t svn_hash_sets(att_hash, "side", side); - if (version->repos_url) - svn_hash_sets(att_hash, "repos-url", version->repos_url); + if (repos_root_url) + svn_hash_sets(att_hash, "repos-url", repos_root_url); - if (version->path_in_repos) - svn_hash_sets(att_hash, "path-in-repos", version->path_in_repos); + if (repos_relpath) + svn_hash_sets(att_hash, "path-in-repos", repos_relpath); - if (SVN_IS_VALID_REVNUM(version->peg_rev)) - svn_hash_sets(att_hash, "revision", apr_ltoa(pool, version->peg_rev)); + if (SVN_IS_VALID_REVNUM(peg_rev)) + svn_hash_sets(att_hash, "revision", apr_ltoa(pool, peg_rev)); - if (version->node_kind != svn_node_unknown) - svn_hash_sets(att_hash, "kind", - svn_cl__node_kind_str_xml(version->node_kind)); + if (node_kind != svn_node_unknown) + svn_hash_sets(att_hash, "kind", svn_cl__node_kind_str_xml(node_kind)); svn_xml_make_open_tag_hash(pstr, pool, svn_xml_self_closing, "version", att_hash); @@ -415,13 +411,15 @@ add_conflict_version_xml(svn_stringbuf_t static svn_error_t * append_tree_conflict_info_xml(svn_stringbuf_t *str, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool) { apr_hash_t *att_hash = apr_hash_make(pool); const char *tmp; - const svn_wc_conflict_version_t *src_left_version; - const svn_wc_conflict_version_t *src_right_version; + const char *repos_root_url; + const char *repos_relpath; + svn_revnum_t peg_rev; + svn_node_kind_t node_kind; svn_hash_sets(att_hash, "victim", svn_dirent_basename( @@ -429,7 +427,7 @@ append_tree_conflict_info_xml(svn_string svn_hash_sets(att_hash, "kind", svn_cl__node_kind_str_xml( - svn_client_conflict_get_node_kind(conflict))); + svn_client_conflict_tree_get_victim_node_kind(conflict))); svn_hash_sets(att_hash, "operation", svn_cl__operation_str_xml( @@ -449,19 +447,30 @@ append_tree_conflict_info_xml(svn_string /* Add child tags for OLDER_VERSION and THEIR_VERSION. */ - src_left_version = svn_client_conflict_get_src_left_version(conflict); - if (src_left_version) - SVN_ERR(add_conflict_version_xml(&str, - "source-left", - src_left_version, - pool)); - - src_right_version = svn_client_conflict_get_src_right_version(conflict); - if (src_right_version) + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict, + pool, pool)); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + pool, + pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-left", + repos_root_url, repos_relpath, peg_rev, + node_kind, pool)); + + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + pool, + pool)); + if (repos_root_url && repos_relpath) SVN_ERR(add_conflict_version_xml(&str, "source-right", - src_right_version, - pool)); + repos_root_url, repos_relpath, peg_rev, + node_kind, pool)); svn_xml_make_close_tag(&str, pool, "tree-conflict"); @@ -470,15 +479,17 @@ append_tree_conflict_info_xml(svn_string svn_error_t * svn_cl__append_conflict_info_xml(svn_stringbuf_t *str, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *scratch_pool) { apr_hash_t *att_hash; const char *kind; svn_wc_conflict_kind_t conflict_kind; svn_wc_operation_t conflict_operation; - const svn_wc_conflict_version_t *src_left_version; - const svn_wc_conflict_version_t *src_right_version; + const char *repos_root_url; + const char *repos_relpath; + svn_revnum_t peg_rev; + svn_node_kind_t node_kind; conflict_kind = svn_client_conflict_get_kind(conflict); conflict_operation = svn_client_conflict_get_operation(conflict); @@ -507,45 +518,66 @@ svn_cl__append_conflict_info_xml(svn_str svn_xml_make_open_tag_hash(&str, scratch_pool, svn_xml_normal, "conflict", att_hash); - src_left_version = svn_client_conflict_get_src_left_version(conflict); - if (src_left_version) - SVN_ERR(add_conflict_version_xml(&str, - "source-left", - src_left_version, - scratch_pool)); - - src_right_version = svn_client_conflict_get_src_right_version(conflict); - if (src_right_version) - SVN_ERR(add_conflict_version_xml(&str, - "source-right", - src_right_version, - scratch_pool)); + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict, + scratch_pool, scratch_pool)); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-left", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); + + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); + if (repos_root_url && repos_relpath) + SVN_ERR(add_conflict_version_xml(&str, "source-right", + repos_root_url, repos_relpath, peg_rev, + node_kind, scratch_pool)); switch (conflict_kind) { + const char *base_abspath; + const char *my_abspath; + const char *their_abspath; + case svn_wc_conflict_kind_text: + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, + &their_abspath, + conflict, scratch_pool, + scratch_pool)); /* "<prev-base-file> xx </prev-base-file>" */ svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prev-base-file", - svn_client_conflict_get_base_abspath(conflict)); + &str, scratch_pool, "prev-base-file", base_abspath); /* "<prev-wc-file> xx </prev-wc-file>" */ svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prev-wc-file", - svn_client_conflict_get_my_abspath(conflict)); + &str, scratch_pool, "prev-wc-file", my_abspath); /* "<cur-base-file> xx </cur-base-file>" */ svn_cl__xml_tagged_cdata( - &str, scratch_pool, "cur-base-file", - svn_client_conflict_get_their_abspath(conflict)); + &str, scratch_pool, "cur-base-file", their_abspath); break; case svn_wc_conflict_kind_property: - /* "<prop-file> xx </prop-file>" */ - svn_cl__xml_tagged_cdata( - &str, scratch_pool, "prop-file", - svn_client_conflict_get_their_abspath(conflict)); + { + const char *reject_abspath; + + /* "<prop-file> xx </prop-file>" */ + reject_abspath = + svn_client_conflict_prop_get_reject_abspath(conflict); + svn_cl__xml_tagged_cdata( + &str, scratch_pool, "prop-file", reject_abspath); + } break; default: Modified: subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.h?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.h (original) +++ subversion/branches/move-tracking-2/subversion/svn/cl-conflicts.h Mon Jun 29 13:42:10 2015 @@ -31,6 +31,7 @@ #include "svn_types.h" #include "svn_string.h" +#include "svn_client.h" #include "svn_wc.h" #ifdef __cplusplus @@ -48,7 +49,7 @@ extern "C" { svn_error_t * svn_cl__get_human_readable_prop_conflict_description( const char **desc, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool); /** @@ -60,7 +61,7 @@ svn_cl__get_human_readable_prop_conflict svn_error_t * svn_cl__get_human_readable_tree_conflict_description( const char **desc, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool); /* Like svn_cl__get_human_readable_tree_conflict_description but @@ -80,7 +81,7 @@ svn_cl__get_human_readable_action_descri svn_error_t * svn_cl__append_conflict_info_xml( svn_stringbuf_t *str, - const svn_wc_conflict_description2_t *conflict, + const svn_client_conflict_t *conflict, apr_pool_t *pool); #ifdef __cplusplus Modified: subversion/branches/move-tracking-2/subversion/svn/cl.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svn/cl.h?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svn/cl.h (original) +++ subversion/branches/move-tracking-2/subversion/svn/cl.h Mon Jun 29 13:42:10 2015 @@ -777,15 +777,18 @@ svn_cl__args_to_target_array_print_reser svn_boolean_t keep_dest_origpath_on_truepath_collision, apr_pool_t *pool); -/* Return a string showing NODE's kind, URL and revision, to the extent that - * that information is available in NODE. If NODE itself is NULL, this prints - * just a 'none' node kind. +/* Return a string showing a conflicted node's kind, URL and revision, + * to the extent that that information is available. If REPOS_ROOT_URL or + * REPOS_RELPATH are NULL, this prints just a 'none' node kind. * WC_REPOS_ROOT_URL should reflect the target working copy's repository - * root URL. If NODE is from that same URL, the printed URL is abbreviated + * root URL. If the node is from that same URL, the printed URL is abbreviated * to caret notation (^/). WC_REPOS_ROOT_URL may be NULL, in which case * this function tries to print the conflicted node's complete URL. */ const char * -svn_cl__node_description(const svn_wc_conflict_version_t *node, +svn_cl__node_description(const char *repos_root_url, + const char *repos_relpath, + svn_revnum_t peg_rev, + svn_node_kind_t node_kind, const char *wc_repos_root_URL, apr_pool_t *pool); Modified: subversion/branches/move-tracking-2/subversion/svn/conflict-callbacks.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svn/conflict-callbacks.c?rev=1688213&r1=1688212&r2=1688213&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svn/conflict-callbacks.c (original) +++ subversion/branches/move-tracking-2/subversion/svn/conflict-callbacks.c Mon Jun 29 13:42:10 2015 @@ -128,9 +128,10 @@ svn_cl__accept_from_word(const char *wor /* Print on stdout a diff that shows incoming conflicting changes - * corresponding to the conflict described in DESC. */ + * corresponding to the conflict described in CONFLICT. */ static svn_error_t * -show_diff(const svn_wc_conflict_description2_t *desc, +show_diff(const svn_client_conflict_t *conflict, + const char *merged_abspath, const char *path_prefix, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -141,10 +142,13 @@ show_diff(const svn_wc_conflict_descript svn_diff_t *diff; svn_stream_t *output; svn_diff_file_options_t *options; - const char *merged_file; + const char *my_abspath; + const char *their_abspath; - merged_file = svn_client_conflict_get_merged_file(desc); - if (merged_file) + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, NULL, + &their_abspath, + conflict, pool, pool)); + if (merged_abspath) { /* For conflicts recorded by the 'merge' operation, show a diff between * 'mine' (the working version of the file as it appeared before the @@ -158,26 +162,26 @@ show_diff(const svn_wc_conflict_descript * * This way, the diff is always minimal and clearly identifies changes * brought into the working copy by the update/switch/merge operation. */ - if (svn_client_conflict_get_operation(desc) == svn_wc_operation_merge) + if (svn_client_conflict_get_operation(conflict) == svn_wc_operation_merge) { - path1 = svn_client_conflict_get_my_abspath(desc); + path1 = my_abspath; label1 = _("MINE"); } else { - path1 = svn_client_conflict_get_their_abspath(desc); + path1 = their_abspath; label1 = _("THEIRS"); } - path2 = merged_file; + path2 = merged_abspath; label2 = _("MERGED"); } else { /* There's no merged file, but we can show the difference between mine and theirs. */ - path1 = svn_client_conflict_get_their_abspath(desc); + path1 = their_abspath; label1 = _("THEIRS"); - path2 = svn_client_conflict_get_my_abspath(desc); + path2 = my_abspath; label2 = _("MINE"); } @@ -206,9 +210,9 @@ show_diff(const svn_wc_conflict_descript /* Print on stdout just the conflict hunks of a diff among the 'base', 'their' - * and 'my' files of DESC. */ + * and 'my' files of CONFLICT. */ static svn_error_t * -show_conflicts(const svn_wc_conflict_description2_t *desc, +show_conflicts(const svn_client_conflict_t *conflict, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -216,22 +220,22 @@ show_conflicts(const svn_wc_conflict_des svn_diff_t *diff; svn_stream_t *output; svn_diff_file_options_t *options; - + const char *base_abspath; + const char *my_abspath; + const char *their_abspath; + + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, &their_abspath, + conflict, pool, pool)); options = svn_diff_file_options_create(pool); options->ignore_eol_style = TRUE; SVN_ERR(svn_stream_for_stdout(&output, pool)); - SVN_ERR(svn_diff_file_diff3_2(&diff, - svn_client_conflict_get_base_abspath(desc), - svn_client_conflict_get_my_abspath(desc), - svn_client_conflict_get_their_abspath(desc), + SVN_ERR(svn_diff_file_diff3_2(&diff, base_abspath, my_abspath, their_abspath, options, pool)); /* ### Consider putting the markers/labels from ### svn_wc__merge_internal in the conflict description. */ return svn_diff_file_output_merge3( - output, diff, - svn_client_conflict_get_base_abspath(desc), - svn_client_conflict_get_my_abspath(desc), - svn_client_conflict_get_their_abspath(desc), + output, diff, base_abspath, my_abspath, their_abspath, _("||||||| ORIGINAL"), _("<<<<<<< MINE (select with 'mc')"), _(">>>>>>> THEIRS (select with 'tc')"), @@ -245,61 +249,49 @@ show_conflicts(const svn_wc_conflict_des /* Perform a 3-way merge of the conflicting values of a property, * and write the result to the OUTPUT stream. * - * If MERGED_ABSPATH is non-NULL, use it as 'my' version instead of - * DESC->MY_ABSPATH. + * If MERGED_PROPVAL is non-NULL, use it as 'my' version instead of + * MY_ABSPATH. * * Assume the values are printable UTF-8 text. */ static svn_error_t * merge_prop_conflict(svn_stream_t *output, - const svn_wc_conflict_description2_t *desc, - const char *merged_abspath, + const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, + const svn_string_t *merged_propval, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); svn_diff_file_options_t *options = svn_diff_file_options_create(pool); svn_diff_t *diff; - /* If any of the property values is missing, use an empty file instead + /* If any of the property values is missing, use an empty value instead * for the purpose of showing a diff. */ - if (! base_abspath || ! my_abspath || ! their_abspath) - { - const char *empty_file; - - SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file, - NULL, svn_io_file_del_on_pool_cleanup, - pool, pool)); - if (! base_abspath) - base_abspath = empty_file; - if (! my_abspath) - my_abspath = empty_file; - if (! their_abspath) - their_abspath = empty_file; - } - + if (base_propval == NULL) + base_propval = svn_string_create_empty(pool); + if (my_propval == NULL) + my_propval = svn_string_create_empty(pool); + if (my_propval == NULL) + my_propval = svn_string_create_empty(pool); + options->ignore_eol_style = TRUE; - SVN_ERR(svn_diff_file_diff3_2(&diff, - base_abspath, - merged_abspath ? merged_abspath : my_abspath, - their_abspath, - options, pool)); - SVN_ERR(svn_diff_file_output_merge3(output, diff, - base_abspath, - merged_abspath ? merged_abspath - : my_abspath, - their_abspath, - _("||||||| ORIGINAL"), - _("<<<<<<< MINE"), - _(">>>>>>> THEIRS"), - "=======", - svn_diff_conflict_display_modified_original_latest, - cancel_func, - cancel_baton, - pool)); + SVN_ERR(svn_diff_mem_string_diff3(&diff, base_propval, + merged_propval ? + merged_propval : my_propval, + their_propval, options, pool)); + SVN_ERR(svn_diff_mem_string_output_merge3( + output, diff, base_propval, + merged_propval ? merged_propval : my_propval, their_propval, + _("||||||| ORIGINAL"), + _("<<<<<<< MINE"), + _(">>>>>>> THEIRS"), + "=======", + svn_diff_conflict_display_modified_original_latest, + cancel_func, + cancel_baton, + pool)); return SVN_NO_ERROR; } @@ -312,8 +304,10 @@ merge_prop_conflict(svn_stream_t *output * Assume the values are printable UTF-8 text. */ static svn_error_t * -show_prop_conflict(const svn_wc_conflict_description2_t *desc, - const char *merged_abspath, +show_prop_conflict(const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, + const svn_string_t *merged_propval, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -321,13 +315,13 @@ show_prop_conflict(const svn_wc_conflict svn_stream_t *output; SVN_ERR(svn_stream_for_stdout(&output, pool)); - SVN_ERR(merge_prop_conflict(output, desc, merged_abspath, - cancel_func, cancel_baton, pool)); + SVN_ERR(merge_prop_conflict(output, base_propval, my_propval, their_propval, + merged_propval, cancel_func, cancel_baton, pool)); return SVN_NO_ERROR; } -/* Run an external editor, passing it the MERGED_FILE, or, if the +/* Run an external editor, passing it the MERGED_ABSPATH, or, if the * 'merged' file is null, return an error. The tool to use is determined by * B->editor_cmd, B->config and environment variables; see * svn_cl__edit_file_externally() for details. @@ -338,15 +332,15 @@ show_prop_conflict(const svn_wc_conflict * return that error. */ static svn_error_t * open_editor(svn_boolean_t *performed_edit, - const char *merged_file, + const char *merged_abspath, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *pool) { svn_error_t *err; - if (merged_file) + if (merged_abspath) { - err = svn_cmdline__edit_file_externally(merged_file, b->editor_cmd, + err = svn_cmdline__edit_file_externally(merged_abspath, b->editor_cmd, b->config, pool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR || err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)) @@ -371,12 +365,16 @@ open_editor(svn_boolean_t *performed_edi return SVN_NO_ERROR; } -/* Run an external editor, passing it the 'merged' property in DESC. +/* Run an external editor on the merged property value with conflict markers. + * Return the edited result in *MERGED_PROPVAL. + * If the edit is aborted, set *MERGED_ABSPATH and *MERGED_PROPVAL to NULL. * The tool to use is determined by B->editor_cmd, B->config and * environment variables; see svn_cl__edit_file_externally() for details. */ static svn_error_t * -edit_prop_conflict(const char **merged_file_path, - const svn_wc_conflict_description2_t *desc, +edit_prop_conflict(const svn_string_t **merged_propval, + const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -391,14 +389,23 @@ edit_prop_conflict(const char **merged_f result_pool, scratch_pool)); merged_prop = svn_stream_from_aprfile2(file, TRUE /* disown */, scratch_pool); - SVN_ERR(merge_prop_conflict(merged_prop, desc, NULL, + SVN_ERR(merge_prop_conflict(merged_prop, base_propval, my_propval, + their_propval, NULL, b->pb->cancel_func, b->pb->cancel_baton, scratch_pool)); SVN_ERR(svn_stream_close(merged_prop)); SVN_ERR(svn_io_file_flush(file, scratch_pool)); SVN_ERR(open_editor(&performed_edit, file_path, b, scratch_pool)); - *merged_file_path = (performed_edit ? file_path : NULL); + if (performed_edit) + { + svn_stringbuf_t *buf; + + SVN_ERR(svn_stringbuf_from_file2(&buf, file_path, scratch_pool)); + *merged_propval = svn_string_create_from_buf(buf, result_pool); + } + else + *merged_propval = NULL; return SVN_NO_ERROR; } @@ -695,13 +702,13 @@ prompt_user(const resolver_option_t **op return SVN_NO_ERROR; } -/* Ask the user what to do about the text conflict described by DESC. +/* Ask the user what to do about the text conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_text_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *scratch_pool) { @@ -715,15 +722,19 @@ handle_text_conflict(svn_wc_conflict_res give them a rational basis for choosing (r)esolved? */ svn_boolean_t knows_something = FALSE; const char *local_relpath; - const char *local_abspath = svn_client_conflict_get_local_abspath(desc); - svn_boolean_t is_binary = svn_client_conflict_get_is_binary(desc); - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); - const char *merged_file = svn_client_conflict_get_merged_file(desc); - - SVN_ERR_ASSERT(svn_client_conflict_get_kind(desc) == - svn_wc_conflict_kind_text); + const char *local_abspath = svn_client_conflict_get_local_abspath(conflict); + const char *mime_type = svn_client_conflict_text_get_mime_type(conflict); + svn_boolean_t is_binary = mime_type ? svn_mime_type_is_binary(mime_type) + : FALSE; + const char *base_abspath; + const char *my_abspath; + const char *their_abspath; + const char *merged_abspath = svn_client_conflict_get_local_abspath(conflict); + + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, &their_abspath, + conflict, scratch_pool, + scratch_pool)); local_relpath = svn_cl__local_style_skip_ancestor(b->path_prefix, local_abspath, @@ -747,7 +758,7 @@ handle_text_conflict(svn_wc_conflict_res scenario), or if no base is available, we can show a diff between mine and theirs. */ if (!is_binary && - ((merged_file && base_abspath) + ((merged_abspath && base_abspath) || (!base_abspath && my_abspath && their_abspath))) diff_allowed = TRUE; @@ -833,7 +844,7 @@ handle_text_conflict(svn_wc_conflict_res "files not available.\n\n"))); continue; } - SVN_ERR(show_conflicts(desc, + SVN_ERR(show_conflicts(conflict, b->pb->cancel_func, b->pb->cancel_baton, iterpool)); @@ -850,14 +861,14 @@ handle_text_conflict(svn_wc_conflict_res continue; } - SVN_ERR(show_diff(desc, b->path_prefix, + SVN_ERR(show_diff(conflict, merged_abspath, b->path_prefix, b->pb->cancel_func, b->pb->cancel_baton, iterpool)); knows_something = TRUE; } else if (strcmp(opt->code, "e") == 0 || strcmp(opt->code, ":-E") == 0) { - SVN_ERR(open_editor(&performed_edit, merged_file, b, iterpool)); + SVN_ERR(open_editor(&performed_edit, merged_abspath, b, iterpool)); if (performed_edit) knows_something = TRUE; } @@ -878,7 +889,7 @@ handle_text_conflict(svn_wc_conflict_res err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, NULL, iterpool); if (err) @@ -893,7 +904,7 @@ handle_text_conflict(svn_wc_conflict_res base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->path_prefix, b->editor_cmd, @@ -931,9 +942,9 @@ handle_text_conflict(svn_wc_conflict_res { /* ### This check should be earlier as it's nasty to offer an option * and then when the user chooses it say 'Invalid option'. */ - /* ### 'merged_file' shouldn't be necessary *before* we launch the + /* ### 'merged_abspath' shouldn't be necessary *before* we launch the * resolver: it should be the *result* of doing so. */ - if (base_abspath && their_abspath && my_abspath && merged_file) + if (base_abspath && their_abspath && my_abspath && merged_abspath) { svn_error_t *err; char buf[1024]; @@ -942,7 +953,7 @@ handle_text_conflict(svn_wc_conflict_res err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, NULL, iterpool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL || @@ -973,7 +984,7 @@ handle_text_conflict(svn_wc_conflict_res base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->path_prefix, b->editor_cmd, @@ -1022,41 +1033,40 @@ handle_text_conflict(svn_wc_conflict_res return SVN_NO_ERROR; } -/* Ask the user what to do about the property conflict described by DESC. +/* Ask the user what to do about the property conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_prop_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_pool_t *iterpool; const char *message; - const char *merged_file_path = NULL; + const svn_string_t *merged_propval = NULL; svn_boolean_t resolved_allowed = FALSE; - - /* ### Work around a historical bug in the provider: the path to the - * conflict description file was put in the 'theirs' field, and - * 'theirs' was put in the 'merged' field. */ - ((svn_wc_conflict_description2_t *)desc)->their_abspath = desc->merged_file; - ((svn_wc_conflict_description2_t *)desc)->merged_file = NULL; - - SVN_ERR_ASSERT(svn_client_conflict_get_kind(desc) == - svn_wc_conflict_kind_property); + const svn_string_t *base_propval; + const svn_string_t *my_propval; + const svn_string_t *their_propval; + + SVN_ERR(svn_client_conflict_prop_get_propvals(NULL, &my_propval, + &base_propval, &their_propval, + conflict, scratch_pool)); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, _("Conflict for property '%s' discovered" " on '%s'.\n"), - svn_client_conflict_get_property_name(desc), + svn_client_conflict_prop_get_propname(conflict), svn_cl__local_style_skip_ancestor( b->path_prefix, - svn_client_conflict_get_local_abspath(desc), + svn_client_conflict_get_local_abspath(conflict), scratch_pool))); - SVN_ERR(svn_cl__get_human_readable_prop_conflict_description(&message, desc, + 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)); @@ -1094,15 +1104,17 @@ handle_prop_conflict(svn_wc_conflict_res } else if (strcmp(opt->code, "dc") == 0) { - SVN_ERR(show_prop_conflict(desc, merged_file_path, + SVN_ERR(show_prop_conflict(base_propval, my_propval, their_propval, + merged_propval, b->pb->cancel_func, b->pb->cancel_baton, scratch_pool)); } else if (strcmp(opt->code, "e") == 0) { - SVN_ERR(edit_prop_conflict(&merged_file_path, desc, b, - result_pool, scratch_pool)); - resolved_allowed = (merged_file_path != NULL); + SVN_ERR(edit_prop_conflict(&merged_propval, + base_propval, my_propval, their_propval, + b, result_pool, scratch_pool)); + resolved_allowed = (merged_propval != NULL); } else if (strcmp(opt->code, "r") == 0) { @@ -1114,7 +1126,7 @@ handle_prop_conflict(svn_wc_conflict_res continue; } - result->merged_file = merged_file_path; + result->merged_value = merged_propval; result->choice = svn_wc_conflict_choose_merged; break; } @@ -1129,43 +1141,58 @@ handle_prop_conflict(svn_wc_conflict_res return SVN_NO_ERROR; } -/* Ask the user what to do about the tree conflict described by DESC. +/* Ask the user what to do about the tree conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_tree_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *scratch_pool) { const char *readable_desc; const char *src_left_version; const char *src_right_version; + const char *repos_root_url; + const char *repos_relpath; + svn_revnum_t peg_rev; + svn_node_kind_t node_kind; apr_pool_t *iterpool; - + SVN_ERR(svn_cl__get_human_readable_tree_conflict_description( - &readable_desc, desc, scratch_pool)); + &readable_desc, conflict, scratch_pool)); SVN_ERR(svn_cmdline_fprintf( stderr, scratch_pool, _("Tree conflict on '%s'\n > %s\n"), svn_cl__local_style_skip_ancestor(b->path_prefix, - svn_client_conflict_get_local_abspath(desc), scratch_pool), + svn_client_conflict_get_local_abspath(conflict), scratch_pool), readable_desc)); + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict, + scratch_pool, scratch_pool)); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); src_left_version = - svn_cl__node_description( - svn_client_conflict_get_src_left_version(desc), - svn_client_conflict_get_src_left_version(desc)->repos_url, - scratch_pool); + svn_cl__node_description(repos_root_url, repos_relpath, peg_rev, + node_kind, repos_root_url, scratch_pool); if (src_left_version) SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s: %s\n", _("Source left"), src_left_version)); + + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); src_right_version = - svn_cl__node_description( - svn_client_conflict_get_src_right_version(desc), - svn_client_conflict_get_src_right_version(desc)->repos_url, - scratch_pool); + svn_cl__node_description(repos_root_url, repos_relpath, peg_rev, + node_kind, repos_root_url, scratch_pool); if (src_right_version) SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s: %s\n", _("Source right"), src_right_version)); @@ -1180,12 +1207,14 @@ handle_tree_conflict(svn_wc_conflict_res tc_opts = tree_conflict_options; - if (svn_client_conflict_get_operation(desc) == svn_wc_operation_update || - svn_client_conflict_get_operation(desc) == svn_wc_operation_switch) + if (svn_client_conflict_get_operation(conflict) == + svn_wc_operation_update || + svn_client_conflict_get_operation(conflict) == + svn_wc_operation_switch) { svn_wc_conflict_reason_t reason; - reason = svn_client_conflict_get_local_change(desc); + reason = svn_client_conflict_get_local_change(conflict); if (reason == svn_wc_conflict_reason_moved_away) { tc_opts = tree_conflict_options_update_moved_away; @@ -1193,9 +1222,10 @@ handle_tree_conflict(svn_wc_conflict_res else if (reason == svn_wc_conflict_reason_deleted || reason == svn_wc_conflict_reason_replaced) { - if (svn_client_conflict_get_incoming_change(desc) == + if (svn_client_conflict_get_incoming_change(conflict) == svn_wc_conflict_action_edit && - svn_client_conflict_get_node_kind(desc) == svn_node_dir) + svn_client_conflict_tree_get_victim_node_kind(conflict) == + svn_node_dir) tc_opts = tree_conflict_options_update_edit_deleted_dir; } } @@ -1225,17 +1255,24 @@ handle_tree_conflict(svn_wc_conflict_res /* The body of svn_cl__conflict_func_interactive(). */ static svn_error_t * conflict_func_interactive(svn_wc_conflict_result_t **result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_cl__interactive_conflict_baton_t *b = baton; svn_error_t *err; - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); - const char *merged_file = svn_client_conflict_get_merged_file(desc); + const char *base_abspath = NULL; + const char *my_abspath = NULL; + const char *their_abspath = NULL; + const char *merged_abspath = svn_client_conflict_get_local_abspath(conflict); + + if (svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_text) + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, + &their_abspath, + conflict, scratch_pool, + scratch_pool)); /* Start out assuming we're going to postpone the conflict. */ *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, @@ -1254,10 +1291,6 @@ conflict_func_interactive(svn_wc_conflic (*result)->choice = svn_wc_conflict_choose_base; return SVN_NO_ERROR; case svn_cl__accept_working: - /* If the caller didn't merge the property values, then I guess - * 'choose working' means 'choose mine'... */ - if (! merged_file) - (*result)->merged_file = my_abspath; (*result)->choice = svn_wc_conflict_choose_merged; return SVN_NO_ERROR; case svn_cl__accept_mine_conflict: @@ -1273,7 +1306,7 @@ conflict_func_interactive(svn_wc_conflic (*result)->choice = svn_wc_conflict_choose_theirs_full; return SVN_NO_ERROR; case svn_cl__accept_edit: - if (merged_file) + if (merged_abspath) { if (b->external_failed) { @@ -1281,7 +1314,7 @@ conflict_func_interactive(svn_wc_conflic return SVN_NO_ERROR; } - err = svn_cmdline__edit_file_externally(merged_file, + err = svn_cmdline__edit_file_externally(merged_abspath, b->editor_cmd, b->config, scratch_pool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR || @@ -1304,7 +1337,7 @@ conflict_func_interactive(svn_wc_conflic /* else, fall through to prompting. */ break; case svn_cl__accept_launch: - if (base_abspath && their_abspath && my_abspath && merged_file) + if (base_abspath && their_abspath && my_abspath && merged_abspath) { svn_boolean_t remains_in_conflict; const char *local_abspath; @@ -1315,11 +1348,11 @@ conflict_func_interactive(svn_wc_conflic return SVN_NO_ERROR; } - local_abspath = svn_client_conflict_get_local_abspath(desc); + local_abspath = svn_client_conflict_get_local_abspath(conflict); err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, &remains_in_conflict, @@ -1364,16 +1397,18 @@ conflict_func_interactive(svn_wc_conflic Conflicting edits on a file's text, or Conflicting edits on a property. */ - if (((svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_text) - && (svn_client_conflict_get_incoming_change(desc) == + if (((svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_text) + && (svn_client_conflict_get_incoming_change(conflict) == svn_wc_conflict_action_edit) - && (svn_client_conflict_get_local_change(desc) == + && (svn_client_conflict_get_local_change(conflict) == svn_wc_conflict_reason_edited))) - SVN_ERR(handle_text_conflict(*result, desc, b, scratch_pool)); - else if (svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_property) - SVN_ERR(handle_prop_conflict(*result, desc, b, result_pool, scratch_pool)); - else if (svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_tree) - SVN_ERR(handle_tree_conflict(*result, desc, b, scratch_pool)); + SVN_ERR(handle_text_conflict(*result, conflict, b, scratch_pool)); + else if (svn_client_conflict_get_kind(conflict) == + svn_wc_conflict_kind_property) + SVN_ERR(handle_prop_conflict(*result, conflict, b, result_pool, + scratch_pool)); + else if (svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_tree) + SVN_ERR(handle_tree_conflict(*result, conflict, b, scratch_pool)); else /* other types of conflicts -- do nothing about them. */ { @@ -1391,8 +1426,12 @@ svn_cl__conflict_func_interactive(svn_wc apr_pool_t *scratch_pool) { svn_cl__interactive_conflict_baton_t *b = baton; + svn_client_conflict_t *conflict; - SVN_ERR(conflict_func_interactive(result, desc, baton, + SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, desc, + scratch_pool, + scratch_pool)); + SVN_ERR(conflict_func_interactive(result, conflict, baton, result_pool, scratch_pool)); /* If we are resolving a conflict, adjust the summary of conflicts. */ @@ -1400,11 +1439,11 @@ svn_cl__conflict_func_interactive(svn_wc { const char *local_path = svn_cl__local_style_skip_ancestor( - b->path_prefix, svn_client_conflict_get_local_abspath(desc), + b->path_prefix, svn_client_conflict_get_local_abspath(conflict), scratch_pool); svn_cl__conflict_stats_resolved(b->conflict_stats, local_path, - svn_client_conflict_get_kind(desc)); + svn_client_conflict_get_kind(conflict)); } return SVN_NO_ERROR; }
