@@ -17,9 +17,39 @@ struct batch_options {
17
17
int print_contents ;
18
18
int buffer_output ;
19
19
int all_objects ;
20
+ int cmdmode ; /* may be 'w' or 'c' for --filters or --textconv */
20
21
const char * format ;
21
22
};
22
23
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
+
23
53
static int cat_one_file (int opt , const char * exp_type , const char * obj_name ,
24
54
int unknown_type )
25
55
{
@@ -31,13 +61,19 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
31
61
struct object_info oi = {NULL };
32
62
struct strbuf sb = STRBUF_INIT ;
33
63
unsigned flags = LOOKUP_REPLACE_OBJECT ;
64
+ const char * path = force_path ;
34
65
35
66
if (unknown_type )
36
67
flags |= LOOKUP_UNKNOWN_OBJECT ;
37
68
38
69
if (get_sha1_with_context (obj_name , 0 , sha1 , & obj_context ))
39
70
die ("Not a valid object name %s" , obj_name );
40
71
72
+ if (!path )
73
+ path = obj_context .path ;
74
+ if (obj_context .mode == S_IFINVALID )
75
+ obj_context .mode = 0100644 ;
76
+
41
77
buf = NULL ;
42
78
switch (opt ) {
43
79
case 't' :
@@ -61,12 +97,23 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
61
97
case 'e' :
62
98
return !has_sha1_file (sha1 );
63
99
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
+
64
110
case 'c' :
65
- if (!obj_context . path [0 ])
111
+ if (!path [0 ])
66
112
die ("git cat-file --textconv %s: <object> must be <sha1:path>" ,
67
113
obj_name );
68
114
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 ))
70
117
break ;
71
118
72
119
case 'p' :
@@ -239,7 +286,32 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
239
286
if (data -> type == OBJ_BLOB ) {
240
287
if (opt -> buffer_output )
241
288
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 )
243
315
die ("unable to stream %s to stdout" , sha1_to_hex (sha1 ));
244
316
}
245
317
else {
@@ -376,6 +448,8 @@ static int batch_objects(struct batch_options *opt)
376
448
data .mark_query = 1 ;
377
449
strbuf_expand (& buf , opt -> format , expand_format , & data );
378
450
data .mark_query = 0 ;
451
+ if (opt -> cmdmode )
452
+ data .split_on_whitespace = 1 ;
379
453
380
454
if (opt -> all_objects ) {
381
455
struct object_info empty ;
@@ -440,8 +514,8 @@ static int batch_objects(struct batch_options *opt)
440
514
}
441
515
442
516
static 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] " ),
445
519
NULL
446
520
};
447
521
@@ -486,6 +560,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
486
560
OPT_CMDMODE ('p' , NULL , & opt , N_ ("pretty-print object's content" ), 'p' ),
487
561
OPT_CMDMODE (0 , "textconv" , & opt ,
488
562
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" )),
489
567
OPT_BOOL (0 , "allow-unknown-type" , & unknown_type ,
490
568
N_ ("allow -s and -t to work with broken/corrupt objects" )),
491
569
OPT_BOOL (0 , "buffer" , & batch .buffer_output , N_ ("buffer --batch output" )),
@@ -508,7 +586,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
508
586
argc = parse_options (argc , argv , prefix , options , cat_file_usage , 0 );
509
587
510
588
if (opt ) {
511
- if (argc == 1 )
589
+ if (batch .enabled && (opt == 'c' || opt == 'w' ))
590
+ batch .cmdmode = opt ;
591
+ else if (argc == 1 )
512
592
obj_name = argv [0 ];
513
593
else
514
594
usage_with_options (cat_file_usage , options );
@@ -520,14 +600,28 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
520
600
} else
521
601
usage_with_options (cat_file_usage , options );
522
602
}
523
- if (batch .enabled && (opt || argc )) {
524
- usage_with_options (cat_file_usage , options );
603
+ if (batch .enabled ) {
604
+ if (batch .cmdmode != opt || argc )
605
+ usage_with_options (cat_file_usage , options );
606
+ if (batch .cmdmode && batch .all_objects )
607
+ die ("--batch-all-objects cannot be combined with "
608
+ "--textconv nor with --filters" );
525
609
}
526
610
527
611
if ((batch .follow_symlinks || batch .all_objects ) && !batch .enabled ) {
528
612
usage_with_options (cat_file_usage , options );
529
613
}
530
614
615
+ if (force_path && opt != 'c' && opt != 'w' ) {
616
+ error ("--path=<path> needs --textconv or --filters" );
617
+ usage_with_options (cat_file_usage , options );
618
+ }
619
+
620
+ if (force_path && batch .enabled ) {
621
+ error ("--path=<path> incompatible with --batch" );
622
+ usage_with_options (cat_file_usage , options );
623
+ }
624
+
531
625
if (batch .buffer_output < 0 )
532
626
batch .buffer_output = batch .all_objects ;
533
627
0 commit comments