]>
Commit | Line | Data |
---|---|---|
8bc9a0c7 LT |
1 | /* |
2 | * GIT - The information manager from hell | |
3 | * | |
4 | * Copyright (C) Linus Torvalds, 2005 | |
5 | */ | |
e83c5163 | 6 | #include "cache.h" |
a0f15fa5 | 7 | #include "exec_cmd.h" |
8e440259 PE |
8 | #include "tag.h" |
9 | #include "tree.h" | |
f81daefe | 10 | #include "builtin.h" |
15d8e565 | 11 | #include "parse-options.h" |
e5fba602 CP |
12 | #include "diff.h" |
13 | #include "userdiff.h" | |
00c8fd49 | 14 | #include "streaming.h" |
15d8e565 | 15 | |
9cf71b17 | 16 | static int cat_one_file(int opt, const char *exp_type, const char *obj_name) |
e83c5163 LT |
17 | { |
18 | unsigned char sha1[20]; | |
21666f1a | 19 | enum object_type type; |
e5fba602 | 20 | char *buf; |
e83c5163 | 21 | unsigned long size; |
e5fba602 | 22 | struct object_context obj_context; |
2b6854c8 | 23 | |
33bd598c | 24 | if (get_sha1_with_context(obj_name, 0, sha1, &obj_context)) |
2b6854c8 | 25 | die("Not a valid object name %s", obj_name); |
7950571a | 26 | |
7950571a PA |
27 | buf = NULL; |
28 | switch (opt) { | |
29 | case 't': | |
21666f1a NP |
30 | type = sha1_object_info(sha1, NULL); |
31 | if (type > 0) { | |
32 | printf("%s\n", typename(type)); | |
f2a06330 | 33 | return 0; |
11e7d5c5 | 34 | } |
7950571a PA |
35 | break; |
36 | ||
37 | case 's': | |
21666f1a NP |
38 | type = sha1_object_info(sha1, &size); |
39 | if (type > 0) { | |
7950571a PA |
40 | printf("%lu\n", size); |
41 | return 0; | |
42 | } | |
43 | break; | |
44 | ||
45 | case 'e': | |
46 | return !has_sha1_file(sha1); | |
47 | ||
a0f15fa5 | 48 | case 'p': |
21666f1a NP |
49 | type = sha1_object_info(sha1, NULL); |
50 | if (type < 0) | |
2b6854c8 | 51 | die("Not a valid object name %s", obj_name); |
a0f15fa5 JH |
52 | |
53 | /* custom pretty-print here */ | |
2b6854c8 | 54 | if (type == OBJ_TREE) { |
66dbfd55 GV |
55 | const char *ls_args[3] = { NULL }; |
56 | ls_args[0] = "ls-tree"; | |
57 | ls_args[1] = obj_name; | |
2b6854c8 SP |
58 | return cmd_ls_tree(2, ls_args, NULL); |
59 | } | |
a0f15fa5 | 60 | |
00c8fd49 NTND |
61 | if (type == OBJ_BLOB) |
62 | return stream_blob_to_fd(1, sha1, NULL, 0); | |
21666f1a | 63 | buf = read_sha1_file(sha1, &type, &size); |
a0f15fa5 | 64 | if (!buf) |
2b6854c8 | 65 | die("Cannot read object %s", obj_name); |
a0f15fa5 JH |
66 | |
67 | /* otherwise just spit out the data */ | |
68 | break; | |
e5fba602 CP |
69 | |
70 | case 'c': | |
71 | if (!obj_context.path[0]) | |
72 | die("git cat-file --textconv %s: <object> must be <sha1:path>", | |
73 | obj_name); | |
74 | ||
e5450100 | 75 | if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size)) |
e5fba602 CP |
76 | die("git cat-file --textconv: unable to run textconv on %s", |
77 | obj_name); | |
78 | break; | |
79 | ||
7950571a | 80 | case 0: |
00c8fd49 NTND |
81 | if (type_from_string(exp_type) == OBJ_BLOB) { |
82 | unsigned char blob_sha1[20]; | |
83 | if (sha1_object_info(sha1, NULL) == OBJ_TAG) { | |
84 | enum object_type type; | |
85 | unsigned long size; | |
86 | char *buffer = read_sha1_file(sha1, &type, &size); | |
87 | if (memcmp(buffer, "object ", 7) || | |
88 | get_sha1_hex(buffer + 7, blob_sha1)) | |
89 | die("%s not a valid tag", sha1_to_hex(sha1)); | |
90 | free(buffer); | |
91 | } else | |
92 | hashcpy(blob_sha1, sha1); | |
93 | ||
94 | if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB) | |
95 | return stream_blob_to_fd(1, blob_sha1, NULL, 0); | |
96 | /* | |
97 | * we attempted to dereference a tag to a blob | |
98 | * and failed; there may be new dereference | |
99 | * mechanisms this code is not aware of. | |
100 | * fall-back to the usual case. | |
101 | */ | |
102 | } | |
2b6854c8 | 103 | buf = read_object_with_reference(sha1, exp_type, &size, NULL); |
7950571a PA |
104 | break; |
105 | ||
106 | default: | |
d7530708 | 107 | die("git cat-file: unknown option: %s", exp_type); |
bf0c6e83 LT |
108 | } |
109 | ||
11e7d5c5 | 110 | if (!buf) |
34baebce | 111 | die("git cat-file %s: bad file", obj_name); |
11e7d5c5 | 112 | |
7230e6d0 | 113 | write_or_die(1, buf, size); |
bf0c6e83 | 114 | return 0; |
e83c5163 | 115 | } |
9cf71b17 | 116 | |
98e2092b JK |
117 | static void print_object_or_die(int fd, const unsigned char *sha1, |
118 | enum object_type type, unsigned long size) | |
119 | { | |
120 | if (type == OBJ_BLOB) { | |
121 | if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0) | |
122 | die("unable to stream %s to stdout", sha1_to_hex(sha1)); | |
123 | } | |
124 | else { | |
125 | enum object_type rtype; | |
126 | unsigned long rsize; | |
127 | void *contents; | |
128 | ||
129 | contents = read_sha1_file(sha1, &rtype, &rsize); | |
130 | if (!contents) | |
131 | die("object %s disappeared", sha1_to_hex(sha1)); | |
132 | if (rtype != type) | |
133 | die("object %s changed type!?", sha1_to_hex(sha1)); | |
134 | if (rsize != size) | |
135 | die("object %s change size!?", sha1_to_hex(sha1)); | |
136 | ||
137 | write_or_die(fd, contents, size); | |
138 | free(contents); | |
139 | } | |
140 | } | |
141 | ||
b71bd480 JK |
142 | struct batch_options { |
143 | int enabled; | |
144 | int print_contents; | |
145 | }; | |
146 | ||
147 | static int batch_one_object(const char *obj_name, struct batch_options *opt) | |
05d5667f AR |
148 | { |
149 | unsigned char sha1[20]; | |
3c076dbe | 150 | enum object_type type = 0; |
05d5667f AR |
151 | unsigned long size; |
152 | ||
153 | if (!obj_name) | |
154 | return 1; | |
155 | ||
156 | if (get_sha1(obj_name, sha1)) { | |
157 | printf("%s missing\n", obj_name); | |
422b2063 | 158 | fflush(stdout); |
05d5667f AR |
159 | return 0; |
160 | } | |
161 | ||
98e2092b | 162 | type = sha1_object_info(sha1, &size); |
3c076dbe LW |
163 | if (type <= 0) { |
164 | printf("%s missing\n", obj_name); | |
165 | fflush(stdout); | |
166 | return 0; | |
167 | } | |
05d5667f AR |
168 | |
169 | printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size); | |
a8128ed6 AR |
170 | fflush(stdout); |
171 | ||
b71bd480 | 172 | if (opt->print_contents) { |
98e2092b JK |
173 | print_object_or_die(1, sha1, type, size); |
174 | write_or_die(1, "\n", 1); | |
a8128ed6 | 175 | } |
05d5667f AR |
176 | return 0; |
177 | } | |
178 | ||
b71bd480 | 179 | static int batch_objects(struct batch_options *opt) |
05d5667f | 180 | { |
f285a2d7 | 181 | struct strbuf buf = STRBUF_INIT; |
05d5667f | 182 | |
05d5667f | 183 | while (strbuf_getline(&buf, stdin, '\n') != EOF) { |
b71bd480 | 184 | int error = batch_one_object(buf.buf, opt); |
05d5667f AR |
185 | if (error) |
186 | return error; | |
187 | } | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
15d8e565 | 192 | static const char * const cat_file_usage[] = { |
d68faec7 NTND |
193 | N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"), |
194 | N_("git cat-file (--batch|--batch-check) < <list_of_objects>"), | |
15d8e565 MB |
195 | NULL |
196 | }; | |
4814dbe8 | 197 | |
e5fba602 CP |
198 | static int git_cat_file_config(const char *var, const char *value, void *cb) |
199 | { | |
6680a087 | 200 | if (userdiff_config(var, value) < 0) |
e5fba602 | 201 | return -1; |
e5fba602 CP |
202 | |
203 | return git_default_config(var, value, cb); | |
204 | } | |
205 | ||
b71bd480 JK |
206 | static int batch_option_callback(const struct option *opt, |
207 | const char *arg, | |
208 | int unset) | |
209 | { | |
210 | struct batch_options *bo = opt->value; | |
211 | ||
212 | if (unset) { | |
213 | memset(bo, 0, sizeof(*bo)); | |
214 | return 0; | |
215 | } | |
216 | ||
217 | bo->enabled = 1; | |
218 | bo->print_contents = !strcmp(opt->long_name, "batch"); | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
9cf71b17 AR |
223 | int cmd_cat_file(int argc, const char **argv, const char *prefix) |
224 | { | |
b71bd480 | 225 | int opt = 0; |
4814dbe8 | 226 | const char *exp_type = NULL, *obj_name = NULL; |
b71bd480 | 227 | struct batch_options batch = {0}; |
9cf71b17 | 228 | |
15d8e565 | 229 | const struct option options[] = { |
d68faec7 NTND |
230 | OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")), |
231 | OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'), | |
232 | OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'), | |
15d8e565 | 233 | OPT_SET_INT('e', NULL, &opt, |
d68faec7 NTND |
234 | N_("exit with zero when there's no error"), 'e'), |
235 | OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'), | |
e5fba602 | 236 | OPT_SET_INT(0, "textconv", &opt, |
d68faec7 | 237 | N_("for blob objects, run textconv on object's content"), 'c'), |
b71bd480 JK |
238 | { OPTION_CALLBACK, 0, "batch", &batch, NULL, |
239 | N_("show info and content of objects fed from the standard input"), | |
240 | PARSE_OPT_NOARG, batch_option_callback }, | |
241 | { OPTION_CALLBACK, 0, "batch-check", &batch, NULL, | |
242 | N_("show info about objects fed from the standard input"), | |
243 | PARSE_OPT_NOARG, batch_option_callback }, | |
15d8e565 MB |
244 | OPT_END() |
245 | }; | |
a8128ed6 | 246 | |
e5fba602 | 247 | git_config(git_cat_file_config, NULL); |
4814dbe8 | 248 | |
15d8e565 MB |
249 | if (argc != 3 && argc != 2) |
250 | usage_with_options(cat_file_usage, options); | |
4814dbe8 | 251 | |
37782920 | 252 | argc = parse_options(argc, argv, prefix, options, cat_file_usage, 0); |
05d5667f | 253 | |
15d8e565 MB |
254 | if (opt) { |
255 | if (argc == 1) | |
256 | obj_name = argv[0]; | |
257 | else | |
258 | usage_with_options(cat_file_usage, options); | |
259 | } | |
b71bd480 | 260 | if (!opt && !batch.enabled) { |
15d8e565 MB |
261 | if (argc == 2) { |
262 | exp_type = argv[0]; | |
263 | obj_name = argv[1]; | |
264 | } else | |
265 | usage_with_options(cat_file_usage, options); | |
266 | } | |
b71bd480 | 267 | if (batch.enabled && (opt || argc)) { |
15d8e565 | 268 | usage_with_options(cat_file_usage, options); |
9cf71b17 AR |
269 | } |
270 | ||
b71bd480 JK |
271 | if (batch.enabled) |
272 | return batch_objects(&batch); | |
05d5667f | 273 | |
9cf71b17 AR |
274 | return cat_one_file(opt, exp_type, obj_name); |
275 | } |