contrib/hg-ssh
changeset 16836 1ba3e17186c8
parent 16779 67bfe7f64e57
child 25127 2b9cda9040f7
--- a/contrib/hg-ssh	Sun May 13 10:21:27 2012 +0200
+++ b/contrib/hg-ssh	Tue May 22 15:17:37 2012 -0700
@@ -24,6 +24,9 @@
 
 You can use pattern matching of your normal shell, e.g.:
 command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}"
+
+You can also add a --read-only flag to allow read-only access to a key, e.g.:
+command="hg-ssh --read-only repos/*"
 """
 
 # enable importing on demand to reduce startup time
@@ -35,9 +38,17 @@
 
 def main():
     cwd = os.getcwd()
+    readonly = False
+    args = sys.argv[1:]
+    while len(args):
+        if args[0] == '--read-only':
+            readonly = True
+            args.pop(0)
+        else:
+            break
     allowed_paths = [os.path.normpath(os.path.join(cwd,
                                                    os.path.expanduser(path)))
-                     for path in sys.argv[1:]]
+                     for path in args]
     orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?')
     try:
         cmdargv = shlex.split(orig_cmd)
@@ -49,9 +60,15 @@
         path = cmdargv[2]
         repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path)))
         if repo in allowed_paths:
-            dispatch.dispatch(dispatch.request(['-R', repo,
-                                                'serve',
-                                                '--stdio']))
+            cmd = ['-R', repo, 'serve', '--stdio']
+            if readonly:
+                cmd += [
+                    '--config',
+                    'hooks.prechangegroup.hg-ssh=python:__main__.rejectpush',
+                    '--config',
+                    'hooks.prepushkey.hg-ssh=python:__main__.rejectpush'
+                    ]
+            dispatch.dispatch(dispatch.request(cmd))
         else:
             sys.stderr.write('Illegal repository "%s"\n' % repo)
             sys.exit(255)
@@ -59,5 +76,11 @@
         sys.stderr.write('Illegal command "%s"\n' % orig_cmd)
         sys.exit(255)
 
+def rejectpush(ui, **kwargs):
+    ui.warn("Permission denied\n")
+    # mercurial hooks use unix process conventions for hook return values
+    # so a truthy return means failure
+    return True
+
 if __name__ == '__main__':
     main()