walker.c 7.38 KB
Newer Older
1
#include "cache.h"
2
#include "walker.h"
3
#include "repository.h"
4
#include "object-store.h"
5 6
#include "commit.h"
#include "tree.h"
7
#include "tree-walk.h"
8 9
#include "tag.h"
#include "blob.h"
10 11
#include "refs.h"

12
static struct object_id current_commit_oid;
13

14
void walker_say(struct walker *walker, const char *fmt, ...)
15
{
16 17 18 19 20 21
	if (walker->get_verbosely) {
		va_list ap;
		va_start(ap, fmt);
		vfprintf(stderr, fmt, ap);
		va_end(ap);
	}
22 23
}

24
static 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
}

34
static int process(struct walker *walker, struct object *obj);
35

36
static int process_tree(struct walker *walker, struct tree *tree)
37
{
38
	struct tree_desc desc;
39
	struct name_entry entry;
40 41 42 43

	if (parse_tree(tree))
		return -1;

44
	init_tree_desc(&desc, tree->buffer, tree->size);
45
	while (tree_entry(&desc, &entry)) {
46 47
		struct object *obj = NULL;

48
		/* submodule commits are not stored in the superproject */
Junio C Hamano's avatar
Junio C Hamano committed
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 55 56 57
			if (tree)
				obj = &tree->object;
		}
		else {
58
			struct blob *blob = lookup_blob(the_repository,
59
							&entry.oid);
60 61
			if (blob)
				obj = &blob->object;
62
		}
63
		if (!obj || process(walker, obj))
64 65
			return -1;
	}
66
	free_tree_buffer(tree);
67 68 69
	return 0;
}

70
/* Remember to update object flag allocation in object.h */
71 72 73
#define COMPLETE	(1U << 0)
#define SEEN		(1U << 1)
#define TO_SCAN		(1U << 2)
74

75
static struct commit_list *complete = NULL;
76

77
static int process_commit(struct walker *walker, struct commit *commit)
78
{
79 80
	struct commit_list *parents;

81
	if (parse_commit(commit))
82 83
		return -1;

84
	while (complete && complete->item->date >= commit->date) {
85
		pop_most_recent_commit(&complete, COMPLETE);
86 87
	}

88
	if (commit->object.flags & COMPLETE)
89 90
		return 0;

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 97 98 99
		return -1;

	for (parents = commit->parents; parents; parents = parents->next) {
		if (process(walker, &parents->item->object))
100 101
			return -1;
	}
102

103 104 105
	return 0;
}

106
static 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
}

113 114 115
static struct object_list *process_queue = NULL;
static struct object_list **process_queue_end = &process_queue;

116
static 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 121 122
			return -1;
		return 0;
	}
123
	if (obj->type == OBJ_TREE) {
124
		if (process_tree(walker, (struct tree *)obj))
125 126 127
			return -1;
		return 0;
	}
128
	if (obj->type == OBJ_BLOB) {
129 130
		return 0;
	}
131
	if (obj->type == OBJ_TAG) {
132
		if (process_tag(walker, (struct tag *)obj))
133
			return -1;
134
		return 0;
135 136 137
	}
	return error("Unable to determine requirements "
		     "of type %s for %s",
138
		     type_name(obj->type), oid_to_hex(&obj->oid));
139 140
}

141
static int process(struct walker *walker, struct object *obj)
142
{
143 144 145 146
	if (obj->flags & SEEN)
		return 0;
	obj->flags |= SEEN;

147
	if (has_object_file(&obj->oid)) {
148
		/* We already have it, so we should scan it now. */
149
		obj->flags |= TO_SCAN;
Junio C Hamano's avatar
Junio C Hamano committed
150 151
	}
	else {
152 153
		if (obj->flags & COMPLETE)
			return 0;
154
		walker->prefetch(walker, obj->oid.hash);
155
	}
Junio C Hamano's avatar
Junio C Hamano committed
156

157 158 159 160 161
	object_list_insert(obj, process_queue_end);
	process_queue_end = &(*process_queue_end)->next;
	return 0;
}

