Merge branch 'js/cat-file-filters'
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Sep 2016 22:15:18 +0000 (15:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 Sep 2016 22:15:19 +0000 (15:15 -0700)
Even though "git hash-objects", which is a tool to take an
on-filesystem data stream and put it into the Git object store,
allowed to perform the "outside-world-to-Git" conversions (e.g.
end-of-line conversions and application of the clean-filter), and
it had the feature on by default from very early days, its reverse
operation "git cat-file", which takes an object from the Git object
store and externalize for the consumption by the outside world,
lacked an equivalent mechanism to run the "Git-to-outside-world"
conversion. The command learned the "--filters" option to do so.

* js/cat-file-filters:
cat-file: support --textconv/--filters in batch mode
cat-file --textconv/--filters: allow specifying the path separately
cat-file: introduce the --filters option
cat-file: fix a grammo in the man page

1  2 
builtin/cat-file.c
index 3ee9bc9ad18bf478d7e8fbf4a9950cb58a1a29c1,59dea48dae0606d3ff36fc2d6f8bc7448273fb7c..94e67ebb7eec087390cfecc5c4371a974401d602
@@@ -20,6 -21,30 +21,30 @@@ struct batch_options 
        const char *format;
  };
  
 -                       const unsigned char *sha1,
+ static const char *force_path;
+ static int filter_object(const char *path, unsigned mode,
 -      *buf = read_sha1_file(sha1, &type, size);
++                       const struct object_id *oid,
+                        char **buf, unsigned long *size)
+ {
+       enum object_type type;
 -                      sha1_to_hex(sha1), path);
++      *buf = read_sha1_file(oid->hash, &type, size);
+       if (!*buf)
+               return error(_("cannot read object %s '%s'"),
++                           oid_to_hex(oid), path);
+       if ((type == OBJ_BLOB) && S_ISREG(mode)) {
+               struct strbuf strbuf = STRBUF_INIT;
+               if (convert_to_working_tree(path, *buf, *size, &strbuf)) {
+                       free(*buf);
+                       *size = strbuf.len;
+                       *buf = strbuf_detach(&strbuf, NULL);
+               }
+       }
+       return 0;
+ }
  static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        int unknown_type)
  {
        if (unknown_type)
                flags |= LOOKUP_UNKNOWN_OBJECT;
  
 -      if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
 +      if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context))
                die("Not a valid object name %s", obj_name);
  
+       if (!path)
+               path = obj_context.path;
+       if (obj_context.mode == S_IFINVALID)
+               obj_context.mode = 0100644;
        buf = NULL;
        switch (opt) {
        case 't':
                return 0;
  
        case 'e':
 -              return !has_sha1_file(sha1);
 +              return !has_object_file(&oid);
  
 -                                sha1, &buf, &size))
+       case 'w':
+               if (!path[0])
+                       die("git cat-file --filters %s: <object> must be "
+                           "<sha1:path>", obj_name);
+               if (filter_object(path, obj_context.mode,
++                                &oid, &buf, &size))
+                       return -1;
+               break;
        case 'c':
-               if (!obj_context.path[0])
+               if (!path[0])
                        die("git cat-file --textconv %s: <object> must be <sha1:path>",
                            obj_name);
  
-               if (textconv_object(obj_context.path, obj_context.mode, &oid, 1, &buf, &size))
 -              if (textconv_object(path, obj_context.mode,
 -                                  sha1, 1, &buf, &size))
++              if (textconv_object(path, obj_context.mode, &oid, 1, &buf, &size))
                        break;
  
        case 'p':
@@@ -240,8 -281,33 +281,33 @@@ static void print_object_or_die(struct 
        if (data->type == OBJ_BLOB) {
                if (opt->buffer_output)
                        fflush(stdout);
-               if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
+               if (opt->cmdmode) {
+                       char *contents;
+                       unsigned long size;
+                       if (!data->rest)
 -                              die("missing path for '%s'", sha1_to_hex(sha1));
++                              die("missing path for '%s'", oid_to_hex(oid));
+                       if (opt->cmdmode == 'w') {
 -                              if (filter_object(data->rest, 0100644, sha1,
++                              if (filter_object(data->rest, 0100644, oid,
+                                                 &contents, &size))
+                                       die("could not convert '%s' %s",
 -                                          sha1_to_hex(sha1), data->rest);
++                                          oid_to_hex(oid), data->rest);
+                       } else if (opt->cmdmode == 'c') {
+                               enum object_type type;
 -                              if (!textconv_object(data->rest, 0100644, sha1,
++                              if (!textconv_object(data->rest, 0100644, oid,
+                                                    1, &contents, &size))
 -                                      contents = read_sha1_file(sha1, &type,
++                                      contents = read_sha1_file(oid->hash, &type,
+                                                                 &size);
+                               if (!contents)
+                                       die("could not convert '%s' %s",
 -                                          sha1_to_hex(sha1), data->rest);
++                                          oid_to_hex(oid), data->rest);
+                       } else
+                               die("BUG: invalid cmdmode: %c", opt->cmdmode);
+                       batch_write(opt, contents, size);
+                       free(contents);
 -              } else if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)
 -                      die("unable to stream %s to stdout", sha1_to_hex(sha1));
++              } else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
 +                      die("unable to stream %s to stdout", oid_to_hex(oid));
        }
        else {
                enum object_type type;
@@@ -442,8 -509,8 +510,8 @@@ static int batch_objects(struct batch_o
  }
  
  static const char * const cat_file_usage[] = {
-       N_("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv) <object>"),
-       N_("git cat-file (--batch | --batch-check) [--follow-symlinks]"),
 -      N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>"),
 -      N_("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters]"),
++      N_("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv | --filters) [--path=<path>] <object>"),
++      N_("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv | --filters]"),
        NULL
  };