cat-file.c 8.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 */
6
#include "cache.h"
J
Junio C Hamano 已提交
7
#include "exec_cmd.h"
8 9
#include "tag.h"
#include "tree.h"
T
Timo Hirvonen 已提交
10
#include "builtin.h"
11
#include "parse-options.h"
12 13
#include "diff.h"
#include "userdiff.h"
14
#include "streaming.h"
15

16
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
17 18
{
	unsigned char sha1[20];
19
	enum object_type type;
20
	char *buf;
21
	unsigned long size;
22
	struct object_context obj_context;
S
Shawn O. Pearce 已提交
23

24
	if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
S
Shawn O. Pearce 已提交
25
		die("Not a valid object name %s", obj_name);
26 27 28 29

	buf = NULL;
	switch (opt) {
	case 't':
30 31 32
		type = sha1_object_info(sha1, NULL);
		if (type > 0) {
			printf("%s\n", typename(type));
33
			return 0;
34
		}
35 36 37
		break;

	case 's':
38 39
		type = sha1_object_info(sha1, &size);
		if (type > 0) {
40 41 42 43 44 45 46 47
			printf("%lu\n", size);
			return 0;
		}
		break;

	case 'e':
		return !has_sha1_file(sha1);

J
Junio C Hamano 已提交
48
	case 'p':
49 50
		type = sha1_object_info(sha1, NULL);
		if (type < 0)
S
Shawn O. Pearce 已提交
51
			die("Not a valid object name %s", obj_name);
J
Junio C Hamano 已提交
52 53

		/* custom pretty-print here */
S
Shawn O. Pearce 已提交
54
		if (type == OBJ_TREE) {
55 56 57
			const char *ls_args[3] = { NULL };
			ls_args[0] =  "ls-tree";
			ls_args[1] =  obj_name;
S
Shawn O. Pearce 已提交
58 59
			return cmd_ls_tree(2, ls_args, NULL);
		}
J
Junio C Hamano 已提交
60

61 62
		if (type == OBJ_BLOB)
			return stream_blob_to_fd(1, sha1, NULL, 0);
63
		buf = read_sha1_file(sha1, &type, &size);
J
Junio C Hamano 已提交
64
		if (!buf)
S
Shawn O. Pearce 已提交
65
			die("Cannot read object %s", obj_name);
J
Junio C Hamano 已提交
66 67 68

		/* otherwise just spit out the data */
		break;
69 70 71 72 73 74

	case 'c':
		if (!obj_context.path[0])
			die("git cat-file --textconv %s: <object> must be <sha1:path>",
			    obj_name);

75
		if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
76 77 78 79
			die("git cat-file --textconv: unable to run textconv on %s",
			    obj_name);
		break;

80
	case 0:
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
		if (type_from_string(exp_type) == OBJ_BLOB) {
			unsigned char blob_sha1[20];
			if (sha1_object_info(sha1, NULL) == OBJ_TAG) {
				enum object_type type;
				unsigned long size;
				char *buffer = read_sha1_file(sha1, &type, &size);
				if (memcmp(buffer, "object ", 7) ||
				    get_sha1_hex(buffer + 7, blob_sha1))
					die("%s not a valid tag", sha1_to_hex(sha1));
				free(buffer);
			} else
				hashcpy(blob_sha1, sha1);

			if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
				return stream_blob_to_fd(1, blob_sha1, NULL, 0);
			/*
			 * we attempted to dereference a tag to a blob
			 * and failed; there may be new dereference
			 * mechanisms this code is not aware of.
			 * fall-back to the usual case.
			 */
		}
S
Shawn O. Pearce 已提交
103
		buf = read_object_with_reference(sha1, exp_type, &size, NULL);
104 105 106
		break;

	default:
107
		die("git cat-file: unknown option: %s", exp_type);
108 109
	}

110
	if (!buf)
111
		die("git cat-file %s: bad file", obj_name);
112

113
	write_or_die(1, buf, size);
114
	return 0;
115
}
116

J
Jeff King 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
struct expand_data {
	unsigned char sha1[20];
	enum object_type type;
	unsigned long size;

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

	/*
	 * After a mark_query run, this object_info is set up to be
	 * passed to sha1_object_info_extended. It will point to the data
	 * elements above, so you can retrieve the response from there.
	 */
	struct object_info info;
};

static int is_atom(const char *atom, const char *s, int slen)
{
	int alen = strlen(atom);
	return alen == slen && !memcmp(atom, s, alen);
}

static void expand_atom(struct strbuf *sb, const char *atom, int len,
			void *vdata)
{
	struct expand_data *data = vdata;

	if (is_atom("objectname", atom, len)) {
		if (!data->mark_query)
			strbuf_addstr(sb, sha1_to_hex(data->sha1));
	} else if (is_atom("objecttype", atom, len)) {
		if (!data->mark_query)
			strbuf_addstr(sb, typename(data->type));
	} else if (is_atom("objectsize", atom, len)) {
		if (data->mark_query)
			data->info.sizep = &data->size;
		else
			strbuf_addf(sb, "%lu", data->size);
	} else
		die("unknown format element: %.*s", len, atom);
}

static size_t expand_format(struct strbuf *sb, const char *start, void *data)
{
	const char *end;

	if (*start != '(')
		return 0;
	end = strchr(start + 1, ')');
	if (!end)
		die("format element '%s' does not end in ')'", start);

	expand_atom(sb, start + 1, end - start - 1, data);

	return end - start + 1;
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
static void print_object_or_die(int fd, const unsigned char *sha1,
				enum object_type type, unsigned long size)
{
	if (type == OBJ_BLOB) {
		if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0)
			die("unable to stream %s to stdout", sha1_to_hex(sha1));
	}
	else {
		enum object_type rtype;
		unsigned long rsize;
		void *contents;

		contents = read_sha1_file(sha1, &rtype, &rsize);
		if (!contents)
			die("object %s disappeared", sha1_to_hex(sha1));
		if (rtype != type)
			die("object %s changed type!?", sha1_to_hex(sha1));
		if (rsize != size)
			die("object %s change size!?", sha1_to_hex(sha1));

		write_or_die(fd, contents, size);
		free(contents);
	}
}

