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