17
17
#include "object-store.h"
18
18
#include "promisor-remote.h"
19
19
20
+ enum batch_mode {
21
+ BATCH_MODE_CONTENTS ,
22
+ BATCH_MODE_INFO ,
23
+ BATCH_MODE_QUEUE_AND_DISPATCH ,
24
+ };
25
+
20
26
struct batch_options {
21
27
int enabled ;
22
28
int follow_symlinks ;
23
- int print_contents ;
29
+ enum batch_mode batch_mode ;
24
30
int buffer_output ;
25
31
int all_objects ;
26
32
int unordered ;
27
- int cmdmode ; /* may be 'w' or 'c' for --filters or --textconv */
33
+ int transform_mode ; /* may be 'w' or 'c' for --filters or --textconv */
28
34
const char * format ;
29
35
};
30
36
@@ -302,19 +308,19 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
302
308
if (data -> type == OBJ_BLOB ) {
303
309
if (opt -> buffer_output )
304
310
fflush (stdout );
305
- if (opt -> cmdmode ) {
311
+ if (opt -> transform_mode ) {
306
312
char * contents ;
307
313
unsigned long size ;
308
314
309
315
if (!data -> rest )
310
316
die ("missing path for '%s'" , oid_to_hex (oid ));
311
317
312
- if (opt -> cmdmode == 'w' ) {
318
+ if (opt -> transform_mode == 'w' ) {
313
319
if (filter_object (data -> rest , 0100644 , oid ,
314
320
& contents , & size ))
315
321
die ("could not convert '%s' %s" ,
316
322
oid_to_hex (oid ), data -> rest );
317
- } else if (opt -> cmdmode == 'c' ) {
323
+ } else if (opt -> transform_mode == 'c' ) {
318
324
enum object_type type ;
319
325
if (!textconv_object (the_repository ,
320
326
data -> rest , 0100644 , oid ,
@@ -326,7 +332,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
326
332
die ("could not convert '%s' %s" ,
327
333
oid_to_hex (oid ), data -> rest );
328
334
} else
329
- BUG ("invalid cmdmode : %c" , opt -> cmdmode );
335
+ BUG ("invalid transform_mode : %c" , opt -> transform_mode );
330
336
batch_write (opt , contents , size );
331
337
free (contents );
332
338
} else {
@@ -386,7 +392,7 @@ static void batch_object_write(const char *obj_name,
386
392
strbuf_addch (scratch , '\n' );
387
393
batch_write (opt , scratch -> buf , scratch -> len );
388
394
389
- if (opt -> print_contents ) {
395
+ if (opt -> batch_mode == BATCH_MODE_CONTENTS ) {
390
396
print_object_or_die (opt , data );
391
397
batch_write (opt , "\n" , 1 );
392
398
}
@@ -508,6 +514,135 @@ static int batch_unordered_packed(const struct object_id *oid,
508
514
data );
509
515
}
510
516
517
+ typedef void (* parse_cmd_fn_t )(struct batch_options * , const char * ,
518
+ struct strbuf * , struct expand_data * );
519
+
520
+ struct queued_cmd {
521
+ parse_cmd_fn_t fn ;
522
+ char * line ;
523
+ };
524
+
525
+ static void parse_cmd_contents (struct batch_options * opt ,
526
+ const char * line ,
527
+ struct strbuf * output ,
528
+ struct expand_data * data )
529
+ {
530
+ opt -> batch_mode = BATCH_MODE_CONTENTS ;
531
+ batch_one_object (line , output , opt , data );
532
+ }
533
+
534
+ static void parse_cmd_info (struct batch_options * opt ,
535
+ const char * line ,
536
+ struct strbuf * output ,
537
+ struct expand_data * data )
538
+ {
539
+ opt -> batch_mode = BATCH_MODE_INFO ;
540
+ batch_one_object (line , output , opt , data );
541
+ }
542
+
543
+ static void dispatch_calls (struct batch_options * opt ,
544
+ struct strbuf * output ,
545
+ struct expand_data * data ,
546
+ struct queued_cmd * cmd ,
547
+ int nr )
548
+ {
549
+ int i ;
550
+
551
+ if (!opt -> buffer_output )
552
+ die (_ ("flush is only for --buffer mode" ));
553
+
554
+ for (i = 0 ; i < nr ; i ++ )
555
+ cmd [i ].fn (opt , cmd [i ].line , output , data );
556
+
557
+ fflush (stdout );
558
+ }
559
+
560
+ static void free_cmds (struct queued_cmd * cmd , size_t * nr )
561
+ {
562
+ size_t i ;
563
+
564
+ for (i = 0 ; i < * nr ; i ++ )
565
+ FREE_AND_NULL (cmd [i ].line );
566
+
567
+ * nr = 0 ;
568
+ }
569
+
570
+
571
+ static const struct parse_cmd {
572
+ const char * name ;
573
+ parse_cmd_fn_t fn ;
574
+ unsigned takes_args ;
575
+ } commands [] = {
576
+ { "contents" , parse_cmd_contents , 1 },
577
+ { "info" , parse_cmd_info , 1 },
578
+ { "flush" , NULL , 0 },
579
+ };
580
+
581
+ static void batch_objects_command (struct batch_options * opt ,
582
+ struct strbuf * output ,
583
+ struct expand_data * data )
584
+ {
585
+ struct strbuf input = STRBUF_INIT ;
586
+ struct queued_cmd * queued_cmd = NULL ;
587
+ size_t alloc = 0 , nr = 0 ;
588
+
589
+ while (!strbuf_getline (& input , stdin )) {
590
+ int i ;
591
+ const struct parse_cmd * cmd = NULL ;
592
+ const char * p = NULL , * cmd_end ;
593
+ struct queued_cmd call = {0 };
594
+
595
+ if (!input .len )
596
+ die (_ ("empty command in input" ));
597
+ if (isspace (* input .buf ))
598
+ die (_ ("whitespace before command: '%s'" ), input .buf );
599
+
600
+ for (i = 0 ; i < ARRAY_SIZE (commands ); i ++ ) {
601
+ if (!skip_prefix (input .buf , commands [i ].name , & cmd_end ))
602
+ continue ;
603
+
604
+ cmd = & commands [i ];
605
+ if (cmd -> takes_args ) {
606
+ if (* cmd_end != ' ' )
607
+ die (_ ("%s requires arguments" ),
608
+ commands [i ].name );
609
+
610
+ p = cmd_end + 1 ;
611
+ } else if (* cmd_end ) {
612
+ die (_ ("%s takes no arguments" ),
613
+ commands [i ].name );
614
+ }
615
+
616
+ break ;
617
+ }
618
+
619
+ if (!cmd )
620
+ die (_ ("unknown command: '%s'" ), input .buf );
621
+
622
+ if (!strcmp (cmd -> name , "flush" )) {
623
+ dispatch_calls (opt , output , data , queued_cmd , nr );
624
+ free_cmds (queued_cmd , & nr );
625
+ } else if (!opt -> buffer_output ) {
626
+ cmd -> fn (opt , p , output , data );
627
+ } else {
628
+ ALLOC_GROW (queued_cmd , nr + 1 , alloc );
629
+ call .fn = cmd -> fn ;
630
+ call .line = xstrdup_or_null (p );
631
+ queued_cmd [nr ++ ] = call ;
632
+ }
633
+ }
634
+
635
+ if (opt -> buffer_output &&
636
+ nr &&
637
+ !git_env_bool ("GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT" , 0 )) {
638
+ dispatch_calls (opt , output , data , queued_cmd , nr );
639
+ free_cmds (queued_cmd , & nr );
640
+ }
641
+
642
+ free (queued_cmd );
643
+ strbuf_release (& input );
644
+ }
645
+
511
646
static int batch_objects (struct batch_options * opt )
512
647
{
513
648
struct strbuf input = STRBUF_INIT ;
@@ -529,14 +664,14 @@ static int batch_objects(struct batch_options *opt)
529
664
strbuf_expand (& output , opt -> format , expand_format , & data );
530
665
data .mark_query = 0 ;
531
666
strbuf_release (& output );
532
- if (opt -> cmdmode )
667
+ if (opt -> transform_mode )
533
668
data .split_on_whitespace = 1 ;
534
669
535
670
/*
536
671
* If we are printing out the object, then always fill in the type,
537
672
* since we will want to decide whether or not to stream.
538
673
*/
539
- if (opt -> print_contents )
674
+ if (opt -> batch_mode == BATCH_MODE_CONTENTS )
540
675
data .info .typep = & data .type ;
541
676
542
677
if (opt -> all_objects ) {
@@ -590,6 +725,11 @@ static int batch_objects(struct batch_options *opt)
590
725
save_warning = warn_on_object_refname_ambiguity ;
591
726
warn_on_object_refname_ambiguity = 0 ;
592
727
728
+ if (opt -> batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH ) {
729
+ batch_objects_command (opt , & output , & data );
730
+ goto cleanup ;
731
+ }
732
+
593
733
while (strbuf_getline (& input , stdin ) != EOF ) {
594
734
if (data .split_on_whitespace ) {
595
735
/*
@@ -608,6 +748,7 @@ static int batch_objects(struct batch_options *opt)
608
748
batch_one_object (input .buf , & output , opt , & data );
609
749
}
610
750
751
+ cleanup :
611
752
strbuf_release (& input );
612
753
strbuf_release (& output );
613
754
warn_on_object_refname_ambiguity = save_warning ;
@@ -635,7 +776,16 @@ static int batch_option_callback(const struct option *opt,
635
776
}
636
777
637
778
bo -> enabled = 1 ;
638
- bo -> print_contents = !strcmp (opt -> long_name , "batch" );
779
+
780
+ if (!strcmp (opt -> long_name , "batch" ))
781
+ bo -> batch_mode = BATCH_MODE_CONTENTS ;
782
+ else if (!strcmp (opt -> long_name , "batch-check" ))
783
+ bo -> batch_mode = BATCH_MODE_INFO ;
784
+ else if (!strcmp (opt -> long_name , "batch-command" ))
785
+ bo -> batch_mode = BATCH_MODE_QUEUE_AND_DISPATCH ;
786
+ else
787
+ BUG ("%s given to batch-option-callback" , opt -> long_name );
788
+
639
789
bo -> format = arg ;
640
790
641
791
return 0 ;
@@ -654,7 +804,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
654
804
N_ ("git cat-file <type> <object>" ),
655
805
N_ ("git cat-file (-e | -p) <object>" ),
656
806
N_ ("git cat-file (-t | -s) [--allow-unknown-type] <object>" ),
657
- N_ ("git cat-file (--batch | --batch-check) [--batch-all-objects]\n"
807
+ N_ ("git cat-file (--batch | --batch-check | --batch-command ) [--batch-all-objects]\n"
658
808
" [--buffer] [--follow-symlinks] [--unordered]\n"
659
809
" [--textconv | --filters]" ),
660
810
N_ ("git cat-file (--textconv | --filters)\n"
@@ -683,6 +833,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
683
833
N_ ("like --batch, but don't emit <contents>" ),
684
834
PARSE_OPT_OPTARG | PARSE_OPT_NONEG ,
685
835
batch_option_callback ),
836
+ OPT_CALLBACK_F (0 , "batch-command" , & batch , N_ ("format" ),
837
+ N_ ("read commands from stdin" ),
838
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG ,
839
+ batch_option_callback ),
686
840
OPT_CMDMODE (0 , "batch-all-objects" , & opt ,
687
841
N_ ("with --batch[-check]: ignores stdin, batches all known objects" ), 'b' ),
688
842
/* Batch-specific options */
@@ -742,7 +896,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
742
896
/* Return early if we're in batch mode? */
743
897
if (batch .enabled ) {
744
898
if (opt_cw )
745
- batch .cmdmode = opt ;
899
+ batch .transform_mode = opt ;
746
900
else if (opt && opt != 'b' )
747
901
usage_msg_optf (_ ("'-%c' is incompatible with batch mode" ),
748
902
usage , options , opt );
0 commit comments