##// END OF EJS Templates
#48 rewrite action loggers into hooks with all changesets that are inside a push
marcink -
r654:7f5976da beta
parent child Browse files
Show More
@@ -22,12 +22,12 b' Created on Aug 6, 2010'
22
22
23 @author: marcink
23 @author: marcink
24 """
24 """
25
25 from mercurial.cmdutil import revrange
26 import sys
26 from mercurial.node import nullrev
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.utils import action_logger
27 import os
29 import os
28 from rhodecode.lib import helpers as h
30 import sys
29 from rhodecode.model import meta
30 from rhodecode.model.db import UserLog, User
31
31
32 def repo_size(ui, repo, hooktype=None, **kwargs):
32 def repo_size(ui, repo, hooktype=None, **kwargs):
33
33
@@ -48,31 +48,52 b' def repo_size(ui, repo, hooktype=None, *'
48 sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
48 sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
49 % (size_hg_f, size_root_f, size_total_f))
49 % (size_hg_f, size_root_f, size_total_f))
50
50
51 user_action_mapper(ui, repo, hooktype, **kwargs)
51 def log_pull_action(ui, repo, **kwargs):
52 """
53 Logs user last pull action
54 :param ui:
55 :param repo:
56 """
52
57
53 def user_action_mapper(ui, repo, hooktype=None, **kwargs):
58 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
59 username = extra_params['username']
60 repository = extra_params['repository']
61 action = 'pull'
62
63 action_logger(username, action, repository, extra_params['ip'])
64
65 return 0
66
67 def log_push_action(ui, repo, **kwargs):
54 """
68 """
55 Maps user last push action to new changeset id, from mercurial
69 Maps user last push action to new changeset id, from mercurial
56 :param ui:
70 :param ui:
57 :param repo:
71 :param repo:
58 :param hooktype:
59 """
72 """
60
73
61 try:
74 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
62 sa = meta.Session()
75 username = extra_params['username']
63 username = kwargs['url'].split(':')[-1]
76 repository = extra_params['repository']
64 user_log = sa.query(UserLog)\
77 action = 'push:%s'
65 .filter(UserLog.user == sa.query(User)\
78 node = kwargs['node']
66 .filter(User.username == username).one())\
79
67 .order_by(UserLog.user_log_id.desc()).first()
80 def get_revs(repo, rev_opt):
81 if rev_opt:
82 revs = revrange(repo, rev_opt)
68
83
69 if user_log and not user_log.revision:
84 if len(revs) == 0:
70 user_log.revision = str(repo['tip'])
85 return (nullrev, nullrev)
71 sa.add(user_log)
86 return (max(revs), min(revs))
72 sa.commit()
87 else:
88 return (len(repo) - 1, 0)
89
90 stop, start = get_revs(repo, [node + ':'])
73
91
74 except Exception, e:
92 revs = (str(repo[r]) for r in xrange(start, stop + 1))
75 sa.rollback()
93
76 raise
94 action = action % ','.join(revs)
77 finally:
95
78 meta.Session.remove()
96 action_logger(username, action, repository, extra_params['ip'])
97
98 return 0
99
@@ -49,15 +49,24 b' class SimpleHg(object):'
49 self.config = config
49 self.config = config
50 #authenticate this mercurial request using
50 #authenticate this mercurial request using
51 self.authenticate = AuthBasicAuthenticator('', authfunc)
51 self.authenticate = AuthBasicAuthenticator('', authfunc)
52 self.ipaddr = '0.0.0.0'
53 self.repository = None
54 self.username = None
55 self.action = None
52
56
53 def __call__(self, environ, start_response):
57 def __call__(self, environ, start_response):
54 if not is_mercurial(environ):
58 if not is_mercurial(environ):
55 return self.application(environ, start_response)
59 return self.application(environ, start_response)
56
60
61 proxy_key = 'HTTP_X_REAL_IP'
62 def_key = 'REMOTE_ADDR'
63 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
64
57 #===================================================================
65 #===================================================================
58 # AUTHENTICATE THIS MERCURIAL REQUEST
66 # AUTHENTICATE THIS MERCURIAL REQUEST
59 #===================================================================
67 #===================================================================
60 username = REMOTE_USER(environ)
68 username = REMOTE_USER(environ)
69
61 if not username:
70 if not username:
62 self.authenticate.realm = self.config['rhodecode_realm']
71 self.authenticate.realm = self.config['rhodecode_realm']
63 result = self.authenticate(environ)
72 result = self.authenticate(environ)
@@ -67,10 +76,14 b' class SimpleHg(object):'
67 else:
76 else:
68 return result.wsgi_application(environ, start_response)
77 return result.wsgi_application(environ, start_response)
69
78
79 #=======================================================================
80 # GET REPOSITORY
81 #=======================================================================
70 try:
82 try:
71 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
83 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
72 if repo_name.endswith('/'):
84 if repo_name.endswith('/'):
73 repo_name = repo_name.rstrip('/')
85 repo_name = repo_name.rstrip('/')
86 self.repository = repo_name
74 except:
87 except:
75 log.error(traceback.format_exc())
88 log.error(traceback.format_exc())
76 return HTTPInternalServerError()(environ, start_response)
89 return HTTPInternalServerError()(environ, start_response)
@@ -78,17 +91,18 b' class SimpleHg(object):'
78 #===================================================================
91 #===================================================================
79 # CHECK PERMISSIONS FOR THIS REQUEST
92 # CHECK PERMISSIONS FOR THIS REQUEST
80 #===================================================================
93 #===================================================================
81 action = self.__get_action(environ)
94 self.action = self.__get_action(environ)
82 if action:
95 if self.action:
83 username = self.__get_environ_user(environ)
96 username = self.__get_environ_user(environ)
84 try:
97 try:
85 user = self.__get_user(username)
98 user = self.__get_user(username)
99 self.username = user.username
86 except:
100 except:
87 log.error(traceback.format_exc())
101 log.error(traceback.format_exc())
88 return HTTPInternalServerError()(environ, start_response)
102 return HTTPInternalServerError()(environ, start_response)
89
103
90 #check permissions for this repository
104 #check permissions for this repository
91 if action == 'push':
105 if self.action == 'push':
92 if not HasPermissionAnyMiddleware('repository.write',
106 if not HasPermissionAnyMiddleware('repository.write',
93 'repository.admin')\
107 'repository.admin')\
94 (user, repo_name):
108 (user, repo_name):
@@ -102,13 +116,11 b' class SimpleHg(object):'
102 (user, repo_name):
116 (user, repo_name):
103 return HTTPForbidden()(environ, start_response)
117 return HTTPForbidden()(environ, start_response)
104
118
105 #log action
119 self.extras = {'ip':self.ipaddr,
106 if action in ('push', 'pull', 'clone'):
120 'username':self.username,
107 proxy_key = 'HTTP_X_REAL_IP'
121 'action':self.action,
108 def_key = 'REMOTE_ADDR'
122 'repository':self.repository}
109 ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
123 print self.extras
110 self.__log_user_action(user, action, repo_name, ipaddr)
111
112 #===================================================================
124 #===================================================================
113 # MERCURIAL REQUEST HANDLING
125 # MERCURIAL REQUEST HANDLING
114 #===================================================================
126 #===================================================================
@@ -130,7 +142,7 b' class SimpleHg(object):'
130 return HTTPInternalServerError()(environ, start_response)
142 return HTTPInternalServerError()(environ, start_response)
131
143
132 #invalidate cache on push
144 #invalidate cache on push
133 if action == 'push':
145 if self.action == 'push':
134 self.__invalidate_cache(repo_name)
146 self.__invalidate_cache(repo_name)
135 messages = []
147 messages = []
136 messages.append('thank you for using rhodecode')
148 messages.append('thank you for using rhodecode')
@@ -157,7 +169,7 b' class SimpleHg(object):'
157
169
158 def __make_app(self):
170 def __make_app(self):
159 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
171 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
160 return self.__load_web_settings(hgserve)
172 return self.__load_web_settings(hgserve, self.extras)
161
173
162 def __get_environ_user(self, environ):
174 def __get_environ_user(self, environ):
163 return environ.get('REMOTE_USER')
175 return environ.get('REMOTE_USER')
@@ -174,7 +186,7 b' class SimpleHg(object):'
174 mapping = {'changegroup': 'pull',
186 mapping = {'changegroup': 'pull',
175 'changegroupsubset': 'pull',
187 'changegroupsubset': 'pull',
176 'stream_out': 'pull',
188 'stream_out': 'pull',
177 #'listkeys': 'pull',
189 'listkeys': 'pull',
178 'unbundle': 'push',
190 'unbundle': 'push',
179 'pushkey': 'push', }
191 'pushkey': 'push', }
180 for qry in environ['QUERY_STRING'].split('&'):
192 for qry in environ['QUERY_STRING'].split('&'):
@@ -185,9 +197,6 b' class SimpleHg(object):'
185 else:
197 else:
186 return cmd
198 return cmd
187
199
188 def __log_user_action(self, user, action, repo, ipaddr):
189 action_logger(user, action, repo, ipaddr)
190
191 def __invalidate_cache(self, repo_name):
200 def __invalidate_cache(self, repo_name):
192 """we know that some change was made to repositories and we should
201 """we know that some change was made to repositories and we should
193 invalidate the cache to see the changes right away but only for
202 invalidate the cache to see the changes right away but only for
@@ -196,14 +205,19 b' class SimpleHg(object):'
196 invalidate_cache('full_changelog', repo_name)
205 invalidate_cache('full_changelog', repo_name)
197
206
198
207
199 def __load_web_settings(self, hgserve):
208 def __load_web_settings(self, hgserve, extras={}):
200 #set the global ui for hgserve instance passed
209 #set the global ui for hgserve instance passed
201 hgserve.repo.ui = self.baseui
210 hgserve.repo.ui = self.baseui
202
211
203 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
212 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
213
214 #inject some additional parameters that will be available in ui
215 #for hooks
216 for k, v in extras.items():
217 hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
218
204 repoui = make_ui('file', hgrc, False)
219 repoui = make_ui('file', hgrc, False)
205
220
206
207 if repoui:
221 if repoui:
208 #overwrite our ui instance with the section from hgrc file
222 #overwrite our ui instance with the section from hgrc file
209 for section in ui_sections:
223 for section in ui_sections:
@@ -35,6 +35,7 b' from vcs.backends.base import BaseChange'
35 from vcs.backends.git import GitRepository
35 from vcs.backends.git import GitRepository
36 from vcs.backends.hg import MercurialRepository
36 from vcs.backends.hg import MercurialRepository
37 from vcs.utils.lazy import LazyProperty
37 from vcs.utils.lazy import LazyProperty
38 import traceback
38 import datetime
39 import datetime
39 import logging
40 import logging
40 import os
41 import os
@@ -77,15 +78,15 b' def action_logger(user, action, repo, ip'
77
78
78 try:
79 try:
79 if hasattr(user, 'user_id'):
80 if hasattr(user, 'user_id'):
80 user_id = user.user_id
81 user_obj = user
81 elif isinstance(user, basestring):
82 elif isinstance(user, basestring):
82 user_id = UserModel(sa).get_by_username(user, cache=False).user_id
83 user_obj = UserModel(sa).get_by_username(user, cache=False)
83 else:
84 else:
84 raise Exception('You have to provide user object or username')
85 raise Exception('You have to provide user object or username')
85
86
86 repo_name = repo.lstrip('/')
87 repo_name = repo.lstrip('/')
87 user_log = UserLog()
88 user_log = UserLog()
88 user_log.user_id = user_id
89 user_log.user_id = user_obj.user_id
89 user_log.action = action
90 user_log.action = action
90 user_log.repository_name = repo_name
91 user_log.repository_name = repo_name
91 user_log.repository = RepoModel(sa).get(repo_name, cache=False)
92 user_log.repository = RepoModel(sa).get(repo_name, cache=False)
@@ -95,10 +96,10 b' def action_logger(user, action, repo, ip'
95 sa.commit()
96 sa.commit()
96
97
97 log.info('Adding user %s, action %s on %s',
98 log.info('Adding user %s, action %s on %s',
98 user.username, action, repo)
99 user_obj.username, action, repo)
99 except Exception, e:
100 except:
101 log.error(traceback.format_exc())
100 sa.rollback()
102 sa.rollback()
101 log.error('could not log user action:%s', str(e))
102
103
103 def get_repos(path, recursive=False, initial=False):
104 def get_repos(path, recursive=False, initial=False):
104 """
105 """
General Comments 0
You need to be logged in to leave comments. Login now