git

Форк
0
/
walker.c 
359 строк · 8.0 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "gettext.h"
5
#include "hex.h"
6
#include "walker.h"
7
#include "repository.h"
8
#include "object-store-ll.h"
9
#include "commit.h"
10
#include "strbuf.h"
11
#include "tree.h"
12
#include "tree-walk.h"
13
#include "tag.h"
14
#include "blob.h"
15
#include "refs.h"
16
#include "progress.h"
17

18
static struct object_id current_commit_oid;
19

20
void walker_say(struct walker *walker, const char *fmt, ...)
21
{
22
	if (walker->get_verbosely) {
23
		va_list ap;
24
		va_start(ap, fmt);
25
		vfprintf(stderr, fmt, ap);
26
		va_end(ap);
27
	}
28
}
29

30
static void report_missing(const struct object *obj)
31
{
32
	fprintf(stderr, "Cannot obtain needed %s %s\n",
33
		obj->type ? type_name(obj->type): "object",
34
		oid_to_hex(&obj->oid));
35
	if (!is_null_oid(&current_commit_oid))
36
		fprintf(stderr, "while processing commit %s.\n",
37
			oid_to_hex(&current_commit_oid));
38
}
39

40
static int process(struct walker *walker, struct object *obj);
41

42
static int process_tree(struct walker *walker, struct tree *tree)
43
{
44
	struct tree_desc desc;
45
	struct name_entry entry;
46

47
	if (parse_tree(tree))
48
		return -1;
49

50
	init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
51
	while (tree_entry(&desc, &entry)) {
52
		struct object *obj = NULL;
53

54
		/* submodule commits are not stored in the superproject */
55
		if (S_ISGITLINK(entry.mode))
56
			continue;
57
		if (S_ISDIR(entry.mode)) {
58
			struct tree *tree = lookup_tree(the_repository,
59
							&entry.oid);
60
			if (tree)
61
				obj = &tree->object;
62
		}
63
		else {
64
			struct blob *blob = lookup_blob(the_repository,
65
							&entry.oid);
66
			if (blob)
67
				obj = &blob->object;
68
		}
69
		if (!obj || process(walker, obj))
70
			return -1;
71
	}
72
	free_tree_buffer(tree);
73
	return 0;
74
}
75

76
/* Remember to update object flag allocation in object.h */
77
#define COMPLETE	(1U << 0)
78
#define SEEN		(1U << 1)
79
#define TO_SCAN		(1U << 2)
80

81
static struct commit_list *complete = NULL;
82

83
static int process_commit(struct walker *walker, struct commit *commit)
84
{
85
	struct commit_list *parents;
86

87
	if (repo_parse_commit(the_repository, commit))
88
		return -1;
89

90
	while (complete && complete->item->date >= commit->date) {
91
		pop_most_recent_commit(&complete, COMPLETE);
92
	}
93

94
	if (commit->object.flags & COMPLETE)
95
		return 0;
96

97
	oidcpy(&current_commit_oid, &commit->object.oid);
98

99
	walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
100

101
	if (process(walker, &repo_get_commit_tree(the_repository, commit)->object))
102
		return -1;
103

104
	for (parents = commit->parents; parents; parents = parents->next) {
105
		if (process(walker, &parents->item->object))
106
			return -1;
107
	}
108

109
	return 0;
110
}
111

112
static int process_tag(struct walker *walker, struct tag *tag)
113
{
114
	if (parse_tag(tag))
115
		return -1;
116
	return process(walker, tag->tagged);
117
}
118

119
static struct object_list *process_queue = NULL;
120
static struct object_list **process_queue_end = &process_queue;
121

122
static int process_object(struct walker *walker, struct object *obj)
123
{
124
	if (obj->type == OBJ_COMMIT) {
125
		if (process_commit(walker, (struct commit *)obj))
126
			return -1;
127
		return 0;
128
	}
129
	if (obj->type == OBJ_TREE) {
130
		if (process_tree(walker, (struct tree *)obj))
131
			return -1;
132
		return 0;
133
	}
134
	if (obj->type == OBJ_BLOB) {
135
		return 0;
136
	}
137
	if (obj->type == OBJ_TAG) {
138
		if (process_tag(walker, (struct tag *)obj))
139
			return -1;
140
		return 0;
141
	}
142
	return error("Unable to determine requirements "
143
		     "of type %s for %s",
144
		     type_name(obj->type), oid_to_hex(&obj->oid));
145
}
146

147
static int process(struct walker *walker, struct object *obj)
148
{
149
	if (obj->flags & SEEN)
150
		return 0;
151
	obj->flags |= SEEN;
152

153
	if (repo_has_object_file(the_repository, &obj->oid)) {
154
		/* We already have it, so we should scan it now. */
155
		obj->flags |= TO_SCAN;
156
	}
157
	else {
158
		if (obj->flags & COMPLETE)
159
			return 0;
160
		walker->prefetch(walker, obj->oid.hash);
161
	}
162

163
	object_list_insert(obj, process_queue_end);
164
	process_queue_end = &(*process_queue_end)->next;
165
	return 0;
166
}
167

