##// END OF EJS Templates
Added handling of git hooks, extract pushed revisions and store them inside...
marcink -
r2402:2eeb2ed7 beta
parent child Browse files
Show More
@@ -0,0 +1,29 b''
1 #!/usr/bin/env python
2 import os
3 import sys
4
5 try:
6 import rhodecode
7 from rhodecode.lib.hooks import handle_git_post_receive
8 except ImportError:
9 rhodecode = None
10
11
12 def main():
13 if rhodecode is None:
14 # exit with success if we cannot import rhodecode !!
15 # this allows simply push to this repo even without
16 # rhodecode
17 sys.exit(0)
18
19 repo_path = os.path.abspath('.')
20 push_data = sys.stdin.read().strip().split(' ')
21 # os.environ is modified here by a subprocess call that
22 # runs git and later git executes this hook.
23 # Environ get's some additional info from rhodecode system
24 # like IP or username from basic-auth
25 handle_git_post_receive(repo_path, push_data, os.environ)
26 sys.exit(0)
27
28 if __name__ == '__main__':
29 main() No newline at end of file
@@ -139,7 +139,9 b' def log_push_action(ui, repo, **kwargs):'
139 139 h = binascii.hexlify
140 140 revs = (h(repo[r].node()) for r in xrange(start, stop + 1))
141 141 elif scm == 'git':
142 revs = []
142 revs = kwargs.get('_git_revs', [])
143 if '_git_revs' in kwargs:
144 kwargs.pop('_git_revs')
143 145
144 146 action = action % ','.join(revs)
145 147
@@ -190,3 +192,59 b' def log_create_repository(repository_dic'
190 192 return callback(**kw)
191 193
192 194 return 0
195
196
197 def handle_git_post_receive(repo_path, revs, env):
198 """
199 A really hacky method that is runned by git pre-receive hook and logs
200 an push action together with pushed revisions. It's runned by subprocess
201 thus needs all info to be able to create a temp pylons enviroment, connect
202 to database and run the logging code. Hacky as sh**t but works. ps.
203 GIT SUCKS
204
205 :param repo_path:
206 :type repo_path:
207 :param revs:
208 :type revs:
209 :param env:
210 :type env:
211 """
212 from paste.deploy import appconfig
213 from sqlalchemy import engine_from_config
214 from rhodecode.config.environment import load_environment
215 from rhodecode.model import init_model
216 from rhodecode.model.db import RhodeCodeUi
217 from rhodecode.lib.utils import make_ui
218 from rhodecode.model.db import Repository
219
220 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
221 conf = appconfig('config:%s' % ini_name, relative_to=path)
222 load_environment(conf.global_conf, conf.local_conf)
223
224 engine = engine_from_config(conf, 'sqlalchemy.db1.')
225 init_model(engine)
226
227 baseui = make_ui('db')
228 repo = Repository.get_by_full_path(repo_path)
229
230 _hooks = dict(baseui.configitems('hooks')) or {}
231 # if push hook is enabled via web interface
232 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
233
234 extras = {
235 'username': env['RHODECODE_USER'],
236 'repository': repo.repo_name,
237 'scm': 'git',
238 'action': 'push',
239 'ip': env['RHODECODE_CONFIG_IP'],
240 }
241 for k, v in extras.items():
242 baseui.setconfig('rhodecode_extras', k, v)
243 repo = repo.scm_instance
244 repo.ui = baseui
245 old_rev, new_rev = revs[0:-1]
246
247 cmd = 'log ' + old_rev + '..' + new_rev + ' --reverse --pretty=format:"%H"'
248 git_revs = repo.run_git_command(cmd)[0].splitlines()
249
250 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -41,7 +41,7 b' class GitRepository(object):'
41 41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
42 42 commands = ['git-upload-pack', 'git-receive-pack']
43 43
44 def __init__(self, repo_name, content_path):
44 def __init__(self, repo_name, content_path, username):
45 45 files = set([f.lower() for f in os.listdir(content_path)])
46 46 if not (self.git_folder_signature.intersection(files)
47 47 == self.git_folder_signature):
@@ -50,6 +50,7 b' class GitRepository(object):'
50 50 self.valid_accepts = ['application/x-%s-result' %
51 51 c for c in self.commands]
52 52 self.repo_name = repo_name
53 self.username = username
53 54
54 55 def _get_fixedpath(self, path):
55 56 """
@@ -115,11 +116,25 b' class GitRepository(object):'
115 116 inputstream = environ['wsgi.input']
116 117
117 118 try:
119 gitenv = os.environ
120 from rhodecode import CONFIG
121 from rhodecode.lib.base import _get_ip_addr
122 gitenv['RHODECODE_USER'] = self.username
123 gitenv['RHODECODE_CONFIG_IP'] = _get_ip_addr(environ)
124 # forget all configs
125 gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
126 # we need current .ini file used to later initialize rhodecode
127 # env and connect to db
128 gitenv['RHODECODE_CONFIG_FILE'] = CONFIG['__file__']
129 opts = dict(
130 env=gitenv
131 )
118 132 out = subprocessio.SubprocessIOChunker(
119 133 r'git %s --stateless-rpc "%s"' % (git_command[4:],
120 134 self.content_path),
121 inputstream=inputstream
122 )
135 inputstream=inputstream,
136 **opts
137 )
123 138 except EnvironmentError, e:
124 139 log.exception(e)
125 140 raise exc.HTTPExpectationFailed()
@@ -156,7 +171,7 b' class GitRepository(object):'
156 171
157 172 class GitDirectory(object):
158 173
159 def __init__(self, repo_root, repo_name):
174 def __init__(self, repo_root, repo_name, username):
160 175 repo_location = os.path.join(repo_root, repo_name)
161 176 if not os.path.isdir(repo_location):
162 177 raise OSError(repo_location)
@@ -164,19 +179,20 b' class GitDirectory(object):'
164 179 self.content_path = repo_location
165 180 self.repo_name = repo_name
166 181 self.repo_location = repo_location
182 self.username = username
167 183
168 184 def __call__(self, environ, start_response):
169 185 content_path = self.content_path
170 186 try:
171 app = GitRepository(self.repo_name, content_path)
187 app = GitRepository(self.repo_name, content_path, self.username)
172 188 except (AssertionError, OSError):
173 189 if os.path.isdir(os.path.join(content_path, '.git')):
174 190 app = GitRepository(self.repo_name,
175 191 os.path.join(content_path, '.git'))
176 192 else:
177 return exc.HTTPNotFound()(environ, start_response)
193 return exc.HTTPNotFound()(environ, start_response, self.username)
178 194 return app(environ, start_response)
179 195
180 196
181 def make_wsgi_app(repo_name, repo_root):
182 return GitDirectory(repo_root, repo_name)
197 def make_wsgi_app(repo_name, repo_root, username):
198 return GitDirectory(repo_root, repo_name, username)
@@ -68,8 +68,9 b' dulserver.DEFAULT_HANDLERS = {'
68 68 'git-receive-pack': dulserver.ReceivePackHandler,
69 69 }
70 70
71 from dulwich.repo import Repo
72 from dulwich.web import make_wsgi_chain
71 # not used for now until dulwich get's fixed
72 #from dulwich.repo import Repo
73 #from dulwich.web import make_wsgi_chain
73 74
74 75 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
75 76
@@ -77,7 +78,7 b' from rhodecode.lib.utils2 import safe_st'
77 78 from rhodecode.lib.base import BaseVCSController
78 79 from rhodecode.lib.auth import get_container_username
79 80 from rhodecode.lib.utils import is_valid_repo, make_ui
80 from rhodecode.model.db import User
81 from rhodecode.model.db import User, RhodeCodeUi
81 82
82 83 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
83 84
@@ -205,13 +206,13 b' class SimpleGit(BaseVCSController):'
205 206 self._handle_githooks(repo_name, action, baseui, environ)
206 207
207 208 log.info('%s action on GIT repo "%s"' % (action, repo_name))
208 app = self.__make_app(repo_name, repo_path)
209 app = self.__make_app(repo_name, repo_path, username)
209 210 return app(environ, start_response)
210 211 except Exception:
211 212 log.error(traceback.format_exc())
212 213 return HTTPInternalServerError()(environ, start_response)
213 214
214 def __make_app(self, repo_name, repo_path):
215 def __make_app(self, repo_name, repo_path, username):
215 216 """
216 217 Make an wsgi application using dulserver
217 218
@@ -223,6 +224,7 b' class SimpleGit(BaseVCSController):'
223 224 app = make_wsgi_app(
224 225 repo_root=os.path.dirname(repo_path),
225 226 repo_name=repo_name,
227 username=username,
226 228 )
227 229 return app
228 230
@@ -268,7 +270,10 b' class SimpleGit(BaseVCSController):'
268 270 return op
269 271
270 272 def _handle_githooks(self, repo_name, action, baseui, environ):
271 from rhodecode.lib.hooks import log_pull_action, log_push_action
273 """
274 Handles pull action, push is handled by pre-receive hook
275 """
276 from rhodecode.lib.hooks import log_pull_action
272 277 service = environ['QUERY_STRING'].split('=')
273 278 if len(service) < 2:
274 279 return
@@ -278,12 +283,8 b' class SimpleGit(BaseVCSController):'
278 283 _repo = _repo.scm_instance
279 284 _repo._repo.ui = baseui
280 285
281 push_hook = 'pretxnchangegroup.push_logger'
282 pull_hook = 'preoutgoing.pull_logger'
283 286 _hooks = dict(baseui.configitems('hooks')) or {}
284 if action == 'push' and _hooks.get(push_hook):
285 log_push_action(ui=baseui, repo=_repo._repo)
286 elif action == 'pull' and _hooks.get(pull_hook):
287 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
287 288 log_pull_action(ui=baseui, repo=_repo._repo)
288 289
289 290 def __inject_extras(self, repo_path, baseui, extras={}):
General Comments 0
You need to be logged in to leave comments. Login now