Merge branch 'jc/blame'
authorJunio C Hamano <junkio@cox.net>
Sat, 8 Apr 2006 00:57:46 +0000 (17:57 -0700)
committerJunio C Hamano <junkio@cox.net>
Sat, 8 Apr 2006 00:57:46 +0000 (17:57 -0700)
* 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.

1  2 
Makefile
blame.c

diff --combined Makefile
+++ b/Makefile
@@@ -114,7 -114,7 +114,7 @@@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__pow
  
  SCRIPT_SH = \
        git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
 -      git-cherry.sh git-clone.sh git-commit.sh \
 +      git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
        git-count-objects.sh git-diff.sh git-fetch.sh \
        git-format-patch.sh git-log.sh git-ls-remote.sh \
        git-merge-one-file.sh git-parse-remote.sh \
@@@ -208,7 -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)
diff --combined blame.c
+++ b/blame.c
@@@ -16,6 -16,7 +16,7 @@@
  #include "diff.h"
  #include "diffcore.h"
  #include "revision.h"
+ #include "xdiff-interface.h"
  
  #define DEBUG 0
  
@@@ -57,116 -58,89 +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)
@@@ -674,7 -648,7 +648,7 @@@ static void get_commit_info(struct comm
        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);
  
@@@ -729,11 -703,30 +703,30 @@@ static void* topo_getter(struct commit
        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];
                                  !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;
  
        if(!filename)
                usage(blame_usage);
-       if(!commit)
+       if (commit && sha1_p)
+               usage(blame_usage);
+       else if(!commit)
                commit = "HEAD";
  
        if(prefix)
                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);
        rev.prune_fn = simplify_commit;
        rev.topo_setter = topo_setter;
        rev.topo_getter = topo_getter;
 +      rev.parents = 1;
        rev.limited = 1;
  
        commit_list_insert(start_commit, &rev.commits);
                        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;
                }