git

Форк
0
/
cat-file.c 
1091 строка · 28.3 Кб
1
/*
2
 * GIT - The information manager from hell
3
 *
4
 * Copyright (C) Linus Torvalds, 2005
5
 */
6

7
#include "builtin.h"
8
#include "config.h"
9
#include "convert.h"
10
#include "diff.h"
11
#include "environment.h"
12
#include "gettext.h"
13
#include "hex.h"
14
#include "ident.h"
15
#include "parse-options.h"
16
#include "userdiff.h"
17
#include "streaming.h"
18
#include "oid-array.h"
19
#include "packfile.h"
20
#include "object-file.h"
21
#include "object-name.h"
22
#include "object-store-ll.h"
23
#include "replace-object.h"
24
#include "promisor-remote.h"
25
#include "mailmap.h"
26
#include "write-or-die.h"
27

28
enum batch_mode {
29
	BATCH_MODE_CONTENTS,
30
	BATCH_MODE_INFO,
31
	BATCH_MODE_QUEUE_AND_DISPATCH,
32
};
33

34
struct batch_options {
35
	int enabled;
36
	int follow_symlinks;
37
	enum batch_mode batch_mode;
38
	int buffer_output;
39
	int all_objects;
40
	int unordered;
41
	int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
42
	char input_delim;
43
	char output_delim;
44
	const char *format;
45
};
46

47
static const char *force_path;
48

49
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
50
static int use_mailmap;
51

52
static char *replace_idents_using_mailmap(char *, size_t *);
53

54
static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
55
{
56
	struct strbuf sb = STRBUF_INIT;
57
	const char *headers[] = { "author ", "committer ", "tagger ", NULL };
58

59
	strbuf_attach(&sb, object_buf, *size, *size + 1);
60
	apply_mailmap_to_header(&sb, headers, &mailmap);
61
	*size = sb.len;
62
	return strbuf_detach(&sb, NULL);
63
}
64

65
static int filter_object(const char *path, unsigned mode,
66
			 const struct object_id *oid,
67
			 char **buf, unsigned long *size)
68
{
69
	enum object_type type;
70

71
	*buf = repo_read_object_file(the_repository, oid, &type, size);
72
	if (!*buf)
73
		return error(_("cannot read object %s '%s'"),
74
			     oid_to_hex(oid), path);
75
	if ((type == OBJ_BLOB) && S_ISREG(mode)) {
76
		struct strbuf strbuf = STRBUF_INIT;
77
		struct checkout_metadata meta;
78

79
		init_checkout_metadata(&meta, NULL, NULL, oid);
80
		if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) {
81
			free(*buf);
82
			*size = strbuf.len;
83
			*buf = strbuf_detach(&strbuf, NULL);
84
		}
85
	}
86

87
	return 0;
88
}
89

90
static int stream_blob(const struct object_id *oid)
91
{
92
	if (stream_blob_to_fd(1, oid, NULL, 0))
93
		die("unable to stream %s to stdout", oid_to_hex(oid));
94
	return 0;
95
}
96

97
static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
98
			int unknown_type)
