Fossil Forum

Spaces in commandline e.g. gdiff create error
Login

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.


Example:

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
allow-symlinks
auto-captcha
auto-hyperlink
auto-shun
autosync             (global) ON
autosync-tries
backoffice-disable
backoffice-logfile
backoffice-nodelay
binary-glob          (global) *.ico
case-sensitive
chat-alert-sound
chat-initial-history
chat-inline-images
chat-keep-count
chat-keep-days
chat-poll-timeout
clean-glob
clearsign
comment-format
crlf-glob
crnl-glob            (global) '*'
default-csp
default-perms        (global) sad
diff-binary
diff-command
dont-push
dotfiles
editor
email-admin
email-self
email-send-command
email-send-db
email-send-dir
email-send-method
email-send-relayhost
email-subname
email-url
empty-dirs
encoding-glob        (global) '*'
exec-rel-paths
fileedit-glob
forbid-delta-manifests
gdiff-command        (global) C:\Program Files (x86)\WinMerge\WinMergeU.exe
gmerge-command
hash-digits
hooks
http-port
https-login
ignore-glob          (global) *.suo,*.user,*.webinfo,*.exe,*.hex,*bin/*,*obj/*,*build/*,*debug/*,*release/*,*dist/*
keep-glob
localauth            (local)  0
lock-timeout
main-branch
mainmenu
manifest
max-loadavg
max-upload
mimetypes
mtime-changes
mv-rm-files
pgp-command
preferred-diff-type
proxy
redirect-to-https
relative-paths
repo-cksum
repolist-skin
safe-html
self-register
sitemap-extra
ssh-command
ssl-ca-location
ssl-identity
tclsh
th1-setup
th1-uri-regexp
user-color-map
uv-sync
web-browser

(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
==================================================================
1c1
< 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
#!/bin/bash
exec diff "$@"
[stephan@nuc:~/fossil/fossil]$ f diff
Index: src/diffcmd.c
==================================================================
274c274
<     blob_append(&cmd, zDiffCmd, -1);
---
>     blob_append_escaped_arg(&cmd, zDiffCmd);
361c361
<     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.