Changeset 782 for git/branches/dmik/builtin/cat-file.c
- Timestamp:
- Jun 23, 2014, 9:45:51 PM (11 years ago)
- Location:
- git/branches/dmik
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
git/branches/dmik ¶
- Property svn:mergeinfo changed
/git/vendor/2.0.0 (added) merged: 777 /git/vendor/current merged: 772,774,776
- Property svn:mergeinfo changed
-
TabularUnified git/branches/dmik/builtin/cat-file.c ¶
r347 r782 12 12 #include "diff.h" 13 13 #include "userdiff.h" 14 15 #define BATCH 1 16 #define BATCH_CHECK 2 17 18 static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size) 19 { 20 /* the parser in tag.c is useless here. */ 21 const char *endp = buf + size; 22 const char *cp = buf; 23 24 while (cp < endp) { 25 char c = *cp++; 26 if (c != '\n') 27 continue; 28 if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) { 29 const char *tagger = cp; 30 31 /* Found the tagger line. Copy out the contents 32 * of the buffer so far. 33 */ 34 write_or_die(1, buf, cp - buf); 35 36 /* 37 * Do something intelligent, like pretty-printing 38 * the date. 39 */ 40 while (cp < endp) { 41 if (*cp++ == '\n') { 42 /* tagger to cp is a line 43 * that has ident and time. 44 */ 45 const char *sp = tagger; 46 char *ep; 47 unsigned long date; 48 long tz; 49 while (sp < cp && *sp != '>') 50 sp++; 51 if (sp == cp) { 52 /* give up */ 53 write_or_die(1, tagger, 54 cp - tagger); 55 break; 56 } 57 while (sp < cp && 58 !('0' <= *sp && *sp <= '9')) 59 sp++; 60 write_or_die(1, tagger, sp - tagger); 61 date = strtoul(sp, &ep, 10); 62 tz = strtol(ep, NULL, 10); 63 sp = show_date(date, tz, 0); 64 write_or_die(1, sp, strlen(sp)); 65 xwrite(1, "\n", 1); 66 break; 67 } 68 } 69 break; 70 } 71 if (cp < endp && *cp == '\n') 72 /* end of header */ 73 break; 74 } 75 /* At this point, we have copied out the header up to the end of 76 * the tagger line and cp points at one past \n. It could be the 77 * next header line after the tagger line, or it could be another 78 * \n that marks the end of the headers. We need to copy out the 79 * remainder as is. 80 */ 81 if (cp < endp) 82 write_or_die(1, cp, endp - cp); 83 } 14 #include "streaming.h" 84 15 85 16 static int cat_one_file(int opt, const char *exp_type, const char *obj_name) … … 91 22 struct object_context obj_context; 92 23 93 if (get_sha1_with_context(obj_name, sha1, &obj_context))24 if (get_sha1_with_context(obj_name, 0, sha1, &obj_context)) 94 25 die("Not a valid object name %s", obj_name); 95 26 … … 115 46 return !has_sha1_file(sha1); 116 47 48 case 'c': 49 if (!obj_context.path[0]) 50 die("git cat-file --textconv %s: <object> must be <sha1:path>", 51 obj_name); 52 53 if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size)) 54 break; 55 117 56 case 'p': 118 57 type = sha1_object_info(sha1, NULL); … … 128 67 } 129 68 69 if (type == OBJ_BLOB) 70 return stream_blob_to_fd(1, sha1, NULL, 0); 130 71 buf = read_sha1_file(sha1, &type, &size); 131 72 if (!buf) 132 73 die("Cannot read object %s", obj_name); 133 if (type == OBJ_TAG) {134 pprint_tag(sha1, buf, size);135 return 0;136 }137 74 138 75 /* otherwise just spit out the data */ 139 76 break; 140 77 141 case 'c':142 if (!obj_context.path[0])143 die("git cat-file --textconv %s: <object> must be <sha1:path>",144 obj_name);145 146 if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))147 die("git cat-file --textconv: unable to run textconv on %s",148 obj_name);149 break;150 151 78 case 0: 79 if (type_from_string(exp_type) == OBJ_BLOB) { 80 unsigned char blob_sha1[20]; 81 if (sha1_object_info(sha1, NULL) == OBJ_TAG) { 82 enum object_type type; 83 unsigned long size; 84 char *buffer = read_sha1_file(sha1, &type, &size); 85 if (memcmp(buffer, "object ", 7) || 86 get_sha1_hex(buffer + 7, blob_sha1)) 87 die("%s not a valid tag", sha1_to_hex(sha1)); 88 free(buffer); 89 } else 90 hashcpy(blob_sha1, sha1); 91 92 if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB) 93 return stream_blob_to_fd(1, blob_sha1, NULL, 0); 94 /* 95 * we attempted to dereference a tag to a blob 96 * and failed; there may be new dereference 97 * mechanisms this code is not aware of. 98 * fall-back to the usual case. 99 */ 100 } 152 101 buf = read_object_with_reference(sha1, exp_type, &size, NULL); 153 102 break; … … 164 113 } 165 114 166 static int batch_one_object(const char *obj_name, int print_contents) 167 { 115 struct expand_data { 168 116 unsigned char sha1[20]; 169 enum object_type type = 0;117 enum object_type type; 170 118 unsigned long size; 171 void *contents = contents; 119 unsigned long disk_size; 120 const char *rest; 121 unsigned char delta_base_sha1[20]; 122 123 /* 124 * If mark_query is true, we do not expand anything, but rather 125 * just mark the object_info with items we wish to query. 126 */ 127 int mark_query; 128 129 /* 130 * Whether to split the input on whitespace before feeding it to 131 * get_sha1; this is decided during the mark_query phase based on 132 * whether we have a %(rest) token in our format. 133 */ 134 int split_on_whitespace; 135 136 /* 137 * After a mark_query run, this object_info is set up to be 138 * passed to sha1_object_info_extended. It will point to the data 139 * elements above, so you can retrieve the response from there. 140 */ 141 struct object_info info; 142 }; 143 144 static int is_atom(const char *atom, const char *s, int slen) 145 { 146 int alen = strlen(atom); 147 return alen == slen && !memcmp(atom, s, alen); 148 } 149 150 static void expand_atom(struct strbuf *sb, const char *atom, int len, 151 void *vdata) 152 { 153 struct expand_data *data = vdata; 154 155 if (is_atom("objectname", atom, len)) { 156 if (!data->mark_query) 157 strbuf_addstr(sb, sha1_to_hex(data->sha1)); 158 } else if (is_atom("objecttype", atom, len)) { 159 if (data->mark_query) 160 data->info.typep = &data->type; 161 else 162 strbuf_addstr(sb, typename(data->type)); 163 } else if (is_atom("objectsize", atom, len)) { 164 if (data->mark_query) 165 data->info.sizep = &data->size; 166 else 167 strbuf_addf(sb, "%lu", data->size); 168 } else if (is_atom("objectsize:disk", atom, len)) { 169 if (data->mark_query) 170 data->info.disk_sizep = &data->disk_size; 171 else 172 strbuf_addf(sb, "%lu", data->disk_size); 173 } else if (is_atom("rest", atom, len)) { 174 if (data->mark_query) 175 data->split_on_whitespace = 1; 176 else if (data->rest) 177 strbuf_addstr(sb, data->rest); 178 } else if (is_atom("deltabase", atom, len)) { 179 if (data->mark_query) 180 data->info.delta_base_sha1 = data->delta_base_sha1; 181 else 182 strbuf_addstr(sb, sha1_to_hex(data->delta_base_sha1)); 183 } else 184 die("unknown format element: %.*s", len, atom); 185 } 186 187 static size_t expand_format(struct strbuf *sb, const char *start, void *data) 188 { 189 const char *end; 190 191 if (*start != '(') 192 return 0; 193 end = strchr(start + 1, ')'); 194 if (!end) 195 die("format element '%s' does not end in ')'", start); 196 197 expand_atom(sb, start + 1, end - start - 1, data); 198 199 return end - start + 1; 200 } 201 202 static void print_object_or_die(int fd, struct expand_data *data) 203 { 204 const unsigned char *sha1 = data->sha1; 205 206 assert(data->info.typep); 207 208 if (data->type == OBJ_BLOB) { 209 if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0) 210 die("unable to stream %s to stdout", sha1_to_hex(sha1)); 211 } 212 else { 213 enum object_type type; 214 unsigned long size; 215 void *contents; 216 217 contents = read_sha1_file(sha1, &type, &size); 218 if (!contents) 219 die("object %s disappeared", sha1_to_hex(sha1)); 220 if (type != data->type) 221 die("object %s changed type!?", sha1_to_hex(sha1)); 222 if (data->info.sizep && size != data->size) 223 die("object %s changed size!?", sha1_to_hex(sha1)); 224 225 write_or_die(fd, contents, size); 226 free(contents); 227 } 228 } 229 230 struct batch_options { 231 int enabled; 232 int print_contents; 233 const char *format; 234 }; 235 236 static int batch_one_object(const char *obj_name, struct batch_options *opt, 237 struct expand_data *data) 238 { 239 struct strbuf buf = STRBUF_INIT; 172 240 173 241 if (!obj_name) 174 242 return 1; 175 243 176 if (get_sha1(obj_name, sha1)) {244 if (get_sha1(obj_name, data->sha1)) { 177 245 printf("%s missing\n", obj_name); 178 246 fflush(stdout); … … 180 248 } 181 249 182 if (print_contents == BATCH) 183 contents = read_sha1_file(sha1, &type, &size); 184 else 185 type = sha1_object_info(sha1, &size); 186 187 if (type <= 0) { 250 if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) { 188 251 printf("%s missing\n", obj_name); 189 252 fflush(stdout); 190 if (print_contents == BATCH)191 free(contents);192 253 return 0; 193 254 } 194 255 195 printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size); 196 fflush(stdout); 197 198 if (print_contents == BATCH) { 199 write_or_die(1, contents, size); 200 printf("\n"); 201 fflush(stdout); 202 free(contents); 203 } 204 256 strbuf_expand(&buf, opt->format, expand_format, data); 257 strbuf_addch(&buf, '\n'); 258 write_or_die(1, buf.buf, buf.len); 259 strbuf_release(&buf); 260 261 if (opt->print_contents) { 262 print_object_or_die(1, data); 263 write_or_die(1, "\n", 1); 264 } 205 265 return 0; 206 266 } 207 267 208 static int batch_objects( int print_contents)268 static int batch_objects(struct batch_options *opt) 209 269 { 210 270 struct strbuf buf = STRBUF_INIT; 271 struct expand_data data; 272 int save_warning; 273 int retval = 0; 274 275 if (!opt->format) 276 opt->format = "%(objectname) %(objecttype) %(objectsize)"; 277 278 /* 279 * Expand once with our special mark_query flag, which will prime the 280 * object_info to be handed to sha1_object_info_extended for each 281 * object. 282 */ 283 memset(&data, 0, sizeof(data)); 284 data.mark_query = 1; 285 strbuf_expand(&buf, opt->format, expand_format, &data); 286 data.mark_query = 0; 287 288 /* 289 * If we are printing out the object, then always fill in the type, 290 * since we will want to decide whether or not to stream. 291 */ 292 if (opt->print_contents) 293 data.info.typep = &data.type; 294 295 /* 296 * We are going to call get_sha1 on a potentially very large number of 297 * objects. In most large cases, these will be actual object sha1s. The 298 * cost to double-check that each one is not also a ref (just so we can 299 * warn) ends up dwarfing the actual cost of the object lookups 300 * themselves. We can work around it by just turning off the warning. 301 */ 302 save_warning = warn_on_object_refname_ambiguity; 303 warn_on_object_refname_ambiguity = 0; 211 304 212 305 while (strbuf_getline(&buf, stdin, '\n') != EOF) { 213 int error = batch_one_object(buf.buf, print_contents); 214 if (error) 215 return error; 216 } 217 218 return 0; 306 if (data.split_on_whitespace) { 307 /* 308 * Split at first whitespace, tying off the beginning 309 * of the string and saving the remainder (or NULL) in 310 * data.rest. 311 */ 312 char *p = strpbrk(buf.buf, " \t"); 313 if (p) { 314 while (*p && strchr(" \t", *p)) 315 *p++ = '\0'; 316 } 317 data.rest = p; 318 } 319 320 retval = batch_one_object(buf.buf, opt, &data); 321 if (retval) 322 break; 323 } 324 325 strbuf_release(&buf); 326 warn_on_object_refname_ambiguity = save_warning; 327 return retval; 219 328 } 220 329 221 330 static const char * const cat_file_usage[] = { 222 "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",223 "git cat-file (--batch|--batch-check) < <list_of_objects>",331 N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"), 332 N_("git cat-file (--batch|--batch-check) < <list_of_objects>"), 224 333 NULL 225 334 }; … … 227 336 static int git_cat_file_config(const char *var, const char *value, void *cb) 228 337 { 229 switch (userdiff_config(var, value)) { 230 case 0: 231 break; 232 case -1: 338 if (userdiff_config(var, value) < 0) 233 339 return -1; 234 default: 340 341 return git_default_config(var, value, cb); 342 } 343 344 static int batch_option_callback(const struct option *opt, 345 const char *arg, 346 int unset) 347 { 348 struct batch_options *bo = opt->value; 349 350 if (unset) { 351 memset(bo, 0, sizeof(*bo)); 235 352 return 0; 236 353 } 237 354 238 return git_default_config(var, value, cb); 355 bo->enabled = 1; 356 bo->print_contents = !strcmp(opt->long_name, "batch"); 357 bo->format = arg; 358 359 return 0; 239 360 } 240 361 241 362 int cmd_cat_file(int argc, const char **argv, const char *prefix) 242 363 { 243 int opt = 0 , batch = 0;364 int opt = 0; 244 365 const char *exp_type = NULL, *obj_name = NULL; 366 struct batch_options batch = {0}; 245 367 246 368 const struct option options[] = { 247 OPT_GROUP( "<type> can be one of: blob, tree, commit, tag"),248 OPT_SET_INT('t', NULL, &opt, "show object type", 't'),249 OPT_SET_INT('s', NULL, &opt, "show object size", 's'),369 OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")), 370 OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'), 371 OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'), 250 372 OPT_SET_INT('e', NULL, &opt, 251 "exit with zero when there's no error", 'e'),252 OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),373 N_("exit with zero when there's no error"), 'e'), 374 OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'), 253 375 OPT_SET_INT(0, "textconv", &opt, 254 "for blob objects, run textconv on object's content", 'c'),255 OPT_SET_INT(0, "batch", &batch,256 "show info and content of objects fed from the standard input",257 BATCH),258 OPT_SET_INT(0, "batch-check", &batch,259 "show info about objects fed from the standard input",260 BATCH_CHECK),376 N_("for blob objects, run textconv on object's content"), 'c'), 377 { OPTION_CALLBACK, 0, "batch", &batch, "format", 378 N_("show info and content of objects fed from the standard input"), 379 PARSE_OPT_OPTARG, batch_option_callback }, 380 { OPTION_CALLBACK, 0, "batch-check", &batch, "format", 381 N_("show info about objects fed from the standard input"), 382 PARSE_OPT_OPTARG, batch_option_callback }, 261 383 OPT_END() 262 384 }; … … 275 397 usage_with_options(cat_file_usage, options); 276 398 } 277 if (!opt && !batch ) {399 if (!opt && !batch.enabled) { 278 400 if (argc == 2) { 279 401 exp_type = argv[0]; … … 282 404 usage_with_options(cat_file_usage, options); 283 405 } 284 if (batch && (opt || argc)) {406 if (batch.enabled && (opt || argc)) { 285 407 usage_with_options(cat_file_usage, options); 286 408 } 287 409 288 if (batch )289 return batch_objects( batch);410 if (batch.enabled) 411 return batch_objects(&batch); 290 412 291 413 return cat_one_file(opt, exp_type, obj_name);
Note:
See TracChangeset
for help on using the changeset viewer.