I drove myself nuts today re-organizing some of my projects using hg. I had trouble using subrepositories with spaces in their names, and I think it has to do with the way ssh is called. I didn't see any documentation about repositories with spaces in their names, so I checked out the development version of hg, and found this: sshrepo.py line 60: cmd = '%s %s "%s -R %s serve --stdio"' cmd = cmd % (sshcmd, args, remotecmd, self.path) The problem is that if self.path contains spaces (as in "my repo"), then when you do something like hg clone "ssh://server/my repo" the command executed on the remote machine is literally hg -R my repo serve --stdio and you get an error about remote: hg: unknown command 'repo' What I need is for the remote command to be something like hg -R 'my repo' serve --stdio I've tried putting quote marks in various places on the command line and configuration files (without changing the source code) and had no success getting it to work. I think the only way to fix it is to quote the path in sshrepo.py, something like this: cmd = "%s %s \"%s -R '%s' serve --stdio\"" cmd = cmd % (sshcmd, args, remotecmd, self.path) but I'm not sure exactly how to test it. (I'm new to hg)
There is util.shellquote to do that. But IIRC ssh quoting is a bit weird, being unquoted twice. For example, if I do ssh server mkdir "a b" then it will run the command mkdir a b on the server, and create two directories. To get the directory with a space in the name I must do ssh server mkdir "'a b'"
I'm also curious about intended behavior for hg with respect to quoting and shell interpretation. Is something like hg clone 'ssh://server/$PROJECT/' supposed to work? That is, when we get to ssh server -c "hg -R $PROJECT ..." is the shell on the server expected to insert PROJECT from the environment table? If directories are quoted so as to forbid any transformation by the shell on the server, it would probably fix my problem with spaces in directory names, but will it break a "feature" like the above that someone might be relying on? For that matter, is there a security hole here? As in, what if you try: hg clone "ssh://server/project;rm%20-rf%20/" will it actually evaluate the rm -rf /
If you wanted this then you could do hg clone 'ssh://server/'$PROJECT'/' I can verify that running hg clone --debug 'ssh://server/some.dir;logger -- bah/' -v actually does call the logger command. Now this may not actually be any worse then you could do with your ssh login key anyway. Fixing this on the client side (with quoting) may make it a bit less likely to be accidentally issued, but would not stop any actual abuse. I think the hg-ssh wrapper script probably catches this.
Please send your change to the mailing list fixing the quoting (using shellquote).
I'm working on it. I rearranged the formation of the ssh commands using util.shellquote, but now if I do, say hg clone 'ssh://localhost//tmp/Foo Bar' I get a directory called Foo%20Bar, which isn't really what should happen. Instead, it should be like this: hg clone '/tmp/Foo Bar' which creates a directory called 'Foo Bar' And I see comments elsewhere in the ssh code about how paths aren't being un-escaped in case there's a / embedded as a %##. I'm not sure what else needs to be changed to fix the output path. I'll keep working on it though.
On the remote host, we want a string like: $ hg -R 'with a space' ... which means we want an ssh command like this (single quoted string with single quotes inside): $ ssh host 'hg -R '\''with a space'\' ...' which we can achieve in Python like this (escaped escapes): >>> a = "ssh mercurial 'hg -R '\\''%s'\\'' tip'" % "with a space" >>> os.system(a) abort: repository with a space not found! Hmmm, perhaps that message needs some quotes!
Fixed by http://selenic.com/repo/hg/rev/d8fa35c28335 Mads Kiilerich <mads@kiilerich.com> ssh: quote remote paths (issue2983) (please test the fix)
This currently breaks hg-ssh, because it does not expect the extra quotes. Additionally it is inconsistent with other unix tools like rsync and scp, which require double escaping, too: $ rsync file other.example.com:'foo\ bar'/ puts file in "$HOME/foo bar/file" $ rsync file other.example.com:'foo bar'/ puts file in "$HOME/foo" $ scp file other.example.com:'foo bar'/ aborts with "scp: ambiguous target" $ scp file other.example.com:'foo\ bar'/ puts file in "$HOME/foo bar/file"
Note that I'm not saying Mercurial should behave like rsync and scp here, but when introducing different behaviour it needs to be done carefully. I suggest that quoting/escaping should only done where needed, to keep compatibility with existing installations of hg-ssh, hgsh, mercurial-server, hg-login, hg-gateway and friends.
Sort of. I think that if hg clone '/path/foo bar' clones a repository into 'foo bar', then hg clone 'ssh:server/foo bar' should do the same. Or if that's not possible, then hg clone ssh:server/'foo\ bar' ought to work. Here's what I see with hg 1.9.2 as distributed with fedora 16 $ hg clone 'ssh://grograman/tmp/foo bar' remote: hg: unknown command 'bar' abort: no suitable response from remote hg! $ hg clone ssh://grograman/tmp/foo%20bar remote: hg: unknown command 'bar' abort: no suitable response from remote hg! $ hg clone 'ssh://grograman/tmp/foo\ bar' destination directory: foo%5C%20bar requesting all changes adding changesets adding manifests adding file changes added 8 changesets with 8 changes to 1 files updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved which puts the repository into foo%5C%20bar. Same with "" quotes. Same if I put the quotes just around 'foo\ bar'. None of this consistent with the rsync or ssh examples you posted. When I use the hg development version, $ hg clone 'ssh://grograman/tmp/foo bar' puts the repository into foo%20bar, again, not quite right. $ hg clone 'ssh://grograman/tmp/foo\ bar' remote: abort: There is no Mercurial repository here (.hg not found)! abort: no suitable response from remote hg! So it's not so much the quoting I have to do to the ssh URL, but whether the destination on the local machine is what's expected.
This issue also prevents people from using SSH with Bitbucket: % hg incoming --debug running ssh mg@bitbucket.org ''\''hg'\'' -R '\''mg/test'\'' serve --stdio' sending hello command sending between command remote: conq: invalid command syntax. abort: no suitable response from remote hg! It also prevents crew from working with the crew server.
I've made Bitbucket aware of the issue: https://bitbucket.org/site/master/issue/3366/getting-remote-conq-invalid- command-syntax
Fixed by http://selenic.com/repo/hg/rev/86fc364ca5f8 Mads Kiilerich <mads@kiilerich.com> sshrepo: don't quote obviously safe strings (issue2983) (please test the fix)
I'm getting the same unfortunate behavior in my test cases: The local directory still comes out with % codes in its name when you clone a repository over ssh.
Garrett, can you file a separate issue for the % codes on the local side? Regarding this issue: Now it works much better, but I added some more chars, especially the + was missing. See http://hg.intevation.org/mercurial/crew/rev/be43234a6d60
I just used 'make a copy' to create issue 3145 about the % code problem, so I guess we'll use this issue to deal with the way to quote paths and such when sending commands over ssh.
Fixed by http://selenic.com/repo/hg/rev/be43234a6d60 Thomas Arendsen Hein <thomas@intevation.de> sshrepo: add more safe characters (issue2983) (please test the fix)
--- Bug imported by bugzilla@serpentine.com 2012-05-12 09:23 EDT --- This bug was previously known as _bug_ 2983 at http://mercurial.selenic.com/bts/issue2983