Skip to content

Commit 45fa760

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/blame'
* jc/blame: blame -S <ancestry-file> Match ofs/cnt types in diff interface. blame: use built-in xdiff combine-diff: move the code to parse hunk-header into common library. combine-diff: refactor built-in xdiff interface. combine-diff: use built-in xdiff.
2 parents d69dc37 + 5040f17 commit 45fa760

File tree

7 files changed

+419
-302
lines changed

7 files changed

+419
-302
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ LIB_OBJS = \
208208
quote.o read-cache.o refs.o run-command.o \
209209
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
210210
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
211-
fetch-clone.o revision.o pager.o tree-walk.o \
211+
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
212212
$(DIFF_OBJS)
213213

214214
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)

blame.c

Lines changed: 104 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "diff.h"
1717
#include "diffcore.h"
1818
#include "revision.h"
19+
#include "xdiff-interface.h"
1920

2021
#define DEBUG 0
2122

@@ -57,116 +58,89 @@ static int num_get_patch = 0;
5758
static int num_commits = 0;
5859
static int patch_time = 0;
5960

60-
#define TEMPFILE_PATH_LEN 60
61-
static struct patch *get_patch(struct commit *commit, struct commit *other)
62-
{
61+
struct blame_diff_state {
62+
struct xdiff_emit_state xm;
6363
struct patch *ret;
64-
struct util_info *info_c = (struct util_info *)commit->object.util;
65-
struct util_info *info_o = (struct util_info *)other->object.util;
66-
char tmp_path1[TEMPFILE_PATH_LEN], tmp_path2[TEMPFILE_PATH_LEN];
67-
char diff_cmd[TEMPFILE_PATH_LEN*2 + 20];
68-
struct timeval tv_start, tv_end;
69-
int fd;
70-
FILE *fin;
71-
char buf[1024];
72-
73-
ret = xmalloc(sizeof(struct patch));
74-
ret->chunks = NULL;
75-
ret->num = 0;
76-
77-
get_blob(commit);
78-
get_blob(other);
64+
};
7965

80-
gettimeofday(&tv_start, NULL);
66+
static void process_u0_diff(void *state_, char *line, unsigned long len)
67+
{
68+
struct blame_diff_state *state = state_;
69+
struct chunk *chunk;
8170

82-
fd = git_mkstemp(tmp_path1, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
83-
if (fd < 0)
84-
die("unable to create temp-file: %s", strerror(errno));
71+
if (len < 4 || line[0] != '@' || line[1] != '@')
72+
return;
8573

86-
if (xwrite(fd, info_c->buf, info_c->size) != info_c->size)
87-
die("write failed: %s", strerror(errno));
88-
close(fd);
74+
if (DEBUG)
75+
printf("chunk line: %.*s", (int)len, line);
76+
state->ret->num++;
77+
state->ret->chunks = xrealloc(state->ret->chunks,
78+
sizeof(struct chunk) * state->ret->num);
79+
chunk = &state->ret->chunks[state->ret->num - 1];
80+
81+
assert(!strncmp(line, "@@ -", 4));
82+
83+
if (parse_hunk_header(line, len,
84+
&chunk->off1, &chunk->len1,
85+
&chunk->off2, &chunk->len2)) {
86+
state->ret->num--;
87+
return;
88+
}
8989

90-
fd = git_mkstemp(tmp_path2, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
91-
if (fd < 0)
92-
die("unable to create temp-file: %s", strerror(errno));
90+
if (chunk->len1 == 0)
91+
chunk->off1++;
92+
if (chunk->len2 == 0)
93+
chunk->off2++;
9394

94-
if (xwrite(fd, info_o->buf, info_o->size) != info_o->size)
95-
die("write failed: %s", strerror(errno));
96-
close(fd);
95+
if (chunk->off1 > 0)
96+
chunk->off1--;
97+
if (chunk->off2 > 0)
98+
chunk->off2--;
9799

98-
sprintf(diff_cmd, "diff -U 0 %s %s", tmp_path1, tmp_path2);
99-
fin = popen(diff_cmd, "r");
100-
if (!fin)
101-
die("popen failed: %s", strerror(errno));
100+
assert(chunk->off1 >= 0);
101+
assert(chunk->off2 >= 0);
102+
}
102103

103-
while (fgets(buf, sizeof(buf), fin)) {
104-
struct chunk *chunk;
105-
char *start, *sp;
104+
static struct patch *get_patch(struct commit *commit, struct commit *other)
105+
{
106+
struct blame_diff_state state;
107+
xpparam_t xpp;
108+
xdemitconf_t xecfg;
109+
mmfile_t file_c, file_o;
110+
xdemitcb_t ecb;
111+
struct util_info *info_c = (struct util_info *)commit->object.util;
112+
struct util_info *info_o = (struct util_info *)other->object.util;
113+
struct timeval tv_start, tv_end;
106114

107-
if (buf[0] != '@' || buf[1] != '@')
108-
continue;
115+
get_blob(commit);
116+
file_c.ptr = info_c->buf;
117+
file_c.size = info_c->size;
109118

110-
if (DEBUG)
111-
printf("chunk line: %s", buf);
112-
ret->num++;
113-
ret->chunks = xrealloc(ret->chunks,
114-
sizeof(struct chunk) * ret->num);
115-
chunk = &ret->chunks[ret->num - 1];
116-
117-
assert(!strncmp(buf, "@@ -", 4));
118-
119-
start = buf + 4;
120-
sp = index(start, ' ');
121-
*sp = '\0';
122-
if (index(start, ',')) {
123-
int ret =
124-
sscanf(start, "%d,%d", &chunk->off1, &chunk->len1);
125-
assert(ret == 2);
126-
} else {
127-
int ret = sscanf(start, "%d", &chunk->off1);
128-
assert(ret == 1);
129-
chunk->len1 = 1;
130-
}
131-
*sp = ' ';
132-
133-
start = sp + 1;
134-
sp = index(start, ' ');
135-
*sp = '\0';
136-
if (index(start, ',')) {
137-
int ret =
138-
sscanf(start, "%d,%d", &chunk->off2, &chunk->len2);
139-
assert(ret == 2);
140-
} else {
141-
int ret = sscanf(start, "%d", &chunk->off2);
142-
assert(ret == 1);
143-
chunk->len2 = 1;
144-
}
145-
*sp = ' ';
119+
get_blob(other);
120+
file_o.ptr = info_o->buf;
121+
file_o.size = info_o->size;
146122

147-
if (chunk->len1 == 0)
148-
chunk->off1++;
149-
if (chunk->len2 == 0)
150-
chunk->off2++;
123+
gettimeofday(&tv_start, NULL);
151124

152-
if (chunk->off1 > 0)
153-
chunk->off1--;
154-
if (chunk->off2 > 0)
155-
chunk->off2--;
125+
xpp.flags = XDF_NEED_MINIMAL;
126+
xecfg.ctxlen = 0;
127+
xecfg.flags = 0;
128+
ecb.outf = xdiff_outf;
129+
ecb.priv = &state;
130+
memset(&state, 0, sizeof(state));
131+
state.xm.consume = process_u0_diff;
132+
state.ret = xmalloc(sizeof(struct patch));
133+
state.ret->chunks = NULL;
134+
state.ret->num = 0;
156135

157-
assert(chunk->off1 >= 0);
158-
assert(chunk->off2 >= 0);
159-
}
160-
pclose(fin);
161-
unlink(tmp_path1);
162-
unlink(tmp_path2);
136+
xdl_diff(&file_c, &file_o, &xpp, &xecfg, &ecb);
163137

164138
gettimeofday(&tv_end, NULL);
165139
patch_time += 1000000 * (tv_end.tv_sec - tv_start.tv_sec) +
166140
tv_end.tv_usec - tv_start.tv_usec;
167141

168142
num_get_patch++;
169-
return ret;
143+
return state.ret;
170144
}
171145

172146
static void free_patch(struct patch *p)
@@ -674,7 +648,7 @@ static void get_commit_info(struct commit* commit, struct commit_info* ret)
674648
static char author_buf[1024];
675649

676650
tmp = strstr(commit->buffer, "\nauthor ") + 8;
677-
len = index(tmp, '\n') - tmp;
651+
len = strchr(tmp, '\n') - tmp;
678652
ret->author = author_buf;
679653
memcpy(ret->author, tmp, len);
680654

@@ -729,11 +703,30 @@ static void* topo_getter(struct commit* c)
729703
return util->topo_data;
730704
}
731705

706+
static int read_ancestry(const char *graft_file,
707+
unsigned char **start_sha1)
708+
{
709+
FILE *fp = fopen(graft_file, "r");
710+
char buf[1024];
711+
if (!fp)
712+
return -1;
713+
while (fgets(buf, sizeof(buf), fp)) {
714+
/* The format is just "Commit Parent1 Parent2 ...\n" */
715+
int len = strlen(buf);
716+
struct commit_graft *graft = read_graft_line(buf, len);
717+
register_commit_graft(graft, 0);
718+
if (!*start_sha1)
719+
*start_sha1 = graft->sha1;
720+
}
721+
fclose(fp);
722+
return 0;
723+
}
724+
732725
int main(int argc, const char **argv)
733726
{
734727
int i;
735728
struct commit *initial = NULL;
736-
unsigned char sha1[20];
729+
unsigned char sha1[20], *sha1_p = NULL;
737730

738731
const char *filename = NULL, *commit = NULL;
739732
char filename_buf[256];
@@ -767,6 +760,14 @@ int main(int argc, const char **argv)
767760
!strcmp(argv[i], "--compability")) {
768761
compability = 1;
769762
continue;
763+
} else if(!strcmp(argv[i], "-S")) {
764+
if (i + 1 < argc &&
765+
!read_ancestry(argv[i + 1], &sha1_p)) {
766+
compability = 1;
767+
i++;
768+
continue;
769+
}
770+
usage(blame_usage);
770771
} else if(!strcmp(argv[i], "--")) {
771772
options = 0;
772773
continue;
@@ -788,7 +789,9 @@ int main(int argc, const char **argv)
788789

789790
if(!filename)
790791
usage(blame_usage);
791-
if(!commit)
792+
if (commit && sha1_p)
793+
usage(blame_usage);
794+
else if(!commit)
792795
commit = "HEAD";
793796

794797
if(prefix)
@@ -797,9 +800,12 @@ int main(int argc, const char **argv)
797800
strcpy(filename_buf, filename);
798801
filename = filename_buf;
799802

800-
if (get_sha1(commit, sha1))
801-
die("get_sha1 failed, commit '%s' not found", commit);
802-
start_commit = lookup_commit_reference(sha1);
803+
if (!sha1_p) {
804+
if (get_sha1(commit, sha1))
805+
die("get_sha1 failed, commit '%s' not found", commit);
806+
sha1_p = sha1;
807+
}
808+
start_commit = lookup_commit_reference(sha1_p);
803809
get_util(start_commit)->pathname = filename;
804810
if (fill_util_info(start_commit)) {
805811
printf("%s not found in %s\n", filename, commit);
@@ -876,7 +882,7 @@ int main(int argc, const char **argv)
876882
if(blame_contents[blame_len-1] != '\n')
877883
putc('\n', stdout);
878884
} else {
879-
char* next_buf = index(buf, '\n') + 1;
885+
char* next_buf = strchr(buf, '\n') + 1;
880886
fwrite(buf, next_buf - buf, 1, stdout);
881887
buf = next_buf;
882888
}

0 commit comments

Comments
 (0)