202 203 204
struct batch_options {
	int enabled;
	int print_contents;
J
Jeff King 已提交
205
	const char *format;
206 207
};

J
Jeff King 已提交
208 209
static int batch_one_object(const char *obj_name, struct batch_options *opt,
			    struct expand_data *data)
210
{
J
Jeff King 已提交
211
	struct strbuf buf = STRBUF_INIT;
212 213 214 215

	if (!obj_name)
	   return 1;

J
Jeff King 已提交
216
	if (get_sha1(obj_name, data->sha1)) {
217
		printf("%s missing\n", obj_name);
218
		fflush(stdout);
219 220 221
		return 0;
	}

J
Jeff King 已提交
222 223
	data->type = sha1_object_info_extended(data->sha1, &data->info);
	if (data->type <= 0) {
224 225 226 227
		printf("%s missing\n", obj_name);
		fflush(stdout);
		return 0;
	}
228

J
Jeff King 已提交
229 230 231 232
	strbuf_expand(&buf, opt->format, expand_format, data);
	strbuf_addch(&buf, '\n');
	write_or_die(1, buf.buf, buf.len);
	strbuf_release(&buf);
A
Adam Roben 已提交
233

234
	if (opt->print_contents) {
J
Jeff King 已提交
235
		print_object_or_die(1, data->sha1, data->type, data->size);
236
		write_or_die(1, "\n", 1);
A
Adam Roben 已提交
237
	}
238 239 240
	return 0;
}

241
static int batch_objects(struct batch_options *opt)
242
{
243
	struct strbuf buf = STRBUF_INIT;
J
Jeff King 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257
	struct expand_data data;

	if (!opt->format)
		opt->format = "%(objectname) %(objecttype) %(objectsize)";

	/*
	 * Expand once with our special mark_query flag, which will prime the
	 * object_info to be handed to sha1_object_info_extended for each
	 * object.
	 */
	memset(&data, 0, sizeof(data));
	data.mark_query = 1;
	strbuf_expand(&buf, opt->format, expand_format, &data);
	data.mark_query = 0;
258 259

	while (strbuf_getline(&buf, stdin, '\n') != EOF) {
J
Jeff King 已提交
260
		int error = batch_one_object(buf.buf, opt, &data);
261 262 263 264 265 266 267
		if (error)
			return error;
	}

	return 0;
}

268
static const char * const cat_file_usage[] = {
269 270
	N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
	N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
271 272
	NULL
};
273

274 275
static int git_cat_file_config(const char *var, const char *value, void *cb)
{
276
	if (userdiff_config(var, value) < 0)
277 278 279 280 281
		return -1;

	return git_default_config(var, value, cb);
}

282 283 284 285 286 287 288 289 290 291 292 293 294
static int batch_option_callback(const struct option *opt,
				 const char *arg,
				 int unset)
{
	struct batch_options *bo = opt->value;

	if (unset) {
		memset(bo, 0, sizeof(*bo));
		return 0;
	}

	bo->enabled = 1;
	bo->print_contents = !strcmp(opt->long_name, "batch");
J
Jeff King 已提交
295
	bo->format = arg;
296 297 298 299

	return 0;
}

300 301
int cmd_cat_file(int argc, const char **argv, const char *prefix)
{
302
	int opt = 0;
303
	const char *exp_type = NULL, *obj_name = NULL;
304
	struct batch_options batch = {0};
305

306
	const struct option options[] = {
307 308 309
		OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
		OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'),
		OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'),
310
		OPT_SET_INT('e', NULL, &opt,
311 312
			    N_("exit with zero when there's no error"), 'e'),
		OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
313
		OPT_SET_INT(0, "textconv", &opt,
314
			    N_("for blob objects, run textconv on object's content"), 'c'),
J
Jeff King 已提交
315
		{ OPTION_CALLBACK, 0, "batch", &batch, "format",
316
			N_("show info and content of objects fed from the standard input"),
J
Jeff King 已提交
317 318
			PARSE_OPT_OPTARG, batch_option_callback },
		{ OPTION_CALLBACK, 0, "batch-check", &batch, "format",
319
			N_("show info about objects fed from the standard input"),
J
Jeff King 已提交
320
			PARSE_OPT_OPTARG, batch_option_callback },
321 322
		OPT_END()
	};
A
Adam Roben 已提交
323

324
	git_config(git_cat_file_config, NULL);
325

326 327
	if (argc != 3 && argc != 2)
		usage_with_options(cat_file_usage, options);
328

329
	argc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);
330

331 332 333 334 335 336
	if (opt) {
		if (argc == 1)
			obj_name = argv[0];
		else
			usage_with_options(cat_file_usage, options);
	}
337
	if (!opt && !batch.enabled) {
338 339 340 341 342 343
		if (argc == 2) {
			exp_type = argv[0];
			obj_name = argv[1];
		} else
			usage_with_options(cat_file_usage, options);
	}
344
	if (batch.enabled && (opt || argc)) {
345
		usage_with_options(cat_file_usage, options);
346 347
	}

348 349
	if (batch.enabled)
		return batch_objects(&batch);
350

351 352
	return cat_one_file(opt, exp_type, obj_name);
}