Commit 1a895dd787a5699c21d7925e9cdffa66f23605c4

Vicent Marti 2010-05-22T14:32:59

Add arbritrary ordering revision walking. The 'gitrp_next()' method now correctly does a revision walking of all the pushed revisions in arbritary ordering. Signed-off-by: Vicent Marti <tanoku@gmail.com> Signed-off-by: Andreas Ericsson <ae@op5.se>

diff --git a/src/commit.c b/src/commit.c
index fa33b52..8654e89 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -35,16 +35,15 @@ const git_oid *git_commit_id(git_commit *c)
 	return &c->id;
 }
 
-void git_commit_mark_uninteresting(git_commit *commit)
+void git_commit__mark_uninteresting(git_commit *commit)
 {
+    if (commit == NULL)
+        return;
+
 	git_commit_list *parents = commit->parents;
 
     commit->flags |= GIT_COMMIT_HIDE;
 
-    /*
-     * FIXME: mark recursively the parents' parents?
-     * They are most likely not parsed yet...
-     */
 	while (parents) {
         parents->commit->flags |= GIT_COMMIT_HIDE;
 		parents = parents->next;
@@ -113,8 +112,6 @@ git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id)
     git_oid_cpy(&commit->id, id);
     commit->pool = pool;
 
-    git_commit_list_insert(&pool->commits, commit);
-
     return commit;
 }
 
@@ -187,6 +184,10 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len)
         if ((parent = git_commit_lookup(commit->pool, &oid)) == NULL)
             return -1;
 
+        // Inherit uninteresting flag
+        if (commit->flags & GIT_COMMIT_HIDE)
+            parent->flags |= GIT_COMMIT_HIDE;
+
         git_commit_list_insert(&commit->parents, parent);
     }
 
diff --git a/src/commit.h b/src/commit.h
index 3a6b706..a0c0512 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -29,6 +29,7 @@ struct git_commit {
 int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
 int git_commit__parse_buffer(git_commit *commit, void *data, size_t len);
 int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end);
+void git_commit__mark_uninteresting(git_commit *commit);
 
 int git_commit_parse_existing(git_commit *commit);
 
diff --git a/src/git/commit.h b/src/git/commit.h
index 1a57ba7..279d8e3 100644
--- a/src/git/commit.h
+++ b/src/git/commit.h
@@ -44,6 +44,14 @@ GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id);
  */
 GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit);
 
+
+/**
+ * Mark a commit and all its parents as uninteresting.
+ * @param commit The commit to mark
+ */
+GIT_EXTERN(void) git_commit_mark_uninteresting(git_commit *commit);
+
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/src/revwalk.c b/src/revwalk.c
index fe6f9f2..001d938 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -43,10 +43,12 @@ void gitrp_free(git_revpool *walk)
 {
     git_commit_list *list;
 
-    list = walk->commits;
+    list = walk->roots;
     while (list)
     {
         free(list->commit);
+        free(list);
+
         list = list->next;
     }
 
@@ -67,16 +69,35 @@ void gitrp_push(git_revpool *pool, git_commit *commit)
             return;
     }
 
+    // Sanity check: make sure that if the commit
+    // has been manually marked as uninteresting,
+    // all the parent commits are too.
+    if ((commit->flags & GIT_COMMIT_HIDE) != 0)
+        git_commit__mark_uninteresting(commit);
+
     commit->flags |= GIT_COMMIT_SEEN;
 
     git_commit_list_insert(&pool->roots, commit);
+    git_commit_list_insert(&pool->iterator, commit);
+}
+
+void gitrp_hide(git_revpool *pool, git_commit *commit)
+{
+    git_commit_mark_uninteresting(commit);
+    gitrp_push(pool, commit);
 }
 
 void gitrp_prepare_walk(git_revpool *pool)
 {
-    // TODO: sort commit list based on walk ordering
+    git_commit_list *list;
+
+    list = pool->roots;
+    while (list)
+    {
+        git_commit_list_insert(&pool->iterator, list->commit);
+        list = list->next;
+    }
 
-    pool->iterator = pool->roots;
     pool->walking = 1;
 }
 
@@ -87,17 +108,36 @@ git_commit *gitrp_next(git_revpool *pool)
     if (!pool->walking)
         gitrp_prepare_walk(pool);
 
-    // Iteration finished
-    if (pool->iterator == NULL)
+    while (pool->iterator != NULL)
     {
-        gitrp_reset(pool);
-        return NULL;
-    }
+        git_commit_list *list;
+
+        next = pool->iterator->commit;
+        free(pool->iterator);
+        pool->iterator = pool->iterator->next;
+
+        list = next->parents;
+        while (list)
+        {
+            git_commit *parent = list->commit;
+            list = list->next;
 
-    next = pool->iterator->commit;
-    pool->iterator = pool->iterator->next;
+            if ((parent->flags & GIT_COMMIT_SEEN) != 0)
+                continue;
+
+            if (parent->parsed == 0)
+                git_commit_parse_existing(parent);
+
+            git_commit_list_insert(&pool->iterator, list->commit);
+        }
+
+        if ((next->flags & GIT_COMMIT_HIDE) != 0)
+            return next;
+    }
 
-    return next;
+    // No commits left to iterate
+    gitrp_reset(pool);
+    return NULL;
 }
 
 void gitrp_reset(git_revpool *pool)
diff --git a/src/revwalk.h b/src/revwalk.h
index 34ff337..be01c47 100644
--- a/src/revwalk.h
+++ b/src/revwalk.h
@@ -7,7 +7,6 @@
 struct git_revpool {
 	git_odb *db;
     git_commit_list *iterator;
-    git_commit_list *commits;
     git_commit_list *roots;
 
     unsigned walking:1,