From 3a4375901a92efdc641c714ec9fd07b53f2f781e Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 3 Feb 2012 16:53:01 -0800 Subject: Clean up diff implementation for review This fixes several bugs, updates tests and docs, eliminates the FILE* assumption in favor of printing callbacks for the diff patch formatter helpers, and adds a "diff" example function that can perform a diff from the command line. --- examples/diff.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 examples/diff.c (limited to 'examples/diff.c') diff --git a/examples/diff.c b/examples/diff.c new file mode 100644 index 000000000..9b696dad5 --- /dev/null +++ b/examples/diff.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +void check(int error, const char *message) +{ + if (error) { + fprintf(stderr, "%s (%d)\n", message, error); + exit(1); + } +} + +int resolve_to_tree(git_repository *repo, const char *identifier, git_tree **tree) +{ + int err = 0; + size_t len = strlen(identifier); + git_oid oid; + git_object *obj = NULL; + + /* try to resolve as OID */ + if (git_oid_fromstrn(&oid, identifier, len) == 0) + git_object_lookup_prefix(&obj, repo, &oid, len, GIT_OBJ_ANY); + + /* try to resolve as reference */ + if (obj == NULL) { + git_reference *ref, *resolved; + if (git_reference_lookup(&ref, repo, identifier) == 0) { + git_reference_resolve(&resolved, ref); + git_reference_free(ref); + if (resolved) { + git_object_lookup(&obj, repo, git_reference_oid(resolved), GIT_OBJ_ANY); + git_reference_free(resolved); + } + } + } + + if (obj == NULL) + return GIT_ENOTFOUND; + + switch (git_object_type(obj)) { + case GIT_OBJ_TREE: + *tree = (git_tree *)obj; + break; + case GIT_OBJ_COMMIT: + err = git_commit_tree(tree, (git_commit *)obj); + git_object_free(obj); + break; + default: + err = GIT_ENOTFOUND; + } + + return err; +} + +char *colors[] = { + "\033[m", /* reset */ + "\033[1m", /* bold */ + "\033[31m", /* red */ + "\033[32m", /* green */ + "\033[36m" /* cyan */ +}; + +int printer(void *data, char usage, const char *line) +{ + int *last_color = data, color = 0; + + if (*last_color >= 0) { + switch (usage) { + case GIT_DIFF_LINE_ADDITION: color = 3; break; + case GIT_DIFF_LINE_DELETION: color = 2; break; + case GIT_DIFF_LINE_ADD_EOFNL: color = 3; break; + case GIT_DIFF_LINE_DEL_EOFNL: color = 2; break; + case GIT_DIFF_LINE_FILE_HDR: color = 1; break; + case GIT_DIFF_LINE_HUNK_HDR: color = 4; break; + default: color = 0; + } + if (color != *last_color) { + if (*last_color == 1 || color == 1) + fputs(colors[0], stdout); + fputs(colors[color], stdout); + *last_color = color; + } + } + + fputs(line, stdout); + return 0; +} + +int main(int argc, char *argv[]) +{ + char path[GIT_PATH_MAX]; + git_repository *repo = NULL; + git_tree *a, *b; + git_diff_options opts = {0}; + git_diff_list *diff; + char *dir = "."; + int color = -1; + + if (argc != 3) { + fprintf(stderr, "usage: diff \n"); + exit(1); + } + + check(git_repository_discover(path, sizeof(path), dir, 0, "/"), + "Could not discover repository"); + check(git_repository_open(&repo, path), + "Could not open repository"); + + check(resolve_to_tree(repo, argv[1], &a), "Looking up first tree"); + check(resolve_to_tree(repo, argv[2], &b), "Looking up second tree"); + + check(git_diff_tree_to_tree(repo, &opts, a, b, &diff), "Generating diff"); + + fputs(colors[0], stdout); + + check(git_diff_print_compact(diff, &color, printer), "Displaying diff summary"); + + fprintf(stdout, "--\n"); + + color = 0; + + check(git_diff_print_patch(diff, &color, printer), "Displaying diff"); + + fputs(colors[0], stdout); + + git_diff_list_free(diff); + git_tree_free(a); + git_tree_free(b); + git_repository_free(repo); + + return 0; +} + -- cgit v1.2.1 From a2e895be820a2fd77285ef4576afe53f68c96ca2 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 7 Feb 2012 12:14:28 -0800 Subject: Continue implementation of git-diff * Implemented git_diff_index_to_tree * Reworked git_diff_options structure to handle more options * Made most of the options in git_diff_options actually work * Reorganized code a bit to remove some redundancy * Added option parsing to examples/diff.c to test most options --- examples/diff.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 20 deletions(-) (limited to 'examples/diff.c') diff --git a/examples/diff.c b/examples/diff.c index 9b696dad5..5eb0f3179 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -87,46 +87,123 @@ int printer(void *data, char usage, const char *line) return 0; } +int check_uint16_param(const char *arg, const char *pattern, uint16_t *val) +{ + size_t len = strlen(pattern); + uint16_t strval; + char *endptr = NULL; + if (strncmp(arg, pattern, len)) + return 0; + strval = strtoul(arg + len, &endptr, 0); + if (endptr == arg) + return 0; + *val = strval; + return 1; +} + +int check_str_param(const char *arg, const char *pattern, char **val) +{ + size_t len = strlen(pattern); + if (strncmp(arg, pattern, len)) + return 0; + *val = (char *)(arg + len); + return 1; +} + +void usage(const char *message, const char *arg) +{ + if (message && arg) + fprintf(stderr, "%s: %s\n", message, arg); + else if (message) + fprintf(stderr, "%s\n", message); + fprintf(stderr, "usage: diff \n"); + exit(1); +} + int main(int argc, char *argv[]) { char path[GIT_PATH_MAX]; git_repository *repo = NULL; - git_tree *a, *b; + git_tree *t1 = NULL, *t2 = NULL; git_diff_options opts = {0}; git_diff_list *diff; - char *dir = "."; - int color = -1; + int i, color = -1, compact = 0; + char *a, *dir = ".", *treeish1 = NULL, *treeish2 = NULL; - if (argc != 3) { - fprintf(stderr, "usage: diff \n"); - exit(1); + /* parse arguments as copied from git-diff */ + + for (i = 1; i < argc; ++i) { + a = argv[i]; + + if (a[0] != '-') { + if (treeish1 == NULL) + treeish1 = a; + else if (treeish2 == NULL) + treeish2 = a; + else + usage("Only one or two tree identifiers can be provided", NULL); + } + else if (!strcmp(a, "-p") || !strcmp(a, "-u") || + !strcmp(a, "--patch")) + compact = 0; + else if (!strcmp(a, "--name-status")) + compact = 1; + else if (!strcmp(a, "--color")) + color = 0; + else if (!strcmp(a, "--no-color")) + color = -1; + else if (!strcmp(a, "-R")) + opts.flags |= GIT_DIFF_REVERSE; + else if (!strcmp(a, "-a") || !strcmp(a, "--text")) + opts.flags |= GIT_DIFF_FORCE_TEXT; + else if (!strcmp(a, "--ignore-space-at-eol")) + opts.flags |= GIT_DIFF_IGNORE_WHITESPACE_EOL; + else if (!strcmp(a, "-b") || !strcmp(a, "--ignore-space-change")) + opts.flags |= GIT_DIFF_IGNORE_WHITESPACE_CHANGE; + else if (!strcmp(a, "-w") || !strcmp(a, "--ignore-all-space")) + opts.flags |= GIT_DIFF_IGNORE_WHITESPACE; + else if (!check_uint16_param(a, "-U", &opts.context_lines) && + !check_uint16_param(a, "--unified=", &opts.context_lines) && + !check_uint16_param(a, "--inter-hunk-context=", + &opts.interhunk_lines) && + !check_str_param(a, "--src-prefix=", &opts.src_prefix) && + !check_str_param(a, "--dst-prefix=", &opts.dst_prefix)) + usage("Unknown arg", a); } + if (!treeish1) + usage("Must provide at least one tree identifier (for now)", NULL); + + /* open repo */ + check(git_repository_discover(path, sizeof(path), dir, 0, "/"), "Could not discover repository"); check(git_repository_open(&repo, path), "Could not open repository"); - check(resolve_to_tree(repo, argv[1], &a), "Looking up first tree"); - check(resolve_to_tree(repo, argv[2], &b), "Looking up second tree"); - - check(git_diff_tree_to_tree(repo, &opts, a, b, &diff), "Generating diff"); - - fputs(colors[0], stdout); - - check(git_diff_print_compact(diff, &color, printer), "Displaying diff summary"); + check(resolve_to_tree(repo, treeish1, &t1), "Looking up first tree"); + if (treeish2) + check(resolve_to_tree(repo, treeish2, &t2), "Looking up second tree"); - fprintf(stdout, "--\n"); + if (!treeish2) + check(git_diff_index_to_tree(repo, &opts, t1, &diff), "Generating diff"); + else + check(git_diff_tree_to_tree(repo, &opts, t1, t2, &diff), "Generating diff"); - color = 0; + if (color >= 0) + fputs(colors[0], stdout); - check(git_diff_print_patch(diff, &color, printer), "Displaying diff"); + if (compact) + check(git_diff_print_compact(diff, &color, printer), "Displaying diff summary"); + else + check(git_diff_print_patch(diff, &color, printer), "Displaying diff"); - fputs(colors[0], stdout); + if (color >= 0) + fputs(colors[0], stdout); git_diff_list_free(diff); - git_tree_free(a); - git_tree_free(b); + git_tree_free(t1); + git_tree_free(t2); git_repository_free(repo); return 0; -- cgit v1.2.1 From 74fa4bfae37e9d7c9e35550c881b114d7a83c4fa Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 28 Feb 2012 16:14:47 -0800 Subject: Update diff to use iterators This is a major reorganization of the diff code. This changes the diff functions to use the iterators for traversing the content. This allowed a lot of code to be simplified. Also, this moved the functions relating to outputting a diff into a new file (diff_output.c). This includes a number of other changes - adding utility functions, extending iterators, etc. plus more tests for the diff code. This also takes the example diff.c program much further in terms of emulating git-diff command line options. --- examples/diff.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) (limited to 'examples/diff.c') diff --git a/examples/diff.c b/examples/diff.c index 5eb0f3179..f80f7029c 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -116,7 +116,7 @@ void usage(const char *message, const char *arg) fprintf(stderr, "%s: %s\n", message, arg); else if (message) fprintf(stderr, "%s\n", message); - fprintf(stderr, "usage: diff \n"); + fprintf(stderr, "usage: diff [ []]\n"); exit(1); } @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) git_tree *t1 = NULL, *t2 = NULL; git_diff_options opts = {0}; git_diff_list *diff; - int i, color = -1, compact = 0; + int i, color = -1, compact = 0, cached = 0; char *a, *dir = ".", *treeish1 = NULL, *treeish2 = NULL; /* parse arguments as copied from git-diff */ @@ -146,6 +146,8 @@ int main(int argc, char *argv[]) else if (!strcmp(a, "-p") || !strcmp(a, "-u") || !strcmp(a, "--patch")) compact = 0; + else if (!strcmp(a, "--cached")) + cached = 1; else if (!strcmp(a, "--name-status")) compact = 1; else if (!strcmp(a, "--color")) @@ -162,6 +164,10 @@ int main(int argc, char *argv[]) opts.flags |= GIT_DIFF_IGNORE_WHITESPACE_CHANGE; else if (!strcmp(a, "-w") || !strcmp(a, "--ignore-all-space")) opts.flags |= GIT_DIFF_IGNORE_WHITESPACE; + else if (!strcmp(a, "--ignored")) + opts.flags |= GIT_DIFF_INCLUDE_IGNORED; + else if (!strcmp(a, "--untracked")) + opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; else if (!check_uint16_param(a, "-U", &opts.context_lines) && !check_uint16_param(a, "--unified=", &opts.context_lines) && !check_uint16_param(a, "--inter-hunk-context=", @@ -171,9 +177,6 @@ int main(int argc, char *argv[]) usage("Unknown arg", a); } - if (!treeish1) - usage("Must provide at least one tree identifier (for now)", NULL); - /* open repo */ check(git_repository_discover(path, sizeof(path), dir, 0, "/"), @@ -181,20 +184,40 @@ int main(int argc, char *argv[]) check(git_repository_open(&repo, path), "Could not open repository"); - check(resolve_to_tree(repo, treeish1, &t1), "Looking up first tree"); + if (treeish1) + check(resolve_to_tree(repo, treeish1, &t1), "Looking up first tree"); if (treeish2) check(resolve_to_tree(repo, treeish2, &t2), "Looking up second tree"); - if (!treeish2) - check(git_diff_index_to_tree(repo, &opts, t1, &diff), "Generating diff"); + /* */ + /* --cached */ + /* */ + /* --cached */ + /* nothing */ + + if (t1 && t2) + check(git_diff_tree_to_tree(repo, &opts, t1, t2, &diff), "Diff"); + else if (t1 && cached) + check(git_diff_index_to_tree(repo, &opts, t1, &diff), "Diff"); + else if (t1) { + git_diff_list *diff2; + check(git_diff_index_to_tree(repo, &opts, t1, &diff), "Diff"); + check(git_diff_workdir_to_index(repo, &opts, &diff2), "Diff"); + check(git_diff_merge(diff, diff2), "Merge diffs"); + git_diff_list_free(diff2); + } + else if (cached) { + check(resolve_to_tree(repo, "HEAD", &t1), "looking up HEAD"); + check(git_diff_index_to_tree(repo, &opts, t1, &diff), "Diff"); + } else - check(git_diff_tree_to_tree(repo, &opts, t1, t2, &diff), "Generating diff"); + check(git_diff_workdir_to_index(repo, &opts, &diff), "Diff"); if (color >= 0) fputs(colors[0], stdout); if (compact) - check(git_diff_print_compact(diff, &color, printer), "Displaying diff summary"); + check(git_diff_print_compact(diff, &color, printer), "Displaying diff"); else check(git_diff_print_patch(diff, &color, printer), "Displaying diff"); -- cgit v1.2.1 From 288c8a25750af694685ad71e08b6708729266aa9 Mon Sep 17 00:00:00 2001 From: schu Date: Tue, 13 Mar 2012 16:48:07 +0100 Subject: examples/diff: update example code Signed-off-by: schu --- examples/diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/diff.c') diff --git a/examples/diff.c b/examples/diff.c index f80f7029c..20e14e511 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -172,8 +172,8 @@ int main(int argc, char *argv[]) !check_uint16_param(a, "--unified=", &opts.context_lines) && !check_uint16_param(a, "--inter-hunk-context=", &opts.interhunk_lines) && - !check_str_param(a, "--src-prefix=", &opts.src_prefix) && - !check_str_param(a, "--dst-prefix=", &opts.dst_prefix)) + !check_str_param(a, "--src-prefix=", &opts.old_prefix) && + !check_str_param(a, "--dst-prefix=", &opts.new_prefix)) usage("Unknown arg", a); } -- cgit v1.2.1 From 706a9974a297ea1b38c6aab886b54598409725e8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 17 May 2012 13:05:17 -0700 Subject: Basic setup for profiling This fixes the examples so they will build and adds a PROFILE option to the CMakeFile that enabled gprof info on non-Windows --- examples/diff.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'examples/diff.c') diff --git a/examples/diff.c b/examples/diff.c index 20e14e511..1b4ab549b 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -61,7 +61,13 @@ char *colors[] = { "\033[36m" /* cyan */ }; -int printer(void *data, char usage, const char *line) +int printer( + void *data, + git_diff_delta *delta, + git_diff_range *range, + char usage, + const char *line, + size_t line_len) { int *last_color = data, color = 0; -- cgit v1.2.1