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>
This commit is contained in:
		 Axel Bonnet
					Axel Bonnet
				
			
				
					committed by
					
						 Junio C Hamano
						Junio C Hamano
					
				
			
			
				
	
			
			
			 Junio C Hamano
						Junio C Hamano
					
				
			
						parent
						
							a788d7d58b
						
					
				
				
					commit
					3b8a12e8f8
				
			| @ -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"; | ||||
|  | ||||
| @ -85,17 +86,51 @@ struct origin { | ||||
| 	char path[FLEX_ARRAY]; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * 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, | ||||
| 			   char **buf, | ||||
| 			   unsigned long *buf_size) | ||||
| { | ||||
| 	struct diff_filespec *df; | ||||
| 	struct userdiff_driver *textconv; | ||||
|  | ||||
| 	df = alloc_filespec(path); | ||||
| 	fill_filespec(df, sha1, S_IFREG | 0664); | ||||
| 	textconv = get_textconv(df); | ||||
| 	if (!textconv) { | ||||
| 		free_filespec(df); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*buf_size = fill_textconv(textconv, df, buf); | ||||
| 	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 origin *o, mmfile_t *file) | ||||
| static void fill_origin_blob(struct diff_options *opt, | ||||
| 			     struct origin *o, mmfile_t *file) | ||||
| { | ||||
| 	if (!o->file.ptr) { | ||||
| 		enum object_type type; | ||||
| 		unsigned long file_size; | ||||
|  | ||||
| 		num_read_blob++; | ||||
| 		file->ptr = read_sha1_file(o->blob_sha1, &type, | ||||
| 					   (unsigned long *)(&(file->size))); | ||||
| 		if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && | ||||
| 		    textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size)) | ||||
| 			; | ||||
| 		else | ||||
| 			file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size); | ||||
| 		file->size = file_size; | ||||
|  | ||||
| 		if (!file->ptr) | ||||
| 			die("Cannot read blob %s for path %s", | ||||
| 			    sha1_to_hex(o->blob_sha1), | ||||
| @ -282,7 +317,6 @@ static struct origin *get_origin(struct scoreboard *sb, | ||||
| static int fill_blob_sha1(struct origin *origin) | ||||
| { | ||||
| 	unsigned mode; | ||||
|  | ||||
| 	if (!is_null_sha1(origin->blob_sha1)) | ||||
| 		return 0; | ||||
| 	if (get_tree_entry(origin->commit->object.sha1, | ||||
| @ -741,8 +775,8 @@ static int pass_blame_to_parent(struct scoreboard *sb, | ||||
| 	if (last_in_target < 0) | ||||
| 		return 1; /* nothing remains for this target */ | ||||
|  | ||||
| 	fill_origin_blob(parent, &file_p); | ||||
| 	fill_origin_blob(target, &file_o); | ||||
| 	fill_origin_blob(&sb->revs->diffopt, parent, &file_p); | ||||
| 	fill_origin_blob(&sb->revs->diffopt, target, &file_o); | ||||
| 	num_get_patch++; | ||||
|  | ||||
| 	memset(&xpp, 0, sizeof(xpp)); | ||||
| @ -922,7 +956,7 @@ static int find_move_in_parent(struct scoreboard *sb, | ||||
| 	if (last_in_target < 0) | ||||
| 		return 1; /* nothing remains for this target */ | ||||
|  | ||||
| 	fill_origin_blob(parent, &file_p); | ||||
| 	fill_origin_blob(&sb->revs->diffopt, parent, &file_p); | ||||
| 	if (!file_p.ptr) | ||||
| 		return 0; | ||||
|  | ||||
| @ -1063,7 +1097,7 @@ static int find_copy_in_parent(struct scoreboard *sb, | ||||
|  | ||||
| 			norigin = get_origin(sb, parent, p->one->path); | ||||
| 			hashcpy(norigin->blob_sha1, p->one->sha1); | ||||
| 			fill_origin_blob(norigin, &file_p); | ||||
| 			fill_origin_blob(&sb->revs->diffopt, norigin, &file_p); | ||||
| 			if (!file_p.ptr) | ||||
| 				continue; | ||||
|  | ||||
| @ -1983,6 +2017,16 @@ static int git_blame_config(const char *var, const char *value, void *cb) | ||||
| 		blame_date_mode = parse_date_format(value); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	switch (userdiff_config(var, value)) { | ||||
| 	case 0: | ||||
| 		break; | ||||
| 	case -1: | ||||
| 		return -1; | ||||
| 	default: | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return git_default_config(var, value, cb); | ||||
| } | ||||
|  | ||||
| @ -1990,7 +2034,9 @@ static int git_blame_config(const char *var, const char *value, void *cb) | ||||
|  * Prepare a dummy commit that represents the work tree (or staged) item. | ||||
|  * Note that annotating work tree item never works in the reverse. | ||||
|  */ | ||||
| static struct commit *fake_working_tree_commit(const char *path, const char *contents_from) | ||||
| static struct commit *fake_working_tree_commit(struct diff_options *opt, | ||||
| 					       const char *path, | ||||
| 					       const char *contents_from) | ||||
| { | ||||
| 	struct commit *commit; | ||||
| 	struct origin *origin; | ||||
| @ -2018,6 +2064,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con | ||||
| 	if (!contents_from || strcmp("-", contents_from)) { | ||||
| 		struct stat st; | ||||
| 		const char *read_from; | ||||
| 		unsigned long buf_len; | ||||
|  | ||||
| 		if (contents_from) { | ||||
| 			if (stat(contents_from, &st) < 0) | ||||
| @ -2030,9 +2077,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con | ||||
| 			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) | ||||
| 			if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && | ||||
| 			    textconv_object(read_from, null_sha1, &buf.buf, &buf_len)) | ||||
| 				buf.len = buf_len; | ||||
| 			else 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: | ||||
| @ -2248,6 +2299,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) | ||||
| 	git_config(git_blame_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; | ||||
| @ -2384,7 +2436,8 @@ parse_done: | ||||
| 		 * or "--contents". | ||||
| 		 */ | ||||
| 		setup_work_tree(); | ||||
| 		sb.final = fake_working_tree_commit(path, contents_from); | ||||
| 		sb.final = fake_working_tree_commit(&sb.revs->diffopt, | ||||
| 						    path, contents_from); | ||||
| 		add_pending_object(&revs, &(sb.final->object), ":"); | ||||
| 	} | ||||
| 	else if (contents_from) | ||||
| @ -2411,8 +2464,14 @@ parse_done: | ||||
| 		if (fill_blob_sha1(o)) | ||||
| 			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, (char **) &sb.final_buf, | ||||
| 				    &sb.final_buf_size)) | ||||
| 			; | ||||
| 		else | ||||
| 			sb.final_buf = read_sha1_file(o->blob_sha1, &type, | ||||
| 						      &sb.final_buf_size); | ||||
|  | ||||
| 		if (!sb.final_buf) | ||||
| 			die("Cannot read blob %s for path %s", | ||||
| 			    sha1_to_hex(o->blob_sha1), | ||||
|  | ||||
		Reference in New Issue
	
	Block a user