162
static int loop(struct walker *walker)
163
{
164 165
	struct object_list *elem;

166 167
	while (process_queue) {
		struct object *obj = process_queue->item;
168 169 170
		elem = process_queue;
		process_queue = elem->next;
		free(elem);
171 172 173
		if (!process_queue)
			process_queue_end = &process_queue;

174 175 176 177
		/* If we are not scanning this object, we placed it in
		 * the queue because we needed to fetch it first.
		 */
		if (! (obj->flags & TO_SCAN)) {
178
			if (walker->fetch(walker, obj->oid.hash)) {
179
				report_missing(obj);
180 181 182
				return -1;
			}
		}
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
}

191
static 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 201
			return 0;
		}
202
		free(ref);
203 204 205 206
	}
	return -1;
}

207 208
static int mark_complete(const char *path, const struct object_id *oid,
			 int flag, void *cb_data)
209
{
210 211
	struct commit *commit = lookup_commit_reference_gently(the_repository,
							       oid, 1);
212

213 214
	if (commit) {
		commit->object.flags |= COMPLETE;
215
		commit_list_insert(commit, &complete);
216 217 218
	}
	return 0;
}
219

220
int walker_targets_stdin(char ***target, const char ***write_ref)
221 222
{
	int targets = 0, targets_alloc = 0;
223
	struct strbuf buf = STRBUF_INIT;
224 225 226 227 228
	*target = NULL; *write_ref = NULL;
	while (1) {
		char *rf_one = NULL;
		char *tg_one;

229
		if (strbuf_getline_lf(&buf, stdin) == EOF)
230 231 232 233 234 235 236 237
			break;
		tg_one = buf.buf;
		rf_one = strchr(tg_one, '\t');
		if (rf_one)
			*rf_one++ = 0;

		if (targets >= targets_alloc) {
			targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
238 239
			REALLOC_ARRAY(*target, targets_alloc);
			REALLOC_ARRAY(*write_ref, targets_alloc);
240
		}
241
		(*target)[targets] = xstrdup(tg_one);
242
		(*write_ref)[targets] = xstrdup_or_null(rf_one);
243 244
		targets++;
	}
245
	strbuf_release(&buf);
246 247 248
	return targets;
}

249
void walker_targets_free(int targets, char **target, const char **write_ref)
250 251 252
{
	while (targets--) {
		free(target[targets]);
253
		if (write_ref)
254 255 256 257
			free((char *) write_ref[targets]);
	}
}

258 259
int walker_fetch(struct walker *walker, int targets, char **target,
		 const char **write_ref, const char *write_ref_log_details)
260
{
261 262 263
	struct strbuf refname = STRBUF_INIT;
	struct strbuf err = STRBUF_INIT;
	struct ref_transaction *transaction = NULL;
264
	struct object_id *oids = xmalloc(targets * sizeof(struct object_id));
265 266
	char *msg = NULL;
	int i, ret = -1;
267

268
	save_commit_buffer = 0;
269

270 271 272 273 274
	if (write_ref) {
		transaction = ref_transaction_begin(&err);
		if (!transaction) {
			error("%s", err.buf);
			goto done;
275
		}
276 277
	}

278
	if (!walker->get_recover) {
279
		for_each_ref(mark_complete, NULL);
280 281
		commit_list_sort_by_date(&complete);
	}
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].hash)))
289
			goto done;
290
	}
291

292
	if (loop(walker))
293 294 295 296 297
		goto done;
	if (!write_ref) {
		ret = 0;
		goto done;
	}
298
	if (write_ref_log_details) {
299
		msg = xstrfmt("fetch from %s", write_ref_log_details);
300 301
	} else {
		msg = NULL;
302
	}
303
	for (i = 0; i < targets; i++) {
304
		if (!write_ref[i])
305
			continue;
306 307 308
		strbuf_reset(&refname);
		strbuf_addf(&refname, "refs/%s", write_ref[i]);
		if (ref_transaction_update(transaction, refname.buf,
309
					   oids + i, NULL, 0,
310
					   msg ? msg : "fetch (unknown)",
311 312 313 314 315
					   &err)) {
			error("%s", err.buf);
			goto done;
		}
	}
316
	if (ref_transaction_commit(transaction, &err)) {
317 318
		error("%s", err.buf);
		goto done;
319
	}
320

321
	ret = 0;
322

323 324 325
done:
	ref_transaction_free(transaction);
	free(msg);
326
	free(oids);
327 328 329
	strbuf_release(&err);
	strbuf_release(&refname);
	return ret;
330
}
331 332 333 334 335 336

void walker_free(struct walker *walker)
{
	walker->cleanup(walker);
	free(walker);
}