@matheusbsbs / matheus-bagliano / commits / 3b8a12e8f8
Fork 0

textconv: support for blame

This patches enables to perform textconv with blame if a textconv driver is available fos the file. The main task is performed by the textconv_object function which prepares diff_filespec and if possible converts the file using diff textconv API. Only regular files are converted, so the mode of diff_filespec is faked. Textconv conversion is enabled by default (equivalent to the option --textconv), since blaming binary files is useless in most cases. The option --no-textconv is used to disable textconv conversion. The declarations of several functions are modified to give access to a diff_options, in order to know whether the textconv option is activated or not. Signed-off-by: Axel Bonnet <axel.bonnet@ensimag.imag.fr> Signed-off-by: Clément Poulain <clement.poulain@ensimag.imag.fr> Signed-off-by: Diane Gasselin <diane.gasselin@ensimag.imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Axel Bonnet committed Jun 15, 2010 at 15:58 UTC 3b8a12e8f8c2f4b200e228bc2aa71741c529553c
1 file changed +72 -13
builtin/blame.c
+72 -13
@@ -20,6 +20,7 @@
20 #include "mailmap.h"
21 #include "parse-options.h"
22 #include "utf8.h"
23 +#include "userdiff.h"
24
25 static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
26
@@ -85,17 +86,51 @@ struct origin {
86 char path[FLEX_ARRAY];
87 };
88
89 +/*
90 + * Prepare diff_filespec and convert it using diff textconv API
91 + * if the textconv driver exists.
92 + * Return 1 if the conversion succeeds, 0 otherwise.
93 + */
94 +static int textconv_object(const char *path,
95 + const unsigned char *sha1,
96 + char **buf,
97 + unsigned long *buf_size)
98 +{
99 + struct diff_filespec *df;
100 + struct userdiff_driver *textconv;
101 +
102 + df = alloc_filespec(path);
103 + fill_filespec(df, sha1, S_IFREG | 0664);
104 + textconv = get_textconv(df);
105 + if (!textconv) {
106 + free_filespec(df);
107 + return 0;
108 + }
109 +
110 + *buf_size = fill_textconv(textconv, df, buf);
111 + free_filespec(df);
112 + return 1;
113 +}
114 +
115 /*
116 * Given an origin, prepare mmfile_t structure to be used by the
117 * diff machinery
118 */
92 -static void fill_origin_blob(struct origin *o, mmfile_t *file)
119 +static void fill_origin_blob(struct diff_options *opt,
120 + struct origin *o, mmfile_t *file)
121 {
122 if (!o->file.ptr) {
123 enum object_type type;
124 + unsigned long file_size;
125 +
126 num_read_blob++;
97 - file->ptr = read_sha1_file(o->blob_sha1, &type,
98 - (unsigned long *)(&(file->size)));
127 + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
128 + textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
129 + ;
130 + else
131 + file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
132 + file->size = file_size;
133 +
134 if (!file->ptr)
135 die("Cannot read blob %s for path %s",
136 sha1_to_hex(o->blob_sha1),
@@ -282,7 +317,6 @@ static struct origin *get_origin(struct scoreboard *sb,
317 static int fill_blob_sha1(struct origin *origin)
318 {
319 unsigned mode;
285 -
320 if (!is_null_sha1(origin->blob_sha1))
321 return 0;
322 if (get_tree_entry(origin->commit->object.sha1,
@@ -741,8 +775,8 @@ static int pass_blame_to_parent(struct scoreboard *sb,
775 if (last_in_target < 0)
776 return 1; /* nothing remains for this target */
777
744 - fill_origin_blob(parent, &file_p);
745 - fill_origin_blob(target, &file_o);
778 + fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
779 + fill_origin_blob(&sb->revs->diffopt, target, &file_o);
780 num_get_patch++;
781
782 memset(&xpp, 0, sizeof(xpp));
@@ -922,7 +956,7 @@ static int find_move_in_parent(struct scoreboard *sb,
956 if (last_in_target < 0)
957 return 1; /* nothing remains for this target */
958
925 - fill_origin_blob(parent, &file_p);
959 + fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
960 if (!file_p.ptr)
961 return 0;
962
@@ -1063,7 +1097,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
1097
1098 norigin = get_origin(sb, parent, p->one->path);
1099 hashcpy(norigin->blob_sha1, p->one->sha1);
1066 - fill_origin_blob(norigin, &file_p);
1100 + fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
1101 if (!file_p.ptr)
1102 continue;
1103
@@ -1983,6 +2017,16 @@ static int git_blame_config(const char *var, const char *value, void *cb)
2017 blame_date_mode = parse_date_format(value);
2018 return 0;
2019 }
2020 +
2021 + switch (userdiff_config(var, value)) {
2022 + case 0:
2023 + break;
2024 + case -1:
2025 + return -1;
2026 + default:
2027 + return 0;
2028 + }
2029 +
2030 return git_default_config(var, value, cb);
2031 }
2032
@@ -1990,7 +2034,9 @@ static int git_blame_config(const char *var, const char *value, void *cb)
2034 * Prepare a dummy commit that represents the work tree (or staged) item.
2035 * Note that annotating work tree item never works in the reverse.
2036 */
1993 -static struct commit *fake_working_tree_commit(const char *path, const char *contents_from)
2037 +static struct commit *fake_working_tree_commit(struct diff_options *opt,
2038 + const char *path,
2039 + const char *contents_from)
2040 {
2041 struct commit *commit;
2042 struct origin *origin;
@@ -2018,6 +2064,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
2064 if (!contents_from || strcmp("-", contents_from)) {
2065 struct stat st;
2066 const char *read_from;
2067 + unsigned long buf_len;
2068
2069 if (contents_from) {
2070 if (stat(contents_from, &st) < 0)
@@ -2030,9 +2077,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
2077 read_from = path;
2078 }
2079 mode = canon_mode(st.st_mode);
2080 +
2081 switch (st.st_mode & S_IFMT) {
2082 case S_IFREG:
2035 - if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
2083 + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
2084 + textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
2085 + buf.len = buf_len;
2086 + else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
2087 die_errno("cannot open or read '%s'", read_from);
2088 break;
2089 case S_IFLNK:
@@ -2248,6 +2299,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2299 git_config(git_blame_config, NULL);
2300 init_revisions(&revs, NULL);
2301 revs.date_mode = blame_date_mode;
2302 + DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
2303
2304 save_commit_buffer = 0;
2305 dashdash_pos = 0;
@@ -2384,7 +2436,8 @@ parse_done:
2436 * or "--contents".
2437 */
2438 setup_work_tree();
2387 - sb.final = fake_working_tree_commit(path, contents_from);
2439 + sb.final = fake_working_tree_commit(&sb.revs->diffopt,
2440 + path, contents_from);
2441 add_pending_object(&revs, &(sb.final->object), ":");
2442 }
2443 else if (contents_from)
@@ -2411,8 +2464,14 @@ parse_done:
2464 if (fill_blob_sha1(o))
2465 die("no such path %s in %s", path, final_commit_name);
2466
2414 - sb.final_buf = read_sha1_file(o->blob_sha1, &type,
2415 - &sb.final_buf_size);
2467 + if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
2468 + textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
2469 + &sb.final_buf_size))
2470 + ;
2471 + else
2472 + sb.final_buf = read_sha1_file(o->blob_sha1, &type,
2473 + &sb.final_buf_size);
2474 +
2475 if (!sb.final_buf)
2476 die("Cannot read blob %s for path %s",
2477 sha1_to_hex(o->blob_sha1),