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/02 01:41:32 UTC
svn commit: r1717561 -
/subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c
Author: rhuijben
Date: Wed Dec 2 00:41:31 2015
New Revision: 1717561
URL: http://svn.apache.org/viewvc?rev=1717561&view=rev
Log:
On the ra-git branch: Implement fetching the list of changed paths in a
commit. This makes svnadmin dump and svn log -v quite usable on my test
repository with just a single 'trunk' branch.
Fix a few more memory leaks via libgit2 by wrapping another commonly
used libgit2 function with pool handling.
* subversion/libsvn_fs_git/git-revroot.c
(cleanup_git_tree): New function.
(get_entry_object): Use similar style as other functions.
(get_commit_tree): New function.
(make_fspath): New function.
(walk_tree_for_changes): New function.
(fs_git_paths_changed): Add changes from the actual commit.
(fs_git_check_path,
fs_git_node_relation,
fs_git_node_created_rev): Update caller.
(fs_git_node_created_path): Add implementation.
(fs_git_dir_entries): Update caller. Hide non tree/file entries.
(fs_git_file_length,
fs_git_file_checksum,
fs_git_file_contents,
fs_git_contents_changed): Update caller.
Modified:
subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c
Modified: subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c?rev=1717561&r1=1717560&r2=1717561&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_git/git-revroot.c Wed Dec 2 00:41:31 2015
@@ -84,6 +84,13 @@ cleanup_git_commit(void *baton)
return APR_SUCCESS;
}
+static apr_status_t
+cleanup_git_tree(void *baton)
+{
+ git_tree_free(baton);
+ return APR_SUCCESS;
+}
+
/* Gets the raw git object behind an entry. Takes care of the 'will free'
promise via the pool */
static svn_error_t *
@@ -92,14 +99,24 @@ get_entry_object(git_object **obj,
const git_tree_entry *entry,
apr_pool_t *result_pool)
{
- git_object *obj_out;
+ GIT2_ERR(git_tree_entry_to_object(obj, git_tree_owner(tree), entry));
- GIT2_ERR(git_tree_entry_to_object(&obj_out, git_tree_owner(tree), entry));
+ apr_pool_cleanup_register(result_pool, *obj, cleanup_git_object,
+ apr_pool_cleanup_null);
- apr_pool_cleanup_register(result_pool, obj_out, cleanup_git_object,
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_commit_tree(git_tree **tree,
+ const git_commit *commit,
+ apr_pool_t *result_pool)
+{
+ GIT2_ERR(git_commit_tree(tree, commit));
+
+ apr_pool_cleanup_register(result_pool, *tree, cleanup_git_tree,
apr_pool_cleanup_null);
- *obj = obj_out;
return SVN_NO_ERROR;
}
@@ -166,6 +183,15 @@ make_id(svn_fs_root_t *root,
return fsid;
}
+static const char *
+make_fspath(const char *relpath, apr_pool_t *result_pool)
+{
+ if (*relpath == '/')
+ relpath++;
+
+ return apr_pstrcat(result_pool, "/", relpath, SVN_VA_NULL);
+}
+
/* svn_relpath_split, but then for the first component instead of the last */
static svn_error_t *
relpath_reverse_split(const char **root, const char **remaining,
@@ -283,6 +309,144 @@ find_tree_entry(const git_tree_entry **e
return SVN_NO_ERROR;
}
+static svn_error_t *
+walk_tree_for_changes(apr_hash_t *changed_paths, const char *relpath,
+ svn_fs_root_t *root,
+ const git_tree *new_tree, const git_tree *old_tree,
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+ apr_size_t i;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ for (i = 0; i < git_tree_entrycount(new_tree); i++)
+ {
+ const git_tree_entry *entry = git_tree_entry_byindex(new_tree, i);
+ const char *name = git_tree_entry_name(entry);
+ const git_tree_entry *old_entry = NULL;
+
+ svn_pool_clear(iterpool);
+
+ if (old_tree)
+ old_entry = git_tree_entry_byname(old_tree, name);
+
+ if (old_entry
+ && !git_oid_cmp(git_tree_entry_id(entry),
+ git_tree_entry_id(old_entry))
+ && (git_tree_entry_filemode(entry)
+ == git_tree_entry_filemode(old_entry)))
+ {
+ /* Nothing changed in this subtree */
+ }
+ else if (old_entry
+ && git_tree_entry_type(entry) == GIT_OBJ_TREE
+ && git_tree_entry_type(old_entry) == GIT_OBJ_TREE)
+ {
+ git_object *e_new_tree, *e_old_tree;
+
+ SVN_ERR(get_entry_object(&e_new_tree, new_tree, entry,
+ iterpool));
+ SVN_ERR(get_entry_object(&e_old_tree, old_tree, old_entry,
+ iterpool));
+
+ SVN_ERR(walk_tree_for_changes(
+ changed_paths,
+ svn_relpath_join(relpath, name, iterpool), root,
+ (git_tree *)e_new_tree, (git_tree *)e_old_tree,
+ result_pool, scratch_pool));
+ }
+ else if (old_entry
+ && git_tree_entry_type(entry) == GIT_OBJ_BLOB
+ && git_tree_entry_type(old_entry) == GIT_OBJ_BLOB)
+ {
+ svn_fs_path_change2_t *ch;
+ const char *epath = svn_relpath_join(relpath, name, iterpool);
+
+ ch = svn_fs__path_change_create_internal(
+ make_id(root, epath, result_pool),
+ svn_fs_path_change_modify,
+ result_pool);
+ ch->node_kind = svn_node_file;
+ ch->text_mod = TRUE;
+ svn_hash_sets(changed_paths, make_fspath(epath, result_pool),
+ ch);
+ }
+ else if (git_tree_entry_type(entry) == GIT_OBJ_BLOB)
+ {
+ svn_fs_path_change2_t *ch;
+ const char *epath = svn_relpath_join(relpath, name, iterpool);
+
+ ch = svn_fs__path_change_create_internal(
+ make_id(root, epath, result_pool),
+ old_entry ? svn_fs_path_change_replace
+ : svn_fs_path_change_add,
+ result_pool);
+ ch->node_kind = svn_node_file;
+ svn_hash_sets(changed_paths, make_fspath(epath, result_pool),
+ ch);
+ }
+ else if (git_tree_entry_type(entry) == GIT_OBJ_TREE)
+ {
+ svn_fs_path_change2_t *ch;
+ git_object *e_new_tree;
+ const char *epath = svn_relpath_join(relpath, name, iterpool);
+
+ ch = svn_fs__path_change_create_internal(
+ make_id(root, epath, result_pool),
+ old_entry ? svn_fs_path_change_replace
+ : svn_fs_path_change_add,
+ result_pool);
+ ch->node_kind = svn_node_dir;
+ svn_hash_sets(changed_paths, make_fspath(epath, result_pool),
+ ch);
+
+ SVN_ERR(get_entry_object(&e_new_tree, new_tree, entry,
+ iterpool));
+
+ SVN_ERR(walk_tree_for_changes(
+ changed_paths, epath, root,
+ (git_tree *)e_new_tree, NULL,
+ result_pool, scratch_pool));
+ }
+ }
+
+ if (old_tree)
+ for (i = 0; i < git_tree_entrycount(old_tree); i++)
+ {
+ const git_tree_entry *entry = git_tree_entry_byindex(old_tree, i);
+ const char *name = git_tree_entry_name(entry);
+ const git_tree_entry *new_entry = git_tree_entry_byname(new_tree, name);
+ svn_fs_path_change2_t *ch;
+ const char *epath;
+
+ if (new_entry)
+ continue; /* Handled in first loop */
+
+ epath = svn_relpath_join(relpath, name, iterpool);
+
+ ch = svn_fs__path_change_create_internal(
+ make_id(root, epath, result_pool),
+ svn_fs_path_change_delete,
+ result_pool);
+
+ switch (git_tree_entry_type(entry))
+ {
+ case GIT_OBJ_TREE:
+ ch->node_kind = svn_node_dir;
+ break;
+ case GIT_OBJ_BLOB:
+ ch->node_kind = svn_node_file;
+ break;
+ default:
+ continue;
+ }
+ svn_hash_sets(changed_paths, make_fspath(epath, result_pool),
+ ch);
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
/* Determining what has changed in a root */
static svn_error_t *
fs_git_paths_changed(apr_hash_t **changed_paths_p,
@@ -290,7 +454,14 @@ fs_git_paths_changed(apr_hash_t **change
apr_pool_t *pool)
{
apr_hash_t *changed_paths = apr_hash_make(pool);
+ const git_oid *cmt_oid;
+ const char *branch_path;
+ git_commit *commit, *parent_commit;
+ git_tree *tree, *parent_tree;
+ const git_oid *parent_oid;
+
*changed_paths_p = changed_paths;
+
if (root->rev == 0)
return SVN_NO_ERROR;
else if (root->rev == 1)
@@ -311,6 +482,34 @@ fs_git_paths_changed(apr_hash_t **change
svn_hash_sets(changed_paths, "/branches", ch);
}
+ /* TODO: Add branch + tag changes */
+
+ SVN_ERR(svn_fs_git__db_fetch_oid(NULL, &cmt_oid, &branch_path,
+ root->fs, root->rev,
+ pool, pool));
+
+ if (!cmt_oid)
+ return SVN_NO_ERROR; /* No actual changes in this revision*/
+
+ SVN_ERR(find_commit(&commit, root, cmt_oid, pool));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
+ parent_oid = git_commit_parent_id(commit, 0);
+
+ if (parent_oid)
+ {
+ SVN_ERR(find_commit(&parent_commit, root, parent_oid, pool));
+ SVN_ERR(get_commit_tree(&parent_tree, parent_commit, pool));
+ }
+ else
+ {
+ parent_commit = NULL;
+ parent_tree = NULL;
+ }
+
+ SVN_ERR(walk_tree_for_changes(changed_paths, branch_path, root,
+ tree, parent_tree,
+ pool, pool));
+
return SVN_NO_ERROR;
}
@@ -351,7 +550,7 @@ fs_git_check_path(svn_node_kind_t *kind_
return SVN_NO_ERROR;
}
- GIT2_ERR(git_commit_tree(&tree, commit));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
SVN_ERR(find_tree_entry(&entry, tree, relpath, pool, pool));
if (!entry)
@@ -449,8 +648,8 @@ fs_git_node_relation(svn_fs_node_relatio
return SVN_NO_ERROR;
}
- GIT2_ERR(git_commit_tree(&tree_a, commit_a));
- GIT2_ERR(git_commit_tree(&tree_b, commit_b));
+ SVN_ERR(get_commit_tree(&tree_a, commit_a, scratch_pool));
+ SVN_ERR(get_commit_tree(&tree_b, commit_b, scratch_pool));
SVN_ERR(find_tree_entry(&entry_a, tree_a, relpath_a,
scratch_pool, scratch_pool));
@@ -514,7 +713,7 @@ fs_git_node_created_rev(svn_revnum_t *re
}
iterpool = svn_pool_create(pool);
- GIT2_ERR(git_commit_tree(&rev_tree, rev_commit));
+ SVN_ERR(get_commit_tree(&rev_tree, rev_commit, iterpool));
SVN_ERR(find_tree_entry(&rev_entry, rev_tree, relpath, pool, iterpool));
last_oid = *git_commit_id(rev_commit);
@@ -531,7 +730,7 @@ fs_git_node_created_rev(svn_revnum_t *re
SVN_ERR(find_commit(&cmt, root, oid_p, iterpool));
- GIT2_ERR(git_commit_tree(&cmt_tree, cmt));
+ SVN_ERR(get_commit_tree(&cmt_tree, cmt, iterpool));
SVN_ERR(find_tree_entry(&cmt_entry, cmt_tree, relpath,
iterpool, iterpool));
@@ -559,6 +758,9 @@ fs_git_node_created_rev(svn_revnum_t *re
root->fs, &last_oid,
pool, iterpool));
+ if (SVN_IS_VALID_REVNUM(*revision))
+ *revision = root->rev;
+
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
@@ -578,7 +780,24 @@ fs_git_node_created_path(const char **cr
svn_fs_root_t *root, const char *path,
apr_pool_t *pool)
{
- return svn_error_create(APR_ENOTIMPL, NULL, NULL);
+ svn_revnum_t rev;
+ git_commit *commit;
+ const char *relpath, *basepath;
+
+ SVN_ERR(fs_git_node_created_rev(&rev, root, path, pool));
+
+ if (rev == root->rev)
+ {
+ *created_path = make_fspath(path, pool);
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(find_branch(&commit, &relpath, root, path, pool));
+ SVN_ERR(svn_fs_git__db_fetch_oid(NULL, NULL, &basepath, root->fs, rev,
+ pool, pool));
+
+ *created_path = make_fspath(svn_relpath_join(basepath, relpath, pool), pool);
+ return SVN_NO_ERROR;
}
static svn_error_t *
@@ -635,6 +854,7 @@ fs_git_node_prop(svn_string_t **value_p,
{
return svn_error_create(APR_ENOTIMPL, NULL, NULL);
}
+
static svn_error_t *
fs_git_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
@@ -718,7 +938,7 @@ fs_git_dir_entries(apr_hash_t **entries_
return SVN_NO_ERROR;
}
- GIT2_ERR(git_commit_tree(&tree, commit));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
if (*relpath)
{
@@ -746,8 +966,10 @@ fs_git_dir_entries(apr_hash_t **entries_
if (git_tree_entry_type(e) == GIT_OBJ_TREE)
de->kind = svn_node_dir;
- else
+ else if (git_tree_entry_type(e) == GIT_OBJ_BLOB)
de->kind = svn_node_file;
+ else
+ continue;
svn_hash_sets(*entries_p, de->name, de);
}
@@ -798,7 +1020,7 @@ fs_git_file_length(svn_filesize_t *lengt
if (!commit)
return SVN_FS__ERR_NOT_FILE(root->fs, path);
- GIT2_ERR(git_commit_tree(&tree, commit));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
SVN_ERR(find_tree_entry(&entry, tree, relpath, pool, pool));
@@ -834,7 +1056,7 @@ fs_git_file_checksum(svn_checksum_t **ch
if (!commit)
return SVN_FS__ERR_NOT_FILE(root->fs, path);
- GIT2_ERR(git_commit_tree(&tree, commit));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
SVN_ERR(find_tree_entry(&entry, tree, relpath, pool, pool));
@@ -868,7 +1090,7 @@ fs_git_file_contents(svn_stream_t **cont
if (!commit)
return SVN_FS__ERR_NOT_FILE(root->fs, path);
- GIT2_ERR(git_commit_tree(&tree, commit));
+ SVN_ERR(get_commit_tree(&tree, commit, pool));
SVN_ERR(find_tree_entry(&entry, tree, relpath, pool, pool));
@@ -947,8 +1169,8 @@ fs_git_contents_changed(int *changed_p,
else if (!commit_b)
return SVN_FS__ERR_NOT_FILE(root_b->fs, path_b);
- GIT2_ERR(git_commit_tree(&tree_a, commit_a));
- GIT2_ERR(git_commit_tree(&tree_b, commit_b));
+ SVN_ERR(get_commit_tree(&tree_a, commit_a, scratch_pool));
+ SVN_ERR(get_commit_tree(&tree_b, commit_b, scratch_pool));
SVN_ERR(find_tree_entry(&entry_a, tree_a, relpath_a,
scratch_pool, scratch_pool));
@@ -1011,6 +1233,7 @@ fs_git_merge(const char **conflict_p,
{
return svn_error_create(APR_ENOTIMPL, NULL, NULL);
}
+
/* Mergeinfo. */
static svn_error_t *
fs_git_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,