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