def is_valid(cls, repo_name): """ returns True if given repo name is a valid filesystem repository :param cls: :param repo_name: """ from kallithea.lib.utils import is_valid_repo return is_valid_repo(repo_name, cls.base_path())
def check_repo(environ, match_dict): """ Check for valid repository for proper 404 handling. Also, a bit of side effect modifying match_dict ... """ if match_dict.get('f_path'): # fix for multiple initial slashes that causes errors match_dict['f_path'] = match_dict['f_path'].lstrip('/') return is_valid_repo(match_dict['repo_name'], config['base_path'])
def __call__(self, environ, start_response): try: # try parsing a request for this VCS - if it fails, call the wrapped app parsed_request = self.parse_request(environ) if parsed_request is None: return self.application(environ, start_response) # skip passing error to error controller environ['pylons.status_code_redirect'] = True # quick check if repo exists... if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias): raise webob.exc.HTTPNotFound() if parsed_request.action is None: # Note: the client doesn't get the helpful error message raise webob.exc.HTTPBadRequest( 'Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name) #====================================================================== # CHECK PERMISSIONS #====================================================================== ip_addr = self._get_ip_addr(environ) user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr) if response_app is not None: return response_app(environ, start_response) #====================================================================== # REQUEST HANDLING #====================================================================== set_hook_environment(user.username, ip_addr, parsed_request.repo_name, self.scm_alias, parsed_request.action) try: log.info('%s action on %s repo "%s" by "%s" from %s', parsed_request.action, self.scm_alias, parsed_request.repo_name, user.username, ip_addr) app = self._make_app(parsed_request) return app(environ, start_response) except Exception: log.error(traceback.format_exc()) raise webob.exc.HTTPInternalServerError() except webob.exc.HTTPException as e: return e(environ, start_response)
def check_repo(environ, match_dict): """ check for valid repository for proper 404 handling :param environ: :param match_dict: """ repo_name = match_dict.get('repo_name') if match_dict.get('f_path'): #fix for multiple initial slashes that causes errors match_dict['f_path'] = match_dict['f_path'].lstrip('/') by_id_match = get_repo_by_id(repo_name) if by_id_match: repo_name = by_id_match match_dict['repo_name'] = repo_name return is_valid_repo(repo_name, config['base_path'])
def check_repo(environ, match_dict): """ check for valid repository for proper 404 handling :param environ: :param match_dict: """ repo_name = match_dict.get('repo_name') if match_dict.get('f_path'): #fix for multiple initial slashes that causes errors match_dict['f_path'] = match_dict['f_path'].lstrip('/') by_id_match = get_repo_by_id(repo_name) if by_id_match: repo_name = by_id_match match_dict['repo_name'] = repo_name return is_valid_repo(repo_name, config['base_path'])
def _create_filesystem_repo(self, repo_name, repo_type, repo_group, clone_uri=None, repo_store_location=None): """ Makes repository on filesystem. Operation is group aware, meaning that it will create a repository within a group, and alter the paths accordingly to the group location. :param repo_name: :param alias: :param parent: :param clone_uri: :param repo_store_location: """ from kallithea.lib.utils import is_valid_repo, is_valid_repo_group from kallithea.model.scm import ScmModel if '/' in repo_name: raise ValueError('repo_name must not contain groups got `%s`' % repo_name) if isinstance(repo_group, RepoGroup): new_parent_path = os.sep.join(repo_group.full_path_splitted) else: new_parent_path = repo_group or '' if repo_store_location: _paths = [repo_store_location] else: _paths = [self.repos_path, new_parent_path, repo_name] # we need to make it str for mercurial repo_path = os.path.join(*map(lambda x: safe_str(x), _paths)) # check if this path is not a repository if is_valid_repo(repo_path, self.repos_path): raise Exception('This path %s is a valid repository' % repo_path) # check if this path is a group if is_valid_repo_group(repo_path, self.repos_path): raise Exception('This path %s is a valid group' % repo_path) log.info('creating repo %s in %s from url: `%s`', repo_name, safe_unicode(repo_path), obfuscate_url_pw(clone_uri)) backend = get_backend(repo_type) if repo_type == 'hg': baseui = make_ui('db', clear_session=False) # patch and reset hooks section of UI config to not run any # hooks on creating remote repo for k, v in baseui.configitems('hooks'): baseui.setconfig('hooks', k, None) repo = backend(repo_path, create=True, src_url=clone_uri, baseui=baseui) elif repo_type == 'git': repo = backend(repo_path, create=True, src_url=clone_uri, bare=True) # add kallithea hook into this repo ScmModel().install_git_hooks(repo=repo) else: raise Exception('Not supported repo_type %s expected hg/git' % repo_type) log.debug('Created repo %s with %s backend', safe_unicode(repo_name), safe_unicode(repo_type)) return repo
def _handle_request(self, environ, start_response): if not is_mercurial(environ): return self.application(environ, start_response) ip_addr = self._get_ip_addr(environ) # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: str_repo_name = environ['REPO_NAME'] = self.__get_repository(environ) assert isinstance(str_repo_name, str), str_repo_name repo_name = safe_unicode(str_repo_name) assert safe_str(repo_name) == str_repo_name, (str_repo_name, repo_name) log.debug('Extracted repo name is %s', repo_name) except Exception as e: log.error('error extracting repo_name: %r', e) return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'hg'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== try: action = self.__get_action(environ) except HTTPBadRequest as e: return e(environ, start_response) #====================================================================== # CHECK PERMISSIONS #====================================================================== user, response_app = self._authorize(environ, start_response, action, repo_name, ip_addr) if response_app is not None: return response_app(environ, start_response) # extras are injected into mercurial UI object and later available # in hg hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': user.username, 'action': action, 'repository': repo_name, 'scm': 'hg', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #====================================================================== # MERCURIAL REQUEST HANDLING #====================================================================== repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) # A Mercurial HTTP server will see listkeys operations (bookmarks, # phases and obsolescence marker) in a different request - we don't # want to check locking on those if environ['QUERY_STRING'] == 'cmd=listkeys': pass # CHECK LOCKING only if it's not ANONYMOUS USER elif not user.is_default_user: log.debug('Checking locking on repository') make_lock, locked, locked_by = check_locking_state(action, repo_name, user) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: log.info('%s action on Mercurial repo "%s" by "%s" from %s', action, str_repo_name, safe_str(user.username), ip_addr) app = self.__make_app(repo_path, baseui, extras) result = app(environ, start_response) if action == 'push': result = WSGIResultCloseCallback(result, lambda: self._invalidate_cache(repo_name)) return result except RepoError as e: if str(e).find('not found') != -1: return HTTPNotFound()(environ, start_response) except HTTPLockedRC as e: # Before Mercurial 3.6, lock exceptions were caught here log.debug('Locked, response %s: %s', e.code, e.title) return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response)
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: str_repo_name = self.__get_repository(environ) repo_name = safe_unicode(str_repo_name) log.debug('Extracted repo name is %s', repo_name) except Exception as e: log.error('error extracting repo_name: %r', e) return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = User.get_default_user(cache=True) username = anonymous_user.username if anonymous_user.active: # ONLY check permissions if the user is activated anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr) else: anonymous_perm = False if not anonymous_user.active or not anonymous_perm: if not anonymous_user.active: log.debug('Anonymous access is disabled, running ' 'authentication') if not anonymous_perm: log.debug('Not enough credentials to access this ' 'repository as anonymous user') username = None #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # try to auth based on environ, container auth methods log.debug('Running PRE-AUTH for container based authentication') pre_auth = auth_modules.authenticate('', '', environ) if pre_auth is not None and pre_auth.get('username'): username = pre_auth['username'] log.debug('PRE-AUTH got %s as username', username) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = User.get_by_username_or_email(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== repo_path = os.path.join(safe_str(self.basepath),str_repo_name) log.debug('Repository path is %s', repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state( environ=environ, action=action, repo=repo_name, user_id=user.user_id ) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on Git repo "%s" by "%s" from %s', action, str_repo_name, safe_str(username), ip_addr) app = self.__make_app(repo_name, repo_path, extras) result = app(environ, start_response) if action == 'push': result = WSGIResultCloseCallback(result, lambda: self._invalidate_cache(repo_name)) return result except HTTPLockedRC as e: _code = CONFIG.get('lock_ret_code') log.debug('Repository LOCKED ret code %s!', _code) return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response)
def _create_filesystem_repo(self, repo_name, repo_type, repo_group, clone_uri=None, repo_store_location=None): """ Makes repository on filesystem. Operation is group aware, meaning that it will create a repository within a group, and alter the paths accordingly to the group location. :param repo_name: :param alias: :param parent: :param clone_uri: :param repo_store_location: """ from kallithea.lib.utils import is_valid_repo, is_valid_repo_group from kallithea.model.scm import ScmModel if '/' in repo_name: raise ValueError('repo_name must not contain groups got `%s`' % repo_name) if isinstance(repo_group, RepoGroup): new_parent_path = os.sep.join(repo_group.full_path_splitted) else: new_parent_path = repo_group or '' if repo_store_location: _paths = [repo_store_location] else: _paths = [self.repos_path, new_parent_path, repo_name] # we need to make it str for mercurial repo_path = os.path.join(*map(lambda x: safe_str(x), _paths)) # check if this path is not a repository if is_valid_repo(repo_path, self.repos_path): raise Exception('This path %s is a valid repository' % repo_path) # check if this path is a group if is_valid_repo_group(repo_path, self.repos_path): raise Exception('This path %s is a valid group' % repo_path) log.info('creating repo %s in %s from url: `%s`' % ( repo_name, safe_unicode(repo_path), obfuscate_url_pw(clone_uri))) backend = get_backend(repo_type) if repo_type == 'hg': baseui = make_ui('db', clear_session=False) # patch and reset hooks section of UI config to not run any # hooks on creating remote repo for k, v in baseui.configitems('hooks'): baseui.setconfig('hooks', k, None) repo = backend(repo_path, create=True, src_url=clone_uri, baseui=baseui) elif repo_type == 'git': repo = backend(repo_path, create=True, src_url=clone_uri, bare=True) # add kallithea hook into this repo ScmModel().install_git_hook(repo=repo) else: raise Exception('Not supported repo_type %s expected hg/git' % repo_type) log.debug('Created repo %s with %s backend' % (safe_unicode(repo_name), safe_unicode(repo_type))) return repo
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) ip_addr = self._get_ip_addr(environ) self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: str_repo_name = self.__get_repository(environ) repo_name = safe_unicode(str_repo_name) log.debug('Extracted repo name is %s', repo_name) except Exception as e: log.error('error extracting repo_name: %r', e) return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK PERMISSIONS #====================================================================== user, response_app = self._authorize(environ, start_response, action, repo_name, ip_addr) if response_app is not None: return response_app(environ, start_response) # extras are injected into UI object and later available # in hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': user.username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== repo_path = os.path.join(safe_str(self.basepath),str_repo_name) log.debug('Repository path is %s', repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if not user.is_default_user: log.debug('Checking locking on repository') make_lock, locked, locked_by = check_locking_state(action, repo_name, user) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on Git repo "%s" by "%s" from %s', action, str_repo_name, safe_str(user.username), ip_addr) app = self.__make_app(repo_name, repo_path, extras) result = app(environ, start_response) if action == 'push': result = WSGIResultCloseCallback(result, lambda: self._invalidate_cache(repo_name)) return result except HTTPLockedRC as e: log.debug('Locked, response %s: %s', e.code, e.title) return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response)
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) ip_addr = self._get_ip_addr(environ) self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: str_repo_name = self.__get_repository(environ) repo_name = safe_unicode(str_repo_name) log.debug('Extracted repo name is %s', repo_name) except Exception as e: log.error('error extracting repo_name: %r', e) return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK PERMISSIONS #====================================================================== user, response_app = self._authorize(environ, start_response, action, repo_name, ip_addr) if response_app is not None: return response_app(environ, start_response) # extras are injected into UI object and later available # in hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': user.username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if not user.is_default_user: log.debug('Checking locking on repository') make_lock, locked, locked_by = check_locking_state( action, repo_name, user) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on Git repo "%s" by "%s" from %s', action, str_repo_name, safe_str(user.username), ip_addr) app = self.__make_app(repo_name, repo_path, extras) result = app(environ, start_response) if action == 'push': result = WSGIResultCloseCallback( result, lambda: self._invalidate_cache(repo_name)) return result except HTTPLockedRC as e: log.debug('Locked, response %s: %s', e.code, e.title) return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response)
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: repo_name = self.__get_repository(environ) log.debug('Extracted repo name is %s' % repo_name) except Exception: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = self.__get_user('default') username = anonymous_user.username if anonymous_user.active: # ONLY check permissions if the user is activated anonymous_perm = self._check_permission( action, anonymous_user, repo_name, ip_addr) else: anonymous_perm = False if not anonymous_user.active or not anonymous_perm: if not anonymous_user.active: log.debug('Anonymous access is disabled, running ' 'authentication') if not anonymous_perm: log.debug('Not enough credentials to access this ' 'repository as anonymous user') username = None #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # try to auth based on environ, container auth methods log.debug( 'Running PRE-AUTH for container based authentication') pre_auth = auth_modules.authenticate('', '', environ) if pre_auth and pre_auth.get('username'): username = pre_auth['username'] log.debug('PRE-AUTH got %s as username' % username) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== str_repo_name = safe_str(repo_name) repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s' % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state(environ=environ, action=action, repo=repo_name, user_id=user.user_id) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s' % extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on Git repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) except HTTPLockedRC, e: _code = CONFIG.get('lock_ret_code') log.debug('Repository LOCKED ret code %s!' % (_code)) return e(environ, start_response)
def _handle_request(self, environ, start_response): if not is_mercurial(environ): return self.application(environ, start_response) ip_addr = self._get_ip_addr(environ) # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: str_repo_name = environ['REPO_NAME'] = self.__get_repository( environ) assert isinstance(str_repo_name, str), str_repo_name repo_name = safe_unicode(str_repo_name) assert safe_str(repo_name) == str_repo_name, (str_repo_name, repo_name) log.debug('Extracted repo name is %s', repo_name) except Exception as e: log.error('error extracting repo_name: %r', e) return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'hg'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== try: action = self.__get_action(environ) except HTTPBadRequest as e: return e(environ, start_response) #====================================================================== # CHECK PERMISSIONS #====================================================================== user, response_app = self._authorize(environ, start_response, action, repo_name, ip_addr) if response_app is not None: return response_app(environ, start_response) # extras are injected into mercurial UI object and later available # in hg hooks executed by kallithea from kallithea import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': user.username, 'action': action, 'repository': repo_name, 'scm': 'hg', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #====================================================================== # MERCURIAL REQUEST HANDLING #====================================================================== repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) # A Mercurial HTTP server will see listkeys operations (bookmarks, # phases and obsolescence marker) in a different request - we don't # want to check locking on those if environ['QUERY_STRING'] == 'cmd=listkeys': pass # CHECK LOCKING only if it's not ANONYMOUS USER elif not user.is_default_user: log.debug('Checking locking on repository') make_lock, locked, locked_by = check_locking_state( action, repo_name, user) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: log.info('%s action on Mercurial repo "%s" by "%s" from %s', action, str_repo_name, safe_str(user.username), ip_addr) app = self.__make_app(repo_path, baseui, extras) result = app(environ, start_response) if action == 'push': result = WSGIResultCloseCallback( result, lambda: self._invalidate_cache(repo_name)) return result except RepoError as e: if str(e).find('not found') != -1: return HTTPNotFound()(environ, start_response) except HTTPLockedRC as e: # Before Mercurial 3.6, lock exceptions were caught here log.debug('Locked, response %s: %s', e.code, e.title) return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response)