@@ -496,6 +496,7 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
496496
497497#define CAP_CLEAN (1u<<0)
498498#define CAP_SMUDGE (1u<<1)
499+ #define CAP_DELAY (1u<<2)
499500
500501struct cmd2process {
501502 struct subprocess_entry subprocess ; /* must be the first member! */
@@ -521,6 +522,7 @@ static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
521522 } known_caps [] = {
522523 { "clean" , CAP_CLEAN },
523524 { "smudge" , CAP_SMUDGE },
525+ { "delay" , CAP_DELAY },
524526 };
525527
526528 sigchain_push (SIGPIPE , SIG_IGN );
@@ -605,9 +607,11 @@ static void handle_filter_error(const struct strbuf *filter_status,
605607
606608static int apply_multi_file_filter (const char * path , const char * src , size_t len ,
607609 int fd , struct strbuf * dst , const char * cmd ,
608- const unsigned int wanted_capability )
610+ const unsigned int wanted_capability ,
611+ struct delayed_checkout * dco )
609612{
610613 int err ;
614+ int can_delay = 0 ;
611615 struct cmd2process * entry ;
612616 struct child_process * process ;
613617 struct strbuf nbuf = STRBUF_INIT ;
@@ -662,6 +666,14 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
662666 if (err )
663667 goto done ;
664668
669+ if ((entry -> supported_capabilities & CAP_DELAY ) &&
670+ dco && dco -> state == CE_CAN_DELAY ) {
671+ can_delay = 1 ;
672+ err = packet_write_fmt_gently (process -> in , "can-delay=1\n" );
673+ if (err )
674+ goto done ;
675+ }
676+
665677 err = packet_flush_gently (process -> in );
666678 if (err )
667679 goto done ;
@@ -677,14 +689,73 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
677689 if (err )
678690 goto done ;
679691
680- err = strcmp (filter_status .buf , "success" );
692+ if (can_delay && !strcmp (filter_status .buf , "delayed" )) {
693+ string_list_insert (& dco -> filters , cmd );
694+ string_list_insert (& dco -> paths , path );
695+ } else {
696+ /* The filter got the blob and wants to send us a response. */
697+ err = strcmp (filter_status .buf , "success" );
698+ if (err )
699+ goto done ;
700+
701+ err = read_packetized_to_strbuf (process -> out , & nbuf ) < 0 ;
702+ if (err )
703+ goto done ;
704+
705+ err = subprocess_read_status (process -> out , & filter_status );
706+ if (err )
707+ goto done ;
708+
709+ err = strcmp (filter_status .buf , "success" );
710+ }
711+
712+ done :
713+ sigchain_pop (SIGPIPE );
714+
715+ if (err )
716+ handle_filter_error (& filter_status , entry , wanted_capability );
717+ else
718+ strbuf_swap (dst , & nbuf );
719+ strbuf_release (& nbuf );
720+ return !err ;
721+ }
722+
723+
724+ int async_query_available_blobs (const char * cmd , struct string_list * available_paths )
725+ {
726+ int err ;
727+ char * line ;
728+ struct cmd2process * entry ;
729+ struct child_process * process ;
730+ struct strbuf filter_status = STRBUF_INIT ;
731+
732+ assert (subprocess_map_initialized );
733+ entry = (struct cmd2process * )subprocess_find_entry (& subprocess_map , cmd );
734+ if (!entry ) {
735+ error ("external filter '%s' is not available anymore although "
736+ "not all paths have been filtered" , cmd );
737+ return 0 ;
738+ }
739+ process = & entry -> subprocess .process ;
740+ sigchain_push (SIGPIPE , SIG_IGN );
741+
742+ err = packet_write_fmt_gently (
743+ process -> in , "command=list_available_blobs\n" );
681744 if (err )
682745 goto done ;
683746
684- err = read_packetized_to_strbuf (process -> out , & nbuf ) < 0 ;
747+ err = packet_flush_gently (process -> in ) ;
685748 if (err )
686749 goto done ;
687750
751+ while ((line = packet_read_line (process -> out , NULL ))) {
752+ const char * path ;
753+ if (skip_prefix (line , "pathname=" , & path ))
754+ string_list_insert (available_paths , xstrdup (path ));
755+ else
756+ ; /* ignore unknown keys */
757+ }
758+
688759 err = subprocess_read_status (process -> out , & filter_status );
689760 if (err )
690761 goto done ;
@@ -695,10 +766,7 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
695766 sigchain_pop (SIGPIPE );
696767
697768 if (err )
698- handle_filter_error (& filter_status , entry , wanted_capability );
699- else
700- strbuf_swap (dst , & nbuf );
701- strbuf_release (& nbuf );
769+ handle_filter_error (& filter_status , entry , 0 );
702770 return !err ;
703771}
704772
@@ -713,7 +781,8 @@ static struct convert_driver {
713781
714782static int apply_filter (const char * path , const char * src , size_t len ,
715783 int fd , struct strbuf * dst , struct convert_driver * drv ,
716- const unsigned int wanted_capability )
784+ const unsigned int wanted_capability ,
785+ struct delayed_checkout * dco )
717786{
718787 const char * cmd = NULL ;
719788
@@ -731,7 +800,8 @@ static int apply_filter(const char *path, const char *src, size_t len,
731800 if (cmd && * cmd )
732801 return apply_single_file_filter (path , src , len , fd , dst , cmd );
733802 else if (drv -> process && * drv -> process )
734- return apply_multi_file_filter (path , src , len , fd , dst , drv -> process , wanted_capability );
803+ return apply_multi_file_filter (path , src , len , fd , dst ,
804+ drv -> process , wanted_capability , dco );
735805
736806 return 0 ;
737807}
@@ -1072,7 +1142,7 @@ int would_convert_to_git_filter_fd(const char *path)
10721142 if (!ca .drv -> required )
10731143 return 0 ;
10741144
1075- return apply_filter (path , NULL , 0 , -1 , NULL , ca .drv , CAP_CLEAN );
1145+ return apply_filter (path , NULL , 0 , -1 , NULL , ca .drv , CAP_CLEAN , NULL );
10761146}
10771147
10781148const char * get_convert_attr_ascii (const char * path )
@@ -1109,7 +1179,7 @@ int convert_to_git(const char *path, const char *src, size_t len,
11091179
11101180 convert_attrs (& ca , path );
11111181
1112- ret |= apply_filter (path , src , len , -1 , dst , ca .drv , CAP_CLEAN );
1182+ ret |= apply_filter (path , src , len , -1 , dst , ca .drv , CAP_CLEAN , NULL );
11131183 if (!ret && ca .drv && ca .drv -> required )
11141184 die ("%s: clean filter '%s' failed" , path , ca .drv -> name );
11151185
@@ -1134,7 +1204,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,
11341204 assert (ca .drv );
11351205 assert (ca .drv -> clean || ca .drv -> process );
11361206
1137- if (!apply_filter (path , NULL , 0 , fd , dst , ca .drv , CAP_CLEAN ))
1207+ if (!apply_filter (path , NULL , 0 , fd , dst , ca .drv , CAP_CLEAN , NULL ))
11381208 die ("%s: clean filter '%s' failed" , path , ca .drv -> name );
11391209
11401210 crlf_to_git (path , dst -> buf , dst -> len , dst , ca .crlf_action , checksafe );
@@ -1143,7 +1213,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,
11431213
11441214static int convert_to_working_tree_internal (const char * path , const char * src ,
11451215 size_t len , struct strbuf * dst ,
1146- int normalizing )
1216+ int normalizing , struct delayed_checkout * dco )
11471217{
11481218 int ret = 0 , ret_filter = 0 ;
11491219 struct conv_attrs ca ;
@@ -1168,21 +1238,29 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
11681238 }
11691239 }
11701240
1171- ret_filter = apply_filter (path , src , len , -1 , dst , ca .drv , CAP_SMUDGE );
1241+ ret_filter = apply_filter (
1242+ path , src , len , -1 , dst , ca .drv , CAP_SMUDGE , dco );
11721243 if (!ret_filter && ca .drv && ca .drv -> required )
11731244 die ("%s: smudge filter %s failed" , path , ca .drv -> name );
11741245
11751246 return ret | ret_filter ;
11761247}
11771248
1249+ int async_convert_to_working_tree (const char * path , const char * src ,
1250+ size_t len , struct strbuf * dst ,
1251+ void * dco )
1252+ {
1253+ return convert_to_working_tree_internal (path , src , len , dst , 0 , dco );
1254+ }
1255+
11781256int convert_to_working_tree (const char * path , const char * src , size_t len , struct strbuf * dst )
11791257{
1180- return convert_to_working_tree_internal (path , src , len , dst , 0 );
1258+ return convert_to_working_tree_internal (path , src , len , dst , 0 , NULL );
11811259}
11821260
11831261int renormalize_buffer (const char * path , const char * src , size_t len , struct strbuf * dst )
11841262{
1185- int ret = convert_to_working_tree_internal (path , src , len , dst , 1 );
1263+ int ret = convert_to_working_tree_internal (path , src , len , dst , 1 , NULL );
11861264 if (ret ) {
11871265 src = dst -> buf ;
11881266 len = dst -> len ;
0 commit comments