Merge branch 'jt/non-blob-lazy-fetch' into maint
[gitweb.git] / blame.c
diff --git a/blame.c b/blame.c
index 2893f3c1030aab91a42ff9e0daf8a54ba8c3ef3c..aca06f4b1227a4930a2dbb13b87068a618a76f97 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1,11 +1,31 @@
 #include "cache.h"
 #include "refs.h"
+#include "object-store.h"
 #include "cache-tree.h"
 #include "mergesort.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "tag.h"
 #include "blame.h"
+#include "alloc.h"
+#include "commit-slab.h"
+
+define_commit_slab(blame_suspects, struct blame_origin *);
+static struct blame_suspects blame_suspects;
+
+struct blame_origin *get_blame_suspects(struct commit *commit)
+{
+       struct blame_origin **result;
+
+       result = blame_suspects_peek(&blame_suspects, commit);
+
+       return result ? *result : NULL;
+}
+
+static void set_blame_suspects(struct commit *commit, struct blame_origin *origin)
+{
+       *blame_suspects_at(&blame_suspects, commit) = origin;
+}
 
 void blame_origin_decref(struct blame_origin *o)
 {
@@ -15,12 +35,12 @@ void blame_origin_decref(struct blame_origin *o)
                        blame_origin_decref(o->previous);
                free(o->file.ptr);
                /* Should be present exactly once in commit chain */
-               for (p = o->commit->util; p; l = p, p = p->next) {
+               for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) {
                        if (p == o) {
                                if (l)
                                        l->next = p->next;
                                else
-                                       o->commit->util = p->next;
+                                       set_blame_suspects(o->commit, p->next);
                                free(o);
                                return;
                        }
@@ -41,8 +61,8 @@ static struct blame_origin *make_origin(struct commit *commit, const char *path)
        FLEX_ALLOC_STR(o, path, path);
        o->commit = commit;
        o->refcnt = 1;
-       o->next = commit->util;
-       commit->util = o;
+       o->next = get_blame_suspects(commit);
+       set_blame_suspects(commit, o);
        return o;
 }
 
@@ -54,13 +74,13 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path)
 {
        struct blame_origin *o, *l;
 
-       for (o = commit->util, l = NULL; o; l = o, o = o->next) {
+       for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) {
                if (!strcmp(o->path, path)) {
                        /* bump to front */
                        if (l) {
                                l->next = o->next;
-                               o->next = commit->util;
-                               commit->util = o;
+                               o->next = get_blame_suspects(commit);
+                               set_blame_suspects(commit, o);
                        }
                        return blame_origin_incref(o);
                }
@@ -70,7 +90,8 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path)
 
 
 
-static void verify_working_tree_path(struct commit *work_tree, const char *path)
+static void verify_working_tree_path(struct repository *repo,
+                                    struct commit *work_tree, const char *path)
 {
        struct commit_list *parents;
        int pos;
@@ -80,16 +101,16 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
                struct object_id blob_oid;
                unsigned mode;
 
-               if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
-                   sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
+               if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) &&
+                   oid_object_info(repo, &blob_oid, NULL) == OBJ_BLOB)
                        return;
        }
 
-       pos = cache_name_pos(path, strlen(path));
+       pos = index_name_pos(repo->index, path, strlen(path));
        if (pos >= 0)
                ; /* path is in the index */
-       else if (-1 - pos < active_nr &&
-                !strcmp(active_cache[-1 - pos]->name, path))
+       else if (-1 - pos < repo->index->cache_nr &&
+                !strcmp(repo->index->cache[-1 - pos]->name, path))
                ; /* path is in the index, unmerged */
        else
                die("no such path '%s' in HEAD", path);
