summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-06-22 15:32:29 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2015-06-22 15:56:31 +0200
commita3f42fe8e4cdae8c85ba5d7d7b4c9fd1247d5227 (patch)
tree123f33cbc69abe842fe66f1d1eea448a9127575d
parente96a97f18e8f961c434e4fa4fc2c7d950480b9e9 (diff)
downloadlibgit2-cmn/commit-header-field.tar.gz
commit: allow retrieving an arbitrary header fieldcmn/commit-header-field
This allows the user to look up fields which we don't parse in libgit2, and allows them to access gpgsig or mergetag fields if they wish to check the signature.
-rw-r--r--CHANGELOG.md3
-rw-r--r--include/git2/commit.h11
-rw-r--r--src/commit.c55
-rw-r--r--tests/commit/parse.c38
4 files changed, 107 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a8e3e18ac..eb7ae842b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -140,6 +140,9 @@ support for HTTPS connections insead of OpenSSL.
* `git_filter_list_contains` will indicate whether a particular
filter will be run in the given filter list.
+* `git_commit_header_field()` has been added, which allows retrieving
+ the contents of an arbitrary header field.
+
### API removals
* `git_remote_save()` and `git_remote_clear_refspecs()` have been
diff --git a/include/git2/commit.h b/include/git2/commit.h
index fb53a701b..04711c1fa 100644
--- a/include/git2/commit.h
+++ b/include/git2/commit.h
@@ -240,6 +240,17 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
unsigned int n);
/**
+ * Get an arbitrary header field
+ *
+ * @param out the buffer to fill
+ * @param commit the commit to look in
+ * @param field the header field to return
+ * @return 0 on succeess, GIT_ENOTFOUND if the field does not exist,
+ * or an error code
+ */
+GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit, const char *field);
+
+/**
* Create new commit in the repository from a list of `git_object` pointers
*
* The message will **not** be cleaned up automatically. You can do that
diff --git a/src/commit.c b/src/commit.c
index ce13bdb85..616f947db 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -518,3 +518,58 @@ int git_commit_nth_gen_ancestor(
*ancestor = parent;
return 0;
}
+
+int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field)
+{
+ const char *buf = commit->raw_header;
+ const char *h, *eol;
+
+ git_buf_sanitize(out);
+ while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') {
+ h++;
+ if (git__prefixcmp(h, field)) {
+ buf = h;
+ continue;
+ }
+
+ h += strlen(field);
+ eol = strchr(h, '\n');
+ if (h[0] != ' ') {
+ buf = h;
+ continue;
+ }
+ if (!eol)
+ goto malformed;
+
+ h++; /* skip the SP */
+
+ git_buf_put(out, h, eol - h);
+ if (git_buf_oom(out))
+ goto oom;
+
+ /* If the next line starts with SP, it's multi-line, we must continue */
+ while (eol[1] == ' ') {
+ git_buf_putc(out, '\n');
+ h = eol + 2;
+ eol = strchr(h, '\n');
+ if (!eol)
+ goto malformed;
+
+ git_buf_put(out, h, eol - h);
+ }
+
+ if (git_buf_oom(out))
+ goto oom;
+
+ return 0;
+ }
+
+ return GIT_ENOTFOUND;
+
+malformed:
+ giterr_set(GITERR_OBJECT, "malformed header");
+ return -1;
+oom:
+ giterr_set_oom();
+ return -1;
+}
diff --git a/tests/commit/parse.c b/tests/commit/parse.c
index fa079f470..388da078a 100644
--- a/tests/commit/parse.c
+++ b/tests/commit/parse.c
@@ -418,3 +418,41 @@ committer Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
cl_assert_equal_s(raw_message, git_commit_message_raw(commit));
git_commit__free(commit);
}
+
+void test_commit_parse__arbitrary_field(void)
+{
+ git_commit *commit;
+ git_buf buf = GIT_BUF_INIT;
+ const char *gpgsig = "-----BEGIN PGP SIGNATURE-----\n\
+Version: GnuPG v1.4.12 (Darwin)\n\
+\n\
+iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n\
+o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8\n\
+JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq\n\
+AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq\n\
+SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW\n\
+who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok\n\
+6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG\n\
+cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu\n\
+c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9\n\
+ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J\n\
+7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc\n\
+cpxtDQQMGYFpXK/71stq\n\
+=ozeK\n\
+-----END PGP SIGNATURE-----";
+
+ cl_git_pass(parse_commit(&commit, passing_commit_cases[4]));
+
+ cl_git_pass(git_commit_header_field(&buf, commit, "parent"));
+ cl_assert_equal_s("34734e478d6cf50c27c9d69026d93974d052c454", buf.ptr);
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_commit_header_field(&buf, commit, "gpgsig"));
+ cl_assert_equal_s(gpgsig, buf.ptr);
+
+ cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "awesomeness"));
+ cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "par"));
+
+ git_buf_free(&buf);
+ git_commit__free(commit);
+}