Imported Upstream version 2.28.0
[platform/upstream/git.git] / reflog-walk.c
index b2fbdb2..3a25b27 100644 (file)
@@ -10,30 +10,26 @@ struct complete_reflogs {
        char *ref;
        const char *short_ref;
        struct reflog_info {
-               unsigned char osha1[20], nsha1[20];
+               struct object_id ooid, noid;
                char *email;
-               unsigned long timestamp;
+               timestamp_t timestamp;
                int tz;
                char *message;
        } *items;
        int nr, alloc;
 };
 
-static int read_one_reflog(unsigned char *osha1, unsigned char *nsha1,
-               const char *email, unsigned long timestamp, int tz,
+static int read_one_reflog(struct object_id *ooid, struct object_id *noid,
+               const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
 {
        struct complete_reflogs *array = cb_data;
        struct reflog_info *item;
 
-       if (array->nr >= array->alloc) {
-               array->alloc = alloc_nr(array->nr + 1);
-               array->items = xrealloc(array->items, array->alloc *
-                       sizeof(struct reflog_info));
-       }
+       ALLOC_GROW(array->items, array->nr + 1, array->alloc);
        item = array->items + array->nr;
-       memcpy(item->osha1, osha1, 20);
-       memcpy(item->nsha1, nsha1, 20);
+       oidcpy(&item->ooid, ooid);
+       oidcpy(&item->noid, noid);
        item->email = xstrdup(email);
        item->timestamp = timestamp;
        item->tz = tz;
@@ -42,29 +38,44 @@ static int read_one_reflog(unsigned char *osha1, unsigned char *nsha1,
        return 0;
 }
 
+static void free_complete_reflog(struct complete_reflogs *array)
+{
+       int i;
+
+       if (!array)
+               return;
+
+       for (i = 0; i < array->nr; i++) {
+               free(array->items[i].email);
+               free(array->items[i].message);
+       }
+       free(array->items);
+       free(array->ref);
+       free(array);
+}
+
 static struct complete_reflogs *read_complete_reflog(const char *ref)
 {
        struct complete_reflogs *reflogs =
-               xcalloc(sizeof(struct complete_reflogs), 1);
+               xcalloc(1, sizeof(struct complete_reflogs));
        reflogs->ref = xstrdup(ref);
        for_each_reflog_ent(ref, read_one_reflog, reflogs);
        if (reflogs->nr == 0) {
-               unsigned char sha1[20];
                const char *name;
                void *name_to_free;
-               name = name_to_free = resolve_refdup(ref, sha1, 1, NULL);
+               name = name_to_free = resolve_refdup(ref, RESOLVE_REF_READING,
+                                                    NULL, NULL);
                if (name) {
                        for_each_reflog_ent(name, read_one_reflog, reflogs);
                        free(name_to_free);
                }
        }
        if (reflogs->nr == 0) {
-               int len = strlen(ref);
-               char *refname = xmalloc(len + 12);
-               sprintf(refname, "refs/%s", ref);
+               char *refname = xstrfmt("refs/%s", ref);
                for_each_reflog_ent(refname, read_one_reflog, reflogs);
                if (reflogs->nr == 0) {
-                       sprintf(refname, "refs/heads/%s", ref);
+                       free(refname);
+                       refname = xstrfmt("refs/heads/%s", ref);
                        for_each_reflog_ent(refname, read_one_reflog, reflogs);
                }
                free(refname);
@@ -73,7 +84,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
 }
 
 static int get_reflog_recno_by_time(struct complete_reflogs *array,
-       unsigned long timestamp)
+       timestamp_t timestamp)
 {
        int i;
        for (i = array->nr - 1; i >= 0; i--)
@@ -82,49 +93,6 @@ static int get_reflog_recno_by_time(struct complete_reflogs *array,
        return -1;
 }
 
-struct commit_info_lifo {
-       struct commit_info {
-               struct commit *commit;
-               void *util;
-       } *items;
-       int nr, alloc;
-};
-
-static struct commit_info *get_commit_info(struct commit *commit,
-               struct commit_info_lifo *lifo, int pop)
-{
-       int i;
-       for (i = 0; i < lifo->nr; i++)
-               if (lifo->items[i].commit == commit) {
-                       struct commit_info *result = &lifo->items[i];
-                       if (pop) {
-                               if (i + 1 < lifo->nr)
-                                       memmove(lifo->items + i,
-                                               lifo->items + i + 1,
-                                               (lifo->nr - i) *
-                                               sizeof(struct commit_info));
-                               lifo->nr--;
-                       }
-                       return result;
-               }
-       return NULL;
-}
-
-static void add_commit_info(struct commit *commit, void *util,
-               struct commit_info_lifo *lifo)
-{
-       struct commit_info *info;
-       if (lifo->nr >= lifo->alloc) {
-               lifo->alloc = alloc_nr(lifo->nr + 1);
-               lifo->items = xrealloc(lifo->items,
-                       lifo->alloc * sizeof(struct commit_info));
-       }
-       info = lifo->items + lifo->nr;
-       info->commit = commit;
-       info->util = util;
-       lifo->nr++;
-}
-
 struct commit_reflog {
        int recno;
        enum selector_type {
@@ -136,20 +104,22 @@ struct commit_reflog {
 };
 
 struct reflog_walk_info {
-       struct commit_info_lifo reflogs;
+       struct commit_reflog **logs;
+       size_t nr, alloc;
        struct string_list complete_reflogs;
        struct commit_reflog *last_commit_reflog;
 };
 
-void init_reflog_walk(struct reflog_walk_info** info)
+void init_reflog_walk(struct reflog_walk_info **info)
 {
-       *info = xcalloc(sizeof(struct reflog_walk_info), 1);
+       *info = xcalloc(1, sizeof(struct reflog_walk_info));
+       (*info)->complete_reflogs.strdup_strings = 1;
 }
 
 int add_reflog_for_walk(struct reflog_walk_info *info,
                struct commit *commit, const char *name)
 {
-       unsigned long timestamp = 0;
+       timestamp_t timestamp = 0;
        int recno = -1;
        struct string_list_item *item;
        struct complete_reflogs *reflogs;
@@ -158,7 +128,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
        enum selector_type selector = SELECTOR_NONE;
 
        if (commit->object.flags & UNINTERESTING)
-               die ("Cannot walk reflogs for %s", name);
+               die("cannot walk reflogs for %s", name);
 
        branch = xstrdup(name);
        if (at && at[1] == '{') {
@@ -180,38 +150,41 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
                reflogs = item->util;
        else {
                if (*branch == '\0') {
-                       unsigned char sha1[20];
                        free(branch);
-                       branch = resolve_refdup("HEAD", sha1, 0, NULL);
+                       branch = resolve_refdup("HEAD", 0, NULL, NULL);
                        if (!branch)
-                               die ("No current branch");
+                               die("no current branch");
 
                }
                reflogs = read_complete_reflog(branch);
                if (!reflogs || reflogs->nr == 0) {
-                       unsigned char sha1[20];
+                       struct object_id oid;
                        char *b;
-                       if (dwim_log(branch, strlen(branch), sha1, &b) == 1) {
-                               if (reflogs) {
-                                       free(reflogs->ref);
-                                       free(reflogs);
-                               }
+                       int ret = dwim_log(branch, strlen(branch),
+                                          &oid, &b);
+                       if (ret > 1)
+                               free(b);
+                       else if (ret == 1) {
+                               free_complete_reflog(reflogs);
                                free(branch);
                                branch = b;
                                reflogs = read_complete_reflog(branch);
                        }
                }
-               if (!reflogs || reflogs->nr == 0)
+               if (!reflogs || reflogs->nr == 0) {
+                       free_complete_reflog(reflogs);
+                       free(branch);
                        return -1;
+               }
                string_list_insert(&info->complete_reflogs, branch)->util
                        = reflogs;
        }
+       free(branch);
 
-       commit_reflog = xcalloc(sizeof(struct commit_reflog), 1);
+       commit_reflog = xcalloc(1, sizeof(struct commit_reflog));
        if (recno < 0) {
                commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
                if (commit_reflog->recno < 0) {
-                       free(branch);
                        free(commit_reflog);
                        return -1;
                }
@@ -220,43 +193,15 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
        commit_reflog->selector = selector;
        commit_reflog->reflogs = reflogs;
 
-       add_commit_info(commit, commit_reflog, &info->reflogs);
-       return 0;
-}
-
-void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
-{
-       struct commit_info *commit_info =
-               get_commit_info(commit, &info->reflogs, 0);
-       struct commit_reflog *commit_reflog;
-       struct reflog_info *reflog;
-
-       info->last_commit_reflog = NULL;
-       if (!commit_info)
-               return;
-
-       commit_reflog = commit_info->util;
-       if (commit_reflog->recno < 0) {
-               commit->parents = NULL;
-               return;
-       }
+       ALLOC_GROW(info->logs, info->nr + 1, info->alloc);
+       info->logs[info->nr++] = commit_reflog;
 
-       reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
-       info->last_commit_reflog = commit_reflog;
-       commit_reflog->recno--;
-       commit_info->commit = (struct commit *)parse_object(reflog->osha1);
-       if (!commit_info->commit) {
-               commit->parents = NULL;
-               return;
-       }
-
-       commit->parents = xcalloc(sizeof(struct commit_list), 1);
-       commit->parents->item = commit_info->commit;
+       return 0;
 }
 
 void get_reflog_selector(struct strbuf *sb,
                         struct reflog_walk_info *reflog_info,
-                        enum date_mode dmode, int force_date,
+                        const struct date_mode *dmode, int force_date,
                         int shorten)
 {
        struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
@@ -317,8 +262,20 @@ const char *get_reflog_ident(struct reflog_walk_info *reflog_info)
        return info->email;
 }
 
+timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info)
+{
+       struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
+       struct reflog_info *info;
+
+       if (!commit_reflog)
+               return 0;
+
+       info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+       return info->timestamp;
+}
+
 void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
-                        enum date_mode dmode, int force_date)
+                        const struct date_mode *dmode, int force_date)
 {
        if (reflog_info && reflog_info->last_commit_reflog) {
                struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
@@ -338,3 +295,54 @@ void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
                strbuf_release(&selector);
        }
 }
+
+int reflog_walk_empty(struct reflog_walk_info *info)
+{
+       return !info || !info->nr;
+}
+
+static struct commit *next_reflog_commit(struct commit_reflog *log)
+{
+       for (; log->recno >= 0; log->recno--) {
+               struct reflog_info *entry = &log->reflogs->items[log->recno];
+               struct object *obj = parse_object(the_repository,
+                                                 &entry->noid);
+
+               if (obj && obj->type == OBJ_COMMIT)
+                       return (struct commit *)obj;
+       }
+       return NULL;
+}
+
+static timestamp_t log_timestamp(struct commit_reflog *log)
+{
+       return log->reflogs->items[log->recno].timestamp;
+}
+
+struct commit *next_reflog_entry(struct reflog_walk_info *walk)
+{
+       struct commit_reflog *best = NULL;
+       struct commit *best_commit = NULL;
+       size_t i;
+
+       for (i = 0; i < walk->nr; i++) {
+               struct commit_reflog *log = walk->logs[i];
+               struct commit *commit = next_reflog_commit(log);
+
+               if (!commit)
+                       continue;
+
+               if (!best || log_timestamp(log) > log_timestamp(best)) {
+                       best = log;
+                       best_commit = commit;
+               }
+       }
+
+       if (best) {
+               best->recno--;
+               walk->last_commit_reflog = best;
+               return best_commit;
+       }
+
+       return NULL;
+}