2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
8 #include "parse-options.h"
10 #include "streaming.h"
11 #include "tree-walk.h"
13 struct batch_options
{
20 static int cat_one_file(int opt
, const char *exp_type
, const char *obj_name
,
23 unsigned char sha1
[20];
24 enum object_type type
;
27 struct object_context obj_context
;
28 struct object_info oi
= {NULL
};
29 struct strbuf sb
= STRBUF_INIT
;
30 unsigned flags
= LOOKUP_REPLACE_OBJECT
;
33 flags
|= LOOKUP_UNKNOWN_OBJECT
;
35 if (get_sha1_with_context(obj_name
, 0, sha1
, &obj_context
))
36 die("Not a valid object name %s", obj_name
);
42 if (sha1_object_info_extended(sha1
, &oi
, flags
) < 0)
43 die("git cat-file: could not get object info");
45 printf("%s\n", sb
.buf
);
53 if (sha1_object_info_extended(sha1
, &oi
, flags
) < 0)
54 die("git cat-file: could not get object info");
55 printf("%lu\n", size
);
59 return !has_sha1_file(sha1
);
62 if (!obj_context
.path
[0])
63 die("git cat-file --textconv %s: <object> must be <sha1:path>",
66 if (textconv_object(obj_context
.path
, obj_context
.mode
, sha1
, 1, &buf
, &size
))
70 type
= sha1_object_info(sha1
, NULL
);
72 die("Not a valid object name %s", obj_name
);
74 /* custom pretty-print here */
75 if (type
== OBJ_TREE
) {
76 const char *ls_args
[3] = { NULL
};
77 ls_args
[0] = "ls-tree";
78 ls_args
[1] = obj_name
;
79 return cmd_ls_tree(2, ls_args
, NULL
);
83 return stream_blob_to_fd(1, sha1
, NULL
, 0);
84 buf
= read_sha1_file(sha1
, &type
, &size
);
86 die("Cannot read object %s", obj_name
);
88 /* otherwise just spit out the data */
92 if (type_from_string(exp_type
) == OBJ_BLOB
) {
93 unsigned char blob_sha1
[20];
94 if (sha1_object_info(sha1
, NULL
) == OBJ_TAG
) {
95 char *buffer
= read_sha1_file(sha1
, &type
, &size
);
97 if (!skip_prefix(buffer
, "object ", &target
) ||
98 get_sha1_hex(target
, blob_sha1
))
99 die("%s not a valid tag", sha1_to_hex(sha1
));
102 hashcpy(blob_sha1
, sha1
);
104 if (sha1_object_info(blob_sha1
, NULL
) == OBJ_BLOB
)
105 return stream_blob_to_fd(1, blob_sha1
, NULL
, 0);
107 * we attempted to dereference a tag to a blob
108 * and failed; there may be new dereference
109 * mechanisms this code is not aware of.
110 * fall-back to the usual case.
113 buf
= read_object_with_reference(sha1
, exp_type
, &size
, NULL
);
117 die("git cat-file: unknown option: %s", exp_type
);
121 die("git cat-file %s: bad file", obj_name
);
123 write_or_die(1, buf
, size
);
128 unsigned char sha1
[20];
129 enum object_type type
;
131 unsigned long disk_size
;
133 unsigned char delta_base_sha1
[20];
136 * If mark_query is true, we do not expand anything, but rather
137 * just mark the object_info with items we wish to query.
142 * Whether to split the input on whitespace before feeding it to
143 * get_sha1; this is decided during the mark_query phase based on
144 * whether we have a %(rest) token in our format.
146 int split_on_whitespace
;
149 * After a mark_query run, this object_info is set up to be
150 * passed to sha1_object_info_extended. It will point to the data
151 * elements above, so you can retrieve the response from there.
153 struct object_info info
;
156 static int is_atom(const char *atom
, const char *s
, int slen
)
158 int alen
= strlen(atom
);
159 return alen
== slen
&& !memcmp(atom
, s
, alen
);
162 static void expand_atom(struct strbuf
*sb
, const char *atom
, int len
,
165 struct expand_data
*data
= vdata
;
167 if (is_atom("objectname", atom
, len
)) {
168 if (!data
->mark_query
)
169 strbuf_addstr(sb
, sha1_to_hex(data
->sha1
));
170 } else if (is_atom("objecttype", atom
, len
)) {
171 if (data
->mark_query
)
172 data
->info
.typep
= &data
->type
;
174 strbuf_addstr(sb
, typename(data
->type
));
175 } else if (is_atom("objectsize", atom
, len
)) {
176 if (data
->mark_query
)
177 data
->info
.sizep
= &data
->size
;
179 strbuf_addf(sb
, "%lu", data
->size
);
180 } else if (is_atom("objectsize:disk", atom
, len
)) {
181 if (data
->mark_query
)
182 data
->info
.disk_sizep
= &data
->disk_size
;
184 strbuf_addf(sb
, "%lu", data
->disk_size
);
185 } else if (is_atom("rest", atom
, len
)) {
186 if (data
->mark_query
)
187 data
->split_on_whitespace
= 1;
189 strbuf_addstr(sb
, data
->rest
);
190 } else if (is_atom("deltabase", atom
, len
)) {
191 if (data
->mark_query
)
192 data
->info
.delta_base_sha1
= data
->delta_base_sha1
;
194 strbuf_addstr(sb
, sha1_to_hex(data
->delta_base_sha1
));
196 die("unknown format element: %.*s", len
, atom
);
199 static size_t expand_format(struct strbuf
*sb
, const char *start
, void *data
)
205 end
= strchr(start
+ 1, ')');
207 die("format element '%s' does not end in ')'", start
);
209 expand_atom(sb
, start
+ 1, end
- start
- 1, data
);
211 return end
- start
+ 1;
214 static void print_object_or_die(int fd
, struct expand_data
*data
)
216 const unsigned char *sha1
= data
->sha1
;
218 assert(data
->info
.typep
);
220 if (data
->type
== OBJ_BLOB
) {
221 if (stream_blob_to_fd(fd
, sha1
, NULL
, 0) < 0)
222 die("unable to stream %s to stdout", sha1_to_hex(sha1
));
225 enum object_type type
;
229 contents
= read_sha1_file(sha1
, &type
, &size
);
231 die("object %s disappeared", sha1_to_hex(sha1
));
232 if (type
!= data
->type
)
233 die("object %s changed type!?", sha1_to_hex(sha1
));
234 if (data
->info
.sizep
&& size
!= data
->size
)
235 die("object %s changed size!?", sha1_to_hex(sha1
));
237 write_or_die(fd
, contents
, size
);
243 static int batch_one_object(const char *obj_name
, struct batch_options
*opt
,
244 struct expand_data
*data
)
246 struct strbuf buf
= STRBUF_INIT
;
247 struct object_context ctx
;
248 int flags
= opt
->follow_symlinks
? GET_SHA1_FOLLOW_SYMLINKS
: 0;
249 enum follow_symlinks_result result
;
254 result
= get_sha1_with_context(obj_name
, flags
, data
->sha1
, &ctx
);
255 if (result
!= FOUND
) {
258 printf("%s missing\n", obj_name
);
260 case DANGLING_SYMLINK
:
261 printf("dangling %"PRIuMAX
"\n%s\n",
262 (uintmax_t)strlen(obj_name
), obj_name
);
265 printf("loop %"PRIuMAX
"\n%s\n",
266 (uintmax_t)strlen(obj_name
), obj_name
);
269 printf("notdir %"PRIuMAX
"\n%s\n",
270 (uintmax_t)strlen(obj_name
), obj_name
);
273 die("BUG: unknown get_sha1_with_context result %d\n",
282 printf("symlink %"PRIuMAX
"\n%s\n",
283 (uintmax_t)ctx
.symlink_path
.len
,
284 ctx
.symlink_path
.buf
);
289 if (sha1_object_info_extended(data
->sha1
, &data
->info
, LOOKUP_REPLACE_OBJECT
) < 0) {
290 printf("%s missing\n", obj_name
);
295 strbuf_expand(&buf
, opt
->format
, expand_format
, data
);
296 strbuf_addch(&buf
, '\n');
297 write_or_die(1, buf
.buf
, buf
.len
);
298 strbuf_release(&buf
);
300 if (opt
->print_contents
) {
301 print_object_or_die(1, data
);
302 write_or_die(1, "\n", 1);
307 static int batch_objects(struct batch_options
*opt
)
309 struct strbuf buf
= STRBUF_INIT
;
310 struct expand_data data
;
315 opt
->format
= "%(objectname) %(objecttype) %(objectsize)";
318 * Expand once with our special mark_query flag, which will prime the
319 * object_info to be handed to sha1_object_info_extended for each
322 memset(&data
, 0, sizeof(data
));
324 strbuf_expand(&buf
, opt
->format
, expand_format
, &data
);
328 * If we are printing out the object, then always fill in the type,
329 * since we will want to decide whether or not to stream.
331 if (opt
->print_contents
)
332 data
.info
.typep
= &data
.type
;
335 * We are going to call get_sha1 on a potentially very large number of
336 * objects. In most large cases, these will be actual object sha1s. The
337 * cost to double-check that each one is not also a ref (just so we can
338 * warn) ends up dwarfing the actual cost of the object lookups
339 * themselves. We can work around it by just turning off the warning.
341 save_warning
= warn_on_object_refname_ambiguity
;
342 warn_on_object_refname_ambiguity
= 0;
344 while (strbuf_getline(&buf
, stdin
, '\n') != EOF
) {
345 if (data
.split_on_whitespace
) {
347 * Split at first whitespace, tying off the beginning
348 * of the string and saving the remainder (or NULL) in
351 char *p
= strpbrk(buf
.buf
, " \t");
353 while (*p
&& strchr(" \t", *p
))
359 retval
= batch_one_object(buf
.buf
, opt
, &data
);
364 strbuf_release(&buf
);
365 warn_on_object_refname_ambiguity
= save_warning
;
369 static const char * const cat_file_usage
[] = {
370 N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>"),
371 N_("git cat-file (--batch | --batch-check) [--follow-symlinks] < <list-of-objects>"),
375 static int git_cat_file_config(const char *var
, const char *value
, void *cb
)
377 if (userdiff_config(var
, value
) < 0)
380 return git_default_config(var
, value
, cb
);
383 static int batch_option_callback(const struct option
*opt
,
387 struct batch_options
*bo
= opt
->value
;
394 bo
->print_contents
= !strcmp(opt
->long_name
, "batch");
400 int cmd_cat_file(int argc
, const char **argv
, const char *prefix
)
403 const char *exp_type
= NULL
, *obj_name
= NULL
;
404 struct batch_options batch
= {0};
405 int unknown_type
= 0;
407 const struct option options
[] = {
408 OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
409 OPT_CMDMODE('t', NULL
, &opt
, N_("show object type"), 't'),
410 OPT_CMDMODE('s', NULL
, &opt
, N_("show object size"), 's'),
411 OPT_CMDMODE('e', NULL
, &opt
,
412 N_("exit with zero when there's no error"), 'e'),
413 OPT_CMDMODE('p', NULL
, &opt
, N_("pretty-print object's content"), 'p'),
414 OPT_CMDMODE(0, "textconv", &opt
,
415 N_("for blob objects, run textconv on object's content"), 'c'),
416 OPT_BOOL(0, "allow-unknown-type", &unknown_type
,
417 N_("allow -s and -t to work with broken/corrupt objects")),
418 { OPTION_CALLBACK
, 0, "batch", &batch
, "format",
419 N_("show info and content of objects fed from the standard input"),
420 PARSE_OPT_OPTARG
, batch_option_callback
},
421 { OPTION_CALLBACK
, 0, "batch-check", &batch
, "format",
422 N_("show info about objects fed from the standard input"),
423 PARSE_OPT_OPTARG
, batch_option_callback
},
424 OPT_BOOL(0, "follow-symlinks", &batch
.follow_symlinks
,
425 N_("follow in-tree symlinks (used with --batch or --batch-check)")),
429 git_config(git_cat_file_config
, NULL
);
431 argc
= parse_options(argc
, argv
, prefix
, options
, cat_file_usage
, 0);
437 usage_with_options(cat_file_usage
, options
);
439 if (!opt
&& !batch
.enabled
) {
444 usage_with_options(cat_file_usage
, options
);
446 if (batch
.enabled
&& (opt
|| argc
)) {
447 usage_with_options(cat_file_usage
, options
);
450 if (batch
.follow_symlinks
&& !batch
.enabled
) {
451 usage_with_options(cat_file_usage
, options
);
455 return batch_objects(&batch
);
457 if (unknown_type
&& opt
!= 't' && opt
!= 's')
458 die("git cat-file --allow-unknown-type: use with -s or -t");
459 return cat_one_file(opt
, exp_type
, obj_name
, unknown_type
);