diff options
author | Tyler Wanek <tylerw@axosoft.com> | 2019-01-11 09:16:58 -0700 |
---|---|---|
committer | Tyler Wanek <tylerw@axosoft.com> | 2019-01-23 17:13:22 -0700 |
commit | 546e40c9b9da8cc7f7c992829ae927d07132236a (patch) | |
tree | 2c1a466fce9de7d9ae5c648d161ef5759b6c6109 | |
parent | 635693d3bc55770ec7a6640ba3f2f0ee434a6042 (diff) | |
download | libgit2-546e40c9b9da8cc7f7c992829ae927d07132236a.tar.gz |
Add signing callbacks for git_rebase_commit in git_rebase_options
2 callbacks have been added to git_rebase_options, git_rebase_commit_signature_cb and git_rebase_commit_signature_field_cb. When git_rebase_commit_signature_cb is present in git_rebase_options, it will be called whenever git_rebase_commit is performed, giving an opportunity to sign the commit. The signing procedure can be skipped if the callback specifies passthrough as the error. The git_rebase_commit_signature_field_cb will only be called if the other callback is present or did not passthrough, and it provides means to specify which field a signature is for.
Git_rebase_options was chosen as the home for these callbacks as it keeps backwards compatibility with the current rebase api.
-rw-r--r-- | include/git2/rebase.h | 54 | ||||
-rw-r--r-- | src/rebase.c | 45 |
2 files changed, 94 insertions, 5 deletions
diff --git a/include/git2/rebase.h b/include/git2/rebase.h index f6b2e20ad..81d194ec0 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -24,6 +24,36 @@ GIT_BEGIN_DECL /** + * Rebase commit signature callback. + * + * The callback will be called with the commit content, giving a user an + * opportunity to sign the commit content in a rebase. + * The signature parameter will be owned by LibGit2 after this callback returns. + * + * When the callback: + * - returns GIT_PASSTHROUGH, no signature will be added to the commit. + * - returns < 0, git_rebase_commit will be aborted. + * - returns GIT_OK, the signature parameter is expected to be filled. + */ +typedef int (*git_rebase_commit_signature_cb)( + char **signature, const char *commit_content, void *payload); + +/** + * Rebase commit signature field callback. + * + * The callback will be called if a signature_cb was called and successful. + * This callback will provide the field that a user is signing in a git_rebase_commit. + * The signature_field parameter will be owned by LibGit2 after this callback returns. + * + * When the callback: + * - returns GIT_PASSTHROUGH, signature_field is expected to remain null. + * - returns < 0, git_rebase_commit will be aborted. + * - returns GIT_OK, the signature_field parameter is expected to be filled. + */ +typedef int (*git_rebase_commit_signature_field_cb)( + char **signature_field, void *payload); + +/** * Rebase options * * Use to tell the rebase machinery how to operate. @@ -72,6 +102,28 @@ typedef struct { * `abort` to match git semantics. */ git_checkout_options checkout_options; + + /** + * If provided, this will be called with the commit content, allowing + * a signature to be added to the rebase commit. Can be skipped with + * GIT_PASSTHROUGH. If GIT_PASSTHROUGH is returned, a commit will be made + * without a signature. + * This field is only used when performing git_rebase_commit. + */ + git_rebase_commit_signature_cb signature_cb; + + /** + * If provided and the signature_cb is provided, this will be called asking + * for the field to write the signature to. Can be skipped with GIT_PASSTHROUGH. + * This field is only used when performing git_rebase_commit. + */ + git_rebase_commit_signature_field_cb signature_field_cb; + + /** + * This will be passed to each of the callbacks in this struct + * as the last parameter. + */ + void *payload; } git_rebase_options; /** @@ -118,7 +170,7 @@ typedef enum { #define GIT_REBASE_OPTIONS_VERSION 1 #define GIT_REBASE_OPTIONS_INIT \ { GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \ - GIT_CHECKOUT_OPTIONS_INIT} + GIT_CHECKOUT_OPTIONS_INIT, 0, 0, NULL } /** Indicates that a rebase operation is not (yet) in progress. */ #define GIT_REBASE_NO_OPERATION SIZE_MAX diff --git a/src/rebase.c b/src/rebase.c index 45460367e..8ead1cfc4 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -945,6 +945,8 @@ static int rebase_commit__create( git_commit *current_commit = NULL, *commit = NULL; git_tree *parent_tree = NULL, *tree = NULL; git_oid tree_id, commit_id; + git_buf commit_content = GIT_BUF_INIT; + char *signature = NULL, *signature_field = NULL; int error; operation = git_array_get(rebase->operations, rebase->current); @@ -975,10 +977,40 @@ static int rebase_commit__create( message = git_commit_message(current_commit); } - if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author, - committer, message_encoding, message, tree, 1, - (const git_commit **)&parent_commit)) < 0 || - (error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) + /* this error will be cleared by the signing process, but should be set + * to signal the unsigned commit create process if we are not going to sign */ + error = GIT_PASSTHROUGH; + if (rebase->options.signature_cb) { + if ((error = git_commit_create_buffer(&commit_content, rebase->repo, author, committer, + message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0) + goto done; + + if ((error = rebase->options.signature_cb(&signature, git_buf_cstr(&commit_content), + rebase->options.payload)) < 0 && error != GIT_PASSTHROUGH) + goto done; + + if (error != GIT_PASSTHROUGH) { + if (rebase->options.signature_field_cb && + (error = rebase->options.signature_field_cb(&signature_field, rebase->options.payload)) < 0) { + if (error == GIT_PASSTHROUGH) + assert(signature_field == NULL); + else + goto done; + } + + if ((error = git_commit_create_with_signature(&commit_id, rebase->repo, + git_buf_cstr(&commit_content), signature, signature_field)) < 0) + goto done; + } + } + + /* if we skipped signing, create the commit normally */ + if (error == GIT_PASSTHROUGH && + (error = git_commit_create(&commit_id, rebase->repo, NULL, author, committer, + message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0) + goto done; + + if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) goto done; *out = commit; @@ -987,6 +1019,11 @@ done: if (error < 0) git_commit_free(commit); + if (signature) + free(signature); + if (signature_field) + free(signature_field); + git_buf_dispose(&commit_content); git_commit_free(current_commit); git_tree_free(parent_tree); git_tree_free(tree); |