Skip to content

Commit be3cfa8

Browse files
Junio C HamanoLinus Torvalds
authored andcommitted
[PATCH] Diff-tree-helper take two.
This reworks the diff-tree-helper and show-diff to further make external diff command interface simpler. These commands now honor GIT_EXTERNAL_DIFF environment variable which can point at an arbitrary program that takes 7 parameters: name file1 file1-sha1 file1-mode file2 file2-sha1 file2-mode The parameters for an external diff command are as follows: name this invocation of the command is to emit diff for the named cache/tree entry. file1 pathname that holds the contents of the first file. This can be a file inside the working tree, or a temporary file created from the blob object, or /dev/null. The command should not attempt to unlink it -- the temporary is unlinked by the caller. file1-sha1 sha1 hash if file1 is a blob object, or "." otherwise. file1-mode mode bits for file1, or "." for a deleted file. If GIT_EXTERNAL_DIFF environment variable is not set, the default is to invoke diff with the set of parameters old show-diff used to use. This built-in implementation honors the GIT_DIFF_CMD and GIT_DIFF_OPTS environment variables as before. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent d1df574 commit be3cfa8

File tree

4 files changed

+271
-270
lines changed

4 files changed

+271
-270
lines changed

diff-tree-helper.c

Lines changed: 39 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/*
2+
* Copyright (C) 2005 Junio C Hamano
3+
*/
14
#include "cache.h"
25
#include "strbuf.h"
36
#include "diff.h"
@@ -17,15 +20,22 @@ static int matches_pathspec(const char *name, char **spec, int cnt)
1720
return 0;
1821
}
1922

