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