99
{
100
	int ret;
101
	struct object_id oid;
102
	enum object_type type;
103
	char *buf;
104
	unsigned long size;
105
	struct object_context obj_context = {0};
106
	struct object_info oi = OBJECT_INFO_INIT;
107
	struct strbuf sb = STRBUF_INIT;
108
	unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
109
	unsigned get_oid_flags =
110
		GET_OID_RECORD_PATH |
111
		GET_OID_ONLY_TO_DIE |
112
		GET_OID_HASH_ANY;
113
	const char *path = force_path;
114
	const int opt_cw = (opt == 'c' || opt == 'w');
115
	if (!path && opt_cw)
116
		get_oid_flags |= GET_OID_REQUIRE_PATH;
117

118
	if (unknown_type)
119
		flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
120

121
	if (get_oid_with_context(the_repository, obj_name, get_oid_flags, &oid,
122
				 &obj_context))
123
		die("Not a valid object name %s", obj_name);
124

125
	if (!path)
126
		path = obj_context.path;
127
	if (obj_context.mode == S_IFINVALID)
128
		obj_context.mode = 0100644;
129

130
	buf = NULL;
131
	switch (opt) {
132
	case 't':
133
		oi.type_name = &sb;
134
		if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
135
			die("git cat-file: could not get object info");
136
		if (sb.len) {
137
			printf("%s\n", sb.buf);
138
			strbuf_release(&sb);
139
			ret = 0;
140
			goto cleanup;
141
		}
142
		break;
143

144
	case 's':
145
		oi.sizep = &size;
146

147
		if (use_mailmap) {
148
			oi.typep = &type;
149
			oi.contentp = (void**)&buf;
150
		}
151

152
		if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
153
			die("git cat-file: could not get object info");
154

155
		if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
156
			size_t s = size;
157
			buf = replace_idents_using_mailmap(buf, &s);
158
			size = cast_size_t_to_ulong(s);
159
		}
160

161
		printf("%"PRIuMAX"\n", (uintmax_t)size);
162
		ret = 0;
163
		goto cleanup;
164

165
	case 'e':
166
		ret = !repo_has_object_file(the_repository, &oid);
167
		goto cleanup;
168

169
	case 'w':
170

171
		if (filter_object(path, obj_context.mode,
172
				  &oid, &buf, &size)) {
173
			ret = -1;
174
			goto cleanup;
175
		}
176
		break;
177

178
	case 'c':
179
		if (textconv_object(the_repository, path, obj_context.mode,
180
				    &oid, 1, &buf, &size))
181
			break;
182
		/* else fallthrough */
183

184
	case 'p':
185
		type = oid_object_info(the_repository, &oid, NULL);
186
		if (type < 0)
187
			die("Not a valid object name %s", obj_name);
188

189
		/* custom pretty-print here */
190
		if (type == OBJ_TREE) {
191
			const char *ls_args[3] = { NULL };
192
			ls_args[0] =  "ls-tree";
193
			ls_args[1] =  obj_name;
194
			ret = cmd_ls_tree(2, ls_args, NULL);
195
			goto cleanup;
196
		}
197

198
		if (type == OBJ_BLOB) {
199
			ret = stream_blob(&oid);
200
			goto cleanup;
201
		}
202
		buf = repo_read_object_file(the_repository, &oid, &type,
203
					    &size);
204
		if (!buf)
205
			die("Cannot read object %s", obj_name);
206

207
		if (use_mailmap) {
208
			size_t s = size;
209
			buf = replace_idents_using_mailmap(buf, &s);
210
			size = cast_size_t_to_ulong(s);
211
		}
212

213
		/* otherwise just spit out the data */
214
		break;
215

216
	case 0:
217
	{
218
		enum object_type exp_type_id = type_from_string(exp_type);
219

220
		if (exp_type_id == OBJ_BLOB) {
221
			struct object_id blob_oid;
222
			if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
223
				char *buffer = repo_read_object_file(the_repository,
224
								     &oid,
225
								     &type,
226
								     &size);
227
				const char *target;
228

229
				if (!buffer)
230
					die(_("unable to read %s"), oid_to_hex(&oid));
231

232
				if (!skip_prefix(buffer, "object ", &target) ||
233
				    get_oid_hex_algop(target, &blob_oid,
234
						      &hash_algos[oid.algo]))
235
					die("%s not a valid tag", oid_to_hex(&oid));
236
				free(buffer);
237
			} else
238
				oidcpy(&blob_oid, &oid);
239

240
			if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) {
241
				ret = stream_blob(&blob_oid);
242
				goto cleanup;
243
			}
244
			/*
245
			 * we attempted to dereference a tag to a blob
246
			 * and failed; there may be new dereference
247
			 * mechanisms this code is not aware of.
248
			 * fall-back to the usual case.
249
			 */
250
		}
251
		buf = read_object_with_reference(the_repository, &oid,
252
						 exp_type_id, &size, NULL);
253

254
		if (use_mailmap) {
255
			size_t s = size;
256
			buf = replace_idents_using_mailmap(buf, &s);
257
			size = cast_size_t_to_ulong(s);
258
		}
259
		break;
260
	}
261
	default:
262
		die("git cat-file: unknown option: %s", exp_type);
263
	}
264

265
	if (!buf)
266
		die("git cat-file %s: bad file", obj_name);
267

268
	write_or_die(1, buf, size);
269
	ret = 0;
270
cleanup:
271
	free(buf);
272
	object_context_release(&obj_context);
273
	return ret;
274
}
275

276
struct expand_data {
277
	struct object_id oid;
278
	enum object_type type;
279
	unsigned long size;
280
	off_t disk_size;
281
	const char *rest;
282
	struct object_id delta_base_oid;
283

284
	/*
285
	 * If mark_query is true, we do not expand anything, but rather
286
	 * just mark the object_info with items we wish to query.
287
	 */
288
	int mark_query;
289

290
	/*
291
	 * Whether to split the input on whitespace before feeding it to
292
	 * get_sha1; this is decided during the mark_query phase based on
293
	 * whether we have a %(rest) token in our format.
294
	 */
295
	int split_on_whitespace;
296

297
	/*
298
	 * After a mark_query run, this object_info is set up to be
299
	 * passed to oid_object_info_extended. It will point to the data
300
	 * elements above, so you can retrieve the response from there.
301
	 */
302
	struct object_info info;
303

304
	/*
305
	 * This flag will be true if the requested batch format and options
306
	 * don't require us to call oid_object_info, which can then be
307
	 * optimized out.
308
	 */
309
	unsigned skip_object_info : 1;
310
};
311

