1515#include "unpack-trees.h"
1616#include "path-list.h"
1717#include "xdiff-interface.h"
18+ #include "interpolate.h"
1819#include "attr.h"
1920
2021static int subtree_merge ;
@@ -661,12 +662,14 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
661662}
662663
663664/* Low-level merge functions */
664- typedef int (* ll_merge_fn )(mmfile_t * orig ,
665+ typedef int (* ll_merge_fn )(const char * cmd ,
666+ mmfile_t * orig ,
665667 mmfile_t * src1 , const char * name1 ,
666668 mmfile_t * src2 , const char * name2 ,
667669 mmbuffer_t * result );
668670
669- static int ll_xdl_merge (mmfile_t * orig ,
671+ static int ll_xdl_merge (const char * cmd__unused ,
672+ mmfile_t * orig ,
670673 mmfile_t * src1 , const char * name1 ,
671674 mmfile_t * src2 , const char * name2 ,
672675 mmbuffer_t * result )
@@ -681,7 +684,8 @@ static int ll_xdl_merge(mmfile_t *orig,
681684 result );
682685}
683686
684- static int ll_union_merge (mmfile_t * orig ,
687+ static int ll_union_merge (const char * cmd__unused ,
688+ mmfile_t * orig ,
685689 mmfile_t * src1 , const char * name1 ,
686690 mmfile_t * src2 , const char * name2 ,
687691 mmbuffer_t * result )
@@ -690,7 +694,8 @@ static int ll_union_merge(mmfile_t *orig,
690694 long size ;
691695 const int marker_size = 7 ;
692696
693- int status = ll_xdl_merge (orig , src1 , NULL , src2 , NULL , result );
697+ int status = ll_xdl_merge (cmd__unused , orig ,
698+ src1 , NULL , src2 , NULL , result );
694699 if (status <= 0 )
695700 return status ;
696701 size = result -> size ;
@@ -721,7 +726,8 @@ static int ll_union_merge(mmfile_t *orig,
721726 return 0 ;
722727}
723728
724- static int ll_binary_merge (mmfile_t * orig ,
729+ static int ll_binary_merge (const char * cmd__unused ,
730+ mmfile_t * orig ,
725731 mmfile_t * src1 , const char * name1 ,
726732 mmfile_t * src2 , const char * name2 ,
727733 mmbuffer_t * result )
@@ -743,24 +749,169 @@ static struct {
743749 const char * name ;
744750 ll_merge_fn fn ;
745751} ll_merge_fns [] = {
746- { "text" , ll_xdl_merge },
747752 { "binary" , ll_binary_merge },
753+ { "text" , ll_xdl_merge },
748754 { "union" , ll_union_merge },
749755 { NULL , NULL },
750756};
751757
752- static ll_merge_fn find_ll_merge_fn ( void * merge_attr )
758+ static void create_temp ( mmfile_t * src , char * path )
753759{
760+ int fd ;
761+
762+ strcpy (path , ".merge_file_XXXXXX" );
763+ fd = mkstemp (path );
764+ if (fd < 0 )
765+ die ("unable to create temp-file" );
766+ if (write_in_full (fd , src -> ptr , src -> size ) != src -> size )
767+ die ("unable to write temp-file" );
768+ close (fd );
769+ }
770+
771+ static int ll_ext_merge (const char * cmd ,
772+ mmfile_t * orig ,
773+ mmfile_t * src1 , const char * name1 ,
774+ mmfile_t * src2 , const char * name2 ,
775+ mmbuffer_t * result )
776+ {
777+ char temp [3 ][50 ];
778+ char cmdbuf [2048 ];
779+ struct interp table [] = {
780+ { "%O" },
781+ { "%A" },
782+ { "%B" },
783+ };
784+ struct child_process child ;
785+ const char * args [20 ];
786+ int status , fd , i ;
787+ struct stat st ;
788+
789+ result -> ptr = NULL ;
790+ result -> size = 0 ;
791+ create_temp (orig , temp [0 ]);
792+ create_temp (src1 , temp [1 ]);
793+ create_temp (src2 , temp [2 ]);
794+
795+ interp_set_entry (table , 0 , temp [0 ]);
796+ interp_set_entry (table , 1 , temp [1 ]);
797+ interp_set_entry (table , 2 , temp [2 ]);
798+
799+ interpolate (cmdbuf , sizeof (cmdbuf ), cmd , table , 3 );
800+
801+ memset (& child , 0 , sizeof (child ));
802+ child .argv = args ;
803+ args [0 ] = "sh" ;
804+ args [1 ] = "-c" ;
805+ args [2 ] = cmdbuf ;
806+ args [3 ] = NULL ;
807+
808+ status = run_command (& child );
809+ if (status < - ERR_RUN_COMMAND_FORK )
810+ ; /* failure in run-command */
811+ else
812+ status = - status ;
813+ fd = open (temp [1 ], O_RDONLY );
814+ if (fd < 0 )
815+ goto bad ;
816+ if (fstat (fd , & st ))
817+ goto close_bad ;
818+ result -> size = st .st_size ;
819+ result -> ptr = xmalloc (result -> size + 1 );
820+ if (read_in_full (fd , result -> ptr , result -> size ) != result -> size ) {
821+ free (result -> ptr );
822+ result -> ptr = NULL ;
823+ result -> size = 0 ;
824+ }
825+ close_bad :
826+ close (fd );
827+ bad :
828+ for (i = 0 ; i < 3 ; i ++ )
829+ unlink (temp [i ]);
830+ return status ;
831+ }
832+
833+ /*
834+ * merge.default and merge.driver configuration items
835+ */
836+ static struct user_merge_fn {
837+ struct user_merge_fn * next ;
838+ const char * name ;
839+ char * cmdline ;
840+ char b_ [1 ];
841+ } * ll_user_merge_fns , * * ll_user_merge_fns_tail ;
842+
843+ static int read_merge_config (const char * var , const char * value )
844+ {
845+ struct user_merge_fn * fn ;
846+ int blen , nlen ;
847+
848+ if (strcmp (var , "merge.driver" ))
849+ return 0 ;
850+ if (!value )
851+ return error ("%s: lacks value" , var );
852+ /*
853+ * merge.driver is a multi-valued configuration, whose value is
854+ * of form:
855+ *
856+ * name command-line
857+ *
858+ * The command-line will be interpolated with the following
859+ * tokens and is given to the shell:
860+ *
861+ * %O - temporary file name for the merge base.
862+ * %A - temporary file name for our version.
863+ * %B - temporary file name for the other branches' version.
864+ *
865+ * The external merge driver should write the results in the file
866+ * named by %A, and signal that it has done with exit status 0.
867+ */
868+ for (nlen = -1 , blen = 0 ; value [blen ]; blen ++ )
869+ if (nlen < 0 && isspace (value [blen ]))
870+ nlen = blen ;
871+ if (nlen < 0 )
872+ return error ("%s '%s': lacks command line" , var , value );
873+ fn = xcalloc (1 , sizeof (struct user_merge_fn ) + blen + 1 );
874+ memcpy (fn -> b_ , value , blen + 1 );
875+ fn -> name = fn -> b_ ;
876+ fn -> b_ [nlen ] = 0 ;
877+ fn -> cmdline = fn -> b_ + nlen + 1 ;
878+ fn -> next = * ll_user_merge_fns_tail ;
879+ * ll_user_merge_fns_tail = fn ;
880+ return 0 ;
881+ }
882+
883+ static void initialize_ll_merge (void )
884+ {
885+ if (ll_user_merge_fns_tail )
886+ return ;
887+ ll_user_merge_fns_tail = & ll_user_merge_fns ;
888+ git_config (read_merge_config );
889+ }
890+
891+ static ll_merge_fn find_ll_merge_fn (void * merge_attr , const char * * cmdline )
892+ {
893+ struct user_merge_fn * fn ;
754894 const char * name ;
755895 int i ;
756896
757- if (ATTR_TRUE (merge_attr ) || ATTR_UNSET (merge_attr ))
897+ initialize_ll_merge ();
898+
899+ if (ATTR_TRUE (merge_attr ))
758900 return ll_xdl_merge ;
759901 else if (ATTR_FALSE (merge_attr ))
760902 return ll_binary_merge ;
903+ else if (ATTR_UNSET (merge_attr ))
904+ return ll_xdl_merge ;
905+ else
906+ name = merge_attr ;
907+
908+ for (fn = ll_user_merge_fns ; fn ; fn = fn -> next ) {
909+ if (!strcmp (fn -> name , name )) {
910+ * cmdline = fn -> cmdline ;
911+ return ll_ext_merge ;
912+ }
913+ }
761914
762- /* Otherwise merge_attr may name the merge function */
763- name = merge_attr ;
764915 for (i = 0 ; ll_merge_fns [i ].name ; i ++ )
765916 if (!strcmp (ll_merge_fns [i ].name , name ))
766917 return ll_merge_fns [i ].fn ;
@@ -793,6 +944,7 @@ static int ll_merge(mmbuffer_t *result_buf,
793944 int merge_status ;
794945 void * merge_attr ;
795946 ll_merge_fn fn ;
947+ const char * driver = NULL ;
796948
797949 name1 = xstrdup (mkpath ("%s:%s" , branch1 , a -> path ));
798950 name2 = xstrdup (mkpath ("%s:%s" , branch2 , b -> path ));
@@ -802,9 +954,10 @@ static int ll_merge(mmbuffer_t *result_buf,
802954 fill_mm (b -> sha1 , & src2 );
803955
804956 merge_attr = git_path_check_merge (a -> path );
805- fn = find_ll_merge_fn (merge_attr );
957+ fn = find_ll_merge_fn (merge_attr , & driver );
806958
807- merge_status = fn (& orig , & src1 , name1 , & src2 , name2 , result_buf );
959+ merge_status = fn (driver , & orig ,
960+ & src1 , name1 , & src2 , name2 , result_buf );
808961
809962 free (name1 );
810963 free (name2 );
0 commit comments