diff options
author | Ben Straub <bs@github.com> | 2013-09-16 16:12:31 -0700 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-09-16 16:12:31 -0700 |
commit | 549931679a77b280eb1f36afeda8930eb31d70f7 (patch) | |
tree | 2744e3e198ad146bae72f35369bbeb4f8028c8c3 /src/diff_print.c | |
parent | 1a68c168a6cdbe0db6e44fb582a7026a7d536c9d (diff) | |
parent | 8821c9aa5baf31e21c21825e8c91c765e6631e7f (diff) | |
download | libgit2-549931679a77b280eb1f36afeda8930eb31d70f7.tar.gz |
Merge branch 'development' into blame_rebased
Conflicts:
include/git2.h
Diffstat (limited to 'src/diff_print.c')
-rw-r--r-- | src/diff_print.c | 221 |
1 files changed, 130 insertions, 91 deletions
diff --git a/src/diff_print.c b/src/diff_print.c index 244aa6e1d..ee4b5fc17 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -7,7 +7,7 @@ #include "common.h" #include "diff.h" #include "diff_patch.h" -#include "buffer.h" +#include "fileops.h" typedef struct { git_diff_list *diff; @@ -21,14 +21,15 @@ static int diff_print_info_init( diff_print_info *pi, git_buf *out, git_diff_list *diff, git_diff_data_cb cb, void *payload) { - assert(diff && diff->repo); - pi->diff = diff; pi->print_cb = cb; pi->payload = payload; pi->buf = out; - if (git_repository__cvar(&pi->oid_strlen, diff->repo, GIT_CVAR_ABBREV) < 0) + if (!diff || !diff->repo) + pi->oid_strlen = GIT_ABBREV_DEFAULT; + else if (git_repository__cvar( + &pi->oid_strlen, diff->repo, GIT_CVAR_ABBREV) < 0) return -1; pi->oid_strlen += 1; /* for NUL byte */ @@ -41,11 +42,11 @@ static int diff_print_info_init( return 0; } -static char pick_suffix(int mode) +static char diff_pick_suffix(int mode) { if (S_ISDIR(mode)) return '/'; - else if (mode & 0100) //-V536 + else if (GIT_PERMS_IS_EXEC(mode)) /* -V536 */ /* in git, modes are very regular, so we must have 0100755 mode */ return '*'; else @@ -76,45 +77,49 @@ static int callback_error(void) return GIT_EUSER; } -static int print_compact( +static int diff_print_one_compact( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; + git_buf *out = pi->buf; char old_suffix, new_suffix, code = git_diff_status_char(delta->status); + int (*strcomp)(const char *, const char *) = + pi->diff ? pi->diff->strcomp : git__strcmp; GIT_UNUSED(progress); if (code == ' ') return 0; - old_suffix = pick_suffix(delta->old_file.mode); - new_suffix = pick_suffix(delta->new_file.mode); + old_suffix = diff_pick_suffix(delta->old_file.mode); + new_suffix = diff_pick_suffix(delta->new_file.mode); - git_buf_clear(pi->buf); + git_buf_clear(out); if (delta->old_file.path != delta->new_file.path && - pi->diff->strcomp(delta->old_file.path,delta->new_file.path) != 0) - git_buf_printf(pi->buf, "%c\t%s%c -> %s%c\n", code, + strcomp(delta->old_file.path,delta->new_file.path) != 0) + git_buf_printf(out, "%c\t%s%c %s%c\n", code, delta->old_file.path, old_suffix, delta->new_file.path, new_suffix); else if (delta->old_file.mode != delta->new_file.mode && delta->old_file.mode != 0 && delta->new_file.mode != 0) - git_buf_printf(pi->buf, "%c\t%s%c (%o -> %o)\n", code, - delta->old_file.path, new_suffix, delta->old_file.mode, delta->new_file.mode); + git_buf_printf(out, "%c\t%s%c %s%c\n", code, + delta->old_file.path, old_suffix, delta->new_file.path, new_suffix); else if (old_suffix != ' ') - git_buf_printf(pi->buf, "%c\t%s%c\n", code, delta->old_file.path, old_suffix); + git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix); else - git_buf_printf(pi->buf, "%c\t%s\n", code, delta->old_file.path); + git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path); - if (git_buf_oom(pi->buf)) + if (git_buf_oom(out)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) + git_buf_cstr(out), git_buf_len(out), pi->payload)) return callback_error(); return 0; } +/* print a git_diff_list to a print callback in compact format */ int git_diff_print_compact( git_diff_list *diff, git_diff_data_cb print_cb, @@ -125,17 +130,18 @@ int git_diff_print_compact( diff_print_info pi; if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) - error = git_diff_foreach(diff, print_compact, NULL, NULL, &pi); + error = git_diff_foreach(diff, diff_print_one_compact, NULL, NULL, &pi); git_buf_free(&buf); return error; } -static int print_raw( +static int diff_print_one_raw( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; + git_buf *out = pi->buf; char code = git_diff_status_char(delta->status); char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; @@ -144,36 +150,37 @@ static int print_raw( if (code == ' ') return 0; - git_buf_clear(pi->buf); + git_buf_clear(out); git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); git_buf_printf( - pi->buf, ":%06o %06o %s... %s... %c", + out, ":%06o %06o %s... %s... %c", delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code); if (delta->similarity > 0) - git_buf_printf(pi->buf, "%03u", delta->similarity); + git_buf_printf(out, "%03u", delta->similarity); - if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED) + if (delta->old_file.path != delta->new_file.path) git_buf_printf( - pi->buf, "\t%s %s\n", delta->old_file.path, delta->new_file.path); + out, "\t%s %s\n", delta->old_file.path, delta->new_file.path); else git_buf_printf( - pi->buf, "\t%s\n", delta->old_file.path ? + out, "\t%s\n", delta->old_file.path ? delta->old_file.path : delta->new_file.path); - if (git_buf_oom(pi->buf)) + if (git_buf_oom(out)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) + git_buf_cstr(out), git_buf_len(out), pi->payload)) return callback_error(); return 0; } +/* print a git_diff_list to a print callback in raw output format */ int git_diff_print_raw( git_diff_list *diff, git_diff_data_cb print_cb, @@ -184,87 +191,115 @@ int git_diff_print_raw( diff_print_info pi; if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) - error = git_diff_foreach(diff, print_raw, NULL, NULL, &pi); + error = git_diff_foreach(diff, diff_print_one_raw, NULL, NULL, &pi); git_buf_free(&buf); return error; } -static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta) +static int diff_print_oid_range( + git_buf *out, const git_diff_delta *delta, int oid_strlen) { char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; - git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); - git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); + git_oid_tostr(start_oid, oid_strlen, &delta->old_file.oid); + git_oid_tostr(end_oid, oid_strlen, &delta->new_file.oid); /* TODO: Match git diff more closely */ if (delta->old_file.mode == delta->new_file.mode) { - git_buf_printf(pi->buf, "index %s..%s %o\n", + git_buf_printf(out, "index %s..%s %o\n", start_oid, end_oid, delta->old_file.mode); } else { if (delta->old_file.mode == 0) { - git_buf_printf(pi->buf, "new file mode %o\n", delta->new_file.mode); + git_buf_printf(out, "new file mode %o\n", delta->new_file.mode); } else if (delta->new_file.mode == 0) { - git_buf_printf(pi->buf, "deleted file mode %o\n", delta->old_file.mode); + git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode); } else { - git_buf_printf(pi->buf, "old mode %o\n", delta->old_file.mode); - git_buf_printf(pi->buf, "new mode %o\n", delta->new_file.mode); + git_buf_printf(out, "old mode %o\n", delta->old_file.mode); + git_buf_printf(out, "new mode %o\n", delta->new_file.mode); } - git_buf_printf(pi->buf, "index %s..%s\n", start_oid, end_oid); + git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); } - if (git_buf_oom(pi->buf)) + if (git_buf_oom(out)) return -1; return 0; } -static int print_patch_file( - const git_diff_delta *delta, float progress, void *data) +static int diff_delta_format_with_paths( + git_buf *out, + const git_diff_delta *delta, + const char *oldpfx, + const char *newpfx, + const char *template) { - diff_print_info *pi = data; - const char *oldpfx = pi->diff->opts.old_prefix; const char *oldpath = delta->old_file.path; - const char *newpfx = pi->diff->opts.new_prefix; const char *newpath = delta->new_file.path; - GIT_UNUSED(progress); + if (git_oid_iszero(&delta->old_file.oid)) { + oldpfx = ""; + oldpath = "/dev/null"; + } + if (git_oid_iszero(&delta->new_file.oid)) { + newpfx = ""; + newpath = "/dev/null"; + } - if (S_ISDIR(delta->new_file.mode) || - delta->status == GIT_DELTA_UNMODIFIED || - delta->status == GIT_DELTA_IGNORED || - (delta->status == GIT_DELTA_UNTRACKED && - (pi->diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) - return 0; + return git_buf_printf(out, template, oldpfx, oldpath, newpfx, newpath); +} +int git_diff_delta__format_file_header( + git_buf *out, + const git_diff_delta *delta, + const char *oldpfx, + const char *newpfx, + int oid_strlen) +{ if (!oldpfx) oldpfx = DIFF_OLD_PREFIX_DEFAULT; - if (!newpfx) newpfx = DIFF_NEW_PREFIX_DEFAULT; + if (!oid_strlen) + oid_strlen = GIT_ABBREV_DEFAULT + 1; - git_buf_clear(pi->buf); - git_buf_printf(pi->buf, "diff --git %s%s %s%s\n", oldpfx, delta->old_file.path, newpfx, delta->new_file.path); + git_buf_clear(out); - if (print_oid_range(pi, delta) < 0) + git_buf_printf(out, "diff --git %s%s %s%s\n", + oldpfx, delta->old_file.path, newpfx, delta->new_file.path); + + if (diff_print_oid_range(out, delta, oid_strlen) < 0) return -1; - if (git_oid_iszero(&delta->old_file.oid)) { - oldpfx = ""; - oldpath = "/dev/null"; - } - if (git_oid_iszero(&delta->new_file.oid)) { - newpfx = ""; - newpath = "/dev/null"; - } + if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) + diff_delta_format_with_paths( + out, delta, oldpfx, newpfx, "--- %s%s\n+++ %s%s\n"); - if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) { - git_buf_printf(pi->buf, "--- %s%s\n", oldpfx, oldpath); - git_buf_printf(pi->buf, "+++ %s%s\n", newpfx, newpath); - } + return git_buf_oom(out) ? -1 : 0; +} - if (git_buf_oom(pi->buf)) +static int diff_print_patch_file( + const git_diff_delta *delta, float progress, void *data) +{ + diff_print_info *pi = data; + const char *oldpfx = + pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT; + const char *newpfx = + pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT; + uint32_t opts_flags = pi->diff ? pi->diff->opts.flags : GIT_DIFF_NORMAL; + + GIT_UNUSED(progress); + + if (S_ISDIR(delta->new_file.mode) || + delta->status == GIT_DELTA_UNMODIFIED || + delta->status == GIT_DELTA_IGNORED || + (delta->status == GIT_DELTA_UNTRACKED && + (opts_flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) + return 0; + + if (git_diff_delta__format_file_header( + pi->buf, delta, oldpfx, newpfx, pi->oid_strlen) < 0) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, @@ -275,10 +310,10 @@ static int print_patch_file( return 0; git_buf_clear(pi->buf); - git_buf_printf( - pi->buf, "Binary files %s%s and %s%s differ\n", - oldpfx, oldpath, newpfx, newpath); - if (git_buf_oom(pi->buf)) + + if (diff_delta_format_with_paths( + pi->buf, delta, oldpfx, newpfx, + "Binary files %s%s and %s%s differ\n") < 0) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, @@ -288,7 +323,7 @@ static int print_patch_file( return 0; } -static int print_patch_hunk( +static int diff_print_patch_hunk( const git_diff_delta *d, const git_diff_range *r, const char *header, @@ -311,7 +346,7 @@ static int print_patch_hunk( return 0; } -static int print_patch_line( +static int diff_print_patch_line( const git_diff_delta *delta, const git_diff_range *range, char line_origin, /* GIT_DIFF_LINE value from above */ @@ -343,6 +378,7 @@ static int print_patch_line( return 0; } +/* print a git_diff_list to an output callback in patch format */ int git_diff_print_patch( git_diff_list *diff, git_diff_data_cb print_cb, @@ -354,27 +390,15 @@ int git_diff_print_patch( if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) error = git_diff_foreach( - diff, print_patch_file, print_patch_hunk, print_patch_line, &pi); + diff, diff_print_patch_file, diff_print_patch_hunk, + diff_print_patch_line, &pi); git_buf_free(&buf); return error; } - -static int print_to_buffer_cb( - const git_diff_delta *delta, - const git_diff_range *range, - char line_origin, - const char *content, - size_t content_len, - void *payload) -{ - git_buf *output = payload; - GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); - return git_buf_put(output, content, content_len); -} - +/* print a git_diff_patch to an output callback */ int git_diff_patch_print( git_diff_patch *patch, git_diff_data_cb print_cb, @@ -389,13 +413,28 @@ int git_diff_patch_print( if (!(error = diff_print_info_init( &pi, &temp, git_diff_patch__diff(patch), print_cb, payload))) error = git_diff_patch__invoke_callbacks( - patch, print_patch_file, print_patch_hunk, print_patch_line, &pi); + patch, diff_print_patch_file, diff_print_patch_hunk, + diff_print_patch_line, &pi); git_buf_free(&temp); return error; } +static int diff_print_to_buffer_cb( + const git_diff_delta *delta, + const git_diff_range *range, + char line_origin, + const char *content, + size_t content_len, + void *payload) +{ + git_buf *output = payload; + GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); + return git_buf_put(output, content, content_len); +} + +/* print a git_diff_patch to a string buffer */ int git_diff_patch_to_str( char **string, git_diff_patch *patch) @@ -403,7 +442,7 @@ int git_diff_patch_to_str( int error; git_buf output = GIT_BUF_INIT; - error = git_diff_patch_print(patch, print_to_buffer_cb, &output); + error = git_diff_patch_print(patch, diff_print_to_buffer_cb, &output); /* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1, * meaning a memory allocation failure, so just map to -1... |