walker.con commit object-store: move object access functions to object-store.h (cbd53a2)
   1#include "cache.h"
   2#include "walker.h"
   3#include "object-store.h"
   4#include "commit.h"
   5#include "tree.h"
   6#include "tree-walk.h"
   7#include "tag.h"
   8#include "blob.h"
   9#include "refs.h"
  10
  11static struct object_id current_commit_oid;
  12
  13void walker_say(struct walker *walker, const char *fmt, ...)
  14{
  15        if (walker->get_verbosely) {
  16                va_list ap;
  17                va_start(ap, fmt);
  18                vfprintf(stderr, fmt, ap);
  19                va_end(ap);
  20        }
  21}
  22
  23static void report_missing(const struct object *obj)
  24{
  25        fprintf(stderr, "Cannot obtain needed %s %s\n",
  26                obj->type ? type_name(obj->type): "object",
  27                oid_to_hex(&obj->oid));
  28        if (!is_null_oid(&current_commit_oid))
  29                fprintf(stderr, "while processing commit %s.\n",
  30                        oid_to_hex(&current_commit_oid));
  31}
  32
  33static int process(struct walker *walker, struct object *obj);
  34
  35static int process_tree(struct walker *walker, struct tree *tree)
  36{
  37        struct tree_desc desc;
  38        struct name_entry entry;
  39
  40        if (parse_tree(tree))
  41                return -1;
  42
  43        init_tree_desc(&desc, tree->buffer, tree->size);
  44        while (tree_entry(&desc, &entry)) {
  45                struct object *obj = NULL;
  46
  47                /* submodule commits are not stored in the superproject */
  48                if (S_ISGITLINK(entry.mode))
  49                        continue;
  50                if (S_ISDIR(entry.mode)) {
  51                        struct tree *tree = lookup_tree(entry.oid);
  52                        if (tree)
  53                                obj = &tree->object;
  54                }
  55                else {
  56                        struct blob *blob = lookup_blob(entry.oid);
  57                        if (blob)
  58                                obj = &blob->object;
  59                }
  60                if (!obj || process(walker, obj))
  61                        return -1;
  62        }
  63        free_tree_buffer(tree);
  64        return 0;
  65}
  66
  67/* Remember to update object flag allocation in object.h */
  68#define COMPLETE        (1U << 0)
  69#define SEEN            (1U << 1)
  70#define TO_SCAN         (1U << 2)
  71
  72static struct commit_list *complete = NULL;
  73
  74static int process_commit(struct walker *walker, struct commit *commit)
  75{
  76        if (parse_commit(commit))
  77                return -1;
  78
  79        while (complete && complete->item->date >= commit->date) {
  80                pop_most_recent_commit(&complete, COMPLETE);
  81        }
  82
  83        if (commit->object.flags & COMPLETE)
  84                return 0;
  85
  86        oidcpy(&current_commit_oid, &commit->object.oid);
  87
  88        walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
  89
  90        if (walker->get_tree) {
  91                if (process(walker, &commit->tree->object))
  92                        return -1;
  93                if (!walker->get_all)
  94                        walker->get_tree = 0;
  95        }
  96        if (walker->get_history) {
  97                struct commit_list *parents = commit->parents;
  98                for (; parents; parents = parents->next) {
  99                        if (process(walker, &parents->item->object))
 100                                return -1;
 101                }
 102        }
 103        return 0;
 104}
 105
 106static int process_tag(struct walker *walker, struct tag *tag)
 107{
 108        if (parse_tag(tag))
 109                return -1;
 110        return process(walker, tag->tagged);
 111}
 112
 113static struct object_list *process_queue = NULL;
 114static struct object_list **process_queue_end = &process_queue;
 115
 116static int process_object(struct walker *walker, struct object *obj)
 117{
 118        if (obj->type == OBJ_COMMIT) {
 119                if (process_commit(walker, (struct commit *)obj))
 120                        return -1;
 121                return 0;
 122        }
 123        if (obj->type == OBJ_TREE) {
 124                if (process_tree(walker, (struct tree *)obj))
 125                        return -1;
 126                return 0;
 127        }
 128        if (obj->type == OBJ_BLOB) {
 129                return 0;
 130        }
 131        if (obj->type == OBJ_TAG) {
 132                if (process_tag(walker, (struct tag *)obj))
 133                        return -1;
 134                return 0;
 135        }
 136        return error("Unable to determine requirements "
 137                     "of type %s for %s",
 138                     type_name(obj->type), oid_to_hex(&obj->oid));
 139}
 140
 141static int process(struct walker *walker, struct object *obj)
 142{
 143        if (obj->flags & SEEN)
 144                return 0;
 145        obj->flags |= SEEN;
 146
 147        if (has_object_file(&obj->oid)) {
 148                /* We already have it, so we should scan it now. */
 149                obj->flags |= TO_SCAN;
 150        }
 151        else {
 152                if (obj->flags & COMPLETE)
 153                        return 0;
 154                walker->prefetch(walker, obj->oid.hash);
 155        }
 156
 157        object_list_insert(obj, process_queue_end);
 158        process_queue_end = &(*process_queue_end)->next;
 159        return 0;
 160}
 161
 162static int loop(struct walker *walker)
 163{
 164        struct object_list *elem;
 165
 166        while (process_queue) {
 167                struct object *obj = process_queue->item;
 168                elem = process_queue;
 169                process_queue = elem->next;
 170                free(elem);
 171                if (!process_queue)
 172                        process_queue_end = &process_queue;
 173
 174                /* If we are not scanning this object, we placed it in
 175                 * the queue because we needed to fetch it first.
 176                 */
 177                if (! (obj->flags & TO_SCAN)) {
 178                        if (walker->fetch(walker, obj->oid.hash)) {
 179                                report_missing(obj);
 180                                return -1;
 181                        }
 182                }
 183                if (!obj->type)
 184                        parse_object(&obj->oid);
 185                if (process_object(walker, obj))
 186                        return -1;
 187        }
 188        return 0;
 189}
 190
 191static int interpret_target(struct walker *walker, char *target, struct object_id *oid)
 192{
 193        if (!get_oid_hex(target, oid))
 194                return 0;
 195        if (!check_refname_format(target, 0)) {
 196                struct ref *ref = alloc_ref(target);
 197                if (!walker->fetch_ref(walker, ref)) {
 198                        oidcpy(oid, &ref->old_oid);
 199                        free(ref);
 200                        return 0;
 201                }
 202                free(ref);
 203        }
 204        return -1;
 205}
 206
 207static int mark_complete(const char *path, const struct object_id *oid,
 208                         int flag, void *cb_data)
 209{
 210        struct commit *commit = lookup_commit_reference_gently(oid, 1);
 211
 212        if (commit) {
 213                commit->object.flags |= COMPLETE;
 214                commit_list_insert(commit, &complete);
 215        }
 216        return 0;
 217}
 218
 219int walker_targets_stdin(char ***target, const char ***write_ref)
 220{
 221        int targets = 0, targets_alloc = 0;
 222        struct strbuf buf = STRBUF_INIT;
 223        *target = NULL; *write_ref = NULL;
 224        while (1) {
 225                char *rf_one = NULL;
 226                char *tg_one;
 227
 228                if (strbuf_getline_lf(&buf, stdin) == EOF)
 229                        break;
 230                tg_one = buf.buf;
 231                rf_one = strchr(tg_one, '\t');
 232                if (rf_one)
 233                        *rf_one++ = 0;
 234
 235                if (targets >= targets_alloc) {
 236                        targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
 237                        REALLOC_ARRAY(*target, targets_alloc);
 238                        REALLOC_ARRAY(*write_ref, targets_alloc);
 239                }
 240                (*target)[targets] = xstrdup(tg_one);
 241                (*write_ref)[targets] = xstrdup_or_null(rf_one);
 242                targets++;
 243        }
 244        strbuf_release(&buf);
 245        return targets;
 246}
 247
 248void walker_targets_free(int targets, char **target, const char **write_ref)
 249{
 250        while (targets--) {
 251                free(target[targets]);
 252                if (write_ref)
 253                        free((char *) write_ref[targets]);
 254        }
 255}
 256
 257int walker_fetch(struct walker *walker, int targets, char **target,
 258                 const char **write_ref, const char *write_ref_log_details)
 259{
 260        struct strbuf refname = STRBUF_INIT;
 261        struct strbuf err = STRBUF_INIT;
 262        struct ref_transaction *transaction = NULL;
 263        struct object_id *oids = xmalloc(targets * sizeof(struct object_id));
 264        char *msg = NULL;
 265        int i, ret = -1;
 266
 267        save_commit_buffer = 0;
 268
 269        if (write_ref) {
 270                transaction = ref_transaction_begin(&err);
 271                if (!transaction) {
 272                        error("%s", err.buf);
 273                        goto done;
 274                }
 275        }
 276
 277        if (!walker->get_recover) {
 278                for_each_ref(mark_complete, NULL);
 279                commit_list_sort_by_date(&complete);
 280        }
 281
 282        for (i = 0; i < targets; i++) {
 283                if (interpret_target(walker, target[i], oids + i)) {
 284                        error("Could not interpret response from server '%s' as something to pull", target[i]);
 285                        goto done;
 286                }
 287                if (process(walker, lookup_unknown_object(oids[i].hash)))
 288                        goto done;
 289        }
 290
 291        if (loop(walker))
 292                goto done;
 293        if (!write_ref) {
 294                ret = 0;
 295                goto done;
 296        }
 297        if (write_ref_log_details) {
 298                msg = xstrfmt("fetch from %s", write_ref_log_details);
 299        } else {
 300                msg = NULL;
 301        }
 302        for (i = 0; i < targets; i++) {
 303                if (!write_ref[i])
 304                        continue;
 305                strbuf_reset(&refname);
 306                strbuf_addf(&refname, "refs/%s", write_ref[i]);
 307                if (ref_transaction_update(transaction, refname.buf,
 308                                           oids + i, NULL, 0,
 309                                           msg ? msg : "fetch (unknown)",
 310                                           &err)) {
 311                        error("%s", err.buf);
 312                        goto done;
 313                }
 314        }
 315        if (ref_transaction_commit(transaction, &err)) {
 316                error("%s", err.buf);
 317                goto done;
 318        }
 319
 320        ret = 0;
 321
 322done:
 323        ref_transaction_free(transaction);
 324        free(msg);
 325        free(oids);
 326        strbuf_release(&err);
 327        strbuf_release(&refname);
 328        return ret;
 329}
 330
 331void walker_free(struct walker *walker)
 332{
 333        walker->cleanup(walker);
 334        free(walker);
 335}