20-
static int parse_oneside_change(const char *cp, unsigned char *sha1,
21-
char *path) {
23+
static int parse_oneside_change(const char *cp, struct diff_spec *one,
24+
char *path)
25+
{
2226
int ch;
23-
while ((ch = *cp) && '0' <= ch && ch <= '7')
24-
cp++; /* skip mode bits */
27+
28+
one->file_valid = one->sha1_valid = 1;
29+
one->mode = 0;
30+
while ((ch = *cp) && '0' <= ch && ch <= '7') {
31+
one->mode = (one->mode << 3) | (ch - '0');
32+
cp++;
33+
}
34+
2535
if (strncmp(cp, "\tblob\t", 6))
2636
return -1;
2737
cp += 6;
28-
if (get_sha1_hex(cp, sha1))
38+
if (get_sha1_hex(cp, one->u.sha1))
2939
return -1;
3040
cp += 40;
3141
if (*cp++ != '\t')
@@ -34,223 +44,57 @@ static int parse_oneside_change(const char *cp, unsigned char *sha1,
3444
return 0;
3545
}
3646

37-
#define STATUS_CACHED 0 /* cached and sha1 valid */
38-
#define STATUS_ABSENT 1 /* diff-tree says old removed or new added */
39-
#define STATUS_UNCACHED 2 /* diff-cache output: read from working tree */
40-
4147
static int parse_diff_tree_output(const char *buf,
42-
unsigned char *old_sha1,
43-
int *old_status,
44-
unsigned char *new_sha1,
45-
int *new_status,
48+
struct diff_spec *old,
49+
struct diff_spec *new,
4650
char *path) {
4751
const char *cp = buf;
4852
int ch;
49-
static unsigned char null_sha[20] = { 0, };
5053

5154
switch (*cp++) {
5255
case '+':
53-
*old_status = STATUS_ABSENT;
54-
*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?
55-
STATUS_CACHED : STATUS_UNCACHED);
56-
return parse_oneside_change(cp, new_sha1, path);
56+
old->file_valid = 0;
57+
return parse_oneside_change(cp, new, path);
5758
case '-':
58-
*new_status = STATUS_ABSENT;
59-
*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?
60-
STATUS_CACHED : STATUS_UNCACHED);
61-
return parse_oneside_change(cp, old_sha1, path);
59+
new->file_valid = 0;
60+
return parse_oneside_change(cp, old, path);
6261
case '*':
6362
break;
6463
default:
6564
return -1;
6665
}
6766

6867
/* This is for '*' entries */
69-
while ((ch = *cp) && ('0' <= ch && ch <= '7'))
70-
cp++; /* skip mode bits */
68+
old->file_valid = old->sha1_valid = 1;
69+
new->file_valid = new->sha1_valid = 1;
70+
71+
old->mode = new->mode = 0;
72+
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
73+
old->mode = (old->mode << 3) | (ch - '0');
74+
cp++;
75+
}
7176
if (strncmp(cp, "->", 2))
7277
return -1;
7378
cp += 2;
74-
while ((ch = *cp) && ('0' <= ch && ch <= '7'))
75-
cp++; /* skip mode bits */
79+
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
80+
new->mode = (new->mode << 3) | (ch - '0');
81+
cp++;
82+
}
7683
if (strncmp(cp, "\tblob\t", 6))
7784
return -1;
7885
cp += 6;
79-
if (get_sha1_hex(cp, old_sha1))
86+
if (get_sha1_hex(cp, old->u.sha1))
8087
return -1;
8188
cp += 40;
8289
if (strncmp(cp, "->", 2))
8390
return -1;
8491
cp += 2;
85-
if (get_sha1_hex(cp, new_sha1))
92+
if (get_sha1_hex(cp, new->u.sha1))
8693
return -1;
8794
cp += 40;
8895
if (*cp++ != '\t')
8996
return -1;
9097
strcpy(path, cp);
91-
*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?
92-
STATUS_CACHED : STATUS_UNCACHED);
93-
*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?
94-
STATUS_CACHED : STATUS_UNCACHED);
95-
return 0;
96-
}
97-
98-
static int sha1err(const char *path, const unsigned char *sha1)
99-
{
100-
return error("diff-tree-helper: unable to read sha1 file of %s (%s)",
101-
path, sha1_to_hex(sha1));
102-
}
103-
104-
static int fserr(const char *path)
105-
{
106-
return error("diff-tree-helper: unable to read file %s", path);
107-
}
108-
109-
static char *map_whole_file(const char *path, unsigned long *size) {
110-
int fd;
111-
struct stat st;
112-
void *buf;
113-
114-
if ((fd = open(path, O_RDONLY)) < 0) {
115-
error("diff-tree-helper: unable to read file %s", path);
116-
return 0;
117-
}
118-
if (fstat(fd, &st) < 0) {
119-
close(fd);
120-
error("diff-tree-helper: unable to stat file %s", path);
121-
return 0;
122-
}
123-
*size = st.st_size;
124-
buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
125-
close(fd);
126-
return buf;
127-
}
128-
129-
static int show_diff(const unsigned char *old_sha1, int old_status,
130-
const unsigned char *new_sha1, int new_status,
131-
const char *path, int reverse_diff)
132-
{
133-
char other[PATH_MAX];
134-
unsigned long size;
135-
char type[20];
136-
int fd;
137-
int reverse;
138-
void *blob = 0;
139-
const char *fs = 0;
140-
int need_unmap = 0;
141-
int need_unlink = 0;
142-
143-
144-
switch (old_status) {
145-
case STATUS_CACHED:
146-
blob = read_sha1_file(old_sha1, type, &size);
147-
if (! blob)
148-
return sha1err(path, old_sha1);
149-
150-
switch (new_status) {
151-
case STATUS_CACHED:
152-
strcpy(other, ".diff_tree_helper_XXXXXX");
153-
fd = mkstemp(other);
154-
if (fd < 0)
155-
die("unable to create temp-file");
156-
if (write(fd, blob, size) != size)
157-
die("unable to write temp-file");
158-
close(fd);
159-
free(blob);
160-
161-
blob = read_sha1_file(new_sha1, type, &size);
162-
if (! blob)
163-
return sha1err(path, new_sha1);
164-
165-
need_unlink = 1;
166-
/* new = blob, old = fs */
167-
reverse = !reverse_diff;
168-
fs = other;
169-
break;
170-
171-
case STATUS_ABSENT:
172-
case STATUS_UNCACHED:
173-
fs = ((new_status == STATUS_ABSENT) ?
174-
"/dev/null" : path);
175-
reverse = reverse_diff;
176-
break;
177-
178-
default:
179-
reverse = reverse_diff;
180-
}
181-
break;
182-
183-
case STATUS_ABSENT:
184-
switch (new_status) {
185-
case STATUS_CACHED:
186-
blob = read_sha1_file(new_sha1, type, &size);
187-
if (! blob)
188-
return sha1err(path, new_sha1);
189-
/* old = fs, new = blob */
190-
fs = "/dev/null";
191-
reverse = !reverse_diff;
192-
break;
193-
194-
case STATUS_ABSENT:
195-
return error("diff-tree-helper: absent from both old and new?");
196-
case STATUS_UNCACHED:
197-
fs = path;
198-
blob = strdup("");
199-
size = 0;
200-
/* old = blob, new = fs */
201-
reverse = reverse_diff;
202-
break;
203-
default:
204-
reverse = reverse_diff;
205-
}
206-
break;
207-
208-
case STATUS_UNCACHED:
209-
fs = path; /* old = fs, new = blob */
210-
reverse = !reverse_diff;
211-
212-
switch (new_status) {
213-
case STATUS_CACHED:
214-
blob = read_sha1_file(new_sha1, type, &size);
215-
if (! blob)
216-
return sha1err(path, new_sha1);
217-
break;
218-
219-
case STATUS_ABSENT:
220-
blob = strdup("");
221-
size = 0;
222-
break;
223-
224-
case STATUS_UNCACHED:
225-
/* old = fs */
226-
blob = map_whole_file(path, &size);
227-
if (! blob)
228-
return fserr(path);
229-
need_unmap = 1;
230-
break;
231-
default:
232-
reverse = reverse_diff;
233-
}
234-
break;
235-
236-
default:
237-
reverse = reverse_diff;
238-
}
239-
240-
if (fs)
241-
show_differences(fs,
242-
path, /* label */
243-
blob,
244-
size,
245-
reverse /* 0: diff blob fs
246-
1: diff fs blob */);
247-
248-
if (need_unlink)
249-
unlink(other);
250-
if (need_unmap && blob)
251-
munmap(blob, size);
252-
else
253-
free(blob);
25498
return 0;
25599
}
256100

@@ -275,28 +119,20 @@ int main(int ac, char **av) {
275119
}
276120
/* the remaining parameters are paths patterns */
277121

278-
prepare_diff_cmd();
279-
280122
while (1) {
281-
int old_status, new_status;
282-
unsigned char old_sha1[20], new_sha1[20];
123+
struct diff_spec old, new;
283124
char path[PATH_MAX];
284125
read_line(&sb, stdin, line_termination);
285126
if (sb.eof)
286127
break;
287-
if (parse_diff_tree_output(sb.buf,
288-
old_sha1, &old_status,
289-
new_sha1, &new_status,
290-
path)) {
128+
if (parse_diff_tree_output(sb.buf, &old, &new, path)) {
291129
fprintf(stderr, "cannot parse %s\n", sb.buf);
292130
continue;
293131
}
294-
if (1 < ac && ! matches_pathspec(path, av+1, ac-1))
132+
if (1 < ac && !matches_pathspec(path, av+1, ac-1))
295133
continue;
296134

297-
show_diff(old_sha1, old_status,
298-
new_sha1, new_status,
299-
path, reverse_diff);
135+
run_external_diff(path, &old, &new);
300136
}
301137
return 0;
302138
}

0 commit comments

Comments
 (0)