312
static int is_atom(const char *atom, const char *s, int slen)
313
{
314
	int alen = strlen(atom);
315
	return alen == slen && !memcmp(atom, s, alen);
316
}
317

318
static int expand_atom(struct strbuf *sb, const char *atom, int len,
319
		       struct expand_data *data)
320
{
321
	if (is_atom("objectname", atom, len)) {
322
		if (!data->mark_query)
323
			strbuf_addstr(sb, oid_to_hex(&data->oid));
324
	} else if (is_atom("objecttype", atom, len)) {
325
		if (data->mark_query)
326
			data->info.typep = &data->type;
327
		else
328
			strbuf_addstr(sb, type_name(data->type));
329
	} else if (is_atom("objectsize", atom, len)) {
330
		if (data->mark_query)
331
			data->info.sizep = &data->size;
332
		else
333
			strbuf_addf(sb, "%"PRIuMAX , (uintmax_t)data->size);
334
	} else if (is_atom("objectsize:disk", atom, len)) {
335
		if (data->mark_query)
336
			data->info.disk_sizep = &data->disk_size;
337
		else
338
			strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
339
	} else if (is_atom("rest", atom, len)) {
340
		if (data->mark_query)
341
			data->split_on_whitespace = 1;
342
		else if (data->rest)
343
			strbuf_addstr(sb, data->rest);
344
	} else if (is_atom("deltabase", atom, len)) {
345
		if (data->mark_query)
346
			data->info.delta_base_oid = &data->delta_base_oid;
347
		else
348
			strbuf_addstr(sb,
349
				      oid_to_hex(&data->delta_base_oid));
350
	} else
351
		return 0;
352
	return 1;
353
}
354

355
static void expand_format(struct strbuf *sb, const char *start,
356
			  struct expand_data *data)
357
{
358
	while (strbuf_expand_step(sb, &start)) {
359
		const char *end;
360

361
		if (skip_prefix(start, "%", &start) || *start != '(')
362
			strbuf_addch(sb, '%');
363
		else if ((end = strchr(start + 1, ')')) &&
364
			 expand_atom(sb, start + 1, end - start - 1, data))
365
			start = end + 1;
366
		else
367
			strbuf_expand_bad_format(start, "cat-file");
368
	}
369
}
370

371
static void batch_write(struct batch_options *opt, const void *data, int len)
372
{
373
	if (opt->buffer_output) {
374
		if (fwrite(data, 1, len, stdout) != len)
375
			die_errno("unable to write to stdout");
376
	} else
377
		write_or_die(1, data, len);
378
}
379

380
static void print_object_or_die(struct batch_options *opt, struct expand_data *data)
381
{
382
	const struct object_id *oid = &data->oid;
383

384
	assert(data->info.typep);
385

386
	if (data->type == OBJ_BLOB) {
387
		if (opt->buffer_output)
388
			fflush(stdout);
389
		if (opt->transform_mode) {
390
			char *contents;
391
			unsigned long size;
392

393
			if (!data->rest)
394
				die("missing path for '%s'", oid_to_hex(oid));
395

396
			if (opt->transform_mode == 'w') {
397
				if (filter_object(data->rest, 0100644, oid,
398
						  &contents, &size))
399
					die("could not convert '%s' %s",
400
					    oid_to_hex(oid), data->rest);
401
			} else if (opt->transform_mode == 'c') {
402
				enum object_type type;
403
				if (!textconv_object(the_repository,
404
						     data->rest, 0100644, oid,
405
						     1, &contents, &size))
406
					contents = repo_read_object_file(the_repository,
407
									 oid,
408
									 &type,
409
									 &size);
410
				if (!contents)
411
					die("could not convert '%s' %s",
412
					    oid_to_hex(oid), data->rest);
413
			} else
414
				BUG("invalid transform_mode: %c", opt->transform_mode);
415
			batch_write(opt, contents, size);
416
			free(contents);
417
		} else {
418
			stream_blob(oid);
419
		}
420
	}
421
	else {
422
		enum object_type type;
423
		unsigned long size;
424
		void *contents;
425

426
		contents = repo_read_object_file(the_repository, oid, &type,
427
						 &size);
428
		if (!contents)
429
			die("object %s disappeared", oid_to_hex(oid));
430

431
		if (use_mailmap) {
432
			size_t s = size;
433
			contents = replace_idents_using_mailmap(contents, &s);
434
			size = cast_size_t_to_ulong(s);
435
		}
436

437
		if (type != data->type)
438
			die("object %s changed type!?", oid_to_hex(oid));
439
		if (data->info.sizep && size != data->size && !use_mailmap)
440
			die("object %s changed size!?", oid_to_hex(oid));
441

442
		batch_write(opt, contents, size);
443
		free(contents);
444
	}
445
}
446

