diff options
-rw-r--r-- | include/git2/commit.h | 21 | ||||
-rw-r--r-- | src/commit.c | 64 | ||||
-rw-r--r-- | tests/commit/write.c | 100 |
3 files changed, 185 insertions, 0 deletions
diff --git a/include/git2/commit.h b/include/git2/commit.h index 44ea8882b..f63a90685 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -440,6 +440,27 @@ GIT_EXTERN(int) git_commit_create_buffer( size_t parent_count, const git_commit *parents[]); +/** + * Create a commit object from the given buffer and signature + * + * Given the unsigned commit object's contents, its signature and the + * header field in which to store the signature, attach the signature + * to the commit and write it into the given repository. + * + * @param out the resulting commit id + * @param commit_content the content of the unsigned commit object + * @param signature the signature to add to the commit + * @param signature_field which header field should contain this + * signature. Leave `NULL` for the default of "gpgsig" + * @return 0 or an error code + */ +GIT_EXTERN(int) git_commit_create_with_signature( + git_oid *out, + git_repository *repo, + const char *commit_content, + const char *signature, + const char *signature_field); + /** @} */ GIT_END_DECL #endif diff --git a/src/commit.c b/src/commit.c index 9d675ac97..f6b2d6517 100644 --- a/src/commit.c +++ b/src/commit.c @@ -820,3 +820,67 @@ int git_commit_create_buffer(git_buf *out, git_array_clear(parents_arr); return error; } + +/** + * Append to 'out' properly marking continuations when there's a newline in 'content' + */ +static void format_header_field(git_buf *out, const char *field, const char *content) +{ + const char *lf; + + assert(out && field && content); + + git_buf_puts(out, field); + git_buf_putc(out, ' '); + + while ((lf = strchr(content, '\n')) != NULL) { + git_buf_put(out, content, lf - content); + git_buf_puts(out, "\n "); + content = lf + 1; + } + + git_buf_puts(out, content); + git_buf_putc(out, '\n'); +} + +int git_commit_create_with_signature( + git_oid *out, + git_repository *repo, + const char *commit_content, + const char *signature, + const char *signature_field) +{ + git_odb *odb; + int error = 0; + const char *field; + const char *header_end; + git_buf commit = GIT_BUF_INIT; + + /* We start by identifying the end of the commit header */ + header_end = strstr(commit_content, "\n\n"); + if (!header_end) { + giterr_set(GITERR_INVALID, "malformed commit contents"); + return -1; + } + + field = signature_field ? signature_field : "gpgsig"; + + /* The header ends after the first LF */ + header_end++; + git_buf_put(&commit, commit_content, header_end - commit_content); + format_header_field(&commit, field, signature); + git_buf_puts(&commit, header_end); + + if (git_buf_oom(&commit)) + return -1; + + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) + goto cleanup; + + if ((error = git_odb_write(out, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT)) < 0) + goto cleanup; + +cleanup: + git_buf_free(&commit); + return error; +} diff --git a/tests/commit/write.c b/tests/commit/write.c index 9d1ae78fb..030d41578 100644 --- a/tests/commit/write.c +++ b/tests/commit/write.c @@ -298,3 +298,103 @@ void test_commit_write__can_validate_objects(void) git_oid_fromstr(&parent_id, tree_id_str); cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); } + +void test_commit_write__attach_singleline_signature(void) +{ + const char *sig = "magic word: pretty please"; + + const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ +parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +\n\ +a simple commit which works\n"; + + const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ +parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +magicsig magic word: pretty please\n\ +\n\ +a simple commit which works\n"; + + git_oid id; + git_odb *odb; + git_odb_object *obj; + + cl_git_pass(git_commit_create_with_signature(&id, g_repo, data, sig, "magicsig")); + + cl_git_pass(git_repository_odb(&odb, g_repo)); + cl_git_pass(git_odb_read(&obj, odb, &id)); + cl_assert_equal_s(complete, git_odb_object_data(obj)); + + git_odb_object_free(obj); + git_odb_free(odb); +} + +void test_commit_write__attach_multiline_signature(void) +{ + 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-----"; + + const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ +parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +\n\ +a simple commit which works\n"; + +const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ +parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ +author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\ +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-----\n\ +\n\ +a simple commit which works\n"; + + git_oid one, two; + git_odb *odb; + git_odb_object *obj; + + cl_git_pass(git_commit_create_with_signature(&one, g_repo, data, gpgsig, "gpgsig")); + cl_git_pass(git_commit_create_with_signature(&two, g_repo, data, gpgsig, NULL)); + + cl_assert(!git_oid_cmp(&one, &two)); + cl_git_pass(git_repository_odb(&odb, g_repo)); + cl_git_pass(git_odb_read(&obj, odb, &one)); + cl_assert_equal_s(complete, git_odb_object_data(obj)); + + git_odb_object_free(obj); + git_odb_free(odb); +} |