walker.con commit Merge branch 'bp/test-drop-caches-for-windows' (5e98080)
   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        struct commit_list *parents;
  77
  78        if (parse_commit(commit))
  79                return -1;
  80
  81        while (complete && complete->item->date >= commit->date) {
  82                pop_most_recent_commit(&complete, COMPLETE);
  83        }
  84
  85        if (commit->object.flags & COMPLETE)
  86                return 0;
  87
  88        oidcpy(&current_commit_oid, &commit->object.oid);
  89
  90        walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
  91
  92        if (process(walker, &get_commit_tree(commit)->object))
  93                return -1;
  94
  95        for (parents = commit->parents; parents; parents = parents->next) {
  96                if (process(walker, &parents->item->object))
  97                        return -1;
  98        }
  99
 100        return 0;
 101}
 102
 103static int process_tag(struct walker *walker, struct tag *tag)
 104{
 105        if (parse_tag(tag))
 106                return -1;
 107        return process(walker, tag->tagged);
 108}
 109
 110static struct object_list *process_queue = NULL;
 111static struct object_list **process_queue_end = &process_queue;
 112
 113static int process_object(struct walker *walker, struct object *obj)
 114{
 115        if (obj->type == OBJ_COMMIT) {
 116                if (process_commit(walker, (struct commit *)obj))
 117                        return -1;
 118                return 0;
 119        }
 120        if (obj->type == OBJ_TREE) {
 121                if (process_tree(walker, (struct tree *)obj))
 122                        return -1;
 123                return 0;
 124        }
 125        if (obj->type == OBJ_BLOB) {
 126                return 0;
 127        }
 128        if (obj->type == OBJ_TAG) {
 129                if (process_tag(walker, (struct tag *)obj))
 130                        return -1;
 131                return 0;
 132        }
 133        return error("Unable to determine requirements "
 134                     "of type %s for %s",
 135                     type_name(obj->type), oid_to_hex(&obj->oid));
 136}
 137
 138static int process(struct walker *walker, struct object *obj)
 139{
 140        if (obj->flags & SEEN)
 141                return 0;
 142        obj->flags |= SEEN;
 143
 144        if (has_object_file(&obj->oid)) {
 145                /* We already have it, so we should scan it now. */
 146                obj->flags |= TO_SCAN;
 147        }
 148        else {
 149                if (obj->flags & COMPLETE)
 150                        return 0;
 151                walker->prefetch(walker, obj->oid.hash);
 152        }
 153
 154        object_list_insert(obj, process_queue_end);
 155        process_queue_end = &(*process_queue_end)->next;
 156        return 0;
 157}
 158
 159static int loop(struct walker *walker)
 160{
 161        struct object_list *elem;
 162
 163        while (process_queue) {
 164                struct object *obj = process_queue->item;
 165                elem = process_queue;
 166                process_queue = elem->next;
 167                free(elem);
 168                if (!process_queue)
 169                        process_queue_end = &process_queue;
 170
 171                /* If we are not scanning this object, we placed it in
 172                 * the queue because we needed to fetch it first.
 173                 */
 174                if (! (obj->flags & TO_SCAN)) {
 175                        if (walker->fetch(walker, obj->oid.hash)) {
 176                                report_missing(obj);
 177                                return -1;
 178                        }
 179                }
 180                if (!obj->type)
 181                        parse_object(&obj->oid);
 182                if (process_object(walker, obj))
 183                        return -1;
 184        }
 185        return 0;
 186}
 187
 188static int interpret_target(struct walker *walker, char *target, struct object_id *oid)
 189{
 190        if (!get_oid_hex(target, oid))
 191                return 0;
 192        if (!check_refname_format(target, 0)) {
 193                struct ref *ref = alloc_ref(target);
 194                if (!walker->fetch_ref(walker, ref)) {
 195                        oidcpy(oid, &ref->old_oid);
 196                        free(ref);
 197                        return 0;
 198                }
 199                free(ref);
 200        }
 201        return -1;
 202}
 203
 204static int mark_complete(const char *path, const struct object_id *oid,
 205                         int flag, void *cb_data)
 206{
 207        struct commit *commit = lookup_commit_reference_gently(oid, 1);
 208
 209        if (commit) {
 210                commit->object.flags |= COMPLETE;
 211                commit_list_insert(commit, &complete);
 212        }
 213        return 0;
 214}
 215
 216int walker_targets_stdin(char ***target, const char ***write_ref)
 217{
 218        int targets = 0, targets_alloc = 0;
 219        struct strbuf buf = STRBUF_INIT;
 220        *target = NULL; *write_ref = NULL;
 221        while (1) {
 222                char *rf_one = NULL;
 223                char *tg_one;
 224
 225                if (strbuf_getline_lf(&buf, stdin) == EOF)
 226                        break;
 227                tg_one = buf.buf;
 228                rf_one = strchr(tg_one, '\t');
 229                if (rf_one)
 230                        *rf_one++ = 0;
 231
 232                if (targets >= targets_alloc) {
 233                        targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
 234                        REALLOC_ARRAY(*target, targets_alloc);
 235                        REALLOC_ARRAY(*write_ref, targets_alloc);
 236                }
 237                (*target)[targets] = xstrdup(tg_one);
 238                (*write_ref)[targets] = xstrdup_or_null(rf_one);
 239                targets++;
 240        }
 241        strbuf_release(&buf);
 242        return targets;
 243}
 244
 245void walker_targets_free(int targets, char **target, const char **write_ref)
 246{
 247        while (targets--) {
 248                free(target[targets]);
 249                if (write_ref)
 250                        free((char *) write_ref[targets]);
 251        }
 252}
 253
 254int walker_fetch(struct walker *walker, int targets, char **target,
 255                 const char **write_ref, const char *write_ref_log_details)
 256{
 257        struct strbuf refname = STRBUF_INIT;
 258        struct strbuf err = STRBUF_INIT;
 259        struct ref_transaction *transaction = NULL;
 260        struct object_id *oids = xmalloc(targets * sizeof(struct object_id));
 261        char *msg = NULL;
 262        int i, ret = -1;
 263
 264        save_commit_buffer = 0;
 265
 266        if (write_ref) {
 267                transaction = ref_transaction_begin(&err);
 268                if (!transaction) {
 269                        error("%s", err.buf);
 270                        goto done;
 271                }
 272        }
 273
 274        if (!walker->get_recover) {
 275                for_each_ref(mark_complete, NULL);
 276                commit_list_sort_by_date(&complete);
 277        }
 278
 279        for (i = 0; i < targets; i++) {
 280                if (interpret_target(walker, target[i], oids + i)) {
 281                        error("Could not interpret response from server '%s' as something to pull", target[i]);
 282                        goto done;
 283                }
 284                if (process(walker, lookup_unknown_object(oids[i].hash)))
 285                        goto done;
 286        }
 287
 288        if (loop(walker))
 289                goto done;
 290        if (!write_ref) {
 291                ret = 0;
 292                goto done;
 293        }
 294        if (write_ref_log_details) {
 295                msg = xstrfmt("fetch from %s", write_ref_log_details);
 296        } else {
 297                msg = NULL;
 298        }
 299        for (i = 0; i < targets; i++) {
 300                if (!write_ref[i])
 301                        continue;
 302                strbuf_reset(&refname);
 303                strbuf_addf(&refname, "refs/%s", write_ref[i]);
 304                if (ref_transaction_update(transaction, refname.buf,
 305                                           oids + i, NULL, 0,
 306                                           msg ? msg : "fetch (unknown)",
 307                                           &err)) {
 308                        error("%s", err.buf);
 309                        goto done;
 310                }
 311        }
 312        if (ref_transaction_commit(transaction, &err)) {
 313                error("%s", err.buf);
 314                goto done;
 315        }
 316
 317        ret = 0;
 318
 319done:
 320        ref_transaction_free(transaction);
 321        free(msg);
 322        free(oids);
 323        strbuf_release(&err);
 324        strbuf_release(&refname);
 325        return ret;
 326}
 327
 328void walker_free(struct walker *walker)
 329{
 330        walker->cleanup(walker);
 331        free(walker);
 332}