447
static void print_default_format(struct strbuf *scratch, struct expand_data *data,
448
				 struct batch_options *opt)
449
{
450
	strbuf_addf(scratch, "%s %s %"PRIuMAX"%c", oid_to_hex(&data->oid),
451
		    type_name(data->type),
452
		    (uintmax_t)data->size, opt->output_delim);
453
}
454

455
/*
456
 * If "pack" is non-NULL, then "offset" is the byte offset within the pack from
457
 * which the object may be accessed (though note that we may also rely on
458
 * data->oid, too). If "pack" is NULL, then offset is ignored.
459
 */
460
static void batch_object_write(const char *obj_name,
461
			       struct strbuf *scratch,
462
			       struct batch_options *opt,
463
			       struct expand_data *data,
464
			       struct packed_git *pack,
465
			       off_t offset)
466
{
467
	if (!data->skip_object_info) {
468
		int ret;
469

470
		if (use_mailmap)
471
			data->info.typep = &data->type;
472

473
		if (pack)
474
			ret = packed_object_info(the_repository, pack, offset,
475
						 &data->info);
476
		else
477
			ret = oid_object_info_extended(the_repository,
478
						       &data->oid, &data->info,
479
						       OBJECT_INFO_LOOKUP_REPLACE);
480
		if (ret < 0) {
481
			printf("%s missing%c",
482
			       obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim);
483
			fflush(stdout);
484
			return;
485
		}
486

487
		if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
488
			size_t s = data->size;
489
			char *buf = NULL;
490

491
			buf = repo_read_object_file(the_repository, &data->oid, &data->type,
492
						    &data->size);
493
			if (!buf)
494
				die(_("unable to read %s"), oid_to_hex(&data->oid));
495
			buf = replace_idents_using_mailmap(buf, &s);
496
			data->size = cast_size_t_to_ulong(s);
497

498
			free(buf);
499
		}
500
	}
501

502
	strbuf_reset(scratch);
503

504
	if (!opt->format) {
505
		print_default_format(scratch, data, opt);
506
	} else {
507
		expand_format(scratch, opt->format, data);
508
		strbuf_addch(scratch, opt->output_delim);
509
	}
510

511
	batch_write(opt, scratch->buf, scratch->len);
512

513
	if (opt->batch_mode == BATCH_MODE_CONTENTS) {
514
		print_object_or_die(opt, data);
515
		batch_write(opt, &opt->output_delim, 1);
516
	}
517
}
518

519
static void batch_one_object(const char *obj_name,
520
			     struct strbuf *scratch,
521
			     struct batch_options *opt,
522
			     struct expand_data *data)
