comparison rhodecode/lib/middleware/simplegit.py @ 2726:aa17c7a1b8a5 beta

Implemented basic locking functionality. - Reimplemented how githooks behave - emaulate pre-receive hook - install missing git hooks if they aren't already in repo
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 22 Aug 2012 00:30:02 +0200
parents 4c71667160e5
children 63e58ef80ef1 dd2d5b65cae9
comparison
equal deleted inserted replaced
2725:3853e37db97c 2726:aa17c7a1b8a5
29 import logging 29 import logging
30 import traceback 30 import traceback
31 31
32 from dulwich import server as dulserver 32 from dulwich import server as dulserver
33 from dulwich.web import LimitedInputFilter, GunzipFilter 33 from dulwich.web import LimitedInputFilter, GunzipFilter
34 from rhodecode.lib.exceptions import HTTPLockedRC
35 from rhodecode.lib.hooks import pre_pull
34 36
35 37
36 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler): 38 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
37 39
38 def handle(self): 40 def handle(self):
100 102
101 103
102 class SimpleGit(BaseVCSController): 104 class SimpleGit(BaseVCSController):
103 105
104 def _handle_request(self, environ, start_response): 106 def _handle_request(self, environ, start_response):
105
106 if not is_git(environ): 107 if not is_git(environ):
107 return self.application(environ, start_response) 108 return self.application(environ, start_response)
108 if not self._check_ssl(environ, start_response): 109 if not self._check_ssl(environ, start_response):
109 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) 110 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
111
110 ipaddr = self._get_ip_addr(environ) 112 ipaddr = self._get_ip_addr(environ)
111 username = None 113 username = None
112 self._git_first_op = False 114 self._git_first_op = False
113 # skip passing error to error controller 115 # skip passing error to error controller
114 environ['pylons.status_code_redirect'] = True 116 environ['pylons.status_code_redirect'] = True
182 #check permissions for this repository 184 #check permissions for this repository
183 perm = self._check_permission(action, user, repo_name) 185 perm = self._check_permission(action, user, repo_name)
184 if perm is not True: 186 if perm is not True:
185 return HTTPForbidden()(environ, start_response) 187 return HTTPForbidden()(environ, start_response)
186 188
189 # extras are injected into UI object and later available
190 # in hooks executed by rhodecode
187 extras = { 191 extras = {
188 'ip': ipaddr, 192 'ip': ipaddr,
189 'username': username, 193 'username': username,
190 'action': action, 194 'action': action,
191 'repository': repo_name, 195 'repository': repo_name,
192 'scm': 'git', 196 'scm': 'git',
197 'make_lock': None,
198 'locked_by': [None, None]
193 } 199 }
194 # set the environ variables for this request 200
195 os.environ['RC_SCM_DATA'] = json.dumps(extras)
196 #=================================================================== 201 #===================================================================
197 # GIT REQUEST HANDLING 202 # GIT REQUEST HANDLING
198 #=================================================================== 203 #===================================================================
199 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name)) 204 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
200 log.debug('Repository path is %s' % repo_path) 205 log.debug('Repository path is %s' % repo_path)
201 206
207 # CHECK LOCKING only if it's not ANONYMOUS USER
208 if username != User.DEFAULT_USER:
209 log.debug('Checking locking on repository')
210 (make_lock,
211 locked,
212 locked_by) = self._check_locking_state(
213 environ=environ, action=action,
214 repo=repo_name, user_id=user.user_id
215 )
216 # store the make_lock for later evaluation in hooks
217 extras.update({'make_lock': make_lock,
218 'locked_by': locked_by})
219 # set the environ variables for this request
220 os.environ['RC_SCM_DATA'] = json.dumps(extras)
221 log.debug('HOOKS extras is %s' % extras)
202 baseui = make_ui('db') 222 baseui = make_ui('db')
203 self.__inject_extras(repo_path, baseui, extras) 223 self.__inject_extras(repo_path, baseui, extras)
204 224
205 try: 225 try:
206 # invalidate cache on push 226 # invalidate cache on push
207 if action == 'push': 227 if action == 'push':
208 self._invalidate_cache(repo_name) 228 self._invalidate_cache(repo_name)
209 self._handle_githooks(repo_name, action, baseui, environ) 229 self._handle_githooks(repo_name, action, baseui, environ)
210 230
211 log.info('%s action on GIT repo "%s"' % (action, repo_name)) 231 log.info('%s action on GIT repo "%s"' % (action, repo_name))
212 app = self.__make_app(repo_name, repo_path, username) 232 app = self.__make_app(repo_name, repo_path, extras)
213 return app(environ, start_response) 233 return app(environ, start_response)
234 except HTTPLockedRC, e:
235 log.debug('Repositry LOCKED ret code 423!')
236 return e(environ, start_response)
214 except Exception: 237 except Exception:
215 log.error(traceback.format_exc()) 238 log.error(traceback.format_exc())
216 return HTTPInternalServerError()(environ, start_response) 239 return HTTPInternalServerError()(environ, start_response)
217 240
218 def __make_app(self, repo_name, repo_path, username): 241 def __make_app(self, repo_name, repo_path, extras):
219 """ 242 """
220 Make an wsgi application using dulserver 243 Make an wsgi application using dulserver
221 244
222 :param repo_name: name of the repository 245 :param repo_name: name of the repository
223 :param repo_path: full path to the repository 246 :param repo_path: full path to the repository
225 248
226 from rhodecode.lib.middleware.pygrack import make_wsgi_app 249 from rhodecode.lib.middleware.pygrack import make_wsgi_app
227 app = make_wsgi_app( 250 app = make_wsgi_app(
228 repo_root=safe_str(self.basepath), 251 repo_root=safe_str(self.basepath),
229 repo_name=repo_name, 252 repo_name=repo_name,
230 username=username, 253 extras=extras,
231 ) 254 )
232 app = GunzipFilter(LimitedInputFilter(app)) 255 app = GunzipFilter(LimitedInputFilter(app))
233 return app 256 return app
234 257
235 def __get_repository(self, environ): 258 def __get_repository(self, environ):
277 """ 300 """
278 Handles pull action, push is handled by post-receive hook 301 Handles pull action, push is handled by post-receive hook
279 """ 302 """
280 from rhodecode.lib.hooks import log_pull_action 303 from rhodecode.lib.hooks import log_pull_action
281 service = environ['QUERY_STRING'].split('=') 304 service = environ['QUERY_STRING'].split('=')
305
282 if len(service) < 2: 306 if len(service) < 2:
283 return 307 return
284 308
285 from rhodecode.model.db import Repository 309 from rhodecode.model.db import Repository
286 _repo = Repository.get_by_repo_name(repo_name) 310 _repo = Repository.get_by_repo_name(repo_name)
287 _repo = _repo.scm_instance 311 _repo = _repo.scm_instance
288 _repo._repo.ui = baseui 312 _repo._repo.ui = baseui
289 313
290 _hooks = dict(baseui.configitems('hooks')) or {} 314 _hooks = dict(baseui.configitems('hooks')) or {}
315 if action == 'pull':
316 # stupid git, emulate pre-pull hook !
317 pre_pull(ui=baseui, repo=_repo._repo)
291 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL): 318 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
292 log_pull_action(ui=baseui, repo=_repo._repo) 319 log_pull_action(ui=baseui, repo=_repo._repo)
293 320
294 def __inject_extras(self, repo_path, baseui, extras={}): 321 def __inject_extras(self, repo_path, baseui, extras={}):
295 """ 322 """