]> Pileus Git - ~andy/git/blob - git-mergetool--lib.sh
mergetool--lib: don't call "exit" in setup_tool
[~andy/git] / git-mergetool--lib.sh
1 #!/bin/sh
2 # git-mergetool--lib is a library for common merge tool functions
3 diff_mode() {
4         test "$TOOL_MODE" = diff
5 }
6
7 merge_mode() {
8         test "$TOOL_MODE" = merge
9 }
10
11 translate_merge_tool_path () {
12         echo "$1"
13 }
14
15 check_unchanged () {
16         if test "$MERGED" -nt "$BACKUP"
17         then
18                 status=0
19         else
20                 while true
21                 do
22                         echo "$MERGED seems unchanged."
23                         printf "Was the merge successful? [y/n] "
24                         read answer || return 1
25                         case "$answer" in
26                         y*|Y*) status=0; break ;;
27                         n*|N*) status=1; break ;;
28                         esac
29                 done
30         fi
31 }
32
33 valid_tool_config () {
34         if test -n "$(get_merge_tool_cmd "$1")"
35         then
36                 return 0
37         else
38                 return 1
39         fi
40 }
41
42 valid_tool () {
43         setup_tool "$1" || valid_tool_config "$1"
44 }
45
46 setup_tool () {
47         case "$1" in
48         vim*|gvim*)
49                 tool=vim
50                 ;;
51         *)
52                 tool="$1"
53                 ;;
54         esac
55         mergetools="$(git --exec-path)/mergetools"
56
57         # Load the default definitions
58         . "$mergetools/defaults"
59         if ! test -f "$mergetools/$tool"
60         then
61                 # Use a special return code for this case since we want to
62                 # source "defaults" even when an explicit tool path is
63                 # configured since the user can use that to override the
64                 # default path in the scriptlet.
65                 return 2
66         fi
67
68         # Load the redefined functions
69         . "$mergetools/$tool"
70
71         if merge_mode && ! can_merge
72         then
73                 echo "error: '$tool' can not be used to resolve merges" >&2
74                 return 1
75         elif diff_mode && ! can_diff
76         then
77                 echo "error: '$tool' can only be used to resolve merges" >&2
78                 return 1
79         fi
80         return 0
81 }
82
83 get_merge_tool_cmd () {
84         # Prints the custom command for a merge tool
85         merge_tool="$1"
86         if diff_mode
87         then
88                 echo "$(git config difftool.$merge_tool.cmd ||
89                         git config mergetool.$merge_tool.cmd)"
90         else
91                 echo "$(git config mergetool.$merge_tool.cmd)"
92         fi
93 }
94
95 # Entry point for running tools
96 run_merge_tool () {
97         # If GIT_PREFIX is empty then we cannot use it in tools
98         # that expect to be able to chdir() to its value.
99         GIT_PREFIX=${GIT_PREFIX:-.}
100         export GIT_PREFIX
101
102         merge_tool_path="$(get_merge_tool_path "$1")" || exit
103         base_present="$2"
104         status=0
105
106         # Bring tool-specific functions into scope
107         setup_tool "$1"
108         exitcode=$?
109         case $exitcode in
110         0)
111                 :
112                 ;;
113         2)
114                 # The configured tool is not a built-in tool.
115                 test -n "$merge_tool_path" || return 1
116                 ;;
117         *)
118                 return $exitcode
119                 ;;
120         esac
121
122         if merge_mode
123         then
124                 run_merge_cmd "$1"
125         else
126                 run_diff_cmd "$1"
127         fi
128         return $status
129 }
130
131 # Run a either a configured or built-in diff tool
132 run_diff_cmd () {
133         merge_tool_cmd="$(get_merge_tool_cmd "$1")"
134         if test -n "$merge_tool_cmd"
135         then
136                 ( eval $merge_tool_cmd )
137                 status=$?
138                 return $status
139         else
140                 diff_cmd "$1"
141         fi
142 }
143
144 # Run a either a configured or built-in merge tool
145 run_merge_cmd () {
146         merge_tool_cmd="$(get_merge_tool_cmd "$1")"
147         if test -n "$merge_tool_cmd"
148         then
149                 trust_exit_code="$(git config --bool \
150                         mergetool."$1".trustExitCode || echo false)"
151                 if test "$trust_exit_code" = "false"
152                 then
153                         touch "$BACKUP"
154                         ( eval $merge_tool_cmd )
155                         status=$?
156                         check_unchanged
157                 else
158                         ( eval $merge_tool_cmd )
159                         status=$?
160                 fi
161                 return $status
162         else
163                 merge_cmd "$1"
164         fi
165 }
166
167 list_merge_tool_candidates () {
168         if merge_mode
169         then
170                 tools="tortoisemerge"
171         else
172                 tools="kompare"
173         fi
174         if test -n "$DISPLAY"
175         then
176                 if test -n "$GNOME_DESKTOP_SESSION_ID"
177                 then
178                         tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
179                 else
180                         tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
181                 fi
182                 tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
183         fi
184         case "${VISUAL:-$EDITOR}" in
185         *vim*)
186                 tools="$tools vimdiff emerge"
187                 ;;
188         *)
189                 tools="$tools emerge vimdiff"
190                 ;;
191         esac
192 }
193
194 show_tool_help () {
195         unavailable= available= LF='
196 '
197
198         scriptlets="$(git --exec-path)"/mergetools
199         for i in "$scriptlets"/*
200         do
201                 . "$scriptlets"/defaults
202                 . "$i"
203
204                 tool="$(basename "$i")"
205                 if test "$tool" = "defaults"
206                 then
207                         continue
208                 elif merge_mode && ! can_merge
209                 then
210                         continue
211                 elif diff_mode && ! can_diff
212                 then
213                         continue
214                 fi
215
216                 merge_tool_path=$(translate_merge_tool_path "$tool")
217                 if type "$merge_tool_path" >/dev/null 2>&1
218                 then
219                         available="$available$tool$LF"
220                 else
221                         unavailable="$unavailable$tool$LF"
222                 fi
223         done
224
225         cmd_name=${TOOL_MODE}tool
226         if test -n "$available"
227         then
228                 echo "'git $cmd_name --tool=<tool>' may be set to one of the following:"
229                 echo "$available" | sort | sed -e 's/^/ /'
230         else
231                 echo "No suitable tool for 'git $cmd_name --tool=<tool>' found."
232         fi
233         if test -n "$unavailable"
234         then
235                 echo
236                 echo 'The following tools are valid, but not currently available:'
237                 echo "$unavailable" | sort | sed -e 's/^/       /'
238         fi
239         if test -n "$unavailable$available"
240         then
241                 echo
242                 echo "Some of the tools listed above only work in a windowed"
243                 echo "environment. If run in a terminal-only session, they will fail."
244         fi
245         exit 0
246 }
247
248 guess_merge_tool () {
249         list_merge_tool_candidates
250         echo >&2 "merge tool candidates: $tools"
251
252         # Loop over each candidate and stop when a valid merge tool is found.
253         for i in $tools
254         do
255                 merge_tool_path="$(translate_merge_tool_path "$i")"
256                 if type "$merge_tool_path" >/dev/null 2>&1
257                 then
258                         echo "$i"
259                         return 0
260                 fi
261         done
262
263         echo >&2 "No known merge resolution program available."
264         return 1
265 }
266
267 get_configured_merge_tool () {
268         # Diff mode first tries diff.tool and falls back to merge.tool.
269         # Merge mode only checks merge.tool
270         if diff_mode
271         then
272                 merge_tool=$(git config diff.tool || git config merge.tool)
273         else
274                 merge_tool=$(git config merge.tool)
275         fi
276         if test -n "$merge_tool" && ! valid_tool "$merge_tool"
277         then
278                 echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
279                 echo >&2 "Resetting to default..."
280                 return 1
281         fi
282         echo "$merge_tool"
283 }
284
285 get_merge_tool_path () {
286         # A merge tool has been set, so verify that it's valid.
287         merge_tool="$1"
288         if ! valid_tool "$merge_tool"
289         then
290                 echo >&2 "Unknown merge tool $merge_tool"
291                 exit 1
292         fi
293         if diff_mode
294         then
295                 merge_tool_path=$(git config difftool."$merge_tool".path ||
296                                   git config mergetool."$merge_tool".path)
297         else
298                 merge_tool_path=$(git config mergetool."$merge_tool".path)
299         fi
300         if test -z "$merge_tool_path"
301         then
302                 merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
303         fi
304         if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
305                 ! type "$merge_tool_path" >/dev/null 2>&1
306         then
307                 echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
308                          "'$merge_tool_path'"
309                 exit 1
310         fi
311         echo "$merge_tool_path"
312 }
313
314 get_merge_tool () {
315         # Check if a merge tool has been configured
316         merge_tool="$(get_configured_merge_tool)"
317         # Try to guess an appropriate merge tool if no tool has been set.
318         if test -z "$merge_tool"
319         then
320                 merge_tool="$(guess_merge_tool)" || exit
321         fi
322         echo "$merge_tool"
323 }