You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/12/03 19:58:32 UTC

svn commit: r1717833 - /subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c

Author: rhuijben
Date: Thu Dec  3 18:58:32 2015
New Revision: 1717833

URL: http://svn.apache.org/viewvc?rev=1717833&view=rev
Log:
On the ra-git branch: Implement basic node history tracing.

This enables 'svn log' and 'svn blame' support on individual
file and directory nodes within (libsvn_fs_)git repositories.

This code may need some work to properly handle corner cases,
but it appears to work correctly.

* subversion/libsvn_fs_git/git-history.c
  (includes): Add svn_pools.h.
  (fs_git_commit_history_prev): Use cheaper helper function.
  (fs_git_commit_history_location): Store path in right pool.
  (fs_git_node_history_t): New struct.
  (fs_git_node_history_prev,
   fs_git_node_history_location): New function.
  (fs_git_node_history_vtable): New vtable.
  (svn_fs_git__make_history_node): Implement function.

Modified:
    subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c

Modified: subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c?rev=1717833&r1=1717832&r2=1717833&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_git/git-history.c Thu Dec  3 18:58:32 2015
@@ -21,6 +21,7 @@
  */
 
 #include "svn_types.h"
+#include "svn_pools.h"
 #include "svn_fs.h"
 
 #include "fs_git.h"
@@ -145,18 +146,14 @@ fs_git_commit_history_prev(svn_fs_histor
       cht = apr_pcalloc(result_pool, sizeof(*cht));
 
       /* Copy same commit to new result pool */
-      SVN_ERR(svn_git__commit_lookup(&cht->commit,
-                                     git_commit_owner(prev_commit),
-                                     git_commit_id(prev_commit),
-                                     result_pool));
+      SVN_ERR(svn_git__copy_commit(&cht->commit, prev_commit,
+                                   result_pool));
     }
   else if (git_commit_parentcount(prev_commit) > 0)
     {
       cht = apr_pcalloc(result_pool, sizeof(*cht));
 
-      SVN_ERR(svn_git__commit_lookup(&cht->commit,
-                                     git_commit_owner(prev_commit),
-                                     git_commit_parent_id(prev_commit, 0),
+      SVN_ERR(svn_git__commit_parent(&cht->commit, prev_commit, 0,
                                      result_pool));
     }
   else
@@ -208,7 +205,7 @@ fs_git_commit_history_location(const cha
                                        cht->pool, pool));
       if (cht->path && cht->path[0] != '/')
         {
-          cht->path = apr_pstrcat(pool, "/", cht->path, SVN_VA_NULL);
+          cht->path = apr_pstrcat(cht->pool, "/", cht->path, SVN_VA_NULL);
         }
     }
 
@@ -244,6 +241,161 @@ svn_fs_git__make_history_commit(svn_fs_h
 }
 
 /* ------------------------------------------------------- */
