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,


Reply via email to