##// END OF EJS Templates
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
marcink -
r2406:7be31af5 beta
parent child Browse files
Show More
@@ -1,256 +1,257 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.hooks
3 rhodecode.lib.hooks
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Hooks runned by rhodecode
6 Hooks runned by rhodecode
7
7
8 :created_on: Aug 6, 2010
8 :created_on: Aug 6, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import sys
26 import sys
27 import binascii
27 import binascii
28 from inspect import isfunction
28 from inspect import isfunction
29
29
30 from mercurial.scmutil import revrange
30 from mercurial.scmutil import revrange
31 from mercurial.node import nullrev
31 from mercurial.node import nullrev
32
32
33 from rhodecode import EXTENSIONS
34 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
35 from rhodecode.lib.utils import action_logger
34 from rhodecode.lib.utils import action_logger
36 from rhodecode.lib.vcs.backends.base import EmptyChangeset
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
37
36
38
37
39 def _get_scm_size(alias, root_path):
38 def _get_scm_size(alias, root_path):
40
39
41 if not alias.startswith('.'):
40 if not alias.startswith('.'):
42 alias += '.'
41 alias += '.'
43
42
44 size_scm, size_root = 0, 0
43 size_scm, size_root = 0, 0
45 for path, dirs, files in os.walk(root_path):
44 for path, dirs, files in os.walk(root_path):
46 if path.find(alias) != -1:
45 if path.find(alias) != -1:
47 for f in files:
46 for f in files:
48 try:
47 try:
49 size_scm += os.path.getsize(os.path.join(path, f))
48 size_scm += os.path.getsize(os.path.join(path, f))
50 except OSError:
49 except OSError:
51 pass
50 pass
52 else:
51 else:
53 for f in files:
52 for f in files:
54 try:
53 try:
55 size_root += os.path.getsize(os.path.join(path, f))
54 size_root += os.path.getsize(os.path.join(path, f))
56 except OSError:
55 except OSError:
57 pass
56 pass
58
57
59 size_scm_f = h.format_byte_size(size_scm)
58 size_scm_f = h.format_byte_size(size_scm)
60 size_root_f = h.format_byte_size(size_root)
59 size_root_f = h.format_byte_size(size_root)
61 size_total_f = h.format_byte_size(size_root + size_scm)
60 size_total_f = h.format_byte_size(size_root + size_scm)
62
61
63 return size_scm_f, size_root_f, size_total_f
62 return size_scm_f, size_root_f, size_total_f
64
63
65
64
66 def repo_size(ui, repo, hooktype=None, **kwargs):
65 def repo_size(ui, repo, hooktype=None, **kwargs):
67 """
66 """
68 Presents size of repository after push
67 Presents size of repository after push
69
68
70 :param ui:
69 :param ui:
71 :param repo:
70 :param repo:
72 :param hooktype:
71 :param hooktype:
73 """
72 """
74
73
75 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
74 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
76
75
77 last_cs = repo[len(repo) - 1]
76 last_cs = repo[len(repo) - 1]
78
77
79 msg = ('Repository size .hg:%s repo:%s total:%s\n'
78 msg = ('Repository size .hg:%s repo:%s total:%s\n'
80 'Last revision is now r%s:%s\n') % (
79 'Last revision is now r%s:%s\n') % (
81 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
80 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
82 )
81 )
83
82
84 sys.stdout.write(msg)
83 sys.stdout.write(msg)
85
84
86
85
87 def log_pull_action(ui, repo, **kwargs):
86 def log_pull_action(ui, repo, **kwargs):
88 """
87 """
89 Logs user last pull action
88 Logs user last pull action
90
89
91 :param ui:
90 :param ui:
92 :param repo:
91 :param repo:
93 """
92 """
94
93
95 extras = dict(repo.ui.configitems('rhodecode_extras'))
94 extras = dict(repo.ui.configitems('rhodecode_extras'))
96 username = extras['username']
95 username = extras['username']
97 repository = extras['repository']
96 repository = extras['repository']
98 scm = extras['scm']
97 scm = extras['scm']
99 action = 'pull'
98 action = 'pull'
100
99
101 action_logger(username, action, repository, extras['ip'], commit=True)
100 action_logger(username, action, repository, extras['ip'], commit=True)
102 # extension hook call
101 # extension hook call
102 from rhodecode import EXTENSIONS
103 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
103 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
104
104
105 if isfunction(callback):
105 if isfunction(callback):
106 kw = {}
106 kw = {}
107 kw.update(extras)
107 kw.update(extras)
108 callback(**kw)
108 callback(**kw)
109 return 0
109 return 0
110
110
111
111
112 def log_push_action(ui, repo, **kwargs):
112 def log_push_action(ui, repo, **kwargs):
113 """
113 """
114 Maps user last push action to new changeset id, from mercurial
114 Maps user last push action to new changeset id, from mercurial
115
115
116 :param ui:
116 :param ui:
117 :param repo: repo object containing the `ui` object
117 :param repo: repo object containing the `ui` object
118 """
118 """
119
119
120 extras = dict(repo.ui.configitems('rhodecode_extras'))
120 extras = dict(repo.ui.configitems('rhodecode_extras'))
121 username = extras['username']
121 username = extras['username']
122 repository = extras['repository']
122 repository = extras['repository']
123 action = extras['action'] + ':%s'
123 action = extras['action'] + ':%s'
124 scm = extras['scm']
124 scm = extras['scm']
125
125
126 if scm == 'hg':
126 if scm == 'hg':
127 node = kwargs['node']
127 node = kwargs['node']
128
128
129 def get_revs(repo, rev_opt):
129 def get_revs(repo, rev_opt):
130 if rev_opt:
130 if rev_opt:
131 revs = revrange(repo, rev_opt)
131 revs = revrange(repo, rev_opt)
132
132
133 if len(revs) == 0:
133 if len(revs) == 0:
134 return (nullrev, nullrev)
134 return (nullrev, nullrev)
135 return (max(revs), min(revs))
135 return (max(revs), min(revs))
136 else:
136 else:
137 return (len(repo) - 1, 0)
137 return (len(repo) - 1, 0)
138
138
139 stop, start = get_revs(repo, [node + ':'])
139 stop, start = get_revs(repo, [node + ':'])
140 h = binascii.hexlify
140 h = binascii.hexlify
141 revs = (h(repo[r].node()) for r in xrange(start, stop + 1))
141 revs = (h(repo[r].node()) for r in xrange(start, stop + 1))
142 elif scm == 'git':
142 elif scm == 'git':
143 revs = kwargs.get('_git_revs', [])
143 revs = kwargs.get('_git_revs', [])
144 if '_git_revs' in kwargs:
144 if '_git_revs' in kwargs:
145 kwargs.pop('_git_revs')
145 kwargs.pop('_git_revs')
146
146
147 action = action % ','.join(revs)
147 action = action % ','.join(revs)
148
148
149 action_logger(username, action, repository, extras['ip'], commit=True)
149 action_logger(username, action, repository, extras['ip'], commit=True)
150
150
151 # extension hook call
151 # extension hook call
152 from rhodecode import EXTENSIONS
152 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
153 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
153 if isfunction(callback):
154 if isfunction(callback):
154 kw = {'pushed_revs': revs}
155 kw = {'pushed_revs': revs}
155 kw.update(extras)
156 kw.update(extras)
156 callback(**kw)
157 callback(**kw)
157 return 0
158 return 0
158
159
159
160
160 def log_create_repository(repository_dict, created_by, **kwargs):
161 def log_create_repository(repository_dict, created_by, **kwargs):
161 """
162 """
162 Post create repository Hook. This is a dummy function for admins to re-use
163 Post create repository Hook. This is a dummy function for admins to re-use
163 if needed. It's taken from rhodecode-extensions module and executed
164 if needed. It's taken from rhodecode-extensions module and executed
164 if present
165 if present
165
166
166 :param repository: dict dump of repository object
167 :param repository: dict dump of repository object
167 :param created_by: username who created repository
168 :param created_by: username who created repository
168 :param created_date: date of creation
169 :param created_date: date of creation
169
170
170 available keys of repository_dict:
171 available keys of repository_dict:
171
172
172 'repo_type',
173 'repo_type',
173 'description',
174 'description',
174 'private',
175 'private',
175 'created_on',
176 'created_on',
176 'enable_downloads',
177 'enable_downloads',
177 'repo_id',
178 'repo_id',
178 'user_id',
179 'user_id',
179 'enable_statistics',
180 'enable_statistics',
180 'clone_uri',
181 'clone_uri',
181 'fork_id',
182 'fork_id',
182 'group_id',
183 'group_id',
183 'repo_name'
184 'repo_name'
184
185
185 """
186 """
186
187 from rhodecode import EXTENSIONS
187 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
188 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
188 if isfunction(callback):
189 if isfunction(callback):
189 kw = {}
190 kw = {}
190 kw.update(repository_dict)
191 kw.update(repository_dict)
191 kw.update({'created_by': created_by})
192 kw.update({'created_by': created_by})
192 kw.update(kwargs)
193 kw.update(kwargs)
193 return callback(**kw)
194 return callback(**kw)
194
195
195 return 0
196 return 0
196
197
197
198
198 def handle_git_post_receive(repo_path, revs, env):
199 def handle_git_post_receive(repo_path, revs, env):
199 """
200 """
200 A really hacky method that is runned by git pre-receive hook and logs
201 A really hacky method that is runned by git pre-receive hook and logs
201 an push action together with pushed revisions. It's runned by subprocess
202 an push action together with pushed revisions. It's runned by subprocess
202 thus needs all info to be able to create a temp pylons enviroment, connect
203 thus needs all info to be able to create a temp pylons enviroment, connect
203 to database and run the logging code. Hacky as sh**t but works. ps.
204 to database and run the logging code. Hacky as sh**t but works. ps.
204 GIT SUCKS
205 GIT SUCKS
205
206
206 :param repo_path:
207 :param repo_path:
207 :type repo_path:
208 :type repo_path:
208 :param revs:
209 :param revs:
209 :type revs:
210 :type revs:
210 :param env:
211 :param env:
211 :type env:
212 :type env:
212 """
213 """
213 from paste.deploy import appconfig
214 from paste.deploy import appconfig
214 from sqlalchemy import engine_from_config
215 from sqlalchemy import engine_from_config
215 from rhodecode.config.environment import load_environment
216 from rhodecode.config.environment import load_environment
216 from rhodecode.model import init_model
217 from rhodecode.model import init_model
217 from rhodecode.model.db import RhodeCodeUi
218 from rhodecode.model.db import RhodeCodeUi
218 from rhodecode.lib.utils import make_ui
219 from rhodecode.lib.utils import make_ui
219 from rhodecode.model.db import Repository
220 from rhodecode.model.db import Repository
220
221
221 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
222 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
222 conf = appconfig('config:%s' % ini_name, relative_to=path)
223 conf = appconfig('config:%s' % ini_name, relative_to=path)
223 load_environment(conf.global_conf, conf.local_conf)
224 load_environment(conf.global_conf, conf.local_conf)
224
225
225 engine = engine_from_config(conf, 'sqlalchemy.db1.')
226 engine = engine_from_config(conf, 'sqlalchemy.db1.')
226 init_model(engine)
227 init_model(engine)
227
228
228 baseui = make_ui('db')
229 baseui = make_ui('db')
229 repo = Repository.get_by_full_path(repo_path)
230 repo = Repository.get_by_full_path(repo_path)
230
231
231 _hooks = dict(baseui.configitems('hooks')) or {}
232 _hooks = dict(baseui.configitems('hooks')) or {}
232 # if push hook is enabled via web interface
233 # if push hook is enabled via web interface
233 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
234 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
234
235
235 extras = {
236 extras = {
236 'username': env['RHODECODE_USER'],
237 'username': env['RHODECODE_USER'],
237 'repository': repo.repo_name,
238 'repository': repo.repo_name,
238 'scm': 'git',
239 'scm': 'git',
239 'action': 'push',
240 'action': 'push',
240 'ip': env['RHODECODE_CONFIG_IP'],
241 'ip': env['RHODECODE_CONFIG_IP'],
241 }
242 }
242 for k, v in extras.items():
243 for k, v in extras.items():
243 baseui.setconfig('rhodecode_extras', k, v)
244 baseui.setconfig('rhodecode_extras', k, v)
244 repo = repo.scm_instance
245 repo = repo.scm_instance
245 repo.ui = baseui
246 repo.ui = baseui
246 old_rev, new_rev, ref = revs
247 old_rev, new_rev, ref = revs
247 if old_rev == EmptyChangeset().raw_id:
248 if old_rev == EmptyChangeset().raw_id:
248 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
249 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
249 heads = repo.run_git_command(cmd)[0]
250 heads = repo.run_git_command(cmd)[0]
250 heads = heads.replace(ref, '')
251 heads = heads.replace(ref, '')
251 cmd = 'log ' + new_rev + ' --reverse --pretty=format:"%H" --not ' + heads
252 cmd = 'log ' + new_rev + ' --reverse --pretty=format:"%H" --not ' + heads
252 else:
253 else:
253 cmd = 'log ' + old_rev + '..' + new_rev + ' --reverse --pretty=format:"%H"'
254 cmd = 'log ' + old_rev + '..' + new_rev + ' --reverse --pretty=format:"%H"'
254 git_revs = repo.run_git_command(cmd)[0].splitlines()
255 git_revs = repo.run_git_command(cmd)[0].splitlines()
255
256
256 log_push_action(baseui, repo, _git_revs=git_revs)
257 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -1,198 +1,199 b''
1 import os
1 import os
2 import socket
2 import socket
3 import logging
3 import logging
4 import subprocess
4 import subprocess
5
5
6 from webob import Request, Response, exc
6 from webob import Request, Response, exc
7
7
8 from rhodecode.lib import subprocessio
8 from rhodecode.lib import subprocessio
9
9
10 log = logging.getLogger(__name__)
10 log = logging.getLogger(__name__)
11
11
12
12
13 class FileWrapper(object):
13 class FileWrapper(object):
14
14
15 def __init__(self, fd, content_length):
15 def __init__(self, fd, content_length):
16 self.fd = fd
16 self.fd = fd
17 self.content_length = content_length
17 self.content_length = content_length
18 self.remain = content_length
18 self.remain = content_length
19
19
20 def read(self, size):
20 def read(self, size):
21 if size <= self.remain:
21 if size <= self.remain:
22 try:
22 try:
23 data = self.fd.read(size)
23 data = self.fd.read(size)
24 except socket.error:
24 except socket.error:
25 raise IOError(self)
25 raise IOError(self)
26 self.remain -= size
26 self.remain -= size
27 elif self.remain:
27 elif self.remain:
28 data = self.fd.read(self.remain)
28 data = self.fd.read(self.remain)
29 self.remain = 0
29 self.remain = 0
30 else:
30 else:
31 data = None
31 data = None
32 return data
32 return data
33
33
34 def __repr__(self):
34 def __repr__(self):
35 return '<FileWrapper %s len: %s, read: %s>' % (
35 return '<FileWrapper %s len: %s, read: %s>' % (
36 self.fd, self.content_length, self.content_length - self.remain
36 self.fd, self.content_length, self.content_length - self.remain
37 )
37 )
38
38
39
39
40 class GitRepository(object):
40 class GitRepository(object):
41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
42 commands = ['git-upload-pack', 'git-receive-pack']
42 commands = ['git-upload-pack', 'git-receive-pack']
43
43
44 def __init__(self, repo_name, content_path, username):
44 def __init__(self, repo_name, content_path, username):
45 files = set([f.lower() for f in os.listdir(content_path)])
45 files = set([f.lower() for f in os.listdir(content_path)])
46 if not (self.git_folder_signature.intersection(files)
46 if not (self.git_folder_signature.intersection(files)
47 == self.git_folder_signature):
47 == self.git_folder_signature):
48 raise OSError('%s missing git signature' % content_path)
48 raise OSError('%s missing git signature' % content_path)
49 self.content_path = content_path
49 self.content_path = content_path
50 self.valid_accepts = ['application/x-%s-result' %
50 self.valid_accepts = ['application/x-%s-result' %
51 c for c in self.commands]
51 c for c in self.commands]
52 self.repo_name = repo_name
52 self.repo_name = repo_name
53 self.username = username
53 self.username = username
54
54
55 def _get_fixedpath(self, path):
55 def _get_fixedpath(self, path):
56 """
56 """
57 Small fix for repo_path
57 Small fix for repo_path
58
58
59 :param path:
59 :param path:
60 :type path:
60 :type path:
61 """
61 """
62 return path.split(self.repo_name, 1)[-1].strip('/')
62 return path.split(self.repo_name, 1)[-1].strip('/')
63
63
64 def inforefs(self, request, environ):
64 def inforefs(self, request, environ):
65 """
65 """
66 WSGI Response producer for HTTP GET Git Smart
66 WSGI Response producer for HTTP GET Git Smart
67 HTTP /info/refs request.
67 HTTP /info/refs request.
68 """
68 """
69
69
70 git_command = request.GET['service']
70 git_command = request.GET['service']
71 if git_command not in self.commands:
71 if git_command not in self.commands:
72 log.debug('command %s not allowed' % git_command)
72 log.debug('command %s not allowed' % git_command)
73 return exc.HTTPMethodNotAllowed()
73 return exc.HTTPMethodNotAllowed()
74
74
75 # note to self:
75 # note to self:
76 # please, resist the urge to add '\n' to git capture and increment
76 # please, resist the urge to add '\n' to git capture and increment
77 # line count by 1.
77 # line count by 1.
78 # The code in Git client not only does NOT need '\n', but actually
78 # The code in Git client not only does NOT need '\n', but actually
79 # blows up if you sprinkle "flush" (0000) as "0001\n".
79 # blows up if you sprinkle "flush" (0000) as "0001\n".
80 # It reads binary, per number of bytes specified.
80 # It reads binary, per number of bytes specified.
81 # if you do add '\n' as part of data, count it.
81 # if you do add '\n' as part of data, count it.
82 smart_server_advert = '# service=%s' % git_command
82 smart_server_advert = '# service=%s' % git_command
83 try:
83 try:
84 out = subprocessio.SubprocessIOChunker(
84 out = subprocessio.SubprocessIOChunker(
85 r'git %s --stateless-rpc --advertise-refs "%s"' % (
85 r'git %s --stateless-rpc --advertise-refs "%s"' % (
86 git_command[4:], self.content_path),
86 git_command[4:], self.content_path),
87 starting_values=[
87 starting_values=[
88 str(hex(len(smart_server_advert) + 4)[2:]
88 str(hex(len(smart_server_advert) + 4)[2:]
89 .rjust(4, '0') + smart_server_advert + '0000')
89 .rjust(4, '0') + smart_server_advert + '0000')
90 ]
90 ]
91 )
91 )
92 except EnvironmentError, e:
92 except EnvironmentError, e:
93 log.exception(e)
93 log.exception(e)
94 raise exc.HTTPExpectationFailed()
94 raise exc.HTTPExpectationFailed()
95 resp = Response()
95 resp = Response()
96 resp.content_type = 'application/x-%s-advertisement' % str(git_command)
96 resp.content_type = 'application/x-%s-advertisement' % str(git_command)
97 resp.app_iter = out
97 resp.app_iter = out
98 return resp
98 return resp
99
99
100 def backend(self, request, environ):
100 def backend(self, request, environ):
101 """
101 """
102 WSGI Response producer for HTTP POST Git Smart HTTP requests.
102 WSGI Response producer for HTTP POST Git Smart HTTP requests.
103 Reads commands and data from HTTP POST's body.
103 Reads commands and data from HTTP POST's body.
104 returns an iterator obj with contents of git command's
104 returns an iterator obj with contents of git command's
105 response to stdout
105 response to stdout
106 """
106 """
107 git_command = self._get_fixedpath(request.path_info)
107 git_command = self._get_fixedpath(request.path_info)
108 if git_command not in self.commands:
108 if git_command not in self.commands:
109 log.debug('command %s not allowed' % git_command)
109 log.debug('command %s not allowed' % git_command)
110 return exc.HTTPMethodNotAllowed()
110 return exc.HTTPMethodNotAllowed()
111
111
112 if 'CONTENT_LENGTH' in environ:
112 if 'CONTENT_LENGTH' in environ:
113 inputstream = FileWrapper(environ['wsgi.input'],
113 inputstream = FileWrapper(environ['wsgi.input'],
114 request.content_length)
114 request.content_length)
115 else:
115 else:
116 inputstream = environ['wsgi.input']
116 inputstream = environ['wsgi.input']
117
117
118 try:
118 try:
119 gitenv = os.environ
119 gitenv = os.environ
120 from rhodecode import CONFIG
120 from rhodecode import CONFIG
121 from rhodecode.lib.base import _get_ip_addr
121 from rhodecode.lib.base import _get_ip_addr
122 gitenv['RHODECODE_USER'] = self.username
122 gitenv['RHODECODE_USER'] = self.username
123 gitenv['RHODECODE_CONFIG_IP'] = _get_ip_addr(environ)
123 gitenv['RHODECODE_CONFIG_IP'] = _get_ip_addr(environ)
124 # forget all configs
124 # forget all configs
125 gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
125 gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
126 # we need current .ini file used to later initialize rhodecode
126 # we need current .ini file used to later initialize rhodecode
127 # env and connect to db
127 # env and connect to db
128 gitenv['RHODECODE_CONFIG_FILE'] = CONFIG['__file__']
128 gitenv['RHODECODE_CONFIG_FILE'] = CONFIG['__file__']
129 opts = dict(
129 opts = dict(
130 env=gitenv
130 env=gitenv,
131 cwd=os.getcwd()
131 )
132 )
132 out = subprocessio.SubprocessIOChunker(
133 out = subprocessio.SubprocessIOChunker(
133 r'git %s --stateless-rpc "%s"' % (git_command[4:],
134 r'git %s --stateless-rpc "%s"' % (git_command[4:],
134 self.content_path),
135 self.content_path),
135 inputstream=inputstream,
136 inputstream=inputstream,
136 **opts
137 **opts
137 )
138 )
138 except EnvironmentError, e:
139 except EnvironmentError, e:
139 log.exception(e)
140 log.exception(e)
140 raise exc.HTTPExpectationFailed()
141 raise exc.HTTPExpectationFailed()
141
142
142 if git_command in [u'git-receive-pack']:
143 if git_command in [u'git-receive-pack']:
143 # updating refs manually after each push.
144 # updating refs manually after each push.
144 # Needed for pre-1.7.0.4 git clients using regular HTTP mode.
145 # Needed for pre-1.7.0.4 git clients using regular HTTP mode.
145 subprocess.call(u'git --git-dir "%s" '
146 subprocess.call(u'git --git-dir "%s" '
146 'update-server-info' % self.content_path,
147 'update-server-info' % self.content_path,
147 shell=True)
148 shell=True)
148
149
149 resp = Response()
150 resp = Response()
150 resp.content_type = 'application/x-%s-result' % git_command.encode('utf8')
151 resp.content_type = 'application/x-%s-result' % git_command.encode('utf8')
151 resp.app_iter = out
152 resp.app_iter = out
152 return resp
153 return resp
153
154
154 def __call__(self, environ, start_response):
155 def __call__(self, environ, start_response):
155 request = Request(environ)
156 request = Request(environ)
156 _path = self._get_fixedpath(request.path_info)
157 _path = self._get_fixedpath(request.path_info)
157 if _path.startswith('info/refs'):
158 if _path.startswith('info/refs'):
158 app = self.inforefs
159 app = self.inforefs
159 elif [a for a in self.valid_accepts if a in request.accept]:
160 elif [a for a in self.valid_accepts if a in request.accept]:
160 app = self.backend
161 app = self.backend
161 try:
162 try:
162 resp = app(request, environ)
163 resp = app(request, environ)
163 except exc.HTTPException, e:
164 except exc.HTTPException, e:
164 resp = e
165 resp = e
165 log.exception(e)
166 log.exception(e)
166 except Exception, e:
167 except Exception, e:
167 log.exception(e)
168 log.exception(e)
168 resp = exc.HTTPInternalServerError()
169 resp = exc.HTTPInternalServerError()
169 return resp(environ, start_response)
170 return resp(environ, start_response)
170
171
171
172
172 class GitDirectory(object):
173 class GitDirectory(object):
173
174
174 def __init__(self, repo_root, repo_name, username):
175 def __init__(self, repo_root, repo_name, username):
175 repo_location = os.path.join(repo_root, repo_name)
176 repo_location = os.path.join(repo_root, repo_name)
176 if not os.path.isdir(repo_location):
177 if not os.path.isdir(repo_location):
177 raise OSError(repo_location)
178 raise OSError(repo_location)
178
179
179 self.content_path = repo_location
180 self.content_path = repo_location
180 self.repo_name = repo_name
181 self.repo_name = repo_name
181 self.repo_location = repo_location
182 self.repo_location = repo_location
182 self.username = username
183 self.username = username
183
184
184 def __call__(self, environ, start_response):
185 def __call__(self, environ, start_response):
185 content_path = self.content_path
186 content_path = self.content_path
186 try:
187 try:
187 app = GitRepository(self.repo_name, content_path, self.username)
188 app = GitRepository(self.repo_name, content_path, self.username)
188 except (AssertionError, OSError):
189 except (AssertionError, OSError):
189 if os.path.isdir(os.path.join(content_path, '.git')):
190 if os.path.isdir(os.path.join(content_path, '.git')):
190 app = GitRepository(self.repo_name,
191 app = GitRepository(self.repo_name,
191 os.path.join(content_path, '.git'))
192 os.path.join(content_path, '.git'))
192 else:
193 else:
193 return exc.HTTPNotFound()(environ, start_response, self.username)
194 return exc.HTTPNotFound()(environ, start_response, self.username)
194 return app(environ, start_response)
195 return app(environ, start_response)
195
196
196
197
197 def make_wsgi_app(repo_name, repo_root, username):
198 def make_wsgi_app(repo_name, repo_root, username):
198 return GitDirectory(repo_root, repo_name, username)
199 return GitDirectory(repo_root, repo_name, username)
General Comments 0
You need to be logged in to leave comments. Login now