summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2013-01-03 12:44:09 -0600
committerVicent Marti <tanoku@gmail.com>2013-01-04 17:47:51 +0100
commit5a62d659bcd3dd529fde9ab7eae2e216cba055cf (patch)
tree4e935871e103295dae9c9290e04fc15974480988
parent9651fdc29715543ec2d094a24ba92688bdfb7d76 (diff)
downloadlibgit2-5a62d659bcd3dd529fde9ab7eae2e216cba055cf.tar.gz
MERGE_HEAD contents iterator
-rw-r--r--include/git2/errors.h1
-rw-r--r--include/git2/repository.h16
-rw-r--r--src/merge.c53
-rw-r--r--src/merge.h1
-rw-r--r--tests-clar/merge/setup.c159
5 files changed, 230 insertions, 0 deletions
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 8ca900969..4eb9e94ef 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -64,6 +64,7 @@ typedef enum {
GITERR_STASH,
GITERR_CHECKOUT,
GITERR_FETCHHEAD,
+ GITERR_MERGE,
} git_error_t;
/**
diff --git a/include/git2/repository.h b/include/git2/repository.h
index 02e689111..1371d5409 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -517,6 +517,22 @@ GIT_EXTERN(int) git_repository_fetchhead_foreach(git_repository *repo,
git_repository_fetchhead_foreach_cb callback,
void *payload);
+typedef int (*git_repository_mergehead_foreach_cb)(const git_oid *oid,
+ void *payload);
+
+/**
+ * If a merge is in progress, call callback 'cb' for each commit ID in the
+ * MERGE_HEAD file.
+ *
+ * @param repo A repository object
+ * @param callback Callback function
+ * @param apyload Pointer to callback data (optional)
+ * @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error
+ */
+GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo,
+ git_repository_mergehead_foreach_cb callback,
+ void *payload);
+
/**
* Calculate hash of file using repository filtering rules.
*
diff --git a/src/merge.c b/src/merge.c
index dfdadca81..f52c112c9 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -241,3 +241,56 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
*out = result;
return 0;
}
+
+int git_repository_mergehead_foreach(git_repository *repo,
+ git_repository_mergehead_foreach_cb cb,
+ void *payload)
+{
+ git_buf merge_head_path = GIT_BUF_INIT, merge_head_file = GIT_BUF_INIT;
+ char *buffer, *line;
+ size_t line_num = 1;
+ git_oid oid;
+ int error = 0;
+
+ assert(repo && cb);
+
+ if ((error = git_buf_joinpath(&merge_head_path, repo->path_repository,
+ GIT_MERGE_HEAD_FILE)) < 0)
+ return error;
+
+ if ((error = git_futils_readbuffer(&merge_head_file,
+ git_buf_cstr(&merge_head_path))) < 0)
+ goto cleanup;
+
+ buffer = merge_head_file.ptr;
+
+ while ((line = git__strsep(&buffer, "\n")) != NULL) {
+ if (strlen(line) != GIT_OID_HEXSZ) {
+ giterr_set(GITERR_INVALID, "Unable to parse OID - invalid length");
+ error = -1;
+ goto cleanup;
+ }
+
+ if ((error = git_oid_fromstr(&oid, line)) < 0)
+ goto cleanup;
+
+ if (cb(&oid, payload) < 0) {
+ error = GIT_EUSER;
+ goto cleanup;
+ }
+
+ ++line_num;
+ }
+
+ if (*buffer) {
+ giterr_set(GITERR_MERGE, "No EOL at line %d", line_num);
+ error = -1;
+ goto cleanup;
+ }
+
+cleanup:
+ git_buf_free(&merge_head_path);
+ git_buf_free(&merge_head_file);
+
+ return error;
+}
diff --git a/src/merge.h b/src/merge.h
index af24de474..03b41e388 100644
--- a/src/merge.h
+++ b/src/merge.h
@@ -10,6 +10,7 @@
#include "git2/types.h"
#include "git2/merge.h"
#include "commit_list.h"
+#include "vector.h"
#define GIT_MERGE_MSG_FILE "MERGE_MSG"
#define GIT_MERGE_MODE_FILE "MERGE_MODE"
diff --git a/tests-clar/merge/setup.c b/tests-clar/merge/setup.c
new file mode 100644
index 000000000..d88b2d94c
--- /dev/null
+++ b/tests-clar/merge/setup.c
@@ -0,0 +1,159 @@
+#include "clar_libgit2.h"
+#include "git2/repository.h"
+#include "git2/merge.h"
+#include "merge.h"
+#include "refs.h"
+#include "fileops.h"
+
+static git_repository *repo;
+static git_index *repo_index;
+
+#define TEST_REPO_PATH "testrepo"
+#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
+
+#define ORIG_HEAD "bd593285fc7fe4ca18ccdbabf027f5d689101452"
+
+#define THEIRS_SIMPLE_BRANCH "branch"
+#define THEIRS_SIMPLE_OID "7cb63eed597130ba4abb87b3e544b85021905520"
+
+#define OCTO1_BRANCH "octo1"
+#define OCTO1_OID "16f825815cfd20a07a75c71554e82d8eede0b061"
+
+#define OCTO2_BRANCH "octo2"
+#define OCTO2_OID "158dc7bedb202f5b26502bf3574faa7f4238d56c"
+
+#define OCTO3_BRANCH "octo3"
+#define OCTO3_OID "50ce7d7d01217679e26c55939eef119e0c93e272"
+
+#define OCTO4_BRANCH "octo4"
+#define OCTO4_OID "54269b3f6ec3d7d4ede24dd350dd5d605495c3ae"
+
+#define OCTO5_BRANCH "octo5"
+#define OCTO5_OID "e4f618a2c3ed0669308735727df5ebf2447f022f"
+
+// Fixture setup and teardown
+void test_merge_setup__initialize(void)
+{
+ repo = cl_git_sandbox_init(TEST_REPO_PATH);
+ git_repository_index(&repo_index, repo);
+}
+
+void test_merge_setup__cleanup(void)
+{
+ git_index_free(repo_index);
+ cl_git_sandbox_cleanup();
+}
+
+static bool test_file_contents(const char *filename, const char *expected)
+{
+ git_buf file_path_buf = GIT_BUF_INIT, file_buf = GIT_BUF_INIT;
+ bool equals;
+
+ git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename);
+
+ cl_git_pass(git_futils_readbuffer(&file_buf, file_path_buf.ptr));
+ equals = (strcmp(file_buf.ptr, expected) == 0);
+
+ git_buf_free(&file_path_buf);
+ git_buf_free(&file_buf);
+
+ return equals;
+}
+
+static void write_file_contents(const char *filename, const char *output)
+{
+ git_buf file_path_buf = GIT_BUF_INIT;
+
+ git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename);
+ cl_git_rewritefile(file_path_buf.ptr, output);
+
+ git_buf_free(&file_path_buf);
+}
+
+struct merge_head_cb_data {
+ const char **oid_str;
+ unsigned int len;
+
+ unsigned int i;
+};
+
+int merge_head_foreach_cb(git_oid *oid, void *payload)
+{
+ git_oid expected_oid;
+
+ struct merge_head_cb_data *cb_data = payload;
+
+ git_oid_fromstr(&expected_oid, cb_data->oid_str[cb_data->i]);
+
+ cl_assert(git_oid_cmp(&expected_oid, oid) == 0);
+
+ cb_data->i++;
+
+ return 0;
+}
+
+void test_merge_setup__head_notfound(void)
+{
+ int error;
+
+ cl_git_fail((error = git_repository_mergehead_foreach(repo,
+ merge_head_foreach_cb, NULL)));
+ cl_assert(error == GIT_ENOTFOUND);
+}
+
+void test_merge_setup__head_invalid_oid(void)
+{
+ int error;
+
+ write_file_contents(GIT_MERGE_HEAD_FILE, "invalid-oid\n");
+
+ cl_git_fail((error = git_repository_mergehead_foreach(repo,
+ merge_head_foreach_cb, NULL)));
+ cl_assert(error == -1);
+}
+
+void test_merge_setup__head_foreach_nonewline(void)
+{
+ int error;
+
+ write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID);
+
+ cl_git_fail((error = git_repository_mergehead_foreach(repo,
+ merge_head_foreach_cb, NULL)));
+ cl_assert(error == -1);
+}
+
+void test_merge_setup__head_foreach_one(void)
+{
+ const char *expected = THEIRS_SIMPLE_OID;
+
+ struct merge_head_cb_data cb_data = { &expected, 1 };
+
+ write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID "\n");
+
+ cl_git_pass(git_repository_mergehead_foreach(repo,
+ merge_head_foreach_cb, &cb_data));
+
+ cl_assert(cb_data.i == cb_data.len);
+}
+
+void test_merge_setup__head_foreach_octopus(void)
+{
+ const char *expected[] = { THEIRS_SIMPLE_OID,
+ OCTO1_OID, OCTO2_OID, OCTO3_OID, OCTO4_OID, OCTO5_OID };
+
+ struct merge_head_cb_data cb_data = { expected, 6 };
+
+ write_file_contents(GIT_MERGE_HEAD_FILE,
+ THEIRS_SIMPLE_OID "\n"
+ OCTO1_OID "\n"
+ OCTO2_OID "\n"
+ OCTO3_OID "\n"
+ OCTO4_OID "\n"
+ OCTO5_OID "\n");
+
+ cl_git_pass(git_repository_mergehead_foreach(repo,
+ merge_head_foreach_cb, &cb_data));
+
+ cl_assert(cb_data.i == cb_data.len);
+}