Skip to content

Commit

Permalink
Merge branch 'jc/blame'
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
Junio C Hamano committed Apr 8, 2006
2 parents d69dc37 + 5040f17 commit 45fa760
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 302 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ LIB_OBJS = \
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
$(DIFF_OBJS)

GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
Expand Down
202 changes: 104 additions & 98 deletions blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "diff.h"
#include "diffcore.h"
#include "revision.h"
#include "xdiff-interface.h"

#define DEBUG 0

Expand Down Expand Up @@ -57,116 +58,89 @@ static int num_get_patch = 0;
static int num_commits = 0;
static int patch_time = 0;

#define TEMPFILE_PATH_LEN 60
static struct patch *get_patch(struct commit *commit, struct commit *other)
{
struct blame_diff_state {
struct xdiff_emit_state xm;
struct patch *ret;
struct util_info *info_c = (struct util_info *)commit->object.util;
struct util_info *info_o = (struct util_info *)other->object.util;
char tmp_path1[TEMPFILE_PATH_LEN], tmp_path2[TEMPFILE_PATH_LEN];
char diff_cmd[TEMPFILE_PATH_LEN*2 + 20];
struct timeval tv_start, tv_end;
int fd;
FILE *fin;
char buf[1024];

ret = xmalloc(sizeof(struct patch));
ret->chunks = NULL;
ret->num = 0;

get_blob(commit);
get_blob(other);
};

gettimeofday(&tv_start, NULL);
static void process_u0_diff(void *state_, char *line, unsigned long len)
{
struct blame_diff_state *state = state_;
struct chunk *chunk;

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

if (xwrite(fd, info_c->buf, info_c->size) != info_c->size)
die("write failed: %s", strerror(errno));
close(fd);
if (DEBUG)
printf("chunk line: %.*s", (int)len, line);
state->ret->num++;
state->ret->chunks = xrealloc(state->ret->chunks,
sizeof(struct chunk) * state->ret->num);
chunk = &state->ret->chunks[state->ret->num - 1];

assert(!strncmp(line, "@@ -", 4));

if (parse_hunk_header(line, len,
&chunk->off1, &chunk->len1,
&chunk->off2, &chunk->len2)) {
state->ret->num--;
return;
}

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

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

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

while (fgets(buf, sizeof(buf), fin)) {
struct chunk *chunk;
char *start, *sp;
static struct patch *get_patch(struct commit *commit, struct commit *other)
{
struct blame_diff_state state;
xpparam_t xpp;
xdemitconf_t xecfg;
mmfile_t file_c, file_o;
xdemitcb_t ecb;
struct util_info *info_c = (struct util_info *)commit->object.util;
struct util_info *info_o = (struct util_info *)other->object.util;
struct timeval tv_start, tv_end;

if (buf[0] != '@' || buf[1] != '@')
continue;
get_blob(commit);
file_c.ptr = info_c->buf;
file_c.size = info_c->size;

if (DEBUG)
printf("chunk line: %s", buf);
ret->num++;
ret->chunks = xrealloc(ret->chunks,
sizeof(struct chunk) * ret->num);
chunk = &ret->chunks[ret->num - 1];

assert(!strncmp(buf, "@@ -", 4));

start = buf + 4;
sp = index(start, ' ');
*sp = '\0';
if (index(start, ',')) {
int ret =
sscanf(start, "%d,%d", &chunk->off1, &chunk->len1);
assert(ret == 2);
} else {
int ret = sscanf(start, "%d", &chunk->off1);
assert(ret == 1);
chunk->len1 = 1;
}
*sp = ' ';

start = sp + 1;
sp = index(start, ' ');
*sp = '\0';
if (index(start, ',')) {
int ret =
sscanf(start, "%d,%d", &chunk->off2, &chunk->len2);
assert(ret == 2);
} else {
int ret = sscanf(start, "%d", &chunk->off2);
assert(ret == 1);
chunk->len2 = 1;
}
*sp = ' ';
get_blob(other);
file_o.ptr = info_o->buf;
file_o.size = info_o->size;

if (chunk->len1 == 0)
chunk->off1++;
if (chunk->len2 == 0)
chunk->off2++;
gettimeofday(&tv_start, NULL);

if (chunk->off1 > 0)
chunk->off1--;
if (chunk->off2 > 0)
chunk->off2--;
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = 0;
xecfg.flags = 0;
ecb.outf = xdiff_outf;
ecb.priv = &state;
memset(&state, 0, sizeof(state));
state.xm.consume = process_u0_diff;
state.ret = xmalloc(sizeof(struct patch));
state.ret->chunks = NULL;
state.ret->num = 0;

assert(chunk->off1 >= 0);
assert(chunk->off2 >= 0);
}
pclose(fin);
unlink(tmp_path1);
unlink(tmp_path2);
xdl_diff(&file_c, &file_o, &xpp, &xecfg, &ecb);

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

num_get_patch++;
return ret;
return state.ret;
}

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

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

Expand Down Expand Up @@ -729,11 +703,30 @@ static void* topo_getter(struct commit* c)
return util->topo_data;
}

static int read_ancestry(const char *graft_file,
unsigned char **start_sha1)
{
FILE *fp = fopen(graft_file, "r");
char buf[1024];
if (!fp)
return -1;
while (fgets(buf, sizeof(buf), fp)) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
int len = strlen(buf);
struct commit_graft *graft = read_graft_line(buf, len);
register_commit_graft(graft, 0);
if (!*start_sha1)
*start_sha1 = graft->sha1;
}
fclose(fp);
return 0;
}

int main(int argc, const char **argv)
{
int i;
struct commit *initial = NULL;
unsigned char sha1[20];
unsigned char sha1[20], *sha1_p = NULL;

const char *filename = NULL, *commit = NULL;
char filename_buf[256];
Expand Down Expand Up @@ -767,6 +760,14 @@ int main(int argc, const char **argv)
!strcmp(argv[i], "--compability")) {
compability = 1;
continue;
} else if(!strcmp(argv[i], "-S")) {
if (i + 1 < argc &&
!read_ancestry(argv[i + 1], &sha1_p)) {
compability = 1;
i++;
continue;
}
usage(blame_usage);
} else if(!strcmp(argv[i], "--")) {
options = 0;
continue;
Expand All @@ -788,7 +789,9 @@ int main(int argc, const char **argv)

if(!filename)
usage(blame_usage);
if(!commit)
if (commit && sha1_p)
usage(blame_usage);
else if(!commit)
commit = "HEAD";

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

if (get_sha1(commit, sha1))
die("get_sha1 failed, commit '%s' not found", commit);
start_commit = lookup_commit_reference(sha1);
if (!sha1_p) {
if (get_sha1(commit, sha1))
die("get_sha1 failed, commit '%s' not found", commit);
sha1_p = sha1;
}
start_commit = lookup_commit_reference(sha1_p);
get_util(start_commit)->pathname = filename;
if (fill_util_info(start_commit)) {
printf("%s not found in %s\n", filename, commit);
Expand Down Expand Up @@ -876,7 +882,7 @@ int main(int argc, const char **argv)
if(blame_contents[blame_len-1] != '\n')
putc('\n', stdout);
} else {
char* next_buf = index(buf, '\n') + 1;
char* next_buf = strchr(buf, '\n') + 1;
fwrite(buf, next_buf - buf, 1, stdout);
buf = next_buf;
}
Expand Down
Loading

0 comments on commit 45fa760

Please sign in to comment.