threads / patch / 39318

v2mergetools: add winmerge as a builtin tool

Subject: [PATCH v2] mergetools: add winmerge as a builtin tool

## tl;dr

14 messages between May 13, 2015 and May 20, 2015. Diffs are folded; open one to read it.

replies: 13people: 4as markdown or json

David Aguilar· May 13, 2015, 02:00 UTC · lore

Add a winmerge scriptlet with the commands described in [1] so that users can use winmerge without needing to perform any additional configuration.

[1] http://thread.gmane.org/gmane.comp.version-control.git/268631
Helped-by: Philip Oakley <philipoakley@iee.org>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Changes since v1: we now honor the $ProgramW6432 environment variable.
 mergetools/winmerge | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 mergetools/winmerge
Show changes to mergetools/winmerge +40 −0
diff --git a/mergetools/winmerge b/mergetools/winmerge
new file mode 100644
index 0000000..db0b060
--- /dev/null
+++ b/mergetools/winmerge
@@ -0,0 +1,40 @@
+diff_cmd () {
+	"$merge_tool_path" -u -e "$LOCAL" "$REMOTE"
+	return 0
+}
+
+merge_cmd () {
+	# mergetool.winmerge.trustExitCode is implicitly false.
+	# touch $BACKUP so that we can check_unchanged.
+	touch "$BACKUP"
+	"$merge_tool_path" -u -e -dl Local -dr Remote \
+		"$LOCAL" "$REMOTE" "$MERGED"
+	check_unchanged
+}
+
+translate_merge_tool_path() {
+	# Use WinMergeU.exe if it exists in $PATH
+	if type WinMergeU.exe >/dev/null 2>&1
+	then
+		echo WinMergeU.exe
+		return
+	fi
+
+	# Look for WinMergeU.exe in the typical locations
+	winmerge_exe="WinMerge/WinMergeU.exe"
+	if test -n "$ProgramW6432" && test -x "$ProgramW6432/$winmerge_exe"
+	then
+		printf '%s' "$ProgramW6432/$winmerge_exe"
+	elif test -n "$PROGRAMFILES" && test -x "$PROGRAMFILES/$winmerge_exe"
+	then
+		printf '%s' "$PROGRAMFILES/$winmerge_exe"
+	elif test -x "/c/Program Files (x86)/$winmerge_exe"
+	then
+		printf '%s' "/c/Program Files (x86)/$winmerge_exe"
+	elif test -x "/c/Program Files/$winmerge_exe"
+	then
+		printf '%s' "/c/Program Files/$winmerge_exe"
+	else
+		echo WinMergeU.exe
+	fi
+}
-- 
1.8.5.3
Johannes Schindelin· May 13, 2015, 08:10 UTC · re: David Aguilar · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

Hi David,
On 2015-05-13 04:00, David Aguilar wrote:
Show 6 quoted lines
> +	if test -n "$ProgramW6432" && test -x "$ProgramW6432/$winmerge_exe"
> +	then
> +		printf '%s' "$ProgramW6432/$winmerge_exe"
> +	elif test -n "$PROGRAMFILES" && test -x "$PROGRAMFILES/$winmerge_exe"
> +	then
> +		printf '%s' "$PROGRAMFILES/$winmerge_exe"
I am terribly sorry that I confused you... What I *meant* was to test in the following order: $PROGRAMFILES, $ProgramW6432, /c/Program Files, /c/Program Files (x86).
While I am already nitpicking, I would also like to throw out the idea to write that in a loop instead (a little bit more DRY):
for directory in "$PROGRAMFILES" "$ProgramW6432" '/c/Program Files' '/c/Program Files (x86)'
do
    test -n "$directory" &&
    test -x "$directory/$winmerge_exe" &&
    echo "$directory/$winmerge_exe" &&
    break
done

Ciao, Dscho

Sebastian Schuberth· May 13, 2015, 13:19 UTC · re: David Aguilar · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On 13.05.2015 04:00, David Aguilar wrote:
> +	if test -n "$ProgramW6432" && test -x "$ProgramW6432/$winmerge_exe"
> +	then
> +		printf '%s' "$ProgramW6432/$winmerge_exe"

I don't think it makes sense to check "$ProgramW6432". The content of that variable depends on the bitness of the process requesting the environment. Just checking "$PROGRAMFILES" and "$PROGRAMFILES(X86)" should be sufficient and more clear.

