[PATCH 2 of 3] Implemented create for httprepo

Martin Vejnar avakar at ratatanek.cz
Fri Sep 25 09:01:18 CDT 2009


# HG changeset patch
# User Martin Vejnar <avakar at ratatanek.cz>
# Date 1253887056 -7200
# Node ID 58ac824d65d43e7fd060425d4a86b7cd67c02277
# Parent  ee8b03eebdf594b33bf0aa106da922d661b976af
Implemented create for httprepo
hgwebdir intercepts 'init' commands and creates an empty repository.
The user must have both allow_push and allow_init permissions
(the former is to ensure that a clone doesn't fail with an empty repo).

hgwebdir config must not specify any repos using [paths] section
(it might make the determination of the path of the new repository
ambiguous due to ** path wildcards). The entries in [collection]
are used the find a suitable path.

The 'init' web command fails if the repository already exists.

diff -r ee8b03eebdf5 -r 58ac824d65d4 doc/hgrc.5.txt
--- a/doc/hgrc.5.txt	Fri Sep 25 15:54:56 2009 +0200
+++ b/doc/hgrc.5.txt	Fri Sep 25 15:57:36 2009 +0200
@@ -835,6 +835,9 @@
     Default is false.
 ``allowpull``
     Whether to allow pulling from the repository. Default is true.
+``allow_init``
+    Whether to allow the creation of new repositories. The syntax
+    is the same as for allow_push below.
 ``allow_push``
     Whether to allow pushing to the repository. If empty or not set,
     push is not allowed. If the special value "``*``", any remote user can
@@ -864,6 +867,9 @@
 ``contact``
     Name or email address of the person in charge of the repository.
     Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
+``deny_init``
+    Whether to deny the creation of new repositories. The syntax is
+    the same as for deny_push below.
 ``deny_push``
     Whether to deny pushing to the repository. If empty or not set,
     push is not denied. If the special value "``*``", all remote users are
diff -r ee8b03eebdf5 -r 58ac824d65d4 mercurial/hgweb/hgwebdir_mod.py
--- a/mercurial/hgweb/hgwebdir_mod.py	Fri Sep 25 15:54:56 2009 +0200
+++ b/mercurial/hgweb/hgwebdir_mod.py	Fri Sep 25 15:57:36 2009 +0200
@@ -12,8 +12,9 @@
 from mercurial import error, encoding
 from common import ErrorResponse, get_mtime, staticfile, paritygen,\
                    get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
-from hgweb_mod import hgweb
+from hgweb_mod import hgweb, check_perms
 from request import wsgirequest
+import protocol
 import webutil
 
 def cleannames(items):
@@ -48,10 +49,10 @@
         self.conf = conf
         self.baseui = baseui
         self.lastrefresh = 0
-        self.refresh()
+        self.refresh(force=True)
 
-    def refresh(self):
-        if self.lastrefresh + self.refreshinterval > time.time():
+    def refresh(self, force=False):
+        if not force and self.lastrefresh + self.refreshinterval > time.time():
             return
 
         if self.baseui:
@@ -70,6 +71,8 @@
         elif isinstance(self.conf, dict):
             paths = self.conf.items()
 
+        self._have_paths = bool(paths)
+
         encoding.encoding = self.ui.config('web', 'encoding',
                                            encoding.encoding)
         self.motd = self.ui.config('web', 'motd')
@@ -92,6 +95,21 @@
         self.repos.sort()
         self.lastrefresh = time.time()
 
+    def guess_repo_path(self, name):
+        if self._have_paths:
+            return
+
+        for prefix, root in self.ui.configitems('collections'):
+            prefix = util.pconvert(prefix).rstrip('/')
+            root = util.pconvert(os.path.abspath(root)).rstrip('/')
+
+            path = prefix + '/' + name
+            if path.startswith(root):
+                return os.path.normpath(path)
+
+            if name.startswith(root) and not name.startswith(prefix):
+                return os.path.normpath(name)
+
     def run(self):
         if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
             raise RuntimeError("This function is only intended to be "
@@ -149,6 +167,30 @@
                     req.respond(HTTP_OK, ctype)
                     return self.makeindex(req, tmpl)
 
+                elif 'cmd' in req.form and req.form['cmd'][0] == 'init':
+                    try:
+                        check_perms(self.ui, req, ['init', 'push'])
+                    except ErrorResponse, inst:
+                        req.respond(inst, protocol.HGTYPE)
+                        if not inst.message:
+                            return ['3\n']
+                        return '3\n%s\n' % inst.message,
+
+                    real = self.guess_repo_path(virtual)
+                    self.ui.debug('new repository path: %s\n' % real)
+
+                    req.respond(HTTP_OK, protocol.HGTYPE)
+                    if not real:
+                        return [_('2\ncannot create a repository with this name\n')]
+
+                    try:
+                        hg.repository(self.ui, real, create=True)
+                    except error.RepoError, e:
+                        return ['1\n']
+
+                    self.refresh(force=True)
+                    return ['0\n']
+
                 # nested indexes and hgwebs
 
                 repos = dict(self.repos)
diff -r ee8b03eebdf5 -r 58ac824d65d4 mercurial/httprepo.py
--- a/mercurial/httprepo.py	Fri Sep 25 15:54:56 2009 +0200
+++ b/mercurial/httprepo.py	Fri Sep 25 15:57:36 2009 +0200
@@ -22,7 +22,7 @@
     yield zd.flush()
 
 class httprepository(repo.repository):
-    def __init__(self, ui, path):
+    def __init__(self, ui, path, create):
         self.path = path
         self.caps = None
         self.handler = None
@@ -39,6 +39,22 @@
 
         self.urlopener = url.opener(ui, authinfo)
 
+        if create:
+            resp = self.do_read('init', data='')
+            resp_code, output = resp.split('\n', 1)
+            try:
+                ret = int(resp_code)
+            except ValueError, err:
+                raise error.ResponseError(
+                        _('http repository creation failed (unexpected response):'), resp)
+            self.ui.write(output)
+
+            if ret == 1:
+                raise util.Abort(_('remote repository already exists'))
+
+            if ret != 0:
+                raise util.Abort(_('http repository creation failed'))
+
     def __del__(self):
         for h in self.urlopener.handlers:
             h.close()
@@ -237,20 +253,18 @@
         return self.do_cmd('stream_out')
 
 class httpsrepository(httprepository):
-    def __init__(self, ui, path):
+    def __init__(self, ui, path, create):
         if not url.has_https:
             raise util.Abort(_('Python support for SSL and HTTPS '
                                'is not installed'))
-        httprepository.__init__(self, ui, path)
+        httprepository.__init__(self, ui, path, create)
 
 def instance(ui, path, create):
-    if create:
-        raise util.Abort(_('cannot create new http repository'))
     try:
         if path.startswith('https:'):
-            inst = httpsrepository(ui, path)
+            inst = httpsrepository(ui, path, create)
         else:
-            inst = httprepository(ui, path)
+            inst = httprepository(ui, path, create)
         inst.between([(nullid, nullid)])
         return inst
     except error.RepoError:


More information about the Mercurial-devel mailing list