1212 * Copyright (C) 2016 Johannes Schindelin 
1313 */ 
1414
15- #define  USE_THE_REPOSITORY_VARIABLE 
16- 
1715#include  "builtin.h" 
1816
1917#include  "abspath.h" 
3634#include  "entry.h" 
3735#include  "setup.h" 
3836
39- static  int  trust_exit_code ;
40- 
4137static  const  char  * const  builtin_difftool_usage [] =  {
4238	N_ ("git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]" ),
4339	NULL 
4440};
4541
42+ struct  difftool_options  {
43+ 	int  has_symlinks ;
44+ 	int  symlinks ;
45+ 	int  trust_exit_code ;
46+ };
47+ 
4648static  int  difftool_config (const  char  * var , const  char  * value ,
4749			   const  struct  config_context  * ctx , void  * cb )
4850{
51+ 	struct  difftool_options  * dt_options  =  (struct  difftool_options  * )cb ;
4952	if  (!strcmp (var , "difftool.trustexitcode" )) {
50- 		trust_exit_code  =  git_config_bool (var , value );
53+ 		dt_options -> trust_exit_code  =  git_config_bool (var , value );
54+ 		return  0 ;
55+ 	}
56+ 	if  (!strcmp (var , "core.symlinks" )) {
57+ 		dt_options -> has_symlinks  =  git_config_bool (var , value );
5158		return  0 ;
5259	}
5360
@@ -63,7 +70,8 @@ static int print_tool_help(void)
6370	return  run_command (& cmd );
6471}
6572
66- static  int  parse_index_info (char  * p , int  * mode1 , int  * mode2 ,
73+ static  int  parse_index_info (struct  repository  * repo ,
74+ 			    char  * p , int  * mode1 , int  * mode2 ,
6775			    struct  object_id  * oid1 , struct  object_id  * oid2 ,
6876			    char  * status )
6977{
@@ -75,11 +83,11 @@ static int parse_index_info(char *p, int *mode1, int *mode2,
7583	* mode2  =  (int )strtol (p  +  1 , & p , 8 );
7684	if  (* p  !=  ' ' )
7785		return  error ("expected ' ', got '%c'" , * p );
78- 	if  (parse_oid_hex (++ p , oid1 , (const  char  * * )& p ))
86+ 	if  (parse_oid_hex_algop (++ p , oid1 , (const  char  * * )& p ,  repo -> hash_algo ))
7987		return  error ("expected object ID, got '%s'" , p );
8088	if  (* p  !=  ' ' )
8189		return  error ("expected ' ', got '%c'" , * p );
82- 	if  (parse_oid_hex (++ p , oid2 , (const  char  * * )& p ))
90+ 	if  (parse_oid_hex_algop (++ p , oid2 , (const  char  * * )& p ,  repo -> hash_algo ))
8391		return  error ("expected object ID, got '%s'" , p );
8492	if  (* p  !=  ' ' )
8593		return  error ("expected ' ', got '%c'" , * p );
@@ -106,7 +114,8 @@ static void add_path(struct strbuf *buf, size_t base_len, const char *path)
106114/* 
107115 * Determine whether we can simply reuse the file in the worktree. 
108116 */ 
109- static  int  use_wt_file (const  char  * workdir , const  char  * name ,
117+ static  int  use_wt_file (struct  repository  * repo ,
118+ 		       const  char  * workdir , const  char  * name ,
110119		       struct  object_id  * oid )
111120{
112121	struct  strbuf  buf  =  STRBUF_INIT ;
@@ -121,7 +130,7 @@ static int use_wt_file(const char *workdir, const char *name,
121130		int  fd  =  open (buf .buf , O_RDONLY );
122131
123132		if  (fd  >= 0  && 
124- 		    !index_fd (the_repository -> index , & wt_oid , fd , & st , OBJ_BLOB , name , 0 )) {
133+ 		    !index_fd (repo -> index , & wt_oid , fd , & st , OBJ_BLOB , name , 0 )) {
125134			if  (is_null_oid (oid )) {
126135				oidcpy (oid , & wt_oid );
127136				use  =  1 ;
@@ -212,13 +221,14 @@ static int path_entry_cmp(const void *cmp_data UNUSED,
212221	return  strcmp (a -> path , key  ? key  : b -> path );
213222}
214223
215- static  void  changed_files (struct  hashmap  * result , const  char  * index_path ,
224+ static  void  changed_files (struct  repository  * repo ,
225+ 			  struct  hashmap  * result , const  char  * index_path ,
216226			  const  char  * workdir )
217227{
218228	struct  child_process  update_index  =  CHILD_PROCESS_INIT ;
219229	struct  child_process  diff_files  =  CHILD_PROCESS_INIT ;
220230	struct  strbuf  buf  =  STRBUF_INIT ;
221- 	const  char  * git_dir  =  absolute_path (repo_get_git_dir (the_repository ));
231+ 	const  char  * git_dir  =  absolute_path (repo_get_git_dir (repo ));
222232	FILE  * fp ;
223233
224234	strvec_pushl (& update_index .args ,
@@ -291,13 +301,15 @@ static int ensure_leading_directories(char *path)
291301 * to compare the readlink(2) result as text, even on a filesystem that is 
292302 * capable of doing a symbolic link. 
293303 */ 
294- static  char  * get_symlink (const  struct  object_id  * oid , const  char  * path )
304+ static  char  * get_symlink (struct  repository  * repo ,
305+ 			 struct  difftool_options  * dt_options ,
306+ 			 const  struct  object_id  * oid , const  char  * path )
295307{
296308	char  * data ;
297309	if  (is_null_oid (oid )) {
298310		/* The symlink is unknown to Git so read from the filesystem */ 
299311		struct  strbuf  link  =  STRBUF_INIT ;
300- 		if  (has_symlinks ) {
312+ 		if  (dt_options -> has_symlinks ) {
301313			if  (strbuf_readlink (& link , path , strlen (path )))
302314				die (_ ("could not read symlink %s" ), path );
303315		} else  if  (strbuf_read_file (& link , path , 128 ))
@@ -307,8 +319,7 @@ static char *get_symlink(const struct object_id *oid, const char *path)
307319	} else  {
308320		enum  object_type  type ;
309321		unsigned long  size ;
310- 		data  =  repo_read_object_file (the_repository , oid , & type ,
311- 					     & size );
322+ 		data  =  repo_read_object_file (repo , oid , & type , & size );
312323		if  (!data )
313324			die (_ ("could not read object %s for symlink %s" ),
314325				oid_to_hex (oid ), path );
@@ -355,7 +366,9 @@ static void write_standin_files(struct pair_entry *entry,
355366		write_file_in_directory (rdir , rdir_len , entry -> path , entry -> right );
356367}
357368
358- static  int  run_dir_diff (const  char  * extcmd , int  symlinks , const  char  * prefix ,
369+ static  int  run_dir_diff (struct  repository  * repo ,
370+ 			struct  difftool_options  * dt_options ,
371+ 			const  char  * extcmd , const  char  * prefix ,
359372			struct  child_process  * child )
360373{
361374	struct  strbuf  info  =  STRBUF_INIT , lpath  =  STRBUF_INIT ;
@@ -375,15 +388,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
375388	struct  hashmap  symlinks2  =  HASHMAP_INIT (pair_cmp , NULL );
376389	struct  hashmap_iter  iter ;
377390	struct  pair_entry  * entry ;
378- 	struct  index_state  wtindex  =  INDEX_STATE_INIT (the_repository );
391+ 	struct  index_state  wtindex  =  INDEX_STATE_INIT (repo );
379392	struct  checkout  lstate , rstate ;
380393	int  err  =  0 ;
381394	struct  child_process  cmd  =  CHILD_PROCESS_INIT ;
382395	struct  hashmap  wt_modified  =  HASHMAP_INIT (path_entry_cmp , NULL );
383396	struct  hashmap  tmp_modified  =  HASHMAP_INIT (path_entry_cmp , NULL );
384397	int  indices_loaded  =  0 ;
385398
386- 	workdir  =  repo_get_work_tree (the_repository );
399+ 	workdir  =  repo_get_work_tree (repo );
387400
388401	/* Setup temp directories */ 
389402	tmp  =  getenv ("TMPDIR" );
@@ -438,8 +451,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
438451			       "not supported in\n" 
439452			       "directory diff mode ('-d' and '--dir-diff')." ));
440453
441- 		if  (parse_index_info (info .buf , & lmode , & rmode , & loid , & roid ,
442- 				     & status ))
454+ 		if  (parse_index_info (repo , info .buf , & lmode , & rmode , & loid , & roid , & status ))
443455			break ;
444456		if  (strbuf_getline_nul (& lpath , fp ))
445457			break ;
@@ -469,13 +481,13 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
469481		}
470482
471483		if  (S_ISLNK (lmode )) {
472- 			char  * content  =  get_symlink (& loid , src_path );
484+ 			char  * content  =  get_symlink (repo ,  dt_options ,  & loid , src_path );
473485			add_left_or_right (& symlinks2 , src_path , content , 0 );
474486			free (content );
475487		}
476488
477489		if  (S_ISLNK (rmode )) {
478- 			char  * content  =  get_symlink (& roid , dst_path );
490+ 			char  * content  =  get_symlink (repo ,  dt_options ,  & roid , dst_path );
479491			add_left_or_right (& symlinks2 , dst_path , content , 1 );
480492			free (content );
481493		}
@@ -500,7 +512,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
500512			}
501513			hashmap_add (& working_tree_dups , & entry -> entry );
502514
503- 			if  (!use_wt_file (workdir , dst_path , & roid )) {
515+ 			if  (!use_wt_file (repo ,  workdir , dst_path , & roid )) {
504516				if  (checkout_path (rmode , & roid , dst_path ,
505517						  & rstate )) {
506518					ret  =  error ("could not write '%s'" ,
@@ -528,7 +540,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
528540					goto finish ;
529541				}
530542				add_path (& wtdir , wtdir_len , dst_path );
531- 				if  (symlinks ) {
543+ 				if  (dt_options -> symlinks ) {
532544					if  (symlink (wtdir .buf , rdir .buf )) {
533545						ret  =  error_errno ("could not symlink '%s' to '%s'" , wtdir .buf , rdir .buf );
534546						goto finish ;
@@ -614,7 +626,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
614626		if  (lstat (rdir .buf , & st ))
615627			continue ;
616628
617- 		if  ((symlinks  &&  S_ISLNK (st .st_mode )) ||  !S_ISREG (st .st_mode ))
629+ 		if  ((dt_options -> symlinks  &&  S_ISLNK (st .st_mode )) ||  !S_ISREG (st .st_mode ))
618630			continue ;
619631
620632		if  (!indices_loaded ) {
@@ -626,9 +638,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
626638				ret  =  error ("could not write %s" , buf .buf );
627639				goto finish ;
628640			}
629- 			changed_files (& wt_modified , buf .buf , workdir );
641+ 			changed_files (repo ,  & wt_modified , buf .buf , workdir );
630642			strbuf_setlen (& rdir , rdir_len );
631- 			changed_files (& tmp_modified , buf .buf , rdir .buf );
643+ 			changed_files (repo ,  & tmp_modified , buf .buf , rdir .buf );
632644			add_path (& rdir , rdir_len , name );
633645			indices_loaded  =  1 ;
634646		}
@@ -702,11 +714,15 @@ static int run_file_diff(int prompt, const char *prefix,
702714int  cmd_difftool (int  argc ,
703715		 const  char  * * argv ,
704716		 const  char  * prefix ,
705- 		 struct  repository  * repo   UNUSED )
717+ 		 struct  repository  * repo )
706718{
707- 	int  use_gui_tool  =  -1 , dir_diff  =  0 , prompt  =  -1 , symlinks  =  0 ,
708- 	    tool_help  =  0 , no_index  =  0 ;
719+ 	int  use_gui_tool  =  -1 , dir_diff  =  0 , prompt  =  -1 , tool_help  =  0 , no_index  =  0 ;
709720	static  char  * difftool_cmd  =  NULL , * extcmd  =  NULL ;
721+ 	struct  difftool_options  dt_options  =  {
722+ 		.has_symlinks  =  1 ,
723+ 		.symlinks  =  1 ,
724+ 		.trust_exit_code  =  0 
725+ 	};
710726	struct  option  builtin_difftool_options [] =  {
711727		OPT_BOOL ('g' , "gui" , & use_gui_tool ,
712728			 N_ ("use `diff.guitool` instead of `diff.tool`" )),
@@ -717,14 +733,14 @@ int cmd_difftool(int argc,
717733			0 , PARSE_OPT_NONEG ),
718734		OPT_SET_INT_F (0 , "prompt" , & prompt , NULL ,
719735			1 , PARSE_OPT_NONEG  | PARSE_OPT_HIDDEN ),
720- 		OPT_BOOL (0 , "symlinks" , & symlinks ,
736+ 		OPT_BOOL (0 , "symlinks" , & dt_options . symlinks ,
721737			 N_ ("use symlinks in dir-diff mode" )),
722738		OPT_STRING ('t' , "tool" , & difftool_cmd , N_ ("tool" ),
723739			   N_ ("use the specified diff tool" )),
724740		OPT_BOOL (0 , "tool-help" , & tool_help ,
725741			 N_ ("print a list of diff tools that may be used with " 
726742			    "`--tool`" )),
727- 		OPT_BOOL (0 , "trust-exit-code" , & trust_exit_code ,
743+ 		OPT_BOOL (0 , "trust-exit-code" , & dt_options . trust_exit_code ,
728744			 N_ ("make 'git-difftool' exit when an invoked diff " 
729745			    "tool returns a non-zero exit code" )),
730746		OPT_STRING ('x' , "extcmd" , & extcmd , N_ ("command" ),
@@ -734,8 +750,9 @@ int cmd_difftool(int argc,
734750	};
735751	struct  child_process  child  =  CHILD_PROCESS_INIT ;
736752
737- 	git_config (difftool_config , NULL );
738- 	symlinks  =  has_symlinks ;
753+ 	if  (repo )
754+ 		repo_config (repo , difftool_config , & dt_options );
755+ 	dt_options .symlinks  =  dt_options .has_symlinks ;
739756
740757	argc  =  parse_options (argc , argv , prefix , builtin_difftool_options ,
741758			     builtin_difftool_usage , PARSE_OPT_KEEP_UNKNOWN_OPT  |
@@ -749,8 +766,8 @@ int cmd_difftool(int argc,
749766
750767	if  (!no_index ){
751768		setup_work_tree ();
752- 		setenv (GIT_DIR_ENVIRONMENT , absolute_path (repo_get_git_dir (the_repository )), 1 );
753- 		setenv (GIT_WORK_TREE_ENVIRONMENT , absolute_path (repo_get_work_tree (the_repository )), 1 );
769+ 		setenv (GIT_DIR_ENVIRONMENT , absolute_path (repo_get_git_dir (repo )), 1 );
770+ 		setenv (GIT_WORK_TREE_ENVIRONMENT , absolute_path (repo_get_work_tree (repo )), 1 );
754771	} else  if  (dir_diff )
755772		die (_ ("options '%s' and '%s' cannot be used together" ), "--dir-diff" , "--no-index" );
756773
@@ -783,7 +800,7 @@ int cmd_difftool(int argc,
783800	}
784801
785802	setenv ("GIT_DIFFTOOL_TRUST_EXIT_CODE" ,
786- 	       trust_exit_code  ? "true"  : "false" , 1 );
803+ 	       dt_options . trust_exit_code  ? "true"  : "false" , 1 );
787804
788805	/* 
789806	 * In directory diff mode, 'git-difftool--helper' is called once 
@@ -799,6 +816,6 @@ int cmd_difftool(int argc,
799816	strvec_pushv (& child .args , argv );
800817
801818	if  (dir_diff )
802- 		return  run_dir_diff (extcmd ,  symlinks , prefix , & child );
819+ 		return  run_dir_diff (repo ,  & dt_options ,  extcmd , prefix , & child );
803820	return  run_file_diff (prompt , prefix , & child );
804821}
0 commit comments