Also, note that you should use all upper case names when referring to Windows environment variables. While it's true that on plain Windows environment variable names are case-insensitive, MSYS1/2 converts all variable names to upper case and *is* case sensitive. I.e. while "echo $PROGRAMFILES" works as expected from a Git Bash on Windows, "echo $ProgramFiles" results in an empty string.

 > +	elif test -x "/c/Program Files (x86)/$winmerge_exe"
 > +	then
 > +		printf '%s' "/c/Program Files (x86)/$winmerge_exe"
 > +	elif test -x "/c/Program Files/$winmerge_exe"
 > +	then
 > +		printf '%s' "/c/Program Files/$winmerge_exe"

I also think these fallbacks can simply go away. It is *very* unlikely that "$PROGRAMFILES" / "$PROGRAMFILES(X86)" point to something else but WinMerge still is installed there.

-- 
Sebastian Schuberth
Johannes Schindelin· May 13, 2015, 15:22 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

Hi,
On 2015-05-13 15:19, Sebastian Schuberth wrote:
Show 10 quoted lines
> On 13.05.2015 04:00, David Aguilar wrote:
> 
>> +	if test -n "$ProgramW6432" && test -x "$ProgramW6432/$winmerge_exe"
>> +	then
>> +		printf '%s' "$ProgramW6432/$winmerge_exe"
> 
> I don't think it makes sense to check "$ProgramW6432". The content of
> that variable depends on the bitness of the process requesting the
> environment. Just checking "$PROGRAMFILES" and "$PROGRAMFILES(X86)"
> should be sufficient and more clear.
In my tests, "$PROGRAMFILES(X86)" did *not* work:
    $ echo "$PROGRAMFILES(X86)"
    bash: syntax error near unexpected token `('
Show 6 quoted lines
> Also, note that you should use all upper case names when referring to
> Windows environment variables. While it's true that on plain Windows
> environment variable names are case-insensitive, MSYS1/2 converts all
> variable names to upper case and *is* case sensitive. I.e. while "echo
> $PROGRAMFILES" works as expected from a Git Bash on Windows, "echo
> $ProgramFiles" results in an empty string.
Exactly. In my tests, "$ProgramW6432" worked, while "$PROGRAMW6432" did not.
FWIW I think that the idea to test for a WinMerge executable of another bitness makes sense, because we can execute an executable of another bitness (unlike a .dll of another bitness).

Ciao, Johannes

Sebastian Schuberth· May 13, 2015, 15:33 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On Wed, May 13, 2015 at 5:22 PM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

> In my tests, "$PROGRAMFILES(X86)" did *not* work:
>
>     $ echo "$PROGRAMFILES(X86)"
>     bash: syntax error near unexpected token `('
Interesting. In both MSYS1/2 Git Bashes I get on Windows 7 64-bit:

$ echo "$PROGRAMFILES(X86)" C:\Program Files (x86)(X86)

So it seems to resolve only the $PROGRAMFILES part and appending the literal "(X86)". Not sure how to tell Bash that "(X86)" is part of the variable name.

> Exactly. In my tests, "$ProgramW6432" worked, while "$PROGRAMW6432" did not.
Very odd indeed that for me it's the exact opposite.
> FWIW I think that the idea to test for a WinMerge executable of another bitness makes sense, because we can execute an executable of another bitness (unlike a .dll of another bitness).

I agree it makes sense to check for both 64-bit and 32-bit WinMerge installations. But IMO it does not make sense to mix in the bitness of the process requesting the environment as part of running the mergetools/winmerge script, which is what we do by querying "$ProgramW6432" / "$PROGRAMW6432" .

-- 
Sebastian Schuberth
Sebastian Schuberth· May 13, 2015, 20:00 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On 13.05.2015 17:33, Sebastian Schuberth wrote:
Show 17 quoted lines
>> In my tests, "$PROGRAMFILES(X86)" did *not* work:
>>
>>      $ echo "$PROGRAMFILES(X86)"
>>      bash: syntax error near unexpected token `('
> 
> Interesting. In both MSYS1/2 Git Bashes I get on Windows 7 64-bit:
> 
> $ echo "$PROGRAMFILES(X86)"
> C:\Program Files (x86)(X86)
> 
> So it seems to resolve only the $PROGRAMFILES part and appending the
> literal "(X86)". Not sure how to tell Bash that "(X86)" is part of the
> variable name.
> 
>> Exactly. In my tests, "$ProgramW6432" worked, while "$PROGRAMW6432" did not.
> 
> Very odd indeed that for me it's the exact opposite.
So how about something like this which hopefully covers all cases (including case-sensitivity issues regarding environment variable names and the problem of querying a variable that contains parentheses as part of its name):
for directory in "$(env | sed -nr 's/^PROGRAM(FILES(\(X86\))?|W6432)=//pI')"
do
    test -n "$directory" &&
    test -x "$directory/$winmerge_exe" &&
    echo "$directory/$winmerge_exe" &&
    break
done
sed's "I" seems to be a GNU extension that's not available with OS X' BSD sed. This shouldn't be an issue as WinMerge is Windows only anyway. If it still turns out to be an issue we probably should come up with an equivalent Perl expression.
-- 
Sebastian Schuberth
Sebastian Schuberth· May 13, 2015, 20:36 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On 13.05.2015 22:00, Sebastian Schuberth wrote:
Show 11 quoted lines
> So how about something like this which hopefully covers all cases (including case-sensitivity issues regarding environment variable names and the problem of querying a variable that contains parentheses as part of its name):
> 
> for directory in "$(env | sed -nr 's/^PROGRAM(FILES(\(X86\))?|W6432)=//pI')"
> do
>      test -n "$directory" &&
>      test -x "$directory/$winmerge_exe" &&
>      echo "$directory/$winmerge_exe" &&
>      break
> done
> 
> sed's "I" seems to be a GNU extension that's not available with OS X' BSD sed. This shouldn't be an issue as WinMerge is Windows only anyway. If it still turns out to be an issue we probably should come up with an equivalent Perl expression.
Or even better, as that does not rely on GNU sed, sorts matches so that "C:\Program Files" for sure comes before "C:\Program Files (x86)" and removes any duplicates:
for directory in "$(env | grep -E '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2 | sort -u)"
do
     test -n "$directory" &&
     test -x "$directory/$winmerge_exe" &&
     echo "$directory/$winmerge_exe" &&
     break
done
-- 
Sebastian Schuberth
Sebastian Schuberth· May 13, 2015, 20:37 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On 13.05.2015 22:36, Sebastian Schuberth wrote:
> for directory in "$(env | grep -E '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2 | sort -u)"
Sorry, that should have been "grep -Ei" in there.
-- 
Sebastian Schuberth
SZEDER Gábor· May 14, 2015, 21:48 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

Show 7 quoted lines
> for directory in "$(env | grep -E '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2 | sort -u)"
> do
>      test -n "$directory" &&
>      test -x "$directory/$winmerge_exe" &&
>      echo "$directory/$winmerge_exe" &&
>      break
> done

This ain't gonna work, because the output of the pipe won't be split because of the quotes around the command substitution, so $directory will hold everything. Simply loosing those quotes is not good either, because the output will be split on the spaces as well, leading to 'C:\Program', 'Files' and '(x86)', unless the space is already removed from IFS. IIRC Windows doesn't allow newlines in pathnames, so IFS=$'\n' and removing the quotes around the command substitution should do the trick.

Pathnames can contain '=' characters, so, while I think it's outrageous, the paths in those variables can also contain an '=' or two. Well, theoretically, at least, and in that case the 'cut -d= -f2' will cut off the end of the pathname. I don't know whether this is something to be worth worrying about, but in that case it should be 'cut -d= -f2-'.

G�bor
Sebastian Schuberth· May 15, 2015, 05:46 UTC · re: SZEDER Gábor · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On Thu, May 14, 2015 at 11:48 PM, SZEDER Gábor <szeder@ira.uka.de> wrote:
Show 11 quoted lines
>> for directory in "$(env | grep -E '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2 | sort -u)"
>> do
>>      test -n "$directory" &&
>>      test -x "$directory/$winmerge_exe" &&
>>      echo "$directory/$winmerge_exe" &&
>>      break
>> done
>
> This ain't gonna work, because the output of the pipe won't be split
> because of the quotes around the command substitution, so $directory will
> hold everything.  Simply loosing those quotes is not good either, because

That's what I thought at first, too, but simply trying it out proved me wrong (again, in both MSYS1/2):

$ for d in "$(env | grep -Ei '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2- | sort -u)"; do echo "$d"; done C:\Program Files C:\Program Files (x86)

Note that the path, although they are containing spaces, are on separate lines.
-- 
Sebastian Schuberth
SZEDER Gábor· May 15, 2015, 09:01 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

Quoting Sebastian Schuberth <sschuberth@gmail.com>:
Show 25 quoted lines
> On Thu, May 14, 2015 at 11:48 PM, SZEDER Gábor <szeder@ira.uka.de> wrote:
>
>>> for directory in "$(env | grep -E
>>> '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut -d '=' -f 2 | sort -u)"
>>> do
>>>     test -n "$directory" &&
>>>     test -x "$directory/$winmerge_exe" &&
>>>     echo "$directory/$winmerge_exe" &&
>>>     break
>>> done
>>
>> This ain't gonna work, because the output of the pipe won't be split
>> because of the quotes around the command substitution, so $directory will
>> hold everything.  Simply loosing those quotes is not good either, because
>
> That's what I thought at first, too, but simply trying it out proved
> me wrong (again, in both MSYS1/2):
>
> $ for d in "$(env | grep -Ei '^PROGRAM(FILES(\(X86\))?|W6432)=' | cut
> -d '=' -f 2- | sort -u)"; do echo "$d"; done
> C:\Program Files
> C:\Program Files (x86)
>
> Note that the path, although they are containing spaces, are on
> separate lines.

Yeah, exactly the behavior I described in the part you quoted. Although it looks good, it's not what you want. Putting 'echo "** $d **"' in the loop gives me:

** C:\Program Files C:\Program Files (x86) **

(1.9.5 MSysGit)
Gábor
SZEDER Gábor· May 14, 2015, 21:24 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

Show 15 quoted lines
> On Wed, May 13, 2015 at 5:22 PM, Johannes Schindelin <johannes.schindelin <at> gmx.de> wrote:
> 
> > In my tests, "$PROGRAMFILES(X86)" did *not* work:
> >
> >     $ echo "$PROGRAMFILES(X86)"
> >     bash: syntax error near unexpected token `('
> 
> Interesting. In both MSYS1/2 Git Bashes I get on Windows 7 64-bit:
> 
> $ echo "$PROGRAMFILES(X86)"
> C:\Program Files (x86)(X86)
> 
> So it seems to resolve only the $PROGRAMFILES part and appending the
> literal "(X86)". Not sure how to tell Bash that "(X86)" is part of the
> variable name.

It would be ${PROGRAMFILES(X86)}, but POSIX says that variable names can only contain alphanumeric characters and underscores, and Bash adheres when it complains about it in Johannes' example above. Not sure whether there is a clever escaping that could make it work, I couldn't find any.

G�bor
Sebastian Schuberth· May 15, 2015, 05:40 UTC · re: SZEDER Gábor · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On Thu, May 14, 2015 at 11:24 PM, SZEDER Gábor <szeder@ira.uka.de> wrote:
Show 11 quoted lines
>> $ echo "$PROGRAMFILES(X86)"
>> C:\Program Files (x86)(X86)
>>
>> So it seems to resolve only the $PROGRAMFILES part and appending the
>> literal "(X86)". Not sure how to tell Bash that "(X86)" is part of the
>> variable name.
>
> It would be ${PROGRAMFILES(X86)}, but POSIX says that variable names can
> only contain alphanumeric characters and underscores, and Bash adheres
> when it complains about it in Johannes' example above.  Not sure whether
> there is a clever escaping that could make it work, I couldn't find any.

Right, I did already try that curly-braces-style of quoting, and MSYS1/2 both give:

$ echo ${PROGRAMFILES(X86)} sh.exe": ${PROGRAMFILES(X86)}: bad substitution

I couldn't find any other style of quoting that works, either.
-- 
Sebastian Schuberth
David Aguilar· May 20, 2015, 04:10 UTC · re: Sebastian Schuberth · lore

Re: [PATCH v2] mergetools: add winmerge as a builtin tool

On Fri, May 15, 2015 at 07:40:53AM +0200, Sebastian Schuberth wrote:
Show 21 quoted lines
> On Thu, May 14, 2015 at 11:24 PM, SZEDER Gábor <szeder@ira.uka.de> wrote:
> 
> >> $ echo "$PROGRAMFILES(X86)"
> >> C:\Program Files (x86)(X86)
> >>
> >> So it seems to resolve only the $PROGRAMFILES part and appending the
> >> literal "(X86)". Not sure how to tell Bash that "(X86)" is part of the
> >> variable name.
> >
> > It would be ${PROGRAMFILES(X86)}, but POSIX says that variable names can
> > only contain alphanumeric characters and underscores, and Bash adheres
> > when it complains about it in Johannes' example above.  Not sure whether
> > there is a clever escaping that could make it work, I couldn't find any.
> 
> Right, I did already try that curly-braces-style of quoting, and
> MSYS1/2 both give:
> 
> $ echo ${PROGRAMFILES(X86)}
> sh.exe": ${PROGRAMFILES(X86)}: bad substitution
> 
> I couldn't find any other style of quoting that works, either.
How about simply "$PROGRAMFILES (x86)"?

Let the shell handle the programfiles part, and then it'll concat the (x86). That's what's on the filesystem anyways, so it should DTRT. I'll send this in patch form shortly.

-- 
David

← back to recent threads