| 
 | 1 | +#include "builtin.h"  | 
 | 2 | +#include "commit.h"  | 
 | 3 | +#include "config.h"  | 
 | 4 | +#include "diff.h"  | 
 | 5 | +#include "diffcore.h"  | 
 | 6 | +#include "gettext.h"  | 
 | 7 | +#include "hex.h"  | 
 | 8 | +#include "object.h"  | 
 | 9 | +#include "parse-options.h"  | 
 | 10 | +#include "revision.h"  | 
 | 11 | +#include "strbuf.h"  | 
 | 12 | + | 
 | 13 | +static unsigned parse_mode_or_die(const char *mode, const char **endp)  | 
 | 14 | +{  | 
 | 15 | +	uint16_t ret;  | 
 | 16 | + | 
 | 17 | +	*endp = parse_mode(mode, &ret);  | 
 | 18 | +	if (!*endp)  | 
 | 19 | +		die("unable to parse mode: %s", mode);  | 
 | 20 | +	return ret;  | 
 | 21 | +}  | 
 | 22 | + | 
 | 23 | +static void parse_oid(const char *p, struct object_id *oid, const char **endp,  | 
 | 24 | +		      const struct git_hash_algo *algop)  | 
 | 25 | +{  | 
 | 26 | +	if (parse_oid_hex_algop(p, oid, endp, algop) || *(*endp)++ != ' ')  | 
 | 27 | +		die("unable to parse object id: %s", p);  | 
 | 28 | +}  | 
 | 29 | + | 
 | 30 | +static unsigned short parse_score(const char *score)  | 
 | 31 | +{  | 
 | 32 | +	unsigned long ret;  | 
 | 33 | +	char *endp;  | 
 | 34 | + | 
 | 35 | +	errno = 0;  | 
 | 36 | +	ret = strtoul(score, &endp, 10);  | 
 | 37 | +	ret *= MAX_SCORE / 100;  | 
 | 38 | +	if (errno || endp == score || *endp || (unsigned short)ret != ret)  | 
 | 39 | +		die("unable to parse rename/copy score: %s", score);  | 
 | 40 | +	return ret;  | 
 | 41 | +}  | 
 | 42 | + | 
 | 43 | +static void flush_diff_queue(struct diff_options *options)  | 
 | 44 | +{  | 
 | 45 | +	/*  | 
 | 46 | +	 * If rename detection is not requested, use rename information from the  | 
 | 47 | +	 * raw diff formatted input. Setting found_follow ensures diffcore_std()  | 
 | 48 | +	 * does not mess with rename information already present in queued  | 
 | 49 | +	 * filepairs.  | 
 | 50 | +	 */  | 
 | 51 | +	if (!options->detect_rename)  | 
 | 52 | +		options->found_follow = 1;  | 
 | 53 | +	diffcore_std(options);  | 
 | 54 | +	diff_flush(options);  | 
 | 55 | +}  | 
 | 56 | + | 
 | 57 | +int cmd_diff_pairs(int argc, const char **argv, const char *prefix,  | 
 | 58 | +		   struct repository *repo)  | 
 | 59 | +{  | 
 | 60 | +	struct strbuf path_dst = STRBUF_INIT;  | 
 | 61 | +	struct strbuf path = STRBUF_INIT;  | 
 | 62 | +	struct strbuf meta = STRBUF_INIT;  | 
 | 63 | +	struct rev_info revs;  | 
 | 64 | +	int ret;  | 
 | 65 | + | 
 | 66 | +	const char * const usage[] = {  | 
 | 67 | +		N_("git diff-pairs [diff-options]"),  | 
 | 68 | +		NULL  | 
 | 69 | +	};  | 
 | 70 | +	struct option options[] = {  | 
 | 71 | +		OPT_END()  | 
 | 72 | +	};  | 
 | 73 | + | 
 | 74 | +	show_usage_with_options_if_asked(argc, argv, usage, options);  | 
 | 75 | + | 
 | 76 | +	repo_init_revisions(repo, &revs, prefix);  | 
 | 77 | +	repo_config(repo, git_diff_basic_config, NULL);  | 
 | 78 | +	revs.disable_stdin = 1;  | 
 | 79 | +	revs.abbrev = 0;  | 
 | 80 | +	revs.diff = 1;  | 
 | 81 | + | 
 | 82 | +	argc = setup_revisions(argc, argv, &revs, NULL);  | 
 | 83 | + | 
 | 84 | +	/* Don't allow pathspecs at all. */  | 
 | 85 | +	if (revs.prune_data.nr)  | 
 | 86 | +		usage_with_options(usage, options);  | 
 | 87 | + | 
 | 88 | +	if (!revs.diffopt.output_format)  | 
 | 89 | +		revs.diffopt.output_format = DIFF_FORMAT_RAW;  | 
 | 90 | + | 
 | 91 | +	while (1) {  | 
 | 92 | +		struct object_id oid_a, oid_b;  | 
 | 93 | +		struct diff_filepair *pair;  | 
 | 94 | +		unsigned mode_a, mode_b;  | 
 | 95 | +		const char *p;  | 
 | 96 | +		char status;  | 
 | 97 | + | 
 | 98 | +		if (strbuf_getline_nul(&meta, stdin) == EOF)  | 
 | 99 | +			break;  | 
 | 100 | + | 
 | 101 | +		p = meta.buf;  | 
 | 102 | +		if (*p != ':')  | 
 | 103 | +			die("invalid raw diff input");  | 
 | 104 | +		p++;  | 
 | 105 | + | 
 | 106 | +		mode_a = parse_mode_or_die(p, &p);  | 
 | 107 | +		mode_b = parse_mode_or_die(p, &p);  | 
 | 108 | + | 
 | 109 | +		parse_oid(p, &oid_a, &p, repo->hash_algo);  | 
 | 110 | +		parse_oid(p, &oid_b, &p, repo->hash_algo);  | 
 | 111 | + | 
 | 112 | +		status = *p++;  | 
 | 113 | + | 
 | 114 | +		if (strbuf_getline_nul(&path, stdin) == EOF)  | 
 | 115 | +			die("got EOF while reading path");  | 
 | 116 | + | 
 | 117 | +		switch (status) {  | 
 | 118 | +		case DIFF_STATUS_ADDED:  | 
 | 119 | +			pair = diff_filepair_addremove(&revs.diffopt, '+',  | 
 | 120 | +						       mode_b, &oid_b,  | 
 | 121 | +						       1, path.buf, 0);  | 
 | 122 | +			if (pair)  | 
 | 123 | +				pair->status = status;  | 
 | 124 | +			break;  | 
 | 125 | + | 
 | 126 | +		case DIFF_STATUS_DELETED:  | 
 | 127 | +			pair = diff_filepair_addremove(&revs.diffopt, '-',  | 
 | 128 | +						       mode_a, &oid_a,  | 
 | 129 | +						       1, path.buf, 0);  | 
 | 130 | +			if (pair)  | 
 | 131 | +				pair->status = status;  | 
 | 132 | +			break;  | 
 | 133 | + | 
 | 134 | +		case DIFF_STATUS_TYPE_CHANGED:  | 
 | 135 | +		case DIFF_STATUS_MODIFIED:  | 
 | 136 | +			pair = diff_filepair_change(&revs.diffopt,  | 
 | 137 | +						    mode_a, mode_b,  | 
 | 138 | +						    &oid_a, &oid_b, 1, 1,  | 
 | 139 | +						    path.buf, 0, 0);  | 
 | 140 | +			if (pair)  | 
 | 141 | +				pair->status = status;  | 
 | 142 | +			break;  | 
 | 143 | + | 
 | 144 | +		case DIFF_STATUS_RENAMED:  | 
 | 145 | +		case DIFF_STATUS_COPIED:  | 
 | 146 | +			{  | 
 | 147 | +				struct diff_filespec *a, *b;  | 
 | 148 | + | 
 | 149 | +				if (strbuf_getline_nul(&path_dst, stdin) == EOF)  | 
 | 150 | +					die("got EOF while reading destination path");  | 
 | 151 | + | 
 | 152 | +				a = alloc_filespec(path.buf);  | 
 | 153 | +				b = alloc_filespec(path_dst.buf);  | 
 | 154 | +				fill_filespec(a, &oid_a, 1, mode_a);  | 
 | 155 | +				fill_filespec(b, &oid_b, 1, mode_b);  | 
 | 156 | + | 
 | 157 | +				pair = diff_queue(&diff_queued_diff, a, b);  | 
 | 158 | +				pair->status = status;  | 
 | 159 | +				pair->score = parse_score(p);  | 
 | 160 | +				pair->renamed_pair = 1;  | 
 | 161 | +			}  | 
 | 162 | +			break;  | 
 | 163 | + | 
 | 164 | +		default:  | 
 | 165 | +			die("unknown diff status: %c", status);  | 
 | 166 | +		}  | 
 | 167 | +	}  | 
 | 168 | + | 
 | 169 | +	flush_diff_queue(&revs.diffopt);  | 
 | 170 | +	ret = diff_result_code(&revs);  | 
 | 171 | + | 
 | 172 | +	strbuf_release(&path_dst);  | 
 | 173 | +	strbuf_release(&path);  | 
 | 174 | +	strbuf_release(&meta);  | 
 | 175 | +	release_revisions(&revs);  | 
 | 176 | + | 
 | 177 | +	return ret;  | 
 | 178 | +}  | 
0 commit comments