523
{
524
	struct object_context ctx = {0};
525
	int flags =
526
		GET_OID_HASH_ANY |
527
		(opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0);
528
	enum get_oid_result result;
529

530
	result = get_oid_with_context(the_repository, obj_name,
531
				      flags, &data->oid, &ctx);
532
	if (result != FOUND) {
533
		switch (result) {
534
		case MISSING_OBJECT:
535
			printf("%s missing%c", obj_name, opt->output_delim);
536
			break;
537
		case SHORT_NAME_AMBIGUOUS:
538
			printf("%s ambiguous%c", obj_name, opt->output_delim);
539
			break;
540
		case DANGLING_SYMLINK:
541
			printf("dangling %"PRIuMAX"%c%s%c",
542
			       (uintmax_t)strlen(obj_name),
543
			       opt->output_delim, obj_name, opt->output_delim);
544
			break;
545
		case SYMLINK_LOOP:
546
			printf("loop %"PRIuMAX"%c%s%c",
547
			       (uintmax_t)strlen(obj_name),
548
			       opt->output_delim, obj_name, opt->output_delim);
549
			break;
550
		case NOT_DIR:
551
			printf("notdir %"PRIuMAX"%c%s%c",
552
			       (uintmax_t)strlen(obj_name),
553
			       opt->output_delim, obj_name, opt->output_delim);
554
			break;
555
		default:
556
			BUG("unknown get_sha1_with_context result %d\n",
557
			       result);
558
			break;
559
		}
560
		fflush(stdout);
561

562
		goto out;
563
	}
564

565
	if (ctx.mode == 0) {
566
		printf("symlink %"PRIuMAX"%c%s%c",
567
		       (uintmax_t)ctx.symlink_path.len,
568
		       opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
569
		fflush(stdout);
570
		goto out;
571
	}
572

573
	batch_object_write(obj_name, scratch, opt, data, NULL, 0);
574

575
out:
576
	object_context_release(&ctx);
577
}
578

579
struct object_cb_data {
580
	struct batch_options *opt;
581
	struct expand_data *expand;
582
	struct oidset *seen;
583
	struct strbuf *scratch;
584
};
585

586
static int batch_object_cb(const struct object_id *oid, void *vdata)
587
{
588
	struct object_cb_data *data = vdata;
589
	oidcpy(&data->expand->oid, oid);
590
	batch_object_write(NULL, data->scratch, data->opt, data->expand,
591
			   NULL, 0);
592
	return 0;
593
}
594

595
static int collect_loose_object(const struct object_id *oid,
596
				const char *path UNUSED,
597
				void *data)
598
{
599
	oid_array_append(data, oid);
600
	return 0;
601
}
602

603
static int collect_packed_object(const struct object_id *oid,
604
				 struct packed_git *pack UNUSED,
605
				 uint32_t pos UNUSED,
606
				 void *data)
607
{
608
	oid_array_append(data, oid);
609
	return 0;
610
}
611

612
static int batch_unordered_object(const struct object_id *oid,
613
				  struct packed_git *pack, off_t offset,
614
				  void *vdata)
615
{
616
	struct object_cb_data *data = vdata;
617

618
	if (oidset_insert(data->seen, oid))
619
		return 0;
620

621
	oidcpy(&data->expand->oid, oid);
622
	batch_object_write(NULL, data->scratch, data->opt, data->expand,
623
			   pack, offset);
624
	return 0;
625
}
626

627
static int batch_unordered_loose(const struct object_id *oid,
628
				 const char *path UNUSED,
629
				 void *data)
630
{
631
	return batch_unordered_object(oid, NULL, 0, data);
632
}
633

634
static int batch_unordered_packed(const struct object_id *oid,
635
				  struct packed_git *pack,
636
				  uint32_t pos,
637
				  void *data)
638
{
639
	return batch_unordered_object(oid, pack,
640
				      nth_packed_object_offset(pack, pos),
641
				      data);
642
}
643

644
typedef void (*parse_cmd_fn_t)(struct batch_options *, const char *,
645
			       struct strbuf *, struct expand_data *);
646

647
struct queued_cmd {
648
	parse_cmd_fn_t fn;
649
	char *line;
650
};
651

652
static void parse_cmd_contents(struct batch_options *opt,
653
			     const char *line,
654
			     struct strbuf *output,
655
			     struct expand_data *data)
656
{
657
	opt->batch_mode = BATCH_MODE_CONTENTS;
658
	batch_one_object(line, output, opt, data);
659
}
660

661
static void parse_cmd_info(struct batch_options *opt,
662
			   const char *line,
663
			   struct strbuf *output,
664
			   struct expand_data *data)
665
{
666
	opt->batch_mode = BATCH_MODE_INFO;
667
	batch_one_object(line, output, opt, data);
668
}
669

670
static void dispatch_calls(struct batch_options *opt,
671
		struct strbuf *output,
672
		struct expand_data *data,
673
		struct queued_cmd *cmd,
674
		int nr)
675
{
676
	int i;
677

678
	if (!opt->buffer_output)
679
		die(_("flush is only for --buffer mode"));
680

681
	for (i = 0; i < nr; i++)
682
		cmd[i].fn(opt, cmd[i].line, output, data);
683

684
	fflush(stdout);
685
}
686

687
static void free_cmds(struct queued_cmd *cmd, size_t *nr)
688
{
689
	size_t i;
690

691
	for (i = 0; i < *nr; i++)
692
		FREE_AND_NULL(cmd[i].line);
693

694
	*nr = 0;
695
}
696

697

698
static const struct parse_cmd {
699
	const char *name;
700
	parse_cmd_fn_t fn;
701
	unsigned takes_args;
702
} commands[] = {
703
	{ "contents", parse_cmd_contents, 1},
704
	{ "info", parse_cmd_info, 1},
705
	{ "flush", NULL, 0},
706
};
707

708
static void batch_objects_command(struct batch_options *opt,
709
				    struct strbuf *output,
710
				    struct expand_data *data)
711
{
712
	struct strbuf input = STRBUF_INIT;
713
	struct queued_cmd *queued_cmd = NULL;
714
	size_t alloc = 0, nr = 0;
715

716
	while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
717
		int i;
718
		const struct parse_cmd *cmd = NULL;
719
		const char *p = NULL, *cmd_end;
720
		struct queued_cmd call = {0};
721

722
		if (!input.len)
723
			die(_("empty command in input"));
724
		if (isspace(*input.buf))
725
			die(_("whitespace before command: '%s'"), input.buf);
726

727
		for (i = 0; i < ARRAY_SIZE(commands); i++) {
728
			if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
729
				continue;
730

731
			cmd = &commands[i];
732
			if (cmd->takes_args) {
733
				if (*cmd_end != ' ')
734
					die(_("%s requires arguments"),
735
					    commands[i].name);
736

737
				p = cmd_end + 1;
738
			} else if (*cmd_end) {
739
				die(_("%s takes no arguments"),
740
				    commands[i].name);
741
			}
742

743
			break;
744
		}
745

746
		if (!cmd)
747
			die(_("unknown command: '%s'"), input.buf);
748

749
		if (!strcmp(cmd->name, "flush")) {
750
			dispatch_calls(opt, output, data, queued_cmd, nr);
751
			free_cmds(queued_cmd, &nr);
752
		} else if (!opt->buffer_output) {
753
			cmd->fn(opt, p, output, data);
754
		} else {
755
			ALLOC_GROW(queued_cmd, nr + 1, alloc);
756
			call.fn = cmd->fn;
757
			call.line = xstrdup_or_null(p);
758
			queued_cmd[nr++] = call;
759
		}
760
	}
761

762
	if (opt->buffer_output &&
763
	    nr &&
764
	    !git_env_bool("GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT", 0)) {
765
		dispatch_calls(opt, output, data, queued_cmd, nr);
766
		free_cmds(queued_cmd, &nr);
767
	}
768

769
	free_cmds(queued_cmd, &nr);
770
	free(queued_cmd);
771
	strbuf_release(&input);
772
}
773