@@ -99,7 +120,7 @@ static struct commit_list **append_parent(struct commit_list **tail, const struc
 {
        struct commit *parent;
 
-       parent = lookup_commit_reference(oid);
+       parent = lookup_commit_reference(the_repository, oid);
        if (!parent)
                die("no such commit %s", oid_to_hex(oid));
        return &commit_list_insert(parent, tail)->next;
@@ -110,17 +131,19 @@ static void append_merge_parents(struct commit_list **tail)
        int merge_head;
        struct strbuf line = STRBUF_INIT;
 
-       merge_head = open(git_path_merge_head(), O_RDONLY);
+       merge_head = open(git_path_merge_head(the_repository), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
-               die("cannot open '%s' for reading", git_path_merge_head());
+               die("cannot open '%s' for reading",
+                   git_path_merge_head(the_repository));
        }
 
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                struct object_id oid;
                if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
-                       die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
+                       die("unknown line in '%s': %s",
+                           git_path_merge_head(the_repository), line.buf);
                tail = append_parent(tail, &oid);
        }
        close(merge_head);
@@ -136,14 +159,15 @@ static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
 {
        size_t len;
        void *buf = strbuf_detach(sb, &len);
-       set_commit_buffer(c, buf, len);
+       set_commit_buffer(the_repository, c, buf, len);
 }
 
 /*
  * Prepare a dummy commit that represents the work tree (or staged) item.
  * Note that annotating work tree item never works in the reverse.
  */
-static struct commit *fake_working_tree_commit(struct diff_options *opt,
+static struct commit *fake_working_tree_commit(struct repository *repo,
+                                              struct diff_options *opt,
                                               const char *path,
                                               const char *contents_from)
 {
@@ -154,14 +178,14 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        struct strbuf buf = STRBUF_INIT;
        const char *ident;
        time_t now;
-       int size, len;
+       int len;
        struct cache_entry *ce;
        unsigned mode;
        struct strbuf msg = STRBUF_INIT;
 
-       read_cache();
+       read_index(repo->index);
        time(&now);
-       commit = alloc_commit_node();
+       commit = alloc_commit_node(the_repository);
        commit->object.parsed = 1;
        commit->date = now;
        parent_tail = &commit->parents;
@@ -171,7 +195,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 
        parent_tail = append_parent(parent_tail, &head_oid);
        append_merge_parents(parent_tail);
-       verify_working_tree_path(commit, path);
+       verify_working_tree_path(repo, commit, path);
 
        origin = make_origin(commit, path);
 
@@ -229,10 +253,10 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                if (strbuf_read(&buf, 0, 0) < 0)
                        die_errno("failed to read from stdin");
        }
-       convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);
+       convert_to_git(repo->index, path, buf.buf, buf.len, &buf, 0);
        origin->file.ptr = buf.buf;
        origin->file.size = buf.len;
-       pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
+       pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
 
        /*
         * Read the current index, replace the path entry with
@@ -240,28 +264,28 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
         * bits; we are not going to write this index out -- we just
         * want to run "diff-index --cached".
         */
-       discard_cache();
-       read_cache();
+       discard_index(repo->index);
+       read_index(repo->index);
 
        len = strlen(path);
        if (!mode) {
-               int pos = cache_name_pos(path, len);
+               int pos = index_name_pos(repo->index, path, len);
                if (0 <= pos)
-                       mode = active_cache[pos]->ce_mode;
+                       mode = repo->index->cache[pos]->ce_mode;
                else
                        /* Let's not bother reading from HEAD tree */
                        mode = S_IFREG | 0644;
        }
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(repo->index, len);
        oidcpy(&ce->oid, &origin->blob_oid);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
-       add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+       add_index_entry(repo->index, ce,
+                       ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
 
-       cache_tree_invalidate_path(&the_index, path);
+       cache_tree_invalidate_path(repo->index, path);
 
        return commit;
 }
@@ -297,8 +321,8 @@ static void fill_origin_blob(struct diff_options *opt,
                    textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
                        ;
                else
-                       file->ptr = read_sha1_file(o->blob_oid.hash, &type,
-                                                  &file_size);
+                       file->ptr = read_object_file(&o->blob_oid, &type,
+                                                    &file_size);
                file->size = file_size;
 
                if (!file->ptr)
@@ -313,9 +337,7 @@ static void fill_origin_blob(struct diff_options *opt,
 
 static void drop_origin_blob(struct blame_origin *o)
 {
-       if (o->file.ptr) {
-               FREE_AND_NULL(o->file.ptr);
-       }
+       FREE_AND_NULL(o->file.ptr);
 }
 
 /*
@@ -478,7 +500,7 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig
                porigin->suspects = blame_merge(porigin->suspects, sorted);
        else {
                struct blame_origin *o;
-               for (o = porigin->commit->util; o; o = o->next) {
+               for (o = get_blame_suspects(porigin->commit); o; o = o->next) {
                        if (o->suspects) {
                                porigin->suspects = sorted;
                                return;
@@ -498,15 +520,14 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig
  *
  * This also fills origin->mode for corresponding tree path.
  */
-static int fill_blob_sha1_and_mode(struct blame_origin *origin)
+static int fill_blob_sha1_and_mode(struct repository *repo,
+                                  struct blame_origin *origin)
 {
        if (!is_null_oid(&origin->blob_oid))
                return 0;
-       if (get_tree_entry(origin->commit->object.oid.hash,
-                          origin->path,
-                          origin->blob_oid.hash, &origin->mode))
+       if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
                goto error_out;
-       if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
+       if (oid_object_info(repo, &origin->blob_oid, NULL) != OBJ_BLOB)
                goto error_out;
        return 0;
  error_out:
@@ -527,7 +548,7 @@ static struct blame_origin *find_origin(struct commit *parent,
        const char *paths[2];
 
        /* First check any existing origins */
-       for (porigin = parent->util; porigin; porigin = porigin->next)
+       for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next)
                if (!strcmp(porigin->path, origin->path)) {
                        /*
                         * The same path between origin and its parent
@@ -553,10 +574,10 @@ static struct blame_origin *find_origin(struct commit *parent,
        diff_setup_done(&diff_opts);
 
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &origin->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(origin->commit),
                              "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -622,10 +643,10 @@ static struct blame_origin *find_rename(struct commit *parent,
        diff_setup_done(&diff_opts);
 
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &origin->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(origin->commit),
                              "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -998,28 +1019,29 @@ unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
 }
 
 /*
- * best_so_far[] and this[] are both a split of an existing blame_entry
- * that passes blame to the parent.  Maintain best_so_far the best split
- * so far, by comparing this and best_so_far and copying this into
+ * best_so_far[] and potential[] are both a split of an existing blame_entry
+ * that passes blame to the parent.  Maintain best_so_far the best split so
+ * far, by comparing potential and best_so_far and copying potential into
  * bst_so_far as needed.
  */
 static void copy_split_if_better(struct blame_scoreboard *sb,
                                 struct blame_entry *best_so_far,
-                                struct blame_entry *this)
+                                struct blame_entry *potential)
 {
        int i;
 
-       if (!this[1].suspect)
+       if (!potential[1].suspect)
                return;
        if (best_so_far[1].suspect) {
-               if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1]))
+               if (blame_entry_score(sb, &potential[1]) <
+                   blame_entry_score(sb, &best_so_far[1]))
                        return;
        }
 
        for (i = 0; i < 3; i++)
-               blame_origin_incref(this[i].suspect);
+               blame_origin_incref(potential[i].suspect);
        decref_split(best_so_far);
-       memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
+       memcpy(best_so_far, potential, sizeof(struct blame_entry[3]));
 }
 
 /*
@@ -1046,12 +1068,12 @@ static void handle_split(struct blame_scoreboard *sb,
        if (ent->num_lines <= tlno)
                return;
        if (tlno < same) {
-               struct blame_entry this[3];
+               struct blame_entry potential[3];
                tlno += ent->s_lno;
                same += ent->s_lno;
-               split_overlap(this, ent, tlno, plno, same, parent);
-               copy_split_if_better(sb, split, this);
-               decref_split(this);
+               split_overlap(potential, ent, tlno, plno, same, parent);
+               copy_split_if_better(sb, split, potential);
+               decref_split(potential);
        }
 }
 
@@ -1256,10 +1278,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                diff_opts.flags.find_copies_harder = 1;
 
        if (is_null_oid(&target->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &target->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(target->commit),
                              "", &diff_opts);
 
        if (!diff_opts.flags.find_copies_harder)
@@ -1273,7 +1295,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                        struct diff_filepair *p = diff_queued_diff.queue[i];
                        struct blame_origin *norigin;
                        mmfile_t file_p;
-                       struct blame_entry this[3];
+                       struct blame_entry potential[3];
 
                        if (!DIFF_FILE_VALID(p->one))
                                continue; /* does not exist in parent */
@@ -1292,10 +1314,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
 
                        for (j = 0; j < num_ents; j++) {
                                find_copy_in_blob(sb, blame_list[j].ent,
-                                                 norigin, this, &file_p);
+                                                 norigin, potential, &file_p);
                                copy_split_if_better(sb, blame_list[j].split,
-                                                    this);
-                               decref_split(this);
+                                                    potential);
+                               decref_split(potential);
                        }
                        blame_origin_decref(norigin);
                }