168
static int loop(struct walker *walker)
169
{
170
	struct object_list *elem;
171
	struct progress *progress = NULL;
172
	uint64_t nr = 0;
173

174
	if (walker->get_progress)
175
		progress = start_delayed_progress(_("Fetching objects"), 0);
176

177
	while (process_queue) {
178
		struct object *obj = process_queue->item;
179
		elem = process_queue;
180
		process_queue = elem->next;
181
		free(elem);
182
		if (!process_queue)
183
			process_queue_end = &process_queue;
184

185
		/* If we are not scanning this object, we placed it in
186
		 * the queue because we needed to fetch it first.
187
		 */
188
		if (! (obj->flags & TO_SCAN)) {
189
			if (walker->fetch(walker, obj->oid.hash)) {
190
				stop_progress(&progress);
191
				report_missing(obj);
192
				return -1;
193
			}
194
		}
195
		if (!obj->type)
196
			parse_object(the_repository, &obj->oid);
197
		if (process_object(walker, obj)) {
198
			stop_progress(&progress);
199
			return -1;
200
		}
201
		display_progress(progress, ++nr);
202
	}
203
	stop_progress(&progress);
204
	return 0;
205
}
206

207
static int interpret_target(struct walker *walker, char *target, struct object_id *oid)
208
{
209
	if (!get_oid_hex(target, oid))
210
		return 0;
211
	if (!check_refname_format(target, 0)) {
212
		struct ref *ref = alloc_ref(target);
213
		if (!walker->fetch_ref(walker, ref)) {
214
			oidcpy(oid, &ref->old_oid);
215
			free(ref);
216
			return 0;
217
		}
218
		free(ref);
219
	}
220
	return -1;
221
}
222

223
static int mark_complete(const char *path UNUSED,
224
			const char *referent UNUSED,
225
			 const struct object_id *oid,
226
			 int flag UNUSED,
227
			 void *cb_data UNUSED)
228
{
229
	struct commit *commit = lookup_commit_reference_gently(the_repository,
230
							       oid, 1);
231

232
	if (commit) {
233
		commit->object.flags |= COMPLETE;
234
		commit_list_insert(commit, &complete);
235
	}
236
	return 0;
237
}
238

239
int walker_targets_stdin(char ***target, const char ***write_ref)
240
{
241
	int targets = 0, targets_alloc = 0;
242
	struct strbuf buf = STRBUF_INIT;
243
	*target = NULL; *write_ref = NULL;
244
	while (1) {
245
		char *rf_one = NULL;
246
		char *tg_one;
247

248
		if (strbuf_getline_lf(&buf, stdin) == EOF)
249
			break;
250
		tg_one = buf.buf;
251
		rf_one = strchr(tg_one, '\t');
252
		if (rf_one)
253
			*rf_one++ = 0;
254

255
		if (targets >= targets_alloc) {
256
			targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
257
			REALLOC_ARRAY(*target, targets_alloc);
258
			REALLOC_ARRAY(*write_ref, targets_alloc);
259
		}
260
		(*target)[targets] = xstrdup(tg_one);
261
		(*write_ref)[targets] = xstrdup_or_null(rf_one);
262
		targets++;
263
	}
264
	strbuf_release(&buf);
265
	return targets;
266
}
267

268
void walker_targets_free(int targets, char **target, const char **write_ref)
269
{
270
	while (targets--) {
271
		free(target[targets]);
272
		if (write_ref)
273
			free((char *) write_ref[targets]);
274
	}
275
}
276

277
int walker_fetch(struct walker *walker, int targets, char **target,
278
		 const char **write_ref, const char *write_ref_log_details)
279
{
280
	struct strbuf refname = STRBUF_INIT;
281
	struct strbuf err = STRBUF_INIT;
282
	struct ref_transaction *transaction = NULL;
283
	struct object_id *oids;
284
	char *msg = NULL;
285
	int i, ret = -1;
286

287
	save_commit_buffer = 0;
288

289
	ALLOC_ARRAY(oids, targets);
290

291
	if (write_ref) {
292
		transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
293
							  &err);
294
		if (!transaction) {
295
			error("%s", err.buf);
296
			goto done;
297
		}
298
	}
299

300
	if (!walker->get_recover) {
301
		refs_for_each_ref(get_main_ref_store(the_repository),
302
				  mark_complete, NULL);
303
		commit_list_sort_by_date(&complete);
304
	}
305

306
	for (i = 0; i < targets; i++) {
307
		if (interpret_target(walker, target[i], oids + i)) {
308
			error("Could not interpret response from server '%s' as something to pull", target[i]);
309
			goto done;
310
		}
311
		if (process(walker, lookup_unknown_object(the_repository, &oids[i])))
312
			goto done;
313
	}
314

315
	if (loop(walker))
316
		goto done;
317
	if (!write_ref) {
318
		ret = 0;
319
		goto done;
320
	}
321
	if (write_ref_log_details) {
322
		msg = xstrfmt("fetch from %s", write_ref_log_details);
323
	} else {
324
		msg = NULL;
325
	}
326
	for (i = 0; i < targets; i++) {
327
		if (!write_ref[i])
328
			continue;
329
		strbuf_reset(&refname);
330
		strbuf_addf(&refname, "refs/%s", write_ref[i]);
331
		if (ref_transaction_update(transaction, refname.buf,
332
					   oids + i, NULL, NULL, NULL, 0,
333
					   msg ? msg : "fetch (unknown)",
334
					   &err)) {
335
			error("%s", err.buf);
336
			goto done;
337
		}
338
	}
339
	if (ref_transaction_commit(transaction, &err)) {
340
		error("%s", err.buf);
341
		goto done;
342
	}
343

344
	ret = 0;
345

346
done:
347
	ref_transaction_free(transaction);
348
	free(msg);
349
	free(oids);
350
	strbuf_release(&err);
351
	strbuf_release(&refname);
352
	return ret;
353
}
354

355
void walker_free(struct walker *walker)
356
{
357
	walker->cleanup(walker);
358
	free(walker);
359
}
360

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.