##// END OF EJS Templates
fixed error propagation when using git/mercurial requests
marcink -
r898:9c4851dc beta
parent child Browse files
Show More
@@ -1,221 +1,222
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # middleware to handle git api calls
3 # middleware to handle git api calls
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on 2010-04-28
21 Created on 2010-04-28
22
22
23 @author: marcink
23 @author: marcink
24 SimpleGit middleware for handling git protocol request (push/clone etc.)
24 SimpleGit middleware for handling git protocol request (push/clone etc.)
25 It's implemented with basic auth function
25 It's implemented with basic auth function
26 """
26 """
27
27
28 from dulwich import server as dulserver
28 from dulwich import server as dulserver
29
29
30 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
30 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
31
31
32 def handle(self):
32 def handle(self):
33 write = lambda x: self.proto.write_sideband(1, x)
33 write = lambda x: self.proto.write_sideband(1, x)
34
34
35 graph_walker = dulserver.ProtocolGraphWalker(self, self.repo.object_store,
35 graph_walker = dulserver.ProtocolGraphWalker(self, self.repo.object_store,
36 self.repo.get_peeled)
36 self.repo.get_peeled)
37 objects_iter = self.repo.fetch_objects(
37 objects_iter = self.repo.fetch_objects(
38 graph_walker.determine_wants, graph_walker, self.progress,
38 graph_walker.determine_wants, graph_walker, self.progress,
39 get_tagged=self.get_tagged)
39 get_tagged=self.get_tagged)
40
40
41 # Do they want any objects?
41 # Do they want any objects?
42 if len(objects_iter) == 0:
42 if len(objects_iter) == 0:
43 return
43 return
44
44
45 self.progress("counting objects: %d, done.\n" % len(objects_iter))
45 self.progress("counting objects: %d, done.\n" % len(objects_iter))
46 dulserver.write_pack_data(dulserver.ProtocolFile(None, write), objects_iter,
46 dulserver.write_pack_data(dulserver.ProtocolFile(None, write), objects_iter,
47 len(objects_iter))
47 len(objects_iter))
48 messages = []
48 messages = []
49 messages.append('thank you for using rhodecode')
49 messages.append('thank you for using rhodecode')
50
50
51 for msg in messages:
51 for msg in messages:
52 self.progress(msg + "\n")
52 self.progress(msg + "\n")
53 # we are done
53 # we are done
54 self.proto.write("0000")
54 self.proto.write("0000")
55
55
56 dulserver.DEFAULT_HANDLERS = {
56 dulserver.DEFAULT_HANDLERS = {
57 'git-upload-pack': SimpleGitUploadPackHandler,
57 'git-upload-pack': SimpleGitUploadPackHandler,
58 'git-receive-pack': dulserver.ReceivePackHandler,
58 'git-receive-pack': dulserver.ReceivePackHandler,
59 }
59 }
60
60
61 from dulwich.repo import Repo
61 from dulwich.repo import Repo
62 from dulwich.web import HTTPGitApplication
62 from dulwich.web import HTTPGitApplication
63 from paste.auth.basic import AuthBasicAuthenticator
63 from paste.auth.basic import AuthBasicAuthenticator
64 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
64 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
65 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
65 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
66 from rhodecode.lib.utils import invalidate_cache, check_repo_fast
66 from rhodecode.lib.utils import invalidate_cache, check_repo_fast
67 from rhodecode.model.user import UserModel
67 from rhodecode.model.user import UserModel
68 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
68 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
69 import logging
69 import logging
70 import os
70 import os
71 import traceback
71 import traceback
72
72
73 log = logging.getLogger(__name__)
73 log = logging.getLogger(__name__)
74
74
75 def is_git(environ):
75 def is_git(environ):
76 """
76 """
77 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
77 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
78 then have git client version given.
78 then have git client version given.
79
79
80 :param environ:
80 :param environ:
81 """
81 """
82 http_user_agent = environ.get('HTTP_USER_AGENT')
82 http_user_agent = environ.get('HTTP_USER_AGENT')
83 if http_user_agent and http_user_agent.startswith('git'):
83 if http_user_agent and http_user_agent.startswith('git'):
84 return True
84 return True
85 return False
85 return False
86
86
87 class SimpleGit(object):
87 class SimpleGit(object):
88
88
89 def __init__(self, application, config):
89 def __init__(self, application, config):
90 self.application = application
90 self.application = application
91 self.config = config
91 self.config = config
92 #authenticate this git request using
92 #authenticate this git request using
93 self.authenticate = AuthBasicAuthenticator('', authfunc)
93 self.authenticate = AuthBasicAuthenticator('', authfunc)
94 self.ipaddr = '0.0.0.0'
94 self.ipaddr = '0.0.0.0'
95 self.repository = None
95 self.repository = None
96 self.username = None
96 self.username = None
97 self.action = None
97 self.action = None
98
98
99 def __call__(self, environ, start_response):
99 def __call__(self, environ, start_response):
100 if not is_git(environ):
100 if not is_git(environ):
101 return self.application(environ, start_response)
101 return self.application(environ, start_response)
102
102
103 proxy_key = 'HTTP_X_REAL_IP'
103 proxy_key = 'HTTP_X_REAL_IP'
104 def_key = 'REMOTE_ADDR'
104 def_key = 'REMOTE_ADDR'
105 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
105 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
106
106 # skip passing error to error controller
107 environ['pylons.status_code_redirect'] = True
107 #===================================================================
108 #===================================================================
108 # AUTHENTICATE THIS GIT REQUEST
109 # AUTHENTICATE THIS GIT REQUEST
109 #===================================================================
110 #===================================================================
110 username = REMOTE_USER(environ)
111 username = REMOTE_USER(environ)
111 if not username:
112 if not username:
112 self.authenticate.realm = self.config['rhodecode_realm']
113 self.authenticate.realm = self.config['rhodecode_realm']
113 result = self.authenticate(environ)
114 result = self.authenticate(environ)
114 if isinstance(result, str):
115 if isinstance(result, str):
115 AUTH_TYPE.update(environ, 'basic')
116 AUTH_TYPE.update(environ, 'basic')
116 REMOTE_USER.update(environ, result)
117 REMOTE_USER.update(environ, result)
117 else:
118 else:
118 return result.wsgi_application(environ, start_response)
119 return result.wsgi_application(environ, start_response)
119
120
120 #=======================================================================
121 #=======================================================================
121 # GET REPOSITORY
122 # GET REPOSITORY
122 #=======================================================================
123 #=======================================================================
123 try:
124 try:
124 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
125 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
125 if repo_name.endswith('/'):
126 if repo_name.endswith('/'):
126 repo_name = repo_name.rstrip('/')
127 repo_name = repo_name.rstrip('/')
127 self.repository = repo_name
128 self.repository = repo_name
128 except:
129 except:
129 log.error(traceback.format_exc())
130 log.error(traceback.format_exc())
130 return HTTPInternalServerError()(environ, start_response)
131 return HTTPInternalServerError()(environ, start_response)
131
132
132 #===================================================================
133 #===================================================================
133 # CHECK PERMISSIONS FOR THIS REQUEST
134 # CHECK PERMISSIONS FOR THIS REQUEST
134 #===================================================================
135 #===================================================================
135 self.action = self.__get_action(environ)
136 self.action = self.__get_action(environ)
136 if self.action:
137 if self.action:
137 username = self.__get_environ_user(environ)
138 username = self.__get_environ_user(environ)
138 try:
139 try:
139 user = self.__get_user(username)
140 user = self.__get_user(username)
140 self.username = user.username
141 self.username = user.username
141 except:
142 except:
142 log.error(traceback.format_exc())
143 log.error(traceback.format_exc())
143 return HTTPInternalServerError()(environ, start_response)
144 return HTTPInternalServerError()(environ, start_response)
144
145
145 #check permissions for this repository
146 #check permissions for this repository
146 if self.action == 'push':
147 if self.action == 'push':
147 if not HasPermissionAnyMiddleware('repository.write',
148 if not HasPermissionAnyMiddleware('repository.write',
148 'repository.admin')\
149 'repository.admin')\
149 (user, repo_name):
150 (user, repo_name):
150 return HTTPForbidden()(environ, start_response)
151 return HTTPForbidden()(environ, start_response)
151
152
152 else:
153 else:
153 #any other action need at least read permission
154 #any other action need at least read permission
154 if not HasPermissionAnyMiddleware('repository.read',
155 if not HasPermissionAnyMiddleware('repository.read',
155 'repository.write',
156 'repository.write',
156 'repository.admin')\
157 'repository.admin')\
157 (user, repo_name):
158 (user, repo_name):
158 return HTTPForbidden()(environ, start_response)
159 return HTTPForbidden()(environ, start_response)
159
160
160 self.extras = {'ip':self.ipaddr,
161 self.extras = {'ip':self.ipaddr,
161 'username':self.username,
162 'username':self.username,
162 'action':self.action,
163 'action':self.action,
163 'repository':self.repository}
164 'repository':self.repository}
164
165
165 #===================================================================
166 #===================================================================
166 # GIT REQUEST HANDLING
167 # GIT REQUEST HANDLING
167 #===================================================================
168 #===================================================================
168 self.basepath = self.config['base_path']
169 self.basepath = self.config['base_path']
169 self.repo_path = os.path.join(self.basepath, self.repo_name)
170 self.repo_path = os.path.join(self.basepath, self.repo_name)
170 #quick check if that dir exists...
171 #quick check if that dir exists...
171 if check_repo_fast(self.repo_name, self.basepath):
172 if check_repo_fast(self.repo_name, self.basepath):
172 return HTTPNotFound()(environ, start_response)
173 return HTTPNotFound()(environ, start_response)
173 try:
174 try:
174 app = self.__make_app()
175 app = self.__make_app()
175 except:
176 except:
176 log.error(traceback.format_exc())
177 log.error(traceback.format_exc())
177 return HTTPInternalServerError()(environ, start_response)
178 return HTTPInternalServerError()(environ, start_response)
178
179
179 #invalidate cache on push
180 #invalidate cache on push
180 if self.action == 'push':
181 if self.action == 'push':
181 self.__invalidate_cache(self.repo_name)
182 self.__invalidate_cache(self.repo_name)
182 messages = []
183 messages = []
183 messages.append('thank you for using rhodecode')
184 messages.append('thank you for using rhodecode')
184 return app(environ, start_response)
185 return app(environ, start_response)
185 else:
186 else:
186 return app(environ, start_response)
187 return app(environ, start_response)
187
188
188
189
189 def __make_app(self):
190 def __make_app(self):
190 backend = dulserver.DictBackend({'/' + self.repo_name: Repo(self.repo_path)})
191 backend = dulserver.DictBackend({'/' + self.repo_name: Repo(self.repo_path)})
191 gitserve = HTTPGitApplication(backend)
192 gitserve = HTTPGitApplication(backend)
192
193
193 return gitserve
194 return gitserve
194
195
195 def __get_environ_user(self, environ):
196 def __get_environ_user(self, environ):
196 return environ.get('REMOTE_USER')
197 return environ.get('REMOTE_USER')
197
198
198 def __get_user(self, username):
199 def __get_user(self, username):
199 return UserModel().get_by_username(username, cache=True)
200 return UserModel().get_by_username(username, cache=True)
200
201
201 def __get_action(self, environ):
202 def __get_action(self, environ):
202 """
203 """
203 Maps git request commands into a pull or push command.
204 Maps git request commands into a pull or push command.
204 :param environ:
205 :param environ:
205 """
206 """
206 service = environ['QUERY_STRING'].split('=')
207 service = environ['QUERY_STRING'].split('=')
207 if len(service) > 1:
208 if len(service) > 1:
208 service_cmd = service[1]
209 service_cmd = service[1]
209 mapping = {'git-receive-pack': 'push',
210 mapping = {'git-receive-pack': 'push',
210 'git-upload-pack': 'pull',
211 'git-upload-pack': 'pull',
211 }
212 }
212
213
213 return mapping.get(service_cmd, service_cmd if service_cmd else 'other')
214 return mapping.get(service_cmd, service_cmd if service_cmd else 'other')
214 else:
215 else:
215 return 'other'
216 return 'other'
216
217
217 def __invalidate_cache(self, repo_name):
218 def __invalidate_cache(self, repo_name):
218 """we know that some change was made to repositories and we should
219 """we know that some change was made to repositories and we should
219 invalidate the cache to see the changes right away but only for
220 invalidate the cache to see the changes right away but only for
220 push requests"""
221 push requests"""
221 invalidate_cache('get_repo_cached_%s' % repo_name)
222 invalidate_cache('get_repo_cached_%s' % repo_name)
@@ -1,229 +1,230
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # middleware to handle mercurial api calls
3 # middleware to handle mercurial api calls
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on 2010-04-28
21 Created on 2010-04-28
22
22
23 @author: marcink
23 @author: marcink
24 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
24 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
25 It's implemented with basic auth function
25 It's implemented with basic auth function
26 """
26 """
27 from mercurial.error import RepoError
27 from mercurial.error import RepoError
28 from mercurial.hgweb import hgweb
28 from mercurial.hgweb import hgweb
29 from mercurial.hgweb.request import wsgiapplication
29 from mercurial.hgweb.request import wsgiapplication
30 from paste.auth.basic import AuthBasicAuthenticator
30 from paste.auth.basic import AuthBasicAuthenticator
31 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
31 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
32 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
32 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
33 from rhodecode.lib.utils import make_ui, invalidate_cache, \
33 from rhodecode.lib.utils import make_ui, invalidate_cache, \
34 check_repo_fast, ui_sections
34 check_repo_fast, ui_sections
35 from rhodecode.model.user import UserModel
35 from rhodecode.model.user import UserModel
36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
37 import logging
37 import logging
38 import os
38 import os
39 import traceback
39 import traceback
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43 def is_mercurial(environ):
43 def is_mercurial(environ):
44 """
44 """
45 Returns True if request's target is mercurial server - header
45 Returns True if request's target is mercurial server - header
46 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
46 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
47 """
47 """
48 http_accept = environ.get('HTTP_ACCEPT')
48 http_accept = environ.get('HTTP_ACCEPT')
49 if http_accept and http_accept.startswith('application/mercurial'):
49 if http_accept and http_accept.startswith('application/mercurial'):
50 return True
50 return True
51 return False
51 return False
52
52
53 class SimpleHg(object):
53 class SimpleHg(object):
54
54
55 def __init__(self, application, config):
55 def __init__(self, application, config):
56 self.application = application
56 self.application = application
57 self.config = config
57 self.config = config
58 #authenticate this mercurial request using authfunc
58 #authenticate this mercurial request using authfunc
59 self.authenticate = AuthBasicAuthenticator('', authfunc)
59 self.authenticate = AuthBasicAuthenticator('', authfunc)
60 self.ipaddr = '0.0.0.0'
60 self.ipaddr = '0.0.0.0'
61 self.repository = None
61 self.repository = None
62 self.username = None
62 self.username = None
63 self.action = None
63 self.action = None
64
64
65 def __call__(self, environ, start_response):
65 def __call__(self, environ, start_response):
66 if not is_mercurial(environ):
66 if not is_mercurial(environ):
67 return self.application(environ, start_response)
67 return self.application(environ, start_response)
68
68
69 proxy_key = 'HTTP_X_REAL_IP'
69 proxy_key = 'HTTP_X_REAL_IP'
70 def_key = 'REMOTE_ADDR'
70 def_key = 'REMOTE_ADDR'
71 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
71 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
72
72 # skip passing error to error controller
73 environ['pylons.status_code_redirect'] = True
73 #===================================================================
74 #===================================================================
74 # AUTHENTICATE THIS MERCURIAL REQUEST
75 # AUTHENTICATE THIS MERCURIAL REQUEST
75 #===================================================================
76 #===================================================================
76 username = REMOTE_USER(environ)
77 username = REMOTE_USER(environ)
77
78
78 if not username:
79 if not username:
79 self.authenticate.realm = self.config['rhodecode_realm']
80 self.authenticate.realm = self.config['rhodecode_realm']
80 result = self.authenticate(environ)
81 result = self.authenticate(environ)
81 if isinstance(result, str):
82 if isinstance(result, str):
82 AUTH_TYPE.update(environ, 'basic')
83 AUTH_TYPE.update(environ, 'basic')
83 REMOTE_USER.update(environ, result)
84 REMOTE_USER.update(environ, result)
84 else:
85 else:
85 return result.wsgi_application(environ, start_response)
86 return result.wsgi_application(environ, start_response)
86
87
87 #=======================================================================
88 #=======================================================================
88 # GET REPOSITORY
89 # GET REPOSITORY
89 #=======================================================================
90 #=======================================================================
90 try:
91 try:
91 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
92 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
92 if repo_name.endswith('/'):
93 if repo_name.endswith('/'):
93 repo_name = repo_name.rstrip('/')
94 repo_name = repo_name.rstrip('/')
94 self.repository = repo_name
95 self.repository = repo_name
95 except:
96 except:
96 log.error(traceback.format_exc())
97 log.error(traceback.format_exc())
97 return HTTPInternalServerError()(environ, start_response)
98 return HTTPInternalServerError()(environ, start_response)
98
99
99 #===================================================================
100 #===================================================================
100 # CHECK PERMISSIONS FOR THIS REQUEST
101 # CHECK PERMISSIONS FOR THIS REQUEST
101 #===================================================================
102 #===================================================================
102 self.action = self.__get_action(environ)
103 self.action = self.__get_action(environ)
103 if self.action:
104 if self.action:
104 username = self.__get_environ_user(environ)
105 username = self.__get_environ_user(environ)
105 try:
106 try:
106 user = self.__get_user(username)
107 user = self.__get_user(username)
107 self.username = user.username
108 self.username = user.username
108 except:
109 except:
109 log.error(traceback.format_exc())
110 log.error(traceback.format_exc())
110 return HTTPInternalServerError()(environ, start_response)
111 return HTTPInternalServerError()(environ, start_response)
111
112
112 #check permissions for this repository
113 #check permissions for this repository
113 if self.action == 'push':
114 if self.action == 'push':
114 if not HasPermissionAnyMiddleware('repository.write',
115 if not HasPermissionAnyMiddleware('repository.write',
115 'repository.admin')\
116 'repository.admin')\
116 (user, repo_name):
117 (user, repo_name):
117 return HTTPForbidden()(environ, start_response)
118 return HTTPForbidden()(environ, start_response)
118
119
119 else:
120 else:
120 #any other action need at least read permission
121 #any other action need at least read permission
121 if not HasPermissionAnyMiddleware('repository.read',
122 if not HasPermissionAnyMiddleware('repository.read',
122 'repository.write',
123 'repository.write',
123 'repository.admin')\
124 'repository.admin')\
124 (user, repo_name):
125 (user, repo_name):
125 return HTTPForbidden()(environ, start_response)
126 return HTTPForbidden()(environ, start_response)
126
127
127 self.extras = {'ip':self.ipaddr,
128 self.extras = {'ip':self.ipaddr,
128 'username':self.username,
129 'username':self.username,
129 'action':self.action,
130 'action':self.action,
130 'repository':self.repository}
131 'repository':self.repository}
131
132
132 #===================================================================
133 #===================================================================
133 # MERCURIAL REQUEST HANDLING
134 # MERCURIAL REQUEST HANDLING
134 #===================================================================
135 #===================================================================
135 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
136 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
136 self.baseui = make_ui('db')
137 self.baseui = make_ui('db')
137 self.basepath = self.config['base_path']
138 self.basepath = self.config['base_path']
138 self.repo_path = os.path.join(self.basepath, repo_name)
139 self.repo_path = os.path.join(self.basepath, repo_name)
139
140
140 #quick check if that dir exists...
141 #quick check if that dir exists...
141 if check_repo_fast(repo_name, self.basepath):
142 if check_repo_fast(repo_name, self.basepath):
142 return HTTPNotFound()(environ, start_response)
143 return HTTPNotFound()(environ, start_response)
143 try:
144 try:
144 app = wsgiapplication(self.__make_app)
145 app = wsgiapplication(self.__make_app)
145 except RepoError, e:
146 except RepoError, e:
146 if str(e).find('not found') != -1:
147 if str(e).find('not found') != -1:
147 return HTTPNotFound()(environ, start_response)
148 return HTTPNotFound()(environ, start_response)
148 except Exception:
149 except Exception:
149 log.error(traceback.format_exc())
150 log.error(traceback.format_exc())
150 return HTTPInternalServerError()(environ, start_response)
151 return HTTPInternalServerError()(environ, start_response)
151
152
152 #invalidate cache on push
153 #invalidate cache on push
153 if self.action == 'push':
154 if self.action == 'push':
154 self.__invalidate_cache(repo_name)
155 self.__invalidate_cache(repo_name)
155
156
156 return app(environ, start_response)
157 return app(environ, start_response)
157
158
158
159
159 def __make_app(self):
160 def __make_app(self):
160 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
161 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
161 return self.__load_web_settings(hgserve, self.extras)
162 return self.__load_web_settings(hgserve, self.extras)
162
163
163 def __get_environ_user(self, environ):
164 def __get_environ_user(self, environ):
164 return environ.get('REMOTE_USER')
165 return environ.get('REMOTE_USER')
165
166
166 def __get_user(self, username):
167 def __get_user(self, username):
167 return UserModel().get_by_username(username, cache=True)
168 return UserModel().get_by_username(username, cache=True)
168
169
169 def __get_action(self, environ):
170 def __get_action(self, environ):
170 """
171 """
171 Maps mercurial request commands into a clone,pull or push command.
172 Maps mercurial request commands into a clone,pull or push command.
172 This should always return a valid command string
173 This should always return a valid command string
173 :param environ:
174 :param environ:
174 """
175 """
175 mapping = {'changegroup': 'pull',
176 mapping = {'changegroup': 'pull',
176 'changegroupsubset': 'pull',
177 'changegroupsubset': 'pull',
177 'stream_out': 'pull',
178 'stream_out': 'pull',
178 'listkeys': 'pull',
179 'listkeys': 'pull',
179 'unbundle': 'push',
180 'unbundle': 'push',
180 'pushkey': 'push', }
181 'pushkey': 'push', }
181 for qry in environ['QUERY_STRING'].split('&'):
182 for qry in environ['QUERY_STRING'].split('&'):
182 if qry.startswith('cmd'):
183 if qry.startswith('cmd'):
183 cmd = qry.split('=')[-1]
184 cmd = qry.split('=')[-1]
184 if mapping.has_key(cmd):
185 if mapping.has_key(cmd):
185 return mapping[cmd]
186 return mapping[cmd]
186 else:
187 else:
187 return cmd
188 return cmd
188
189
189 def __invalidate_cache(self, repo_name):
190 def __invalidate_cache(self, repo_name):
190 """we know that some change was made to repositories and we should
191 """we know that some change was made to repositories and we should
191 invalidate the cache to see the changes right away but only for
192 invalidate the cache to see the changes right away but only for
192 push requests"""
193 push requests"""
193 invalidate_cache('get_repo_cached_%s' % repo_name)
194 invalidate_cache('get_repo_cached_%s' % repo_name)
194
195
195
196
196 def __load_web_settings(self, hgserve, extras={}):
197 def __load_web_settings(self, hgserve, extras={}):
197 #set the global ui for hgserve instance passed
198 #set the global ui for hgserve instance passed
198 hgserve.repo.ui = self.baseui
199 hgserve.repo.ui = self.baseui
199
200
200 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
201 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
201
202
202 #inject some additional parameters that will be available in ui
203 #inject some additional parameters that will be available in ui
203 #for hooks
204 #for hooks
204 for k, v in extras.items():
205 for k, v in extras.items():
205 hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
206 hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
206
207
207 repoui = make_ui('file', hgrc, False)
208 repoui = make_ui('file', hgrc, False)
208
209
209 if repoui:
210 if repoui:
210 #overwrite our ui instance with the section from hgrc file
211 #overwrite our ui instance with the section from hgrc file
211 for section in ui_sections:
212 for section in ui_sections:
212 for k, v in repoui.configitems(section):
213 for k, v in repoui.configitems(section):
213 hgserve.repo.ui.setconfig(section, k, v)
214 hgserve.repo.ui.setconfig(section, k, v)
214
215
215 return hgserve
216 return hgserve
216
217
217
218
218
219
219
220
220
221
221
222
222
223
223
224
224
225
225
226
226
227
227
228
228
229
229
230
General Comments 0
You need to be logged in to leave comments. Login now