774
#define DEFAULT_FORMAT "%(objectname) %(objecttype) %(objectsize)"
775

776
static int batch_objects(struct batch_options *opt)
777
{
778
	struct strbuf input = STRBUF_INIT;
779
	struct strbuf output = STRBUF_INIT;
780
	struct expand_data data;
781
	int save_warning;
782
	int retval = 0;
783

784
	/*
785
	 * Expand once with our special mark_query flag, which will prime the
786
	 * object_info to be handed to oid_object_info_extended for each
787
	 * object.
788
	 */
789
	memset(&data, 0, sizeof(data));
790
	data.mark_query = 1;
791
	expand_format(&output,
792
		      opt->format ? opt->format : DEFAULT_FORMAT,
793
		      &data);
794
	data.mark_query = 0;
795
	strbuf_release(&output);
796
	if (opt->transform_mode)
797
		data.split_on_whitespace = 1;
798

799
	if (opt->format && !strcmp(opt->format, DEFAULT_FORMAT))
800
		opt->format = NULL;
801
	/*
802
	 * If we are printing out the object, then always fill in the type,
803
	 * since we will want to decide whether or not to stream.
804
	 */
805
	if (opt->batch_mode == BATCH_MODE_CONTENTS)
806
		data.info.typep = &data.type;
807

808
	if (opt->all_objects) {
809
		struct object_cb_data cb;
810
		struct object_info empty = OBJECT_INFO_INIT;
811

812
		if (!memcmp(&data.info, &empty, sizeof(empty)))
813
			data.skip_object_info = 1;
814

815
		if (repo_has_promisor_remote(the_repository))
816
			warning("This repository uses promisor remotes. Some objects may not be loaded.");
817

818
		disable_replace_refs();
819

820
		cb.opt = opt;
821
		cb.expand = &data;
822
		cb.scratch = &output;
823

824
		if (opt->unordered) {
825
			struct oidset seen = OIDSET_INIT;
826

827
			cb.seen = &seen;
828

829
			for_each_loose_object(batch_unordered_loose, &cb, 0);
830
			for_each_packed_object(batch_unordered_packed, &cb,
831
					       FOR_EACH_OBJECT_PACK_ORDER);
832

833
			oidset_clear(&seen);
834
		} else {
835
			struct oid_array sa = OID_ARRAY_INIT;
836

837
			for_each_loose_object(collect_loose_object, &sa, 0);
838
			for_each_packed_object(collect_packed_object, &sa, 0);
839

840
			oid_array_for_each_unique(&sa, batch_object_cb, &cb);
841

842
			oid_array_clear(&sa);
843
		}
844

845
		strbuf_release(&output);
846
		return 0;
847
	}
848

849
	/*
850
	 * We are going to call get_sha1 on a potentially very large number of
851
	 * objects. In most large cases, these will be actual object sha1s. The
852
	 * cost to double-check that each one is not also a ref (just so we can
853
	 * warn) ends up dwarfing the actual cost of the object lookups
854
	 * themselves. We can work around it by just turning off the warning.
855
	 */
856
	save_warning = warn_on_object_refname_ambiguity;
857
	warn_on_object_refname_ambiguity = 0;
858

859
	if (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {
860
		batch_objects_command(opt, &output, &data);
861
		goto cleanup;
862
	}
863

864
	while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
865
		if (data.split_on_whitespace) {
866
			/*
867
			 * Split at first whitespace, tying off the beginning
868
			 * of the string and saving the remainder (or NULL) in
869
			 * data.rest.
870
			 */
871
			char *p = strpbrk(input.buf, " \t");
872
			if (p) {
873
				while (*p && strchr(" \t", *p))
874
					*p++ = '\0';
875
			}
876
			data.rest = p;
877
		}
878

879
		batch_one_object(input.buf, &output, opt, &data);
880
	}
881

882
 cleanup:
883
	strbuf_release(&input);
884
	strbuf_release(&output);
885
	warn_on_object_refname_ambiguity = save_warning;
886
	return retval;
887
}
888

