This patches enables to perform textconv with blame if a textconv driver is available for 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. 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 declaration of fill_blob_sha1 declaration is modified to get back the mode the function was getting. Signed-off-by: Diane Gasselin <diane.gasselin@xxxxxxxxxxxxxxx> Signed-off-by: Clément Poulain <clement.poulain@xxxxxxxxxxxxxxx> Signed-off-by: Axel Bonnet <axel.bonnet@xxxxxxxxxxxxxxx> --- builtin/blame.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 63 insertions(+), 11 deletions(-) diff --git a/builtin/blame.c b/builtin/blame.c index 63b497c..4679fd9 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -20,6 +20,7 @@ #include "mailmap.h" #include "parse-options.h" #include "utf8.h" +#include "userdiff.h" static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; @@ -86,17 +87,57 @@ struct origin { }; /* + * Prepare diff_filespec and convert it using diff textconv API + * if the textconv driver exists. + * Return 1 if the conversion succeeds, 0 otherwise. + */ +static int textconv_object(const char *path, + const unsigned char *sha1, + unsigned short mode, + struct strbuf *buf) +{ + struct diff_filespec *df; + + df = alloc_filespec(path); + fill_filespec(df, sha1, mode); + get_textconv(df); + + if (!df->driver|| !df->driver->textconv) { + free_filespec(df); + return 0; + } + + buf->len = fill_textconv(df->driver, df, &buf->buf); + buf->alloc = 1; + free_filespec(df); + return 1; +} + +/* * Given an origin, prepare mmfile_t structure to be used by the * diff machinery */ static void fill_origin_blob(struct diff_options opt, struct origin *o, mmfile_t *file) { + unsigned mode; + if (!o->file.ptr) { + struct strbuf buf = STRBUF_INIT; enum object_type type; num_read_blob++; - file->ptr = read_sha1_file(o->blob_sha1, &type, - (unsigned long *)(&(file->size))); + + get_tree_entry(o->commit->object.sha1, + o->path, + o->blob_sha1, &mode); + if (DIFF_OPT_TST(&opt, ALLOW_TEXTCONV) && + textconv_object(o->path, o->blob_sha1, mode, &buf)) + file->ptr = strbuf_detach(&buf, (size_t *) &file->size); + else + file->ptr = read_sha1_file(o->blob_sha1, &type, + (unsigned long *)(&(file->size))); + strbuf_release(&buf); + if (!file->ptr) die("Cannot read blob %s for path %s", sha1_to_hex(o->blob_sha1), @@ -280,15 +321,13 @@ static struct origin *get_origin(struct scoreboard *sb, * the parent to detect the case where a child's blob is identical to * that of its parent's. */ -static int fill_blob_sha1(struct origin *origin) +static int fill_blob_sha1(struct origin *origin, unsigned *mode) { - unsigned mode; - if (!is_null_sha1(origin->blob_sha1)) return 0; if (get_tree_entry(origin->commit->object.sha1, origin->path, - origin->blob_sha1, &mode)) + origin->blob_sha1, mode)) goto error_out; if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB) goto error_out; @@ -2033,10 +2072,13 @@ static struct commit *fake_working_tree_commit(struct diff_options opt, read_from = path; } mode = canon_mode(st.st_mode); + switch (st.st_mode & S_IFMT) { case S_IFREG: - if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) - die_errno("cannot open or read '%s'", read_from); + if (!DIFF_OPT_TST(&opt, ALLOW_TEXTCONV) || + !textconv_object(read_from, null_sha1, mode, &buf)) + if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) + die_errno("cannot open or read '%s'", read_from); break; case S_IFLNK: if (strbuf_readlink(&buf, read_from, st.st_size) < 0) @@ -2249,8 +2291,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix) int cmd_is_annotate = !strcmp(argv[0], "annotate"); git_config(git_blame_config, NULL); + git_config(git_diff_ui_config, NULL); init_revisions(&revs, NULL); revs.date_mode = blame_date_mode; + DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV); save_commit_buffer = 0; dashdash_pos = 0; @@ -2411,12 +2455,20 @@ parse_done: sb.final_buf_size = o->file.size; } else { + struct strbuf buf = STRBUF_INIT; + unsigned mode; o = get_origin(&sb, sb.final, path); - if (fill_blob_sha1(o)) + if (fill_blob_sha1(o, &mode)) die("no such path %s in %s", path, final_commit_name); - sb.final_buf = read_sha1_file(o->blob_sha1, &type, - &sb.final_buf_size); + if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) && + textconv_object(path, o->blob_sha1, mode, &buf)) + sb.final_buf= strbuf_detach(&buf, (size_t *) &sb.final_buf_size); + else + sb.final_buf = read_sha1_file(o->blob_sha1, &type, + &sb.final_buf_size); + + strbuf_release(&buf); if (!sb.final_buf) die("Cannot read blob %s for path %s", sha1_to_hex(o->blob_sha1), -- 1.6.6.7.ga5fe3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html