walker.con commit Merge branch 'jk/repo-init-cleanup' (b4a1eec)
   1#include "cache.h"
   2#include "walker.h"
   3#include "repository.h"
   4#include "object-store.h"
   5#include "commit.h"
   6#include "tree.h"
   7#include "tree-walk.h"
   8#include "tag.h"
   9#include "blob.h"
  10#include "refs.h"
  11
  12static struct object_id current_commit_oid;
  13
  14void walker_say(struct walker *walker, const char *fmt, ...)
  15{
  16        if (walker->get_verbosely) {
  17                va_list ap;
  18                va_start(ap, fmt);
  19                vfprintf(stderr, fmt, ap);
  20                va_end(ap);
  21        }
  22}
  23
  24static void report_missing(const struct object *obj)
  25{
  26        fprintf(stderr, "Cannot obtain needed %s %s\n",
  27                obj->type ? type_name(obj->type): "object",
  28                oid_to_hex(&obj->oid));
  29        if (!is_null_oid(&current_commit_oid))
  30                fprintf(stderr, "while processing commit %s.\n",
  31                        oid_to_hex(&current_commit_oid));
  32}
  33
  34static int process(struct walker *walker, struct object *obj);
  35
  36static int process_tree(struct walker *walker, struct tree *tree)
  37{
  38        struct tree_desc desc;
  39        struct name_entry entry;
  40
  41        if (parse_tree(tree))
  42                return -1;
  43
  44        init_tree_desc(&desc, tree->buffer, tree->size);
  45        while (tree_entry(&desc, &entry)) {
  46                struct object *obj = NULL;
  47
  48                /* submodule commits are not stored in the superproject */
  49                if (S_ISGITLINK(entry.mode))
  50                        continue;
  51                if (S_ISDIR(entry.mode)) {
  52                        struct tree *tree = lookup_tree(the_repository,
  53                                                        &entry.oid);
  54                        if (tree)
  55                                obj = &tree->object;
  56                }
  57                else {
  58                        struct blob *blob = lookup_blob(the_repository,
  59                                                        &entry.oid);
  60                        if (blob)
  61                                obj = &blob->object;
  62                }
  63                if (!obj || process(walker, obj))
  64                        return -1;
  65        }
  66        free_tree_buffer(tree);
  67        return 0;
  68}
  69
  70/* Remember to update object flag allocation in object.h */
  71#define COMPLETE        (1U << 0)
  72#define SEEN            (1U << 1)
  73#define TO_SCAN         (1U << 2)
  74
  75static struct commit_list *complete = NULL;
  76
  77static int process_commit(struct walker *walker, struct commit *commit)
  78{
  79        struct commit_list *parents;
  80
  81        if (parse_commit(commit))
  82                return -1;
  83
  84        while (complete && complete->item->date >= commit->date) {
  85                pop_most_recent_commit(&complete, COMPLETE);
  86        }
  87
  88        if (commit->object.flags & COMPLETE)
  89                return 0;
  90
  91        oidcpy(&current_commit_oid, &commit->object.oid);
  92
  93        walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
  94
  95        if (process(walker, &get_commit_tree(commit)->object))
  96                return -1;
  97
  98        for (parents = commit->parents; 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(the_repository, &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(the_repository,
 211                                                               oid, 1);
 212
 213        if (commit) {
 214                commit->object.flags |= COMPLETE;
 215                commit_list_insert(commit, &complete);
 216        }
 217        return 0;
 218}
 219
 220int walker_targets_stdin(char ***target, const char ***write_ref)
 221{
 222        int targets = 0, targets_alloc = 0;
 223        struct strbuf buf = STRBUF_INIT;
 224        *target = NULL; *write_ref = NULL;
 225        while (1) {
 226                char *rf_one = NULL;
 227                char *tg_one;
 228
 229                if (strbuf_getline_lf(&buf, stdin) == EOF)
 230                        break;
 231                tg_one = buf.buf;
 232                rf_one = strchr(tg_one, '\t');
 233                if (rf_one)
 234                        *rf_one++ = 0;
 235
 236                if (targets >= targets_alloc) {
 237                        targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
 238                        REALLOC_ARRAY(*target, targets_alloc);
 239                        REALLOC_ARRAY(*write_ref, targets_alloc);
 240                }
 241                (*target)[targets] = xstrdup(tg_one);
 242                (*write_ref)[targets] = xstrdup_or_null(rf_one);
 243                targets++;
 244        }
 245        strbuf_release(&buf);
 246        return targets;
 247}
 248
 249void walker_targets_free(int targets, char **target, const char **write_ref)
 250{
 251        while (targets--) {
 252                free(target[targets]);
 253                if (write_ref)
 254                        free((char *) write_ref[targets]);
 255        }
 256}
 257
 258int walker_fetch(struct walker *walker, int targets, char **target,
 259                 const char **write_ref, const char *write_ref_log_details)
 260{
 261        struct strbuf refname = STRBUF_INIT;
 262        struct strbuf err = STRBUF_INIT;
 263        struct ref_transaction *transaction = NULL;
 264        struct object_id *oids = xmalloc(targets * sizeof(struct object_id));
 265        char *msg = NULL;
 266        int i, ret = -1;
 267
 268        save_commit_buffer = 0;
 269
 270        if (write_ref) {
 271                transaction = ref_transaction_begin(&err);
 272                if (!transaction) {
 273                        error("%s", err.buf);
 274                        goto done;
 275                }
 276        }
 277
 278        if (!walker->get_recover) {
 279                for_each_ref(mark_complete, NULL);
 280                commit_list_sort_by_date(&complete);
 281        }
 282
 283        for (i = 0; i < targets; i++) {
 284                if (interpret_target(walker, target[i], oids + i)) {
 285                        error("Could not interpret response from server '%s' as something to pull", target[i]);
 286                        goto done;
 287                }
 288                if (process(walker, lookup_unknown_object(&oids[i])))
 289                        goto done;
 290        }
 291
 292        if (loop(walker))
 293                goto done;
 294        if (!write_ref) {
 295                ret = 0;
 296                goto done;
 297        }
 298        if (write_ref_log_details) {
 299                msg = xstrfmt("fetch from %s", write_ref_log_details);
 300        } else {
 301                msg = NULL;
 302        }
 303        for (i = 0; i < targets; i++) {
 304                if (!write_ref[i])
 305                        continue;
 306                strbuf_reset(&refname);
 307                strbuf_addf(&refname, "refs/%s", write_ref[i]);
 308                if (ref_transaction_update(transaction, refname.buf,
 309                                           oids + i, NULL, 0,
 310                                           msg ? msg : "fetch (unknown)",
 311                                           &err)) {
 312                        error("%s", err.buf);
 313                        goto done;
 314                }
 315        }
 316        if (ref_transaction_commit(transaction, &err)) {
 317                error("%s", err.buf);
 318                goto done;
 319        }
 320
 321        ret = 0;
 322
 323done:
 324        ref_transaction_free(transaction);
 325        free(msg);
 326        free(oids);
 327        strbuf_release(&err);
 328        strbuf_release(&refname);
 329        return ret;
 330}
 331
 332void walker_free(struct walker *walker)
 333{
 334        walker->cleanup(walker);
 335        free(walker);
 336}