Fossil Forum

Spaces in commandline e.g. gdiff create error

Spaces in commandline e.g. gdiff create error

(1) By anonymous on 2021-04-23 07:38:10 [source]

Hello together,

as you can see below, the gdiff-command settings has the correct value,
but when using gdiff, the program complains that the command can not found.


c:\Projekte\lissof>fossil version
This is fossil version 2.15.1 [2f901f98b3] 2021-04-08 01:05:44 UTC

c:\Projekte\lissof>fossil.exe  gdiff "sourceLissof\CsFossil.cs" "--from" "6cb646f811" "--to" "c5d950dcd0"
Index: sourceLissof/CsFossil.cs
Der Befehl "C:\Program" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.

c:\Projekte\lissof>fossil settings
access-log           (local)  1
admin-log            (local)  1
autosync             (global) ON
binary-glob          (global) *.ico
crnl-glob            (global) '*'
default-perms        (global) sad
encoding-glob        (global) '*'
gdiff-command        (global) C:\Program Files (x86)\WinMerge\WinMergeU.exe
ignore-glob          (global) *.suo,*.user,*.webinfo,*.exe,*.hex,*bin/*,*obj/*,*build/*,*debug/*,*release/*,*dist/*
localauth            (local)  0

(2) By anonymous on 2021-04-23 19:09:38 in reply to 1 [link] [source]

The external diff command is executed on Windows is executed via _wsystem(), looks like there's already some quoting to handle spaces in the command path or its args.

The trick here is that, _wsystem() passes the command string to cmd.exe for execution, but before that it strips the surrounding double quotes. Thus the resulting command string fails whenever there are spaces in the command path.

One way that seems to work around this behavior is to enclose the whole command-string in parentheses () as follows:

("command-path" "arg1" "arg2")

This is to test the parenthesized string:

cmd.exe /c ("C:\Program Files (x86)\WinMerge\WinMergeU.exe" "/?")  

Not sure if the same works under WinXP.

(3) By anonymous on 2021-06-16 23:23:42 in reply to 1 [link] [source]

Turns out this problem is not just Windows-specific. The external diff/gdiff command path which contains a space will fail to spawn the command on Linux too.

Short of writing a .test file for this, the easiest way to demonstrate is just as following:

cp `which diff` "./diffcommand with spaces"

fossil init test.fossil
fossil open test.fossil -f
echo "test" >file1
fossil add file1
fossil commit -m "added file1"
echo "edited" >file1

fossil set diff-command "./diffcommand with spaces"
fossil diff

fossil close
rm file1 "./diffcommand with spaces"
rm test.fossil

Fails with the following:

Index: file1
sh: 1: ./diffcommand: not found

Workaround, of course, is not to use the explicit path for the command and add it instead to PATH (if it's not the command name itself that has spaces).

The actual fix seems to point to a couple of calls in diffcmd.c like:

blob_append(&cmd, zDiffCmd, -1);

Not sure what would be the proper way to patch this, but changing these calls to:

blob_append_escaped_arg(&cmd, zDiffCmd);

appears to fix it. The resulting output from the test above with the fix:

Index: file1
< test
> edited

Similar approach to "quoting" the command should take care of this issue on Windows as well.

(5.2) By Stephan Beal (stephan) on 2021-06-17 10:35:43 edited from 5.1 in reply to 3 [link] [source]

The actual fix seems to point to a couple of calls in diffcmd.c like:

That's now implemented:

[stephan@nuc:~/fossil/fossil]$ f set diff-command
diff-command         (local)  /home/stephan/fossil/fossil/my diff
[stephan@nuc:~/fossil/fossil]$ cat my\ diff
exec diff "$@"
[stephan@nuc:~/fossil/fossil]$ f diff
Index: src/diffcmd.c
<     blob_append(&cmd, zDiffCmd, -1);
>     blob_append_escaped_arg(&cmd, zDiffCmd);
<     blob_append(&cmd, zDiffCmd, -1);
>     blob_append_escaped_arg(&cmd, zDiffCmd);

However, spaces in the to-diff file names may still be a problem for the time being. The routine used to expand those does not do escaping and will need some refactoring in order to be able to do that properly or the names will need to be post-processed after that routine expands them.

(6) By Richard Hipp (drh) on 2021-06-17 11:23:23 in reply to 5.2 [link] [source]

I don't think that is the right fix.

The gdiff-command setting is intended to be a command prefix, consisting of the command name followed by options or other arguments. If you quote the whole thing, then the system will thing the options are part of the command name.

For example, suppose you wanted to make gdiff use the "fossil test-diff --tk" command as its differ. (That seems a little silly, as it is much easier to use the --tk option on "fossil diff", but this does illustrate my point.) You would write:

fossil setting gdiff-command "/home/drh/bin/fossil test-diff --tk"

The above would work fine, before Stephan's patch. Fossil will append the two filenames to the end of the string and then execute that string as a command. Like this:

/home/drh/bin/fossil test-diff --tk FILE1 FILE2

But after the patch, Fossil will try to quote the command name and its arguments, like this:

"/home/drh/bin/fossil tset-diff --tk" FILE1 FILE2

This clearly won't work.

I think the correct fix for the OPs problem is to quote the name of the command he is attempting to use for gdiff.

(7) By Stephan Beal (stephan) on 2021-06-17 11:31:35 in reply to 6 [link] [source]

The gdiff-command setting is intended to be a command prefix, consisting of the command name followed by options or other arguments. If you quote the whole thing, then the system will thing the options are part of the command name.

Doh, you're absolutely right. That's what i get for coding before coffee :/.

That checkin has been moved off of trunk.

(8) By Richard Hipp (drh) on 2021-06-17 11:33:12 in reply to 3 [link] [source]

You want:

fossil set diff-command "\"./diffcommand with spaces\""

The outer "..." are for the "fossil set" command itself. The inner "..." (escaped for the purposes of the outer "fossil set" command) is what gets stored in the diff-command setting. You can see this when you afterwards run just:

fossil setting diff-command

(9.1) By Richard Hipp (drh) on 2021-06-17 11:45:28 edited from 9.0 in reply to 8 [link] [source]

Could this problem be made easier to solve by adding a new "--url-encoded" option to the "fossil set" command that causes its value argument to be interpreted as text/x-www-form-urlencoded. Then you could do command-lines like this:

fossil set diff-command --url-encoded "c:\path+with+spaces\diff-util"
fossil set gdiff-command --url-encoded "C:%5cProgram+Files+(x86)%5cWinMerge%5cWinMergeU.exe"

Perhaps the --url-encoded option can be abbreviated as -u

fossil set diff-command -u "c:\path+with+spaces\diff-util"
fossil set gdiff-command -u "C:%5cProgram+Files+(x86)%5cWinMerge%5cWinMergeU.exe"

(10) By Stephan Beal (stephan) on 2021-06-17 11:54:04 in reply to 9.1 [link] [source]

Then you could do command-lines like this:

That seems more cryptic than pointing out that the command can simply be quoted twice (once for the shell and once for fossil).

(11) By anonymous on 2021-06-17 14:20:00 in reply to 9.1 [link] [source]

The command, argument breakdown could be naturally handled on the command line if the 'fossil set' command allowed passing and processing of multiple args.

fossil set diff-command "my diff" "my diff argv1" "my diff argv2"

This way the value of the diff-command could be either passed on as argc,argv[] set (needs refactoring) or pre-quoted and joined into the prefix string as done now.

(4) By MBL (RoboManni) on 2021-06-17 04:15:22 in reply to 1 [link] [source]

I am working around this problem by using a cmd file from within a folder without spaces in its name, which folder can be found by the path environment variable.

(12) By skywalk on 2022-02-18 17:53:52 in reply to 4 [link] [source]

Can someone please explain how to make this work on Windows + Chrome?
Many years of attempts failed so I manually start WinMerge. 
I thought I'd give another try with latest Fossil v2.18 [6325f81d06].
This returns with no error, but also no config entry in repo.
  C:\>fossil settings diff-command --global "C:\Program Files\WinMerge\WinMergeU.exe\"

Using SQL actually makes changes to the repo config table, but only 'insert'.
Not 'insert or replace'.
I had to insert a 'gdiff-command' entry 1st.

Using a batch file does seem to be the answer. Does someone have such file that will populate the FROM-TO files for WinMergeU.exe?

(13) By skywalk on 2022-02-18 18:21:15 in reply to 12 [link] [source]

And, from cmd-line I got unexpected behavior.
  C:\myrepo>fossil diff --from prev --to tip
Fossil proceeded to open multiple files in succession using my system's default app for that file extension.

I was expecting fossil's internal diff tool, since there are no entries in my config table under diff.

(14) By Martin Gagnon (mgagnon) on 2022-02-18 18:28:01 in reply to 12 [link] [source]

On windows I never manage to be able to make that works from the CLI.

I always end up firing fossil ui and do it from the setting page on the web interface.

(15) By skywalk on 2022-02-18 18:30:57 in reply to 14 [link] [source]

Yes, frustrating.
Do you mind pasting your last config entries?
diff blah blah
gdiff blah blah

(16) By Martin Gagnon (mgagnon) on 2022-02-18 21:45:14 in reply to 15 [link] [source]

Now I have this:

> fossil set gdiff-command
gdiff-command        (local)  "C:\Program Files\Vim\vim82\gvim.exe" -f -d

> fossil sql "select * from config where name = 'gdiff-command';"
'gdiff-command','"C:\Program Files\Vim\vim82\gvim.exe" -f -d',1639588844

(17) By skywalk on 2022-02-19 17:18:40 in reply to 16 [link] [source]

Finally got gdiff working after manually editing repo.fossil config entry.
Using command line SQL was not applying the " marks.
  OK  -> "C:\Program Files\WinMerge\WinMergeU.exe" -f -d
  BAD -> C:\Program Files\WinMerge\WinMergeU.exe -f -d
But now plain old diff is broken?
My config diff-command entry is empty yet it does not output a textual comparison.
  C:\repo> fossil diff --from prev --to tip
    Spawns the Windows shell app defined by the file extension.

Are text comparisons in the console window obsoleted?

(18) By Martin Gagnon (mgagnon) on 2022-02-19 18:10:46 in reply to 17 [link] [source]

It should works,

What does fossil set diff-command return ?

Are you sure you still don't have something set there (in repo or global)

Also, I think using fossil ui is a lot easier and less error-prone to workaround the quoting difficulty of windows cmd than using SQL.

(19) By Martin Gagnon (mgagnon) on 2022-02-19 18:12:54 in reply to 17 [link] [source]

Also, to be sure the config is really empty, try:

fossil unset diff-command


fossil unset diff-command -global

(20) By skywalk on 2022-02-19 18:37:35 in reply to 19 [link] [source]

Wow, got it! Super confusing :(
Using a db browser I could see nothing in the diff-command entry, but the console request showed this:
c:\repo> fossil settings
diff-command         (global) C:\Program Files\WinMerge\WinMergeU.exe"
That (global) entry was not in the local or remote repo!
Anyway, after several unset's for local and -global,
I now have the text diff dump in console again.
Thanks for the help.
Quirks like this prevent me fully building a customized repo from batch.
I still must fiddle with web ui or SQL.

(21) By Stephan Beal (stephan) on 2022-02-19 19:01:39 in reply to 20 [link] [source]

That (global) entry was not in the local or remote repo!

The global config is a separate config db shared by all fossil instances. Where exactly it's stored on Windows is a mystery buried somewhere in the fossil source code.

(22) By skywalk on 2022-02-19 19:21:07 in reply to 21 [link] [source]

Yes, I was going to mention some buried logic?
Still, I am back to new new fossil version finally.
Shame on me for delaying many years.
Crossing my fingers old ticket sql/setup is not going to be this hard!?

(23) By Marcelo Huerta (richieadler) on 2022-02-19 20:51:02 in reply to 21 [link] [source]

(24) By MBL (RoboManni) on 2022-02-20 17:48:33 in reply to 12 [link] [source]

>fossil.exe settings
gdiff-command        (local)  winmerge.cmd
gmerge-command       (local)  winmerge3w.cmd

and the winmerge.cmd file itself:

C:\UserPrograms\WinMerge\WinMergeU.exe %1 %2

If the WinMergeU.exe is new enough it can also do the 3-way-merge with 3 arguments in same fashion. The cmd file is located in a folder that can be seen by the PATH environment variable.