Show More
@@ -24,6 +24,9 b' command="cd path/to/my/repositories && h' | |||
|
24 | 24 | |
|
25 | 25 | You can use pattern matching of your normal shell, e.g.: |
|
26 | 26 | command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}" |
|
27 | ||
|
28 | You can also add a --read-only flag to allow read-only access to a key, e.g.: | |
|
29 | command="hg-ssh --read-only repos/*" | |
|
27 | 30 | """ |
|
28 | 31 | |
|
29 | 32 | # enable importing on demand to reduce startup time |
@@ -35,9 +38,17 b' import sys, os, shlex' | |||
|
35 | 38 | |
|
36 | 39 | def main(): |
|
37 | 40 | cwd = os.getcwd() |
|
41 | readonly = False | |
|
42 | args = sys.argv[1:] | |
|
43 | while len(args): | |
|
44 | if args[0] == '--read-only': | |
|
45 | readonly = True | |
|
46 | args.pop(0) | |
|
47 | else: | |
|
48 | break | |
|
38 | 49 | allowed_paths = [os.path.normpath(os.path.join(cwd, |
|
39 | 50 | os.path.expanduser(path))) |
|
40 |
for path in |
|
|
51 | for path in args] | |
|
41 | 52 | orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') |
|
42 | 53 | try: |
|
43 | 54 | cmdargv = shlex.split(orig_cmd) |
@@ -49,9 +60,15 b' def main():' | |||
|
49 | 60 | path = cmdargv[2] |
|
50 | 61 | repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) |
|
51 | 62 | if repo in allowed_paths: |
|
52 | dispatch.dispatch(dispatch.request(['-R', repo, | |
|
53 | 'serve', | |
|
54 | '--stdio'])) | |
|
63 | cmd = ['-R', repo, 'serve', '--stdio'] | |
|
64 | if readonly: | |
|
65 | cmd += [ | |
|
66 | '--config', | |
|
67 | 'hooks.prechangegroup.hg-ssh=python:__main__.rejectpush', | |
|
68 | '--config', | |
|
69 | 'hooks.prepushkey.hg-ssh=python:__main__.rejectpush' | |
|
70 | ] | |
|
71 | dispatch.dispatch(dispatch.request(cmd)) | |
|
55 | 72 | else: |
|
56 | 73 | sys.stderr.write('Illegal repository "%s"\n' % repo) |
|
57 | 74 | sys.exit(255) |
@@ -59,5 +76,11 b' def main():' | |||
|
59 | 76 | sys.stderr.write('Illegal command "%s"\n' % orig_cmd) |
|
60 | 77 | sys.exit(255) |
|
61 | 78 | |
|
79 | def rejectpush(ui, **kwargs): | |
|
80 | ui.warn("Permission denied\n") | |
|
81 | # mercurial hooks use unix process conventions for hook return values | |
|
82 | # so a truthy return means failure | |
|
83 | return True | |
|
84 | ||
|
62 | 85 | if __name__ == '__main__': |
|
63 | 86 | main() |
@@ -308,6 +308,41 b' parameters:' | |||
|
308 | 308 | Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation |
|
309 | 309 | [255] |
|
310 | 310 | |
|
311 | Test hg-ssh in read-only mode: | |
|
312 | ||
|
313 | $ cat > ssh.sh << EOF | |
|
314 | > userhost="\$1" | |
|
315 | > SSH_ORIGINAL_COMMAND="\$2" | |
|
316 | > export SSH_ORIGINAL_COMMAND | |
|
317 | > PYTHONPATH="$PYTHONPATH" | |
|
318 | > export PYTHONPATH | |
|
319 | > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote" | |
|
320 | > EOF | |
|
321 | ||
|
322 | $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local | |
|
323 | requesting all changes | |
|
324 | adding changesets | |
|
325 | adding manifests | |
|
326 | adding file changes | |
|
327 | added 4 changesets with 5 changes to 4 files (+1 heads) | |
|
328 | updating to branch default | |
|
329 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
330 | ||
|
331 | $ cd read-only-local | |
|
332 | $ echo "baz" > bar | |
|
333 | $ hg ci -A -m "unpushable commit" bar | |
|
334 | $ hg push --ssh "sh ../ssh.sh" | |
|
335 | pushing to ssh://user@dummy/$TESTTMP/remote | |
|
336 | searching for changes | |
|
337 | remote: Permission denied | |
|
338 | remote: abort: prechangegroup.hg-ssh hook failed | |
|
339 | remote: Permission denied | |
|
340 | remote: abort: prepushkey.hg-ssh hook failed | |
|
341 | abort: unexpected response: empty string | |
|
342 | [255] | |
|
343 | ||
|
344 | $ cd .. | |
|
345 | ||
|
311 | 346 | $ cat dummylog |
|
312 | 347 | Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio |
|
313 | 348 | Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio |
General Comments 0
You need to be logged in to leave comments.
Login now