889
static int git_cat_file_config(const char *var, const char *value,
890
			       const struct config_context *ctx, void *cb)
891
{
892
	if (userdiff_config(var, value) < 0)
893
		return -1;
894

895
	return git_default_config(var, value, ctx, cb);
896
}
897

898
static int batch_option_callback(const struct option *opt,
899
				 const char *arg,
900
				 int unset)
901
{
902
	struct batch_options *bo = opt->value;
903

904
	BUG_ON_OPT_NEG(unset);
905

906
	if (bo->enabled) {
907
		return error(_("only one batch option may be specified"));
908
	}
909

910
	bo->enabled = 1;
911

912
	if (!strcmp(opt->long_name, "batch"))
913
		bo->batch_mode = BATCH_MODE_CONTENTS;
914
	else if (!strcmp(opt->long_name, "batch-check"))
915
		bo->batch_mode = BATCH_MODE_INFO;
916
	else if (!strcmp(opt->long_name, "batch-command"))
917
		bo->batch_mode = BATCH_MODE_QUEUE_AND_DISPATCH;
918
	else
919
		BUG("%s given to batch-option-callback", opt->long_name);
920

921
	bo->format = arg;
922

923
	return 0;
924
}
925

926
int cmd_cat_file(int argc, const char **argv, const char *prefix)
927
{
928
	int opt = 0;
929
	int opt_cw = 0;
930
	int opt_epts = 0;
931
	const char *exp_type = NULL, *obj_name = NULL;
932
	struct batch_options batch = {0};
933
	int unknown_type = 0;
934
	int input_nul_terminated = 0;
935
	int nul_terminated = 0;
936

937
	const char * const usage[] = {
938
		N_("git cat-file <type> <object>"),
939
		N_("git cat-file (-e | -p) <object>"),
940
		N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
941
		N_("git cat-file (--textconv | --filters)\n"
942
		   "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
943
		N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
944
		   "             [--buffer] [--follow-symlinks] [--unordered]\n"
945
		   "             [--textconv | --filters] [-Z]"),
946
		NULL
947
	};
948
	const struct option options[] = {
949
		/* Simple queries */
950
		OPT_GROUP(N_("Check object existence or emit object contents")),
951
		OPT_CMDMODE('e', NULL, &opt,
952
			    N_("check if <object> exists"), 'e'),
953
		OPT_CMDMODE('p', NULL, &opt, N_("pretty-print <object> content"), 'p'),
954

955
		OPT_GROUP(N_("Emit [broken] object attributes")),
956
		OPT_CMDMODE('t', NULL, &opt, N_("show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"), 't'),
957
		OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
958
		OPT_BOOL(0, "allow-unknown-type", &unknown_type,
959
			  N_("allow -s and -t to work with broken/corrupt objects")),
960
		OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")),
961
		OPT_ALIAS(0, "mailmap", "use-mailmap"),
962
		/* Batch mode */
963
		OPT_GROUP(N_("Batch objects requested on stdin (or --batch-all-objects)")),
964
		OPT_CALLBACK_F(0, "batch", &batch, N_("format"),
965
			N_("show full <object> or <rev> contents"),
966
			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
967
			batch_option_callback),
968
		OPT_CALLBACK_F(0, "batch-check", &batch, N_("format"),
969
			N_("like --batch, but don't emit <contents>"),
970
			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
971
			batch_option_callback),
972
		OPT_BOOL_F('z', NULL, &input_nul_terminated, N_("stdin is NUL-terminated"),
973
			PARSE_OPT_HIDDEN),
974
		OPT_BOOL('Z', NULL, &nul_terminated, N_("stdin and stdout is NUL-terminated")),
975
		OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
976
			N_("read commands from stdin"),
977
			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
978
			batch_option_callback),
979
		OPT_CMDMODE(0, "batch-all-objects", &opt,
980
			    N_("with --batch[-check]: ignores stdin, batches all known objects"), 'b'),
981
		/* Batch-specific options */
982
		OPT_GROUP(N_("Change or optimize batch output")),
983
		OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
984
		OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
985
			 N_("follow in-tree symlinks")),
