Mercurial > kallithea
comparison pylons_app/lib/middleware/simplehg.py @ 204:a8ea3ce3cdc4
Created middleware package. Crated special middleware to handle https requests redirections.
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sun, 23 May 2010 00:54:22 +0200 |
parents | pylons_app/lib/simplehg.py@be6d8aaddbd1 |
children | 58b46f9194c3 |
comparison
equal
deleted
inserted
replaced
203:be6d8aaddbd1 | 204:a8ea3ce3cdc4 |
---|---|
1 #!/usr/bin/env python | |
2 # encoding: utf-8 | |
3 # | |
4 # Copyright (c) 2010 marcink. All rights reserved. | |
5 # | |
6 """ | |
7 Created on 2010-04-28 | |
8 | |
9 @author: marcink | |
10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.) | |
11 It's implemented with basic auth function | |
12 """ | |
13 from datetime import datetime | |
14 from mercurial.hgweb import hgweb | |
15 from mercurial.hgweb.request import wsgiapplication | |
16 from paste.auth.basic import AuthBasicAuthenticator | |
17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE | |
18 from pylons_app.lib.auth import authfunc | |
19 from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache | |
20 from pylons_app.model import meta | |
21 from pylons_app.model.db import UserLogs, Users | |
22 from webob.exc import HTTPNotFound | |
23 import logging | |
24 import os | |
25 log = logging.getLogger(__name__) | |
26 | |
27 class SimpleHg(object): | |
28 | |
29 def __init__(self, application, config): | |
30 self.application = application | |
31 self.config = config | |
32 #authenticate this mercurial request using | |
33 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository') | |
34 self.authenticate = AuthBasicAuthenticator(realm, authfunc) | |
35 | |
36 def __call__(self, environ, start_response): | |
37 if not is_mercurial(environ): | |
38 return self.application(environ, start_response) | |
39 else: | |
40 #=================================================================== | |
41 # AUTHENTICATE THIS MERCURIAL REQUEST | |
42 #=================================================================== | |
43 username = REMOTE_USER(environ) | |
44 if not username: | |
45 result = self.authenticate(environ) | |
46 if isinstance(result, str): | |
47 AUTH_TYPE.update(environ, 'basic') | |
48 REMOTE_USER.update(environ, result) | |
49 else: | |
50 return result.wsgi_application(environ, start_response) | |
51 | |
52 try: | |
53 repo_name = environ['PATH_INFO'].split('/')[1] | |
54 except: | |
55 return HTTPNotFound()(environ, start_response) | |
56 | |
57 #since we wrap into hgweb, just reset the path | |
58 environ['PATH_INFO'] = '/' | |
59 self.baseui = make_ui() | |
60 self.basepath = self.baseui.configitems('paths')[0][1]\ | |
61 .replace('*', '') | |
62 self.repo_path = os.path.join(self.basepath, repo_name) | |
63 try: | |
64 app = wsgiapplication(self.__make_app) | |
65 except Exception as e: | |
66 return HTTPNotFound()(environ, start_response) | |
67 | |
68 action = self.__get_action(environ) | |
69 #invalidate cache on push | |
70 if action == 'push': | |
71 self.__invalidate_cache(repo_name) | |
72 | |
73 if action: | |
74 username = self.__get_environ_user(environ) | |
75 self.__log_user_action(username, action, repo_name) | |
76 return app(environ, start_response) | |
77 | |
78 def __make_app(self): | |
79 hgserve = hgweb(self.repo_path) | |
80 return self.load_web_settings(hgserve) | |
81 | |
82 def __get_environ_user(self, environ): | |
83 return environ.get('REMOTE_USER') | |
84 | |
85 def __get_action(self, environ): | |
86 """ | |
87 Maps mercurial request commands into a pull or push command. | |
88 @param environ: | |
89 """ | |
90 mapping = { | |
91 'changegroup': 'pull', | |
92 'changegroupsubset': 'pull', | |
93 'unbundle': 'push', | |
94 'stream_out': 'pull', | |
95 } | |
96 for qry in environ['QUERY_STRING'].split('&'): | |
97 if qry.startswith('cmd'): | |
98 cmd = qry.split('=')[-1] | |
99 if mapping.has_key(cmd): | |
100 return mapping[cmd] | |
101 | |
102 def __log_user_action(self, username, action, repo): | |
103 sa = meta.Session | |
104 try: | |
105 user = sa.query(Users)\ | |
106 .filter(Users.username == username).one() | |
107 user_log = UserLogs() | |
108 user_log.user_id = user.user_id | |
109 user_log.action = action | |
110 user_log.repository = repo.replace('/', '') | |
111 user_log.action_date = datetime.now() | |
112 sa.add(user_log) | |
113 sa.commit() | |
114 log.info('Adding user %s, action %s on %s', | |
115 username, action, repo) | |
116 except Exception as e: | |
117 sa.rollback() | |
118 log.error('could not log user action:%s', str(e)) | |
119 | |
120 def __invalidate_cache(self, repo_name): | |
121 """we know that some change was made to repositories and we should | |
122 invalidate the cache to see the changes right away but only for | |
123 push requests""" | |
124 invalidate_cache('cached_repo_list') | |
125 invalidate_cache('full_changelog', repo_name) | |
126 | |
127 | |
128 def load_web_settings(self, hgserve): | |
129 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False) | |
130 #set the global ui for hgserve | |
131 hgserve.repo.ui = self.baseui | |
132 | |
133 if repoui: | |
134 #set the repository based config | |
135 hgserve.repo.ui = repoui | |
136 | |
137 return hgserve | |
138 | |
139 |