@@ -1551,7 +1573,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
 
        while (commit) {
                struct blame_entry *ent;
-               struct blame_origin *suspect = commit->util;
+               struct blame_origin *suspect = get_blame_suspects(commit);
 
                /* find one suspect to break down */
                while (suspect && !suspect->suspects)
@@ -1653,7 +1675,7 @@ static struct commit *find_single_final(struct rev_info *revs,
                struct object *obj = revs->pending.objects[i].item;
                if (obj->flags & UNINTERESTING)
                        continue;
-               obj = deref_tag(obj, NULL, 0);
+               obj = deref_tag(the_repository, obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
                if (found)
@@ -1684,14 +1706,15 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs,
 
        /* Is that sole rev a committish? */
        obj = revs->pending.objects[0].item;
-       obj = deref_tag(obj, NULL, 0);
+       obj = deref_tag(the_repository, obj, NULL, 0);
        if (obj->type != OBJ_COMMIT)
                return NULL;
 
        /* Do we have HEAD? */
        if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                return NULL;
-       head_commit = lookup_commit_reference_gently(&head_oid, 1);
+       head_commit = lookup_commit_reference_gently(the_repository,
+                                                    &head_oid, 1);
        if (!head_commit)
                return NULL;
 
@@ -1719,7 +1742,7 @@ static struct commit *find_single_initial(struct rev_info *revs,
                struct object *obj = revs->pending.objects[i].item;
                if (!(obj->flags & UNINTERESTING))
                        continue;
-               obj = deref_tag(obj, NULL, 0);
+               obj = deref_tag(the_repository, obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
                if (found)
@@ -1746,16 +1769,23 @@ void init_scoreboard(struct blame_scoreboard *sb)
        sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
 }
 
-void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig)
+void setup_scoreboard(struct blame_scoreboard *sb,
+                     const char *path,
+                     struct blame_origin **orig)
 {
        const char *final_commit_name = NULL;
        struct blame_origin *o;
        struct commit *final_commit = NULL;
        enum object_type type;
 
+       init_blame_suspects(&blame_suspects);
+
        if (sb->reverse && sb->contents_from)
                die(_("--contents and --reverse do not blend well."));
 
+       if (!sb->repo)
+               BUG("repo is NULL");
+
        if (!sb->reverse) {
                sb->final = find_single_final(sb->revs, &final_commit_name);
                sb->commits.compare = compare_commits_by_commit_date;
@@ -1777,7 +1807,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                 * or "--contents".
                 */
                setup_work_tree();
-               sb->final = fake_working_tree_commit(&sb->revs->diffopt,
+               sb->final = fake_working_tree_commit(sb->repo,
+                                                    &sb->revs->diffopt,
                                                     path, sb->contents_from);
                add_pending_object(sb->revs, &(sb->final->object), ":");
        }
@@ -1807,7 +1838,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                        l->item = c;
                        if (add_decoration(&sb->revs->children,
                                           &c->parents->item->object, l))
-                               die("BUG: not unique item in first-parent chain");
+                               BUG("not unique item in first-parent chain");
                        c = c->parents->item;
                }
 
@@ -1816,13 +1847,13 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
        }
 
        if (is_null_oid(&sb->final->object.oid)) {
-               o = sb->final->util;
+               o = get_blame_suspects(sb->final);
                sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
                sb->final_buf_size = o->file.size;
        }
        else {
                o = get_origin(sb->final, path);
-               if (fill_blob_sha1_and_mode(o))
+               if (fill_blob_sha1_and_mode(sb->repo, o))
                        die(_("no such path %s in %s"), path, final_commit_name);
 
                if (sb->revs->diffopt.flags.allow_textconv &&
@@ -1830,8 +1861,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                                    &sb->final_buf_size))
                        ;
                else
-                       sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
-                                                      &sb->final_buf_size);
+                       sb->final_buf = read_object_file(&o->blob_oid, &type,
+                                                        &sb->final_buf_size);
 
                if (!sb->final_buf)
                        die(_("cannot read blob %s for path %s"),