986
		OPT_BOOL(0, "unordered", &batch.unordered,
987
			 N_("do not order objects before emitting them")),
988
		/* Textconv options, stand-ole*/
989
		OPT_GROUP(N_("Emit object (blob or tree) with conversion or filter (stand-alone, or with batch)")),
990
		OPT_CMDMODE(0, "textconv", &opt,
991
			    N_("run textconv on object's content"), 'c'),
992
		OPT_CMDMODE(0, "filters", &opt,
993
			    N_("run filters on object's content"), 'w'),
994
		OPT_STRING(0, "path", &force_path, N_("blob|tree"),
995
			   N_("use a <path> for (--textconv | --filters); Not with 'batch'")),
996
		OPT_END()
997
	};
998

999
	git_config(git_cat_file_config, NULL);
1000

1001
	batch.buffer_output = -1;
1002

1003
	argc = parse_options(argc, argv, prefix, options, usage, 0);
1004
	opt_cw = (opt == 'c' || opt == 'w');
1005
	opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
1006

1007
	if (use_mailmap)
1008
		read_mailmap(&mailmap);
1009

1010
	/* --batch-all-objects? */
1011
	if (opt == 'b')
1012
		batch.all_objects = 1;
1013

1014
	/* Option compatibility */
1015
	if (force_path && !opt_cw)
1016
		usage_msg_optf(_("'%s=<%s>' needs '%s' or '%s'"),
1017
			       usage, options,
1018
			       "--path", _("path|tree-ish"), "--filters",
1019
			       "--textconv");
1020

1021
	/* Option compatibility with batch mode */
1022
	if (batch.enabled)
1023
		;
1024
	else if (batch.follow_symlinks)
1025
		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
1026
			       "--follow-symlinks");
1027
	else if (batch.buffer_output >= 0)
1028
		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
1029
			       "--buffer");
1030
	else if (batch.all_objects)
1031
		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
1032
			       "--batch-all-objects");
1033
	else if (input_nul_terminated)
1034
		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
1035
			       "-z");
1036
	else if (nul_terminated)
1037
		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
1038
			       "-Z");
1039

1040
	batch.input_delim = batch.output_delim = '\n';
1041
	if (input_nul_terminated)
1042
		batch.input_delim = '\0';
1043
	if (nul_terminated)
1044
		batch.input_delim = batch.output_delim = '\0';
1045

1046
	/* Batch defaults */
1047
	if (batch.buffer_output < 0)
1048
		batch.buffer_output = batch.all_objects;
1049

1050
	/* Return early if we're in batch mode? */
1051
	if (batch.enabled) {
1052
		if (opt_cw)
1053
			batch.transform_mode = opt;
1054
		else if (opt && opt != 'b')
1055
			usage_msg_optf(_("'-%c' is incompatible with batch mode"),
1056
				       usage, options, opt);
1057
		else if (argc)
1058
			usage_msg_opt(_("batch modes take no arguments"), usage,
1059
				      options);
1060

1061
		return batch_objects(&batch);
1062
	}
1063

1064
	if (opt) {
1065
		if (!argc && opt == 'c')
1066
			usage_msg_optf(_("<rev> required with '%s'"),
1067
				       usage, options, "--textconv");
1068
		else if (!argc && opt == 'w')
1069
			usage_msg_optf(_("<rev> required with '%s'"),
1070
				       usage, options, "--filters");
1071
		else if (!argc && opt_epts)
1072
			usage_msg_optf(_("<object> required with '-%c'"),
1073
				       usage, options, opt);
1074
		else if (argc == 1)
1075
			obj_name = argv[0];
1076
		else
1077
			usage_msg_opt(_("too many arguments"), usage, options);
1078
	} else if (!argc) {
1079
		usage_with_options(usage, options);
1080
	} else if (argc != 2) {
1081
		usage_msg_optf(_("only two arguments allowed in <type> <object> mode, not %d"),
1082
			      usage, options, argc);
1083
	} else if (argc) {
1084
		exp_type = argv[0];
1085
		obj_name = argv[1];
1086
	}
1087

1088
	if (unknown_type && opt != 't' && opt != 's')
1089
		die("git cat-file --allow-unknown-type: use with -s or -t");
1090
	return cat_one_file(opt, exp_type, obj_name, unknown_type);
1091
}
1092

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

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

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

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