logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

git-mergetool--lib (10908B)


  1. # git-mergetool--lib is a shell library for common merge tool functions
  2. : ${MERGE_TOOLS_DIR=$(git --exec-path)/mergetools}
  3. IFS='
  4. '
  5. mode_ok () {
  6. if diff_mode
  7. then
  8. can_diff
  9. elif merge_mode
  10. then
  11. can_merge
  12. else
  13. false
  14. fi
  15. }
  16. is_available () {
  17. merge_tool_path=$(translate_merge_tool_path "$1") &&
  18. type "$merge_tool_path" >/dev/null 2>&1
  19. }
  20. list_config_tools () {
  21. section=$1
  22. line_prefix=${2:-}
  23. git config --get-regexp $section'\..*\.cmd' |
  24. while read -r key value
  25. do
  26. toolname=${key#$section.}
  27. toolname=${toolname%.cmd}
  28. printf "%s%s\n" "$line_prefix" "$toolname"
  29. done
  30. }
  31. show_tool_names () {
  32. condition=${1:-true} per_line_prefix=${2:-} preamble=${3:-}
  33. not_found_msg=${4:-}
  34. extra_content=${5:-}
  35. shown_any=
  36. ( cd "$MERGE_TOOLS_DIR" && ls ) | {
  37. while read scriptname
  38. do
  39. setup_tool "$scriptname" 2>/dev/null
  40. # We need an actual line feed here
  41. variants="$variants
  42. $(list_tool_variants)"
  43. done
  44. variants="$(echo "$variants" | sort -u)"
  45. for toolname in $variants
  46. do
  47. if setup_tool "$toolname" 2>/dev/null &&
  48. (eval "$condition" "$toolname")
  49. then
  50. if test -n "$preamble"
  51. then
  52. printf "%s\n" "$preamble"
  53. preamble=
  54. fi
  55. shown_any=yes
  56. printf "%s%-15s %s\n" "$per_line_prefix" "$toolname" $(diff_mode && diff_cmd_help "$toolname" || merge_cmd_help "$toolname")
  57. fi
  58. done
  59. if test -n "$extra_content"
  60. then
  61. if test -n "$preamble"
  62. then
  63. # Note: no '\n' here since we don't want a
  64. # blank line if there is no initial content.
  65. printf "%s" "$preamble"
  66. preamble=
  67. fi
  68. shown_any=yes
  69. printf "\n%s\n" "$extra_content"
  70. fi
  71. if test -n "$preamble" && test -n "$not_found_msg"
  72. then
  73. printf "%s\n" "$not_found_msg"
  74. fi
  75. test -n "$shown_any"
  76. }
  77. }
  78. diff_mode () {
  79. test "$TOOL_MODE" = diff
  80. }
  81. merge_mode () {
  82. test "$TOOL_MODE" = merge
  83. }
  84. get_gui_default () {
  85. if diff_mode
  86. then
  87. GUI_DEFAULT_KEY="difftool.guiDefault"
  88. else
  89. GUI_DEFAULT_KEY="mergetool.guiDefault"
  90. fi
  91. GUI_DEFAULT_CONFIG_LCASE=$(git config --default false --get "$GUI_DEFAULT_KEY" | tr 'A-Z' 'a-z')
  92. if test "$GUI_DEFAULT_CONFIG_LCASE" = "auto"
  93. then
  94. if test -n "$DISPLAY"
  95. then
  96. GUI_DEFAULT=true
  97. else
  98. GUI_DEFAULT=false
  99. fi
  100. else
  101. GUI_DEFAULT=$(git config --default false --bool --get "$GUI_DEFAULT_KEY")
  102. subshell_exit_status=$?
  103. if test $subshell_exit_status -ne 0
  104. then
  105. exit $subshell_exit_status
  106. fi
  107. fi
  108. echo $GUI_DEFAULT
  109. }
  110. gui_mode () {
  111. if test -z "$GIT_MERGETOOL_GUI"
  112. then
  113. GIT_MERGETOOL_GUI=$(get_gui_default)
  114. if test $? -ne 0
  115. then
  116. exit 2
  117. fi
  118. fi
  119. test "$GIT_MERGETOOL_GUI" = true
  120. }
  121. translate_merge_tool_path () {
  122. echo "$1"
  123. }
  124. check_unchanged () {
  125. if test "$MERGED" -nt "$BACKUP"
  126. then
  127. return 0
  128. else
  129. while true
  130. do
  131. echo "$MERGED seems unchanged."
  132. printf "Was the merge successful [y/n]? "
  133. read answer || return 1
  134. case "$answer" in
  135. y*|Y*) return 0 ;;
  136. n*|N*) return 1 ;;
  137. esac
  138. done
  139. fi
  140. }
  141. valid_tool () {
  142. setup_tool "$1" 2>/dev/null && return 0
  143. cmd=$(get_merge_tool_cmd "$1")
  144. test -n "$cmd"
  145. }
  146. setup_user_tool () {
  147. merge_tool_cmd=$(get_merge_tool_cmd "$tool")
  148. test -n "$merge_tool_cmd" || return 1
  149. diff_cmd () {
  150. ( eval $merge_tool_cmd )
  151. }
  152. merge_cmd () {
  153. ( eval $merge_tool_cmd )
  154. }
  155. list_tool_variants () {
  156. echo "$tool"
  157. }
  158. }
  159. setup_tool () {
  160. tool="$1"
  161. # Fallback definitions, to be overridden by tools.
  162. can_merge () {
  163. return 0
  164. }
  165. can_diff () {
  166. return 0
  167. }
  168. diff_cmd () {
  169. return 1
  170. }
  171. diff_cmd_help () {
  172. return 0
  173. }
  174. merge_cmd () {
  175. return 1
  176. }
  177. merge_cmd_help () {
  178. return 0
  179. }
  180. hide_resolved_enabled () {
  181. return 0
  182. }
  183. translate_merge_tool_path () {
  184. echo "$1"
  185. }
  186. list_tool_variants () {
  187. echo "$tool"
  188. }
  189. # Most tools' exit codes cannot be trusted, so By default we ignore
  190. # their exit code and check the merged file's modification time in
  191. # check_unchanged() to determine whether or not the merge was
  192. # successful. The return value from run_merge_cmd, by default, is
  193. # determined by check_unchanged().
  194. #
  195. # When a tool's exit code can be trusted then the return value from
  196. # run_merge_cmd is simply the tool's exit code, and check_unchanged()
  197. # is not called.
  198. #
  199. # The return value of exit_code_trustable() tells us whether or not we
  200. # can trust the tool's exit code.
  201. #
  202. # User-defined and built-in tools default to false.
  203. # Built-in tools advertise that their exit code is trustable by
  204. # redefining exit_code_trustable() to true.
  205. exit_code_trustable () {
  206. false
  207. }
  208. if test -f "$MERGE_TOOLS_DIR/$tool"
  209. then
  210. . "$MERGE_TOOLS_DIR/$tool"
  211. elif test -f "$MERGE_TOOLS_DIR/${tool%[0-9]}"
  212. then
  213. . "$MERGE_TOOLS_DIR/${tool%[0-9]}"
  214. else
  215. setup_user_tool
  216. rc=$?
  217. if test $rc -ne 0
  218. then
  219. echo >&2 "error: ${TOOL_MODE}tool.$tool.cmd not set for tool '$tool'"
  220. fi
  221. return $rc
  222. fi
  223. # Now let the user override the default command for the tool. If
  224. # they have not done so then this will return 1 which we ignore.
  225. setup_user_tool
  226. if ! list_tool_variants | grep -q "^$tool$"
  227. then
  228. echo "error: unknown tool variant '$tool'" >&2
  229. return 1
  230. fi
  231. if merge_mode && ! can_merge
  232. then
  233. echo "error: '$tool' can not be used to resolve merges" >&2
  234. return 1
  235. elif diff_mode && ! can_diff
  236. then
  237. echo "error: '$tool' can only be used to resolve merges" >&2
  238. return 1
  239. fi
  240. return 0
  241. }
  242. get_merge_tool_cmd () {
  243. merge_tool="$1"
  244. if diff_mode
  245. then
  246. git config "difftool.$merge_tool.cmd" ||
  247. git config "mergetool.$merge_tool.cmd"
  248. else
  249. git config "mergetool.$merge_tool.cmd"
  250. fi
  251. }
  252. trust_exit_code () {
  253. if git config --bool "mergetool.$1.trustExitCode"
  254. then
  255. :; # OK
  256. elif exit_code_trustable
  257. then
  258. echo true
  259. else
  260. echo false
  261. fi
  262. }
  263. initialize_merge_tool () {
  264. # Bring tool-specific functions into scope
  265. setup_tool "$1" || return 1
  266. }
  267. # Entry point for running tools
  268. run_merge_tool () {
  269. # If GIT_PREFIX is empty then we cannot use it in tools
  270. # that expect to be able to chdir() to its value.
  271. GIT_PREFIX=${GIT_PREFIX:-.}
  272. export GIT_PREFIX
  273. merge_tool_path=$(get_merge_tool_path "$1") || exit
  274. base_present="$2"
  275. if merge_mode
  276. then
  277. run_merge_cmd "$1"
  278. else
  279. run_diff_cmd "$1"
  280. fi
  281. }
  282. # Run a either a configured or built-in diff tool
  283. run_diff_cmd () {
  284. diff_cmd "$1"
  285. }
  286. # Run a either a configured or built-in merge tool
  287. run_merge_cmd () {
  288. mergetool_trust_exit_code=$(trust_exit_code "$1")
  289. if test "$mergetool_trust_exit_code" = "true"
  290. then
  291. merge_cmd "$1"
  292. else
  293. touch "$BACKUP"
  294. merge_cmd "$1"
  295. check_unchanged
  296. fi
  297. }
  298. list_merge_tool_candidates () {
  299. if merge_mode
  300. then
  301. tools="tortoisemerge"
  302. else
  303. tools="kompare"
  304. fi
  305. if test -n "$DISPLAY"
  306. then
  307. if test -n "$GNOME_DESKTOP_SESSION_ID"
  308. then
  309. tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
  310. else
  311. tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
  312. fi
  313. tools="$tools gvimdiff diffuse diffmerge ecmerge"
  314. tools="$tools p4merge araxis bc codecompare"
  315. tools="$tools smerge"
  316. fi
  317. case "${VISUAL:-$EDITOR}" in
  318. *nvim*)
  319. tools="$tools nvimdiff vimdiff emerge"
  320. ;;
  321. *vim*)
  322. tools="$tools vimdiff nvimdiff emerge"
  323. ;;
  324. *)
  325. tools="$tools emerge vimdiff nvimdiff"
  326. ;;
  327. esac
  328. }
  329. show_tool_help () {
  330. tool_opt="'git ${TOOL_MODE}tool --tool=<tool>'"
  331. tab=' '
  332. LF='
  333. '
  334. any_shown=no
  335. cmd_name=${TOOL_MODE}tool
  336. config_tools=$({
  337. diff_mode && list_config_tools difftool "$tab$tab"
  338. list_config_tools mergetool "$tab$tab"
  339. } | sort)
  340. extra_content=
  341. if test -n "$config_tools"
  342. then
  343. extra_content="${tab}user-defined:${LF}$config_tools"
  344. fi
  345. show_tool_names 'mode_ok && is_available' "$tab$tab" \
  346. "$tool_opt may be set to one of the following:" \
  347. "No suitable tool for 'git $cmd_name --tool=<tool>' found." \
  348. "$extra_content" &&
  349. any_shown=yes
  350. show_tool_names 'mode_ok && ! is_available' "$tab$tab" \
  351. "${LF}The following tools are valid, but not currently available:" &&
  352. any_shown=yes
  353. if test "$any_shown" = yes
  354. then
  355. echo
  356. echo "Some of the tools listed above only work in a windowed"
  357. echo "environment. If run in a terminal-only session, they will fail."
  358. fi
  359. exit 0
  360. }
  361. guess_merge_tool () {
  362. list_merge_tool_candidates
  363. cat >&2 <<-EOF
  364. This message is displayed because '$TOOL_MODE.tool' is not configured.
  365. See 'git ${TOOL_MODE}tool --tool-help' or 'git help config' for more details.
  366. 'git ${TOOL_MODE}tool' will now attempt to use one of the following tools:
  367. $tools
  368. EOF
  369. # Loop over each candidate and stop when a valid merge tool is found.
  370. IFS=' '
  371. for tool in $tools
  372. do
  373. is_available "$tool" && echo "$tool" && return 0
  374. done
  375. echo >&2 "No known ${TOOL_MODE} tool is available."
  376. return 1
  377. }
  378. get_configured_merge_tool () {
  379. keys=
  380. if diff_mode
  381. then
  382. if gui_mode
  383. then
  384. keys="diff.guitool merge.guitool diff.tool merge.tool"
  385. else
  386. keys="diff.tool merge.tool"
  387. fi
  388. else
  389. if gui_mode
  390. then
  391. keys="merge.guitool merge.tool"
  392. else
  393. keys="merge.tool"
  394. fi
  395. fi
  396. merge_tool=$(
  397. IFS=' '
  398. for key in $keys
  399. do
  400. selected=$(git config $key)
  401. if test -n "$selected"
  402. then
  403. echo "$selected"
  404. return
  405. fi
  406. done)
  407. if test -n "$merge_tool" && ! valid_tool "$merge_tool"
  408. then
  409. echo >&2 "git config option $TOOL_MODE.${gui_prefix}tool set to unknown tool: $merge_tool"
  410. echo >&2 "Resetting to default..."
  411. return 1
  412. fi
  413. echo "$merge_tool"
  414. }
  415. get_merge_tool_path () {
  416. # A merge tool has been set, so verify that it's valid.
  417. merge_tool="$1"
  418. if ! valid_tool "$merge_tool"
  419. then
  420. echo >&2 "Unknown $TOOL_MODE tool $merge_tool"
  421. exit 1
  422. fi
  423. if diff_mode
  424. then
  425. merge_tool_path=$(git config difftool."$merge_tool".path ||
  426. git config mergetool."$merge_tool".path)
  427. else
  428. merge_tool_path=$(git config mergetool."$merge_tool".path)
  429. fi
  430. if test -z "$merge_tool_path"
  431. then
  432. merge_tool_path=$(translate_merge_tool_path "$merge_tool")
  433. fi
  434. if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
  435. ! type "$merge_tool_path" >/dev/null 2>&1
  436. then
  437. echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
  438. "'$merge_tool_path'"
  439. exit 1
  440. fi
  441. echo "$merge_tool_path"
  442. }
  443. get_merge_tool () {
  444. is_guessed=false
  445. # Check if a merge tool has been configured
  446. merge_tool=$(get_configured_merge_tool)
  447. subshell_exit_status=$?
  448. if test $subshell_exit_status -gt "1"
  449. then
  450. exit $subshell_exit_status
  451. fi
  452. # Try to guess an appropriate merge tool if no tool has been set.
  453. if test -z "$merge_tool"
  454. then
  455. merge_tool=$(guess_merge_tool) || exit
  456. is_guessed=true
  457. fi
  458. echo "$merge_tool"
  459. test "$is_guessed" = false
  460. }
  461. mergetool_find_win32_cmd () {
  462. executable=$1
  463. sub_directory=$2
  464. # Use $executable if it exists in $PATH
  465. if type -p "$executable" >/dev/null 2>&1
  466. then
  467. printf '%s' "$executable"
  468. return
  469. fi
  470. # Look for executable in the typical locations
  471. for directory in $(env | grep -Ei '^PROGRAM(FILES(\(X86\))?|W6432)=' |
  472. cut -d '=' -f 2- | sort -u)
  473. do
  474. if test -n "$directory" && test -x "$directory/$sub_directory/$executable"
  475. then
  476. printf '%s' "$directory/$sub_directory/$executable"
  477. return
  478. fi
  479. done
  480. printf '%s' "$executable"
  481. }