Ignore:
Timestamp:
Jun 23, 2014, 9:45:51 PM (11 years ago)
Author:
dmik
Message:

git: Merge version 2.0.0 from vendor to dmik branch.

Location:
git/branches/dmik
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • git/branches/dmik

  • TabularUnified git/branches/dmik/builtin/cat-file.c

    r347 r782  
    1212#include "diff.h"
    1313#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"
    8415
    8516static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
     
    9122        struct object_context obj_context;
    9223
    93         if (get_sha1_with_context(obj_name, sha1, &obj_context))
     24        if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
    9425                die("Not a valid object name %s", obj_name);
    9526
     
    11546                return !has_sha1_file(sha1);
    11647
     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
    11756        case 'p':
    11857                type = sha1_object_info(sha1, NULL);
     
    12867                }
    12968
     69                if (type == OBJ_BLOB)
     70                        return stream_blob_to_fd(1, sha1, NULL, 0);
    13071                buf = read_sha1_file(sha1, &type, &size);
    13172                if (!buf)
    13273                        die("Cannot read object %s", obj_name);
    133                 if (type == OBJ_TAG) {
    134                         pprint_tag(sha1, buf, size);
    135                         return 0;
    136                 }
    13774
    13875                /* otherwise just spit out the data */
    13976                break;
    14077
    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 
    15178        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                }
    152101                buf = read_object_with_reference(sha1, exp_type, &size, NULL);
    153102                break;
     
    164113}
    165114
    166 static int batch_one_object(const char *obj_name, int print_contents)
    167 {
     115struct expand_data {
    168116        unsigned char sha1[20];
    169         enum object_type type = 0;
     117        enum object_type type;
    170118        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
     144static 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
     150static 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
     187static 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
     202static 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
     230struct batch_options {
     231        int enabled;
     232        int print_contents;
     233        const char *format;
     234};
     235
     236static int batch_one_object(const char *obj_name, struct batch_options *opt,
     237                            struct expand_data *data)
     238{
     239        struct strbuf buf = STRBUF_INIT;
    172240
    173241        if (!obj_name)
    174242           return 1;
    175243
    176         if (get_sha1(obj_name, sha1)) {
     244        if (get_sha1(obj_name, data->sha1)) {
    177245                printf("%s missing\n", obj_name);
    178246                fflush(stdout);
     
    180248        }
    181249
    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) {
    188251                printf("%s missing\n", obj_name);
    189252                fflush(stdout);
    190                 if (print_contents == BATCH)
    191                         free(contents);
    192253                return 0;
    193254        }
    194255
    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        }
    205265        return 0;
    206266}
    207267
    208 static int batch_objects(int print_contents)
     268static int batch_objects(struct batch_options *opt)
    209269{
    210270        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;
    211304
    212305        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;
    219328}
    220329
    221330static 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>"),
    224333        NULL
    225334};
     
    227336static int git_cat_file_config(const char *var, const char *value, void *cb)
    228337{
    229         switch (userdiff_config(var, value)) {
    230         case 0:
    231                 break;
    232         case -1:
     338        if (userdiff_config(var, value) < 0)
    233339                return -1;
    234         default:
     340
     341        return git_default_config(var, value, cb);
     342}
     343
     344static 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));
    235352                return 0;
    236353        }
    237354
    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;
    239360}
    240361
    241362int cmd_cat_file(int argc, const char **argv, const char *prefix)
    242363{
    243         int opt = 0, batch = 0;
     364        int opt = 0;
    244365        const char *exp_type = NULL, *obj_name = NULL;
     366        struct batch_options batch = {0};
    245367
    246368        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'),
    250372                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'),
    253375                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 },
    261383                OPT_END()
    262384        };
     
    275397                        usage_with_options(cat_file_usage, options);
    276398        }
    277         if (!opt && !batch) {
     399        if (!opt && !batch.enabled) {
    278400                if (argc == 2) {
    279401                        exp_type = argv[0];
     
    282404                        usage_with_options(cat_file_usage, options);
    283405        }
    284         if (batch && (opt || argc)) {
     406        if (batch.enabled && (opt || argc)) {
    285407                usage_with_options(cat_file_usage, options);
    286408        }
    287409
    288         if (batch)
    289                 return batch_objects(batch);
     410        if (batch.enabled)
     411                return batch_objects(&batch);
    290412
    291413        return cat_one_file(opt, exp_type, obj_name);
Note: See TracChangeset for help on using the changeset viewer.