diff options
author | Jacques Germishuys <jacquesg@striata.com> | 2014-04-11 19:15:15 +0200 |
---|---|---|
committer | Jacques Germishuys <jacquesg@striata.com> | 2014-04-15 17:22:17 +0200 |
commit | d8cc1fb653387d9acc28b075147084cf452c43dc (patch) | |
tree | 16a50ea72ce6b00d10fa6b9e970fb04918b46caa /src | |
parent | 360314c9dbb383b3737876a9c229e22050ec9c49 (diff) | |
download | libgit2-d8cc1fb653387d9acc28b075147084cf452c43dc.tar.gz |
Introduce git_diff_format_email and git_diff_commit_as_email
Diffstat (limited to 'src')
-rw-r--r-- | src/diff.c | 204 | ||||
-rw-r--r-- | src/diff.h | 3 |
2 files changed, 207 insertions, 0 deletions
diff --git a/src/diff.c b/src/diff.c index e62f45c22..ba3cd26b5 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1427,6 +1427,198 @@ int git_diff__paired_foreach( return error; } +int git_diff__commit( + git_diff **diff, + git_repository *repo, + const git_commit *commit, + const git_diff_options *opts) +{ + git_commit *parent = NULL; + git_diff *commit_diff = NULL; + git_tree *old_tree = NULL, *new_tree = NULL; + size_t parents; + int error = 0; + + if ((parents = git_commit_parentcount(commit)) > 1) { + char commit_oidstr[GIT_OID_HEXSZ + 1]; + + error = -1; + giterr_set(GITERR_INVALID, "Commit %s is a merge commit", + git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); + goto on_error; + } + + if (parents > 0) + if ((error = git_commit_parent(&parent, commit, 0)) < 0 || + (error = git_commit_tree(&old_tree, parent)) < 0) + goto on_error; + + if ((error = git_commit_tree(&new_tree, commit)) < 0 || + (error = git_diff_tree_to_tree(&commit_diff, repo, old_tree, new_tree, opts)) < 0) + goto on_error; + + *diff = commit_diff; + +on_error: + git_tree_free(new_tree); + git_tree_free(old_tree); + git_commit_free(parent); + + return error; +} + +int git_diff_format_email__append_header_tobuf( + git_buf *out, + const git_oid *id, + const git_signature *author, + const char *summary, + size_t patch_no, + size_t total_patches, + bool exclude_patchno_marker) +{ + char idstr[GIT_OID_HEXSZ + 1]; + char date_str[GIT_DATE_RFC2822_SZ]; + int error = 0; + + git_oid_fmt(idstr, id); + idstr[GIT_OID_HEXSZ] = '\0'; + + if ((error = git__date_rfc2822_fmt(date_str, sizeof(date_str), &author->when)) < 0) + return error; + + error = git_buf_printf(out, + "From %s Mon Sep 17 00:00:00 2001\n" \ + "From: %s <%s>\n" \ + "Date: %s\n" \ + "Subject: ", + idstr, + author->name, author->email, + date_str); + + if (error < 0) + return error; + + if (!exclude_patchno_marker) { + if (total_patches == 1) { + error = git_buf_puts(out, "[PATCH] "); + } else { + error = git_buf_printf(out, "[PATCH %"PRIuZ"/%"PRIuZ"] ", patch_no, total_patches); + } + + if (error < 0) + return error; + } + + error = git_buf_printf(out, "%s\n\n", summary); + + return error; +} + +int git_diff_format_email__append_patches_tobuf( + git_buf *out, + git_diff *diff) +{ + size_t i, deltas; + int error = 0; + + deltas = git_diff_num_deltas(diff); + + for (i = 0; i < deltas; ++i) { + git_patch *patch = NULL; + + if ((error = git_patch_from_diff(&patch, diff, i)) >= 0) + error = git_patch_to_buf(out, patch); + + git_patch_free(patch); + + if (error < 0) + break; + } + + return error; +} + +int git_diff_format_email( + git_buf *out, + git_diff *diff, + const git_diff_format_email_options *opts) +{ + git_diff_stats *stats = NULL; + bool ignore_marker; + unsigned int format_flags = 0; + int error; + + assert(out && diff && opts); + assert(opts->summary && opts->id && opts->author); + + GITERR_CHECK_VERSION(opts, GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, "git_format_email_options"); + + if ((ignore_marker = opts->flags & GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) == false) { + if (opts->patch_no > opts->total_patches) { + giterr_set(GITERR_INVALID, "patch %"PRIuZ" out of range. max %"PRIuZ, opts->patch_no, opts->total_patches); + return -1; + } + + if (opts->patch_no == 0) { + giterr_set(GITERR_INVALID, "invalid patch no %"PRIuZ". should be >0", opts->patch_no); + return -1; + } + } + + error = git_diff_format_email__append_header_tobuf(out, + opts->id, opts->author, opts->summary, + opts->patch_no, opts->total_patches, ignore_marker); + + if (error < 0) + goto on_error; + + format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY; + + if ((error = git_buf_puts(out, "---\n")) < 0 || + (error = git_diff_get_stats(&stats, diff)) < 0 || + (error = git_diff_stats_to_buf(out, stats, format_flags)) < 0 || + (error = git_diff_format_email__append_patches_tobuf(out, diff)) < 0) + goto on_error; + + error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n"); + +on_error: + git_diff_stats_free(stats); + + return error; +} + +int git_diff_commit_as_email( + git_buf *out, + git_repository *repo, + git_commit *commit, + size_t patch_no, + size_t total_patches, + git_diff_format_email_flags_t flags, + const git_diff_options *diff_opts) +{ + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + int error; + + assert (out && repo && commit); + + opts.flags = flags; + opts.patch_no = patch_no; + opts.total_patches = total_patches; + opts.id = git_commit_id(commit); + opts.summary = git_commit_summary(commit); + opts.author = git_commit_author(commit); + + if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0) + return error; + + error = git_diff_format_email(out, diff, &opts); + + git_diff_free(diff); + return error; +} + int git_diff_init_options(git_diff_options* opts, int version) { if (version != GIT_DIFF_OPTIONS_VERSION) { @@ -1450,3 +1642,15 @@ int git_diff_find_init_options(git_diff_find_options* opts, int version) return 0; } } + +int git_diff_format_email_init_options(git_diff_format_email_options* opts, int version) +{ + if (version != GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION) { + giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_format_email_options", version); + return -1; + } else { + git_diff_format_email_options o = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + memcpy(opts, &o, sizeof(o)); + return 0; + } +} diff --git a/src/diff.h b/src/diff.h index c588f6301..aae8fbff1 100644 --- a/src/diff.h +++ b/src/diff.h @@ -116,6 +116,9 @@ extern void git_diff_find_similar__hashsig_free(void *sig, void *payload); extern int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload); +extern int git_diff__commit( + git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts); + /* * Sometimes a git_diff_file will have a zero size; this attempts to * fill in the size without loading the blob if possible. If that is |