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