+typedef struct fs_git_node_history_t
+{
+  apr_pool_t *pool;
+  svn_fs_t *fs;
+  const git_commit *commit;
+  const char *relpath;
+
+  svn_revnum_t rev;
+  const char *path;
+  svn_boolean_t last, first;
+} fs_git_node_history_t;
+
+static svn_error_t *
+fs_git_node_history_prev(svn_fs_history_t **prev_history_p,
+                         svn_fs_history_t *history,
+                         svn_boolean_t cross_copies,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  fs_git_node_history_t *p_gnh = history->fsap_data;
+  fs_git_node_history_t *gnh;
+  apr_pool_t *cur_pool = svn_pool_create(result_pool);
+  apr_pool_t *last_pool = svn_pool_create(result_pool);
+
+  /* ### cross_copies is still unused! */
+
+  if (p_gnh->last)
+    {
+      *prev_history_p = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  const git_commit *commit = p_gnh->commit;
+  const git_tree_entry *entry;
+  const char *relpath = p_gnh->relpath;
+
+  if (!p_gnh->first)
+    SVN_ERR(svn_git__commit_parent(&commit, commit, 0, last_pool));
+
+  SVN_ERR(svn_git__commit_tree_entry(&entry, commit, relpath,
+                                     last_pool, cur_pool));
+
+  while (TRUE)
+    {
+      const git_commit *pcommit;
+      const git_tree_entry *pentry;
+      svn_boolean_t modified = FALSE;
+
+      svn_pool_clear(cur_pool);
+
+      if (git_commit_parentcount(commit) == 0)
+        {
+          /* And finally report the revision in which the branch
+             and this path were created */
+          gnh = apr_pcalloc(result_pool, sizeof(*gnh));
+          gnh->pool = result_pool;
+          gnh->fs = p_gnh->fs;
+          gnh->last = TRUE;
+          gnh->rev = SVN_INVALID_REVNUM;
+
+          SVN_ERR(svn_git__copy_commit(&gnh->commit, commit,
+                                       result_pool));
+
+          svn_pool_destroy(cur_pool);
+          svn_pool_destroy(last_pool);
+
+          *prev_history_p = history_make(history->vtable, gnh,
+                                         result_pool);
+          return SVN_NO_ERROR;
+        }
+
+      SVN_ERR(svn_git__commit_parent(&pcommit, commit, 0, cur_pool));
+      SVN_ERR(svn_git__commit_tree_entry(&pentry, pcommit, relpath,
+                                         cur_pool, last_pool));
+
+      if (!pentry)
+        {
+          /* TODO: Follow renames */
+        }
+
+      if (pentry
+          && (git_tree_entry_filemode(pentry) != git_tree_entry_filemode(entry)
+              || git_oid_cmp(git_tree_entry_id(pentry),
+                             git_tree_entry_id(entry))))
+        {
+          modified = TRUE; /* Report as changed */
+        }
+
+      if (modified || !pentry)
+        {
+          /* TODO: Follow in-branch renames */
+
+          /* Report the revision in which this path was created */
+          gnh = apr_pcalloc(result_pool, sizeof(*gnh));
+          gnh->pool = result_pool;
+          gnh->fs = p_gnh->fs;
+          gnh->last = !pentry;
+          gnh->relpath = apr_pstrdup(result_pool, relpath);
+          gnh->rev = SVN_INVALID_REVNUM;
+
+          SVN_ERR(svn_git__copy_commit(&gnh->commit, commit,
+                                       result_pool));
+
+          svn_pool_destroy(cur_pool);
+          svn_pool_destroy(last_pool);
+
+          *prev_history_p = history_make(history->vtable, gnh,
+                                         result_pool);
+          return SVN_NO_ERROR;
+        }
+
+      {
+        apr_pool_t *tmp_pool;
+        commit = pcommit;
+        entry = pentry;
+
+        tmp_pool = last_pool;
+        last_pool = cur_pool;
+        cur_pool = tmp_pool;
+      }
+    }
+}
+
+static svn_error_t *
+fs_git_node_history_location(const char **path,
+                               svn_revnum_t *revision,
+                               svn_fs_history_t *history,
+                               apr_pool_t *pool)
+{
+  fs_git_node_history_t *gnh = history->fsap_data;
+
+  if (!SVN_IS_VALID_REVNUM(gnh->rev))
+    {
+      SVN_ERR(svn_fs_git__db_fetch_rev(&gnh->rev,
+                                       &gnh->path,
+                                       gnh->fs,
+                                       git_commit_id(gnh->commit),
+                                       gnh->pool, pool));
+      if (gnh->path && gnh->path[0] != '/')
+        {
+          gnh->path = apr_pstrcat(pool, "/", gnh->path, SVN_VA_NULL);
+        }
+    }
+
+  *path = apr_pstrdup(pool, gnh->path);
+  *revision = gnh->rev;
+  return SVN_NO_ERROR;
+}
+
+static const history_vtable_t fs_git_node_history_vtable =
+{
+  fs_git_node_history_prev,
+  fs_git_node_history_location
+};
+
 svn_error_t *
 svn_fs_git__make_history_node(svn_fs_history_t **history_p,
                               svn_fs_root_t *root,
@@ -252,5 +404,17 @@ svn_fs_git__make_history_node(svn_fs_his
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
 {
-  return svn_error_create(APR_ENOTIMPL, NULL, NULL);
+  fs_git_node_history_t *gnh = apr_pcalloc(result_pool, sizeof(*gnh));
+
+  gnh->pool = result_pool;
+  gnh->fs = root->fs;
+  gnh->commit = commit;
+  gnh->relpath = apr_pstrdup(result_pool, relpath);
+  gnh->rev = SVN_INVALID_REVNUM;
+  /*gnh->path = NULL;
+  gnh->last = FALSE;*/
+  gnh->first = TRUE;
+
+  *history_p = history_make(&fs_git_node_history_vtable, gnh, result_pool);
+  return SVN_NO_ERROR;
 }