@@ -17,9 +17,39 @@ struct batch_options {
1717 int print_contents ;
1818 int buffer_output ;
1919 int all_objects ;
20+ int cmdmode ; /* may be 'w' or 'c' for --filters or --textconv */
2021 const char * format ;
2122};
2223
24+ static const char * force_path ;
25+
26+ static int filter_object (const char * path , unsigned mode ,
27+ const unsigned char * sha1 ,
28+ char * * buf , unsigned long * size )
29+ {
30+ enum object_type type ;
31+
32+ * buf = read_sha1_file (sha1 , & type , size );
33+ if (!* buf )
34+ return error (_ ("cannot read object %s '%s'" ),
35+ sha1_to_hex (sha1 ), path );
36+ if (type != OBJ_BLOB ) {
37+ free (* buf );
38+ return error (_ ("blob expected for %s '%s'" ),
39+ sha1_to_hex (sha1 ), path );
40+ }
41+ if (S_ISREG (mode )) {
42+ struct strbuf strbuf = STRBUF_INIT ;
43+ if (convert_to_working_tree (path , * buf , * size , & strbuf )) {
44+ free (* buf );
45+ * size = strbuf .len ;
46+ * buf = strbuf_detach (& strbuf , NULL );
47+ }
48+ }
49+
50+ return 0 ;
51+ }
52+
2353static int cat_one_file (int opt , const char * exp_type , const char * obj_name ,
2454 int unknown_type )
2555{
@@ -31,13 +61,19 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
3161 struct object_info oi = {NULL };
3262 struct strbuf sb = STRBUF_INIT ;
3363 unsigned flags = LOOKUP_REPLACE_OBJECT ;
64+ const char * path = force_path ;
3465
3566 if (unknown_type )
3667 flags |= LOOKUP_UNKNOWN_OBJECT ;
3768
3869 if (get_sha1_with_context (obj_name , 0 , sha1 , & obj_context ))
3970 die ("Not a valid object name %s" , obj_name );
4071
72+ if (!path )
73+ path = obj_context .path ;
74+ else if (obj_context .mode == S_IFINVALID )
75+ obj_context .mode = 0100644 ;
76+
4177 buf = NULL ;
4278 switch (opt ) {
4379 case 't' :
@@ -61,12 +97,23 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
6197 case 'e' :
6298 return !has_sha1_file (sha1 );
6399
100+ case 'w' :
101+ if (!path [0 ])
102+ die ("git cat-file --filters %s: <object> must be "
103+ "<sha1:path>" , obj_name );
104+
105+ if (filter_object (path , obj_context .mode ,
106+ sha1 , & buf , & size ))
107+ return -1 ;
108+ break ;
109+
64110 case 'c' :
65- if (!obj_context . path [0 ])
111+ if (!path [0 ])
66112 die ("git cat-file --textconv %s: <object> must be <sha1:path>" ,
67113 obj_name );
68114
69- if (textconv_object (obj_context .path , obj_context .mode , sha1 , 1 , & buf , & size ))
115+ if (textconv_object (path , obj_context .mode ,
116+ sha1 , 1 , & buf , & size ))
70117 break ;
71118
72119 case 'p' :
@@ -239,7 +286,32 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
239286 if (data -> type == OBJ_BLOB ) {
240287 if (opt -> buffer_output )
241288 fflush (stdout );
242- if (stream_blob_to_fd (1 , sha1 , NULL , 0 ) < 0 )
289+ if (opt -> cmdmode ) {
290+ char * contents ;
291+ unsigned long size ;
292+
293+ if (!data -> rest )
294+ die ("missing path for '%s'" , sha1_to_hex (sha1 ));
295+
296+ if (opt -> cmdmode == 'w' ) {
297+ if (filter_object (data -> rest , 0100644 , sha1 ,
298+ & contents , & size ))
299+ die ("could not convert '%s' %s" ,
300+ sha1_to_hex (sha1 ), data -> rest );
301+ } else if (opt -> cmdmode == 'c' ) {
302+ enum object_type type ;
303+ if (!textconv_object (data -> rest , 0100644 , sha1 ,
304+ 1 , & contents , & size ))
305+ contents = read_sha1_file (sha1 , & type ,
306+ & size );
307+ if (!contents )
308+ die ("could not convert '%s' %s" ,
309+ sha1_to_hex (sha1 ), data -> rest );
310+ } else
311+ die ("BUG: invalid cmdmode: %c" , opt -> cmdmode );
312+ batch_write (opt , contents , size );
313+ free (contents );
314+ } else if (stream_blob_to_fd (1 , sha1 , NULL , 0 ) < 0 )
243315 die ("unable to stream %s to stdout" , sha1_to_hex (sha1 ));
244316 }
245317 else {
@@ -376,6 +448,8 @@ static int batch_objects(struct batch_options *opt)
376448 data .mark_query = 1 ;
377449 strbuf_expand (& buf , opt -> format , expand_format , & data );
378450 data .mark_query = 0 ;
451+ if (opt -> cmdmode )
452+ data .split_on_whitespace = 1 ;
379453
380454 if (opt -> all_objects ) {
381455 struct object_info empty ;
@@ -440,8 +514,8 @@ static int batch_objects(struct batch_options *opt)
440514}
441515
442516static const char * const cat_file_usage [] = {
443- N_ ("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>" ),
444- N_ ("git cat-file (--batch | --batch-check) [--follow-symlinks]" ),
517+ N_ ("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>" ),
518+ N_ ("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters] " ),
445519 NULL
446520};
447521
@@ -473,7 +547,7 @@ static int batch_option_callback(const struct option *opt,
473547int cmd_cat_file (int argc , const char * * argv , const char * prefix )
474548{
475549 int opt = 0 ;
476- const char * exp_type = NULL , * obj_name = NULL ;
550+ const char * exp_type = NULL , * obj_name = NULL , * force_use_path = NULL ;
477551 struct batch_options batch = {0 };
478552 int unknown_type = 0 ;
479553
@@ -486,6 +560,14 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
486560 OPT_CMDMODE ('p' , NULL , & opt , N_ ("pretty-print object's content" ), 'p' ),
487561 OPT_CMDMODE (0 , "textconv" , & opt ,
488562 N_ ("for blob objects, run textconv on object's content" ), 'c' ),
563+ OPT_CMDMODE (0 , "filters" , & opt ,
564+ N_ ("for blob objects, run filters on object's content" ), 'w' ),
565+ OPT_STRING (0 , "path" , & force_path , N_ ("blob" ),
566+ N_ ("use a specific path for --textconv/--filters" )),
567+ OPT_CMDMODE (0 , "smudge" , & opt ,
568+ N_ ("deprecated, use --filters instead" ), 'W' ),
569+ OPT_STRING (0 , "use-path" , & force_use_path , N_ ("blob" ),
570+ N_ ("deprecated, use --path=<path> instead" )),
489571 OPT_BOOL (0 , "allow-unknown-type" , & unknown_type ,
490572 N_ ("allow -s and -t to work with broken/corrupt objects" )),
491573 OPT_BOOL (0 , "buffer" , & batch .buffer_output , N_ ("buffer --batch output" )),
@@ -507,8 +589,20 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
507589 batch .buffer_output = -1 ;
508590 argc = parse_options (argc , argv , prefix , options , cat_file_usage , 0 );
509591
592+ if (opt == 'W' ) {
593+ warning ("--smudge is deprecated, please use --filters instead" );
594+ opt = 'w' ;
595+ }
596+ if (force_use_path ) {
597+ warning ("--use-path=<path> is deprecated, please use "
598+ "--path=<path> instead" );
599+ force_path = force_use_path ;
600+ }
601+
510602 if (opt ) {
511- if (argc == 1 )
603+ if (batch .enabled && (opt == 'c' || opt == 'w' ))
604+ batch .cmdmode = opt ;
605+ else if (argc == 1 )
512606 obj_name = argv [0 ];
513607 else
514608 usage_with_options (cat_file_usage , options );
@@ -520,14 +614,28 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
520614 } else
521615 usage_with_options (cat_file_usage , options );
522616 }
523- if (batch .enabled && (opt || argc )) {
524- usage_with_options (cat_file_usage , options );
617+ if (batch .enabled ) {
618+ if (batch .cmdmode != opt || argc )
619+ usage_with_options (cat_file_usage , options );
620+ if (batch .cmdmode && batch .all_objects )
621+ die ("--batch-all-objects cannot be combined with "
622+ "--textconv nor with --filters" );
525623 }
526624
527625 if ((batch .follow_symlinks || batch .all_objects ) && !batch .enabled ) {
528626 usage_with_options (cat_file_usage , options );
529627 }
530628
629+ if (force_path && opt != 'c' && opt != 'w' ) {
630+ error ("--path=<path> needs --textconv or --filters" );
631+ usage_with_options (cat_file_usage , options );
632+ }
633+
634+ if (force_path && batch .enabled ) {
635+ error ("--path=<path> incompatible with --batch" );
636+ usage_with_options (cat_file_usage , options );
637+ }
638+
531639 if (batch .buffer_output < 0 )
532640 batch .buffer_output = batch .all_objects ;
533641
0 commit comments