Author: stefan2 Date: Thu Aug 13 13:31:09 2015 New Revision: 1695708 URL: http://svn.apache.org/r1695708 Log: On the svn-mergeinfo-normalizer branch: Implement the last big feature, detecting whether mergeinfo for a deleted branch is still relevant because copies of that branch or parts therefore still exist @HEAD.
This patch implements the detection of that case. The summary display will be updated in a later commit. * tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h (svn_min__get_copies): Declare new internal API. * tools/client-side/svn-mergeinfo-normalizer/log.c (svn_min__log_t): Add index of all copies ordered by copy-from. (copy_by_source_order): The corresponding comparison function. (svn_min__log): Update constructor. (svn_min__get_copies): Implement the new API. * tools/client-side/svn-mergeinfo-normalizer/logic.c (deletion_state_t): Add a state for "deleted but copies still exists". (show_removed_branch): Handle the new state and add ability to show a surviving copy. (get_copy_target_path): New utility function. (find_surviving_copy): Core logic for finding a surviving copy. (remove_obsolete_line): Detect and handle the new case. Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c?rev=1695708&r1=1695707&r2=1695708&view=diff ============================================================================== --- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c (original) +++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c Thu Aug 13 13:31:09 2015 @@ -65,6 +65,7 @@ struct svn_min__log_t apr_array_header_t *entries; apr_array_header_t *copies; + apr_array_header_t *copies_by_source; apr_array_header_t *deletions; svn_boolean_t quiet; @@ -88,6 +89,23 @@ copy_order(const void *lhs, } static int +copy_by_source_order(const void *lhs, + const void *rhs) +{ + const svn_min__copy_t *lhs_copy = *(const svn_min__copy_t * const *)lhs; + const svn_min__copy_t *rhs_copy = *(const svn_min__copy_t * const *)rhs; + + int diff = strcmp(lhs_copy->copyfrom_path, rhs_copy->copyfrom_path); + if (diff) + return diff; + + if (lhs_copy->copyfrom_revision < rhs_copy->copyfrom_revision) + return -1; + + return lhs_copy->copyfrom_revision == rhs_copy->copyfrom_revision ? 0 : 1; +} + +static int deletion_order(const void *lhs, const void *rhs) { @@ -267,8 +285,11 @@ svn_min__log(svn_min__log_t **log, ctx, scratch_pool)); + result->copies_by_source = apr_array_copy(result_pool, result->copies); + svn_sort__array_reverse(result->entries, scratch_pool); svn_sort__array(result->copies, copy_order); + svn_sort__array(result->copies_by_source, copy_by_source_order); svn_sort__array(result->deletions, deletion_order); if (!baton->opt_state->quiet) @@ -619,6 +640,57 @@ svn_min__find_copy(svn_min__log_t *log, } apr_array_header_t * +svn_min__get_copies(svn_min__log_t *log, + const char *path, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *result = apr_array_make(result_pool, 0, + sizeof(svn_min__copy_t *)); + const svn_min__copy_t **copies = (void *)log->copies_by_source->elts; + int idx; + + /* Find all sub-tree copies, including PATH. */ + svn_min__copy_t *to_find = apr_pcalloc(scratch_pool, sizeof(*to_find)); + to_find->copyfrom_path = path; + to_find->copyfrom_revision = end_rev; + + for (idx = svn_sort__bsearch_lower_bound(log->copies_by_source, + &to_find, + copy_by_source_order); + (idx < log->copies->nelts) + && svn_dirent_is_ancestor(path, copies[idx]->copyfrom_path); + ++idx) + { + if (copies[idx]->copyfrom_revision <= start_rev) + APR_ARRAY_PUSH(result, const svn_min__copy_t *) = copies[idx]; + } + + /* Find all parent copies. */ + while (!svn_fspath__is_root(to_find->copyfrom_path, + strlen(to_find->copyfrom_path))) + { + to_find->copyfrom_path = svn_fspath__dirname(to_find->copyfrom_path, + scratch_pool); + + for (idx = svn_sort__bsearch_lower_bound(log->copies_by_source, + &to_find, + copy_by_source_order); + (idx < log->copies->nelts) + && !strcmp(copies[idx]->copyfrom_path, to_find->copyfrom_path) + && (copies[idx]->copyfrom_revision <= start_rev); + ++idx) + { + APR_ARRAY_PUSH(result, const svn_min__copy_t *) = copies[idx]; + } + } + + return result; +} + +apr_array_header_t * svn_min__get_history(svn_min__log_t *log, const char *path, svn_revnum_t start_rev, Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c?rev=1695708&r1=1695707&r2=1695708&view=diff ============================================================================== --- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c (original) +++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c Thu Aug 13 13:31:09 2015 @@ -236,6 +236,7 @@ typedef enum deletion_state_t { ds_exists, ds_implied, + ds_has_copies, ds_deleted } deletion_state_t; @@ -244,6 +245,7 @@ show_removed_branch(const char *subtree_ svn_min__opt_state_t *opt_state, deletion_state_t deletion_state, svn_boolean_t report_non_removals, + const char *surviving_copy, apr_pool_t *scratch_pool) { if (opt_state->verbose) @@ -262,6 +264,18 @@ show_removed_branch(const char *subtree_ subtree_path)); break; + case ds_has_copies: + if (report_non_removals) + { + SVN_ERR(svn_cmdline_printf(scratch_pool, + _(" has SURVIVING COPIES: %s\n"), + subtree_path)); + SVN_ERR(svn_cmdline_printf(scratch_pool, + _(" e.g.: %s\n"), + surviving_copy)); + } + break; + default: break; } @@ -269,6 +283,69 @@ show_removed_branch(const char *subtree_ return SVN_NO_ERROR; } +static const char * +get_copy_target_path(const char *source, + const svn_min__copy_t *copy, + apr_pool_t *result_pool) +{ + if (svn_dirent_is_ancestor(copy->copyfrom_path, source)) + { + const char *relpath = svn_dirent_skip_ancestor(copy->copyfrom_path, + source); + return svn_dirent_join(copy->path, relpath, result_pool); + } + + return apr_pstrdup(result_pool, copy->path); +} + +static svn_error_t* +find_surviving_copy(const char **surviver, + svn_min__log_t *log, + const char *path, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + apr_array_header_t *copies = svn_min__get_copies(log, path, start_rev, + end_rev, scratch_pool, + scratch_pool); + + int i; + *surviver = NULL; + for (i = 0; (i < copies->nelts) && !*surviver; ++i) + { + const char *copy_target; + const svn_min__copy_t *copy; + svn_revnum_t deletion_rev; + svn_pool_clear(iterpool); + + copy = APR_ARRAY_IDX(copies, i, const svn_min__copy_t *); + copy_target = get_copy_target_path(path, copy, iterpool); + + /* Is this a surviving copy? */ + deletion_rev = svn_min__find_deletion(log, copy_target, + SVN_INVALID_REVNUM, + copy->revision, iterpool); + if (SVN_IS_VALID_REVNUM(deletion_rev)) + { + /* Are there surviving sub-copies? */ + SVN_ERR(find_surviving_copy(surviver, log, copy_target, + copy->revision, deletion_rev - 1, + result_pool, iterpool)); + } + else + { + *surviver = apr_pstrdup(result_pool, copy_target); + } + } + + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + static svn_error_t * remove_obsolete_line(deletion_state_t *state, svn_min__branch_lookup_t *lookup, @@ -282,6 +359,7 @@ remove_obsolete_line(deletion_state_t *s apr_pool_t *scratch_pool) { svn_boolean_t deleted; + const char *surviving_copy = NULL; if (!opt_state->remove_obsoletes) { @@ -307,8 +385,22 @@ remove_obsolete_line(deletion_state_t *s SVN_INVALID_REVNUM, creation_rev, scratch_pool); - *state = SVN_IS_VALID_REVNUM(deletion_rev) ? ds_deleted - : ds_implied; + SVN_ERR(find_surviving_copy(&surviving_copy, log, path, + SVN_IS_VALID_REVNUM(deletion_rev) + ? deletion_rev - 1 + : deletion_rev, + creation_rev, + scratch_pool, scratch_pool)); + + if (surviving_copy) + { + *state = ds_has_copies; + } + else + { + *state = SVN_IS_VALID_REVNUM(deletion_rev) ? ds_deleted + : ds_implied; + } } else { @@ -330,7 +422,7 @@ remove_obsolete_line(deletion_state_t *s } SVN_ERR(show_removed_branch(path, opt_state, *state, report_non_removals, - scratch_pool)); + surviving_copy, scratch_pool)); return SVN_NO_ERROR; } Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h?rev=1695708&r1=1695707&r2=1695708&view=diff ============================================================================== --- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h (original) +++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h Thu Aug 13 13:31:09 2015 @@ -217,6 +217,14 @@ svn_min__find_copy(svn_min__log_t *log, apr_pool_t *scratch_pool); apr_array_header_t * +svn_min__get_copies(svn_min__log_t *log, + const char *path, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +apr_array_header_t * svn_min__get_history(svn_min__log_t *log, const char *path, svn_revnum_t start_rev,