##// END OF EJS Templates
code: fix deprecated octal usage for py3 compatability.
marcink -
r590:09bd53e1 default
parent child Browse files
Show More
@@ -1,154 +1,154 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # RhodeCode VCSServer provides access to different vcs backends via network.
3 # RhodeCode VCSServer provides access to different vcs backends via network.
4 # Copyright (C) 2014-2018 RhodeCode GmbH
4 # Copyright (C) 2014-2018 RhodeCode GmbH
5 #
5 #
6 # This program is free software; you can redistribute it and/or modify
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
9 # (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software Foundation,
17 # along with this program; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
20 import re
20 import re
21 import os
21 import os
22 import sys
22 import sys
23 import datetime
23 import datetime
24 import logging
24 import logging
25 import pkg_resources
25 import pkg_resources
26
26
27 import vcsserver
27 import vcsserver
28
28
29 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
30
30
31
31
32 def install_git_hooks(repo_path, bare, executable=None, force_create=False):
32 def install_git_hooks(repo_path, bare, executable=None, force_create=False):
33 """
33 """
34 Creates a RhodeCode hook inside a git repository
34 Creates a RhodeCode hook inside a git repository
35
35
36 :param repo_path: path to repository
36 :param repo_path: path to repository
37 :param executable: binary executable to put in the hooks
37 :param executable: binary executable to put in the hooks
38 :param force_create: Create even if same name hook exists
38 :param force_create: Create even if same name hook exists
39 """
39 """
40 executable = executable or sys.executable
40 executable = executable or sys.executable
41 hooks_path = os.path.join(repo_path, 'hooks')
41 hooks_path = os.path.join(repo_path, 'hooks')
42 if not bare:
42 if not bare:
43 hooks_path = os.path.join(repo_path, '.git', 'hooks')
43 hooks_path = os.path.join(repo_path, '.git', 'hooks')
44 if not os.path.isdir(hooks_path):
44 if not os.path.isdir(hooks_path):
45 os.makedirs(hooks_path, mode=0777)
45 os.makedirs(hooks_path, mode=0o777)
46
46
47 tmpl_post = pkg_resources.resource_string(
47 tmpl_post = pkg_resources.resource_string(
48 'vcsserver', '/'.join(
48 'vcsserver', '/'.join(
49 ('hook_utils', 'hook_templates', 'git_post_receive.py.tmpl')))
49 ('hook_utils', 'hook_templates', 'git_post_receive.py.tmpl')))
50 tmpl_pre = pkg_resources.resource_string(
50 tmpl_pre = pkg_resources.resource_string(
51 'vcsserver', '/'.join(
51 'vcsserver', '/'.join(
52 ('hook_utils', 'hook_templates', 'git_pre_receive.py.tmpl')))
52 ('hook_utils', 'hook_templates', 'git_pre_receive.py.tmpl')))
53
53
54 path = '' # not used for now
54 path = '' # not used for now
55 timestamp = datetime.datetime.utcnow().isoformat()
55 timestamp = datetime.datetime.utcnow().isoformat()
56
56
57 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
57 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
58 log.debug('Installing git hook in repo %s', repo_path)
58 log.debug('Installing git hook in repo %s', repo_path)
59 _hook_file = os.path.join(hooks_path, '%s-receive' % h_type)
59 _hook_file = os.path.join(hooks_path, '%s-receive' % h_type)
60 _rhodecode_hook = check_rhodecode_hook(_hook_file)
60 _rhodecode_hook = check_rhodecode_hook(_hook_file)
61
61
62 if _rhodecode_hook or force_create:
62 if _rhodecode_hook or force_create:
63 log.debug('writing git %s hook file at %s !', h_type, _hook_file)
63 log.debug('writing git %s hook file at %s !', h_type, _hook_file)
64 try:
64 try:
65 with open(_hook_file, 'wb') as f:
65 with open(_hook_file, 'wb') as f:
66 template = template.replace(
66 template = template.replace(
67 '_TMPL_', vcsserver.__version__)
67 '_TMPL_', vcsserver.__version__)
68 template = template.replace('_DATE_', timestamp)
68 template = template.replace('_DATE_', timestamp)
69 template = template.replace('_ENV_', executable)
69 template = template.replace('_ENV_', executable)
70 template = template.replace('_PATH_', path)
70 template = template.replace('_PATH_', path)
71 f.write(template)
71 f.write(template)
72 os.chmod(_hook_file, 0755)
72 os.chmod(_hook_file, 0o755)
73 except IOError:
73 except IOError:
74 log.exception('error writing hook file %s', _hook_file)
74 log.exception('error writing hook file %s', _hook_file)
75 else:
75 else:
76 log.debug('skipping writing hook file')
76 log.debug('skipping writing hook file')
77
77
78 return True
78 return True
79
79
80
80
81 def install_svn_hooks(repo_path, executable=None, force_create=False):
81 def install_svn_hooks(repo_path, executable=None, force_create=False):
82 """
82 """
83 Creates RhodeCode hooks inside a svn repository
83 Creates RhodeCode hooks inside a svn repository
84
84
85 :param repo_path: path to repository
85 :param repo_path: path to repository
86 :param executable: binary executable to put in the hooks
86 :param executable: binary executable to put in the hooks
87 :param force_create: Create even if same name hook exists
87 :param force_create: Create even if same name hook exists
88 """
88 """
89 executable = executable or sys.executable
89 executable = executable or sys.executable
90 hooks_path = os.path.join(repo_path, 'hooks')
90 hooks_path = os.path.join(repo_path, 'hooks')
91 if not os.path.isdir(hooks_path):
91 if not os.path.isdir(hooks_path):
92 os.makedirs(hooks_path, mode=0777)
92 os.makedirs(hooks_path, mode=0o777)
93
93
94 tmpl_post = pkg_resources.resource_string(
94 tmpl_post = pkg_resources.resource_string(
95 'vcsserver', '/'.join(
95 'vcsserver', '/'.join(
96 ('hook_utils', 'hook_templates', 'svn_post_commit_hook.py.tmpl')))
96 ('hook_utils', 'hook_templates', 'svn_post_commit_hook.py.tmpl')))
97 tmpl_pre = pkg_resources.resource_string(
97 tmpl_pre = pkg_resources.resource_string(
98 'vcsserver', '/'.join(
98 'vcsserver', '/'.join(
99 ('hook_utils', 'hook_templates', 'svn_pre_commit_hook.py.tmpl')))
99 ('hook_utils', 'hook_templates', 'svn_pre_commit_hook.py.tmpl')))
100
100
101 path = '' # not used for now
101 path = '' # not used for now
102 timestamp = datetime.datetime.utcnow().isoformat()
102 timestamp = datetime.datetime.utcnow().isoformat()
103
103
104 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
104 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
105 log.debug('Installing svn hook in repo %s', repo_path)
105 log.debug('Installing svn hook in repo %s', repo_path)
106 _hook_file = os.path.join(hooks_path, '%s-commit' % h_type)
106 _hook_file = os.path.join(hooks_path, '%s-commit' % h_type)
107 _rhodecode_hook = check_rhodecode_hook(_hook_file)
107 _rhodecode_hook = check_rhodecode_hook(_hook_file)
108
108
109 if _rhodecode_hook or force_create:
109 if _rhodecode_hook or force_create:
110 log.debug('writing svn %s hook file at %s !', h_type, _hook_file)
110 log.debug('writing svn %s hook file at %s !', h_type, _hook_file)
111
111
112 try:
112 try:
113 with open(_hook_file, 'wb') as f:
113 with open(_hook_file, 'wb') as f:
114 template = template.replace(
114 template = template.replace(
115 '_TMPL_', vcsserver.__version__)
115 '_TMPL_', vcsserver.__version__)
116 template = template.replace('_DATE_', timestamp)
116 template = template.replace('_DATE_', timestamp)
117 template = template.replace('_ENV_', executable)
117 template = template.replace('_ENV_', executable)
118 template = template.replace('_PATH_', path)
118 template = template.replace('_PATH_', path)
119
119
120 f.write(template)
120 f.write(template)
121 os.chmod(_hook_file, 0755)
121 os.chmod(_hook_file, 0o755)
122 except IOError:
122 except IOError:
123 log.exception('error writing hook file %s', _hook_file)
123 log.exception('error writing hook file %s', _hook_file)
124 else:
124 else:
125 log.debug('skipping writing hook file')
125 log.debug('skipping writing hook file')
126
126
127 return True
127 return True
128
128
129
129
130 def check_rhodecode_hook(hook_path):
130 def check_rhodecode_hook(hook_path):
131 """
131 """
132 Check if the hook was created by RhodeCode
132 Check if the hook was created by RhodeCode
133 """
133 """
134 if not os.path.exists(hook_path):
134 if not os.path.exists(hook_path):
135 return True
135 return True
136
136
137 log.debug('hook exists, checking if it is from rhodecode')
137 log.debug('hook exists, checking if it is from rhodecode')
138 hook_content = read_hook_content(hook_path)
138 hook_content = read_hook_content(hook_path)
139 matches = re.search(r'(?:RC_HOOK_VER)\s*=\s*(.*)', hook_content)
139 matches = re.search(r'(?:RC_HOOK_VER)\s*=\s*(.*)', hook_content)
140 if matches:
140 if matches:
141 try:
141 try:
142 version = matches.groups()[0]
142 version = matches.groups()[0]
143 log.debug('got version %s from hooks.', version)
143 log.debug('got version %s from hooks.', version)
144 return True
144 return True
145 except Exception:
145 except Exception:
146 log.exception("Exception while reading the hook version.")
146 log.exception("Exception while reading the hook version.")
147
147
148 return False
148 return False
149
149
150
150
151 def read_hook_content(hook_path):
151 def read_hook_content(hook_path):
152 with open(hook_path, 'rb') as f:
152 with open(hook_path, 'rb') as f:
153 content = f.read()
153 content = f.read()
154 return content
154 return content
@@ -1,607 +1,607 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2018 RhodeCode GmbH
2 # Copyright (C) 2014-2018 RhodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import os
18 import os
19 import sys
19 import sys
20 import base64
20 import base64
21 import locale
21 import locale
22 import logging
22 import logging
23 import uuid
23 import uuid
24 import wsgiref.util
24 import wsgiref.util
25 import traceback
25 import traceback
26 import tempfile
26 import tempfile
27 from itertools import chain
27 from itertools import chain
28
28
29 import simplejson as json
29 import simplejson as json
30 import msgpack
30 import msgpack
31 from pyramid.config import Configurator
31 from pyramid.config import Configurator
32 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
33 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
34 from pyramid.compat import configparser
34 from pyramid.compat import configparser
35
35
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39 # due to Mercurial/glibc2.27 problems we need to detect if locale settings are
39 # due to Mercurial/glibc2.27 problems we need to detect if locale settings are
40 # causing problems and "fix" it in case they do and fallback to LC_ALL = C
40 # causing problems and "fix" it in case they do and fallback to LC_ALL = C
41
41
42 try:
42 try:
43 locale.setlocale(locale.LC_ALL, '')
43 locale.setlocale(locale.LC_ALL, '')
44 except locale.Error as e:
44 except locale.Error as e:
45 log.error(
45 log.error(
46 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e)
46 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e)
47 os.environ['LC_ALL'] = 'C'
47 os.environ['LC_ALL'] = 'C'
48
48
49 import vcsserver
49 import vcsserver
50 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
50 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
51 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
51 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
52 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
52 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
53 from vcsserver.echo_stub.echo_app import EchoApp
53 from vcsserver.echo_stub.echo_app import EchoApp
54 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
54 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
55 from vcsserver.lib.exc_tracking import store_exception
55 from vcsserver.lib.exc_tracking import store_exception
56 from vcsserver.server import VcsServer
56 from vcsserver.server import VcsServer
57
57
58 try:
58 try:
59 from vcsserver.git import GitFactory, GitRemote
59 from vcsserver.git import GitFactory, GitRemote
60 except ImportError:
60 except ImportError:
61 GitFactory = None
61 GitFactory = None
62 GitRemote = None
62 GitRemote = None
63
63
64 try:
64 try:
65 from vcsserver.hg import MercurialFactory, HgRemote
65 from vcsserver.hg import MercurialFactory, HgRemote
66 except ImportError:
66 except ImportError:
67 MercurialFactory = None
67 MercurialFactory = None
68 HgRemote = None
68 HgRemote = None
69
69
70 try:
70 try:
71 from vcsserver.svn import SubversionFactory, SvnRemote
71 from vcsserver.svn import SubversionFactory, SvnRemote
72 except ImportError:
72 except ImportError:
73 SubversionFactory = None
73 SubversionFactory = None
74 SvnRemote = None
74 SvnRemote = None
75
75
76
76
77 def _is_request_chunked(environ):
77 def _is_request_chunked(environ):
78 stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
78 stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
79 return stream
79 return stream
80
80
81
81
82 def _int_setting(settings, name, default):
82 def _int_setting(settings, name, default):
83 settings[name] = int(settings.get(name, default))
83 settings[name] = int(settings.get(name, default))
84 return settings[name]
84 return settings[name]
85
85
86
86
87 def _bool_setting(settings, name, default):
87 def _bool_setting(settings, name, default):
88 input_val = settings.get(name, default)
88 input_val = settings.get(name, default)
89 if isinstance(input_val, unicode):
89 if isinstance(input_val, unicode):
90 input_val = input_val.encode('utf8')
90 input_val = input_val.encode('utf8')
91 settings[name] = asbool(input_val)
91 settings[name] = asbool(input_val)
92 return settings[name]
92 return settings[name]
93
93
94
94
95 def _list_setting(settings, name, default):
95 def _list_setting(settings, name, default):
96 raw_value = settings.get(name, default)
96 raw_value = settings.get(name, default)
97
97
98 # Otherwise we assume it uses pyramids space/newline separation.
98 # Otherwise we assume it uses pyramids space/newline separation.
99 settings[name] = aslist(raw_value)
99 settings[name] = aslist(raw_value)
100 return settings[name]
100 return settings[name]
101
101
102
102
103 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
103 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
104 value = settings.get(name, default)
104 value = settings.get(name, default)
105
105
106 if default_when_empty and not value:
106 if default_when_empty and not value:
107 # use default value when value is empty
107 # use default value when value is empty
108 value = default
108 value = default
109
109
110 if lower:
110 if lower:
111 value = value.lower()
111 value = value.lower()
112 settings[name] = value
112 settings[name] = value
113 return settings[name]
113 return settings[name]
114
114
115
115
116 class VCS(object):
116 class VCS(object):
117 def __init__(self, locale=None, cache_config=None):
117 def __init__(self, locale=None, cache_config=None):
118 self.locale = locale
118 self.locale = locale
119 self.cache_config = cache_config
119 self.cache_config = cache_config
120 self._configure_locale()
120 self._configure_locale()
121
121
122 if GitFactory and GitRemote:
122 if GitFactory and GitRemote:
123 git_factory = GitFactory()
123 git_factory = GitFactory()
124 self._git_remote = GitRemote(git_factory)
124 self._git_remote = GitRemote(git_factory)
125 else:
125 else:
126 log.info("Git client import failed")
126 log.info("Git client import failed")
127
127
128 if MercurialFactory and HgRemote:
128 if MercurialFactory and HgRemote:
129 hg_factory = MercurialFactory()
129 hg_factory = MercurialFactory()
130 self._hg_remote = HgRemote(hg_factory)
130 self._hg_remote = HgRemote(hg_factory)
131 else:
131 else:
132 log.info("Mercurial client import failed")
132 log.info("Mercurial client import failed")
133
133
134 if SubversionFactory and SvnRemote:
134 if SubversionFactory and SvnRemote:
135 svn_factory = SubversionFactory()
135 svn_factory = SubversionFactory()
136
136
137 # hg factory is used for svn url validation
137 # hg factory is used for svn url validation
138 hg_factory = MercurialFactory()
138 hg_factory = MercurialFactory()
139 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
139 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
140 else:
140 else:
141 log.info("Subversion client import failed")
141 log.info("Subversion client import failed")
142
142
143 self._vcsserver = VcsServer()
143 self._vcsserver = VcsServer()
144
144
145 def _configure_locale(self):
145 def _configure_locale(self):
146 if self.locale:
146 if self.locale:
147 log.info('Settings locale: `LC_ALL` to %s', self.locale)
147 log.info('Settings locale: `LC_ALL` to %s', self.locale)
148 else:
148 else:
149 log.info(
149 log.info(
150 'Configuring locale subsystem based on environment variables')
150 'Configuring locale subsystem based on environment variables')
151 try:
151 try:
152 # If self.locale is the empty string, then the locale
152 # If self.locale is the empty string, then the locale
153 # module will use the environment variables. See the
153 # module will use the environment variables. See the
154 # documentation of the package `locale`.
154 # documentation of the package `locale`.
155 locale.setlocale(locale.LC_ALL, self.locale)
155 locale.setlocale(locale.LC_ALL, self.locale)
156
156
157 language_code, encoding = locale.getlocale()
157 language_code, encoding = locale.getlocale()
158 log.info(
158 log.info(
159 'Locale set to language code "%s" with encoding "%s".',
159 'Locale set to language code "%s" with encoding "%s".',
160 language_code, encoding)
160 language_code, encoding)
161 except locale.Error:
161 except locale.Error:
162 log.exception(
162 log.exception(
163 'Cannot set locale, not configuring the locale system')
163 'Cannot set locale, not configuring the locale system')
164
164
165
165
166 class WsgiProxy(object):
166 class WsgiProxy(object):
167 def __init__(self, wsgi):
167 def __init__(self, wsgi):
168 self.wsgi = wsgi
168 self.wsgi = wsgi
169
169
170 def __call__(self, environ, start_response):
170 def __call__(self, environ, start_response):
171 input_data = environ['wsgi.input'].read()
171 input_data = environ['wsgi.input'].read()
172 input_data = msgpack.unpackb(input_data)
172 input_data = msgpack.unpackb(input_data)
173
173
174 error = None
174 error = None
175 try:
175 try:
176 data, status, headers = self.wsgi.handle(
176 data, status, headers = self.wsgi.handle(
177 input_data['environment'], input_data['input_data'],
177 input_data['environment'], input_data['input_data'],
178 *input_data['args'], **input_data['kwargs'])
178 *input_data['args'], **input_data['kwargs'])
179 except Exception as e:
179 except Exception as e:
180 data, status, headers = [], None, None
180 data, status, headers = [], None, None
181 error = {
181 error = {
182 'message': str(e),
182 'message': str(e),
183 '_vcs_kind': getattr(e, '_vcs_kind', None)
183 '_vcs_kind': getattr(e, '_vcs_kind', None)
184 }
184 }
185
185
186 start_response(200, {})
186 start_response(200, {})
187 return self._iterator(error, status, headers, data)
187 return self._iterator(error, status, headers, data)
188
188
189 def _iterator(self, error, status, headers, data):
189 def _iterator(self, error, status, headers, data):
190 initial_data = [
190 initial_data = [
191 error,
191 error,
192 status,
192 status,
193 headers,
193 headers,
194 ]
194 ]
195
195
196 for d in chain(initial_data, data):
196 for d in chain(initial_data, data):
197 yield msgpack.packb(d)
197 yield msgpack.packb(d)
198
198
199
199
200 def not_found(request):
200 def not_found(request):
201 return {'status': '404 NOT FOUND'}
201 return {'status': '404 NOT FOUND'}
202
202
203
203
204 class VCSViewPredicate(object):
204 class VCSViewPredicate(object):
205 def __init__(self, val, config):
205 def __init__(self, val, config):
206 self.remotes = val
206 self.remotes = val
207
207
208 def text(self):
208 def text(self):
209 return 'vcs view method = %s' % (self.remotes.keys(),)
209 return 'vcs view method = %s' % (self.remotes.keys(),)
210
210
211 phash = text
211 phash = text
212
212
213 def __call__(self, context, request):
213 def __call__(self, context, request):
214 """
214 """
215 View predicate that returns true if given backend is supported by
215 View predicate that returns true if given backend is supported by
216 defined remotes.
216 defined remotes.
217 """
217 """
218 backend = request.matchdict.get('backend')
218 backend = request.matchdict.get('backend')
219 return backend in self.remotes
219 return backend in self.remotes
220
220
221
221
222 class HTTPApplication(object):
222 class HTTPApplication(object):
223 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
223 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
224
224
225 remote_wsgi = remote_wsgi
225 remote_wsgi = remote_wsgi
226 _use_echo_app = False
226 _use_echo_app = False
227
227
228 def __init__(self, settings=None, global_config=None):
228 def __init__(self, settings=None, global_config=None):
229 self._sanitize_settings_and_apply_defaults(settings)
229 self._sanitize_settings_and_apply_defaults(settings)
230
230
231 self.config = Configurator(settings=settings)
231 self.config = Configurator(settings=settings)
232 self.global_config = global_config
232 self.global_config = global_config
233 self.config.include('vcsserver.lib.rc_cache')
233 self.config.include('vcsserver.lib.rc_cache')
234
234
235 locale = settings.get('locale', '') or 'en_US.UTF-8'
235 locale = settings.get('locale', '') or 'en_US.UTF-8'
236 vcs = VCS(locale=locale, cache_config=settings)
236 vcs = VCS(locale=locale, cache_config=settings)
237 self._remotes = {
237 self._remotes = {
238 'hg': vcs._hg_remote,
238 'hg': vcs._hg_remote,
239 'git': vcs._git_remote,
239 'git': vcs._git_remote,
240 'svn': vcs._svn_remote,
240 'svn': vcs._svn_remote,
241 'server': vcs._vcsserver,
241 'server': vcs._vcsserver,
242 }
242 }
243 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
243 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
244 self._use_echo_app = True
244 self._use_echo_app = True
245 log.warning("Using EchoApp for VCS operations.")
245 log.warning("Using EchoApp for VCS operations.")
246 self.remote_wsgi = remote_wsgi_stub
246 self.remote_wsgi = remote_wsgi_stub
247
247
248 self._configure_settings(global_config, settings)
248 self._configure_settings(global_config, settings)
249 self._configure()
249 self._configure()
250
250
251 def _configure_settings(self, global_config, app_settings):
251 def _configure_settings(self, global_config, app_settings):
252 """
252 """
253 Configure the settings module.
253 Configure the settings module.
254 """
254 """
255 settings_merged = global_config.copy()
255 settings_merged = global_config.copy()
256 settings_merged.update(app_settings)
256 settings_merged.update(app_settings)
257
257
258 git_path = app_settings.get('git_path', None)
258 git_path = app_settings.get('git_path', None)
259 if git_path:
259 if git_path:
260 settings.GIT_EXECUTABLE = git_path
260 settings.GIT_EXECUTABLE = git_path
261 binary_dir = app_settings.get('core.binary_dir', None)
261 binary_dir = app_settings.get('core.binary_dir', None)
262 if binary_dir:
262 if binary_dir:
263 settings.BINARY_DIR = binary_dir
263 settings.BINARY_DIR = binary_dir
264
264
265 # Store the settings to make them available to other modules.
265 # Store the settings to make them available to other modules.
266 vcsserver.PYRAMID_SETTINGS = settings_merged
266 vcsserver.PYRAMID_SETTINGS = settings_merged
267 vcsserver.CONFIG = settings_merged
267 vcsserver.CONFIG = settings_merged
268
268
269 def _sanitize_settings_and_apply_defaults(self, settings):
269 def _sanitize_settings_and_apply_defaults(self, settings):
270 temp_store = tempfile.gettempdir()
270 temp_store = tempfile.gettempdir()
271 default_cache_dir = os.path.join(temp_store, 'rc_cache')
271 default_cache_dir = os.path.join(temp_store, 'rc_cache')
272
272
273 # save default, cache dir, and use it for all backends later.
273 # save default, cache dir, and use it for all backends later.
274 default_cache_dir = _string_setting(
274 default_cache_dir = _string_setting(
275 settings,
275 settings,
276 'cache_dir',
276 'cache_dir',
277 default_cache_dir, lower=False, default_when_empty=True)
277 default_cache_dir, lower=False, default_when_empty=True)
278
278
279 # ensure we have our dir created
279 # ensure we have our dir created
280 if not os.path.isdir(default_cache_dir):
280 if not os.path.isdir(default_cache_dir):
281 os.makedirs(default_cache_dir, mode=0755)
281 os.makedirs(default_cache_dir, mode=0o755)
282
282
283 # exception store cache
283 # exception store cache
284 _string_setting(
284 _string_setting(
285 settings,
285 settings,
286 'exception_tracker.store_path',
286 'exception_tracker.store_path',
287 temp_store, lower=False, default_when_empty=True)
287 temp_store, lower=False, default_when_empty=True)
288
288
289 # repo_object cache
289 # repo_object cache
290 _string_setting(
290 _string_setting(
291 settings,
291 settings,
292 'rc_cache.repo_object.backend',
292 'rc_cache.repo_object.backend',
293 'dogpile.cache.rc.memory_lru')
293 'dogpile.cache.rc.memory_lru')
294 _int_setting(
294 _int_setting(
295 settings,
295 settings,
296 'rc_cache.repo_object.expiration_time',
296 'rc_cache.repo_object.expiration_time',
297 300)
297 300)
298 _int_setting(
298 _int_setting(
299 settings,
299 settings,
300 'rc_cache.repo_object.max_size',
300 'rc_cache.repo_object.max_size',
301 1024)
301 1024)
302
302
303 def _configure(self):
303 def _configure(self):
304 self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
304 self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
305
305
306 self.config.add_route('service', '/_service')
306 self.config.add_route('service', '/_service')
307 self.config.add_route('status', '/status')
307 self.config.add_route('status', '/status')
308 self.config.add_route('hg_proxy', '/proxy/hg')
308 self.config.add_route('hg_proxy', '/proxy/hg')
309 self.config.add_route('git_proxy', '/proxy/git')
309 self.config.add_route('git_proxy', '/proxy/git')
310 self.config.add_route('vcs', '/{backend}')
310 self.config.add_route('vcs', '/{backend}')
311 self.config.add_route('stream_git', '/stream/git/*repo_name')
311 self.config.add_route('stream_git', '/stream/git/*repo_name')
312 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
312 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
313
313
314 self.config.add_view(self.status_view, route_name='status', renderer='json')
314 self.config.add_view(self.status_view, route_name='status', renderer='json')
315 self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
315 self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
316
316
317 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
317 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
318 self.config.add_view(self.git_proxy(), route_name='git_proxy')
318 self.config.add_view(self.git_proxy(), route_name='git_proxy')
319 self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
319 self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
320 vcs_view=self._remotes)
320 vcs_view=self._remotes)
321
321
322 self.config.add_view(self.hg_stream(), route_name='stream_hg')
322 self.config.add_view(self.hg_stream(), route_name='stream_hg')
323 self.config.add_view(self.git_stream(), route_name='stream_git')
323 self.config.add_view(self.git_stream(), route_name='stream_git')
324
324
325 self.config.add_view_predicate('vcs_view', VCSViewPredicate)
325 self.config.add_view_predicate('vcs_view', VCSViewPredicate)
326
326
327 self.config.add_notfound_view(not_found, renderer='json')
327 self.config.add_notfound_view(not_found, renderer='json')
328
328
329 self.config.add_view(self.handle_vcs_exception, context=Exception)
329 self.config.add_view(self.handle_vcs_exception, context=Exception)
330
330
331 self.config.add_tween(
331 self.config.add_tween(
332 'vcsserver.tweens.RequestWrapperTween',
332 'vcsserver.tweens.RequestWrapperTween',
333 )
333 )
334
334
335 def wsgi_app(self):
335 def wsgi_app(self):
336 return self.config.make_wsgi_app()
336 return self.config.make_wsgi_app()
337
337
338 def vcs_view(self, request):
338 def vcs_view(self, request):
339 remote = self._remotes[request.matchdict['backend']]
339 remote = self._remotes[request.matchdict['backend']]
340 payload = msgpack.unpackb(request.body, use_list=True)
340 payload = msgpack.unpackb(request.body, use_list=True)
341 method = payload.get('method')
341 method = payload.get('method')
342 params = payload.get('params')
342 params = payload.get('params')
343 wire = params.get('wire')
343 wire = params.get('wire')
344 args = params.get('args')
344 args = params.get('args')
345 kwargs = params.get('kwargs')
345 kwargs = params.get('kwargs')
346 context_uid = None
346 context_uid = None
347
347
348 if wire:
348 if wire:
349 try:
349 try:
350 wire['context'] = context_uid = uuid.UUID(wire['context'])
350 wire['context'] = context_uid = uuid.UUID(wire['context'])
351 except KeyError:
351 except KeyError:
352 pass
352 pass
353 args.insert(0, wire)
353 args.insert(0, wire)
354
354
355 log.debug('method called:%s with kwargs:%s context_uid: %s',
355 log.debug('method called:%s with kwargs:%s context_uid: %s',
356 method, kwargs, context_uid)
356 method, kwargs, context_uid)
357 try:
357 try:
358 resp = getattr(remote, method)(*args, **kwargs)
358 resp = getattr(remote, method)(*args, **kwargs)
359 except Exception as e:
359 except Exception as e:
360 exc_info = list(sys.exc_info())
360 exc_info = list(sys.exc_info())
361 exc_type, exc_value, exc_traceback = exc_info
361 exc_type, exc_value, exc_traceback = exc_info
362
362
363 org_exc = getattr(e, '_org_exc', None)
363 org_exc = getattr(e, '_org_exc', None)
364 org_exc_name = None
364 org_exc_name = None
365 if org_exc:
365 if org_exc:
366 org_exc_name = org_exc.__class__.__name__
366 org_exc_name = org_exc.__class__.__name__
367 # replace our "faked" exception with our org
367 # replace our "faked" exception with our org
368 exc_info[0] = org_exc.__class__
368 exc_info[0] = org_exc.__class__
369 exc_info[1] = org_exc
369 exc_info[1] = org_exc
370
370
371 store_exception(id(exc_info), exc_info)
371 store_exception(id(exc_info), exc_info)
372
372
373 tb_info = ''.join(
373 tb_info = ''.join(
374 traceback.format_exception(exc_type, exc_value, exc_traceback))
374 traceback.format_exception(exc_type, exc_value, exc_traceback))
375
375
376 type_ = e.__class__.__name__
376 type_ = e.__class__.__name__
377 if type_ not in self.ALLOWED_EXCEPTIONS:
377 if type_ not in self.ALLOWED_EXCEPTIONS:
378 type_ = None
378 type_ = None
379
379
380 resp = {
380 resp = {
381 'id': payload.get('id'),
381 'id': payload.get('id'),
382 'error': {
382 'error': {
383 'message': e.message,
383 'message': e.message,
384 'traceback': tb_info,
384 'traceback': tb_info,
385 'org_exc': org_exc_name,
385 'org_exc': org_exc_name,
386 'type': type_
386 'type': type_
387 }
387 }
388 }
388 }
389 try:
389 try:
390 resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None)
390 resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None)
391 except AttributeError:
391 except AttributeError:
392 pass
392 pass
393 else:
393 else:
394 resp = {
394 resp = {
395 'id': payload.get('id'),
395 'id': payload.get('id'),
396 'result': resp
396 'result': resp
397 }
397 }
398
398
399 return resp
399 return resp
400
400
401 def status_view(self, request):
401 def status_view(self, request):
402 import vcsserver
402 import vcsserver
403 return {'status': 'OK', 'vcsserver_version': vcsserver.__version__,
403 return {'status': 'OK', 'vcsserver_version': vcsserver.__version__,
404 'pid': os.getpid()}
404 'pid': os.getpid()}
405
405
406 def service_view(self, request):
406 def service_view(self, request):
407 import vcsserver
407 import vcsserver
408
408
409 payload = msgpack.unpackb(request.body, use_list=True)
409 payload = msgpack.unpackb(request.body, use_list=True)
410
410
411 try:
411 try:
412 path = self.global_config['__file__']
412 path = self.global_config['__file__']
413 config = configparser.ConfigParser()
413 config = configparser.ConfigParser()
414 config.read(path)
414 config.read(path)
415 parsed_ini = config
415 parsed_ini = config
416 if parsed_ini.has_section('server:main'):
416 if parsed_ini.has_section('server:main'):
417 parsed_ini = dict(parsed_ini.items('server:main'))
417 parsed_ini = dict(parsed_ini.items('server:main'))
418 except Exception:
418 except Exception:
419 log.exception('Failed to read .ini file for display')
419 log.exception('Failed to read .ini file for display')
420 parsed_ini = {}
420 parsed_ini = {}
421
421
422 resp = {
422 resp = {
423 'id': payload.get('id'),
423 'id': payload.get('id'),
424 'result': dict(
424 'result': dict(
425 version=vcsserver.__version__,
425 version=vcsserver.__version__,
426 config=parsed_ini,
426 config=parsed_ini,
427 payload=payload,
427 payload=payload,
428 )
428 )
429 }
429 }
430 return resp
430 return resp
431
431
432 def _msgpack_renderer_factory(self, info):
432 def _msgpack_renderer_factory(self, info):
433 def _render(value, system):
433 def _render(value, system):
434 value = msgpack.packb(value)
434 value = msgpack.packb(value)
435 request = system.get('request')
435 request = system.get('request')
436 if request is not None:
436 if request is not None:
437 response = request.response
437 response = request.response
438 ct = response.content_type
438 ct = response.content_type
439 if ct == response.default_content_type:
439 if ct == response.default_content_type:
440 response.content_type = 'application/x-msgpack'
440 response.content_type = 'application/x-msgpack'
441 return value
441 return value
442 return _render
442 return _render
443
443
444 def set_env_from_config(self, environ, config):
444 def set_env_from_config(self, environ, config):
445 dict_conf = {}
445 dict_conf = {}
446 try:
446 try:
447 for elem in config:
447 for elem in config:
448 if elem[0] == 'rhodecode':
448 if elem[0] == 'rhodecode':
449 dict_conf = json.loads(elem[2])
449 dict_conf = json.loads(elem[2])
450 break
450 break
451 except Exception:
451 except Exception:
452 log.exception('Failed to fetch SCM CONFIG')
452 log.exception('Failed to fetch SCM CONFIG')
453 return
453 return
454
454
455 username = dict_conf.get('username')
455 username = dict_conf.get('username')
456 if username:
456 if username:
457 environ['REMOTE_USER'] = username
457 environ['REMOTE_USER'] = username
458 # mercurial specific, some extension api rely on this
458 # mercurial specific, some extension api rely on this
459 environ['HGUSER'] = username
459 environ['HGUSER'] = username
460
460
461 ip = dict_conf.get('ip')
461 ip = dict_conf.get('ip')
462 if ip:
462 if ip:
463 environ['REMOTE_HOST'] = ip
463 environ['REMOTE_HOST'] = ip
464
464
465 if _is_request_chunked(environ):
465 if _is_request_chunked(environ):
466 # set the compatibility flag for webob
466 # set the compatibility flag for webob
467 environ['wsgi.input_terminated'] = True
467 environ['wsgi.input_terminated'] = True
468
468
469 def hg_proxy(self):
469 def hg_proxy(self):
470 @wsgiapp
470 @wsgiapp
471 def _hg_proxy(environ, start_response):
471 def _hg_proxy(environ, start_response):
472 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
472 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
473 return app(environ, start_response)
473 return app(environ, start_response)
474 return _hg_proxy
474 return _hg_proxy
475
475
476 def git_proxy(self):
476 def git_proxy(self):
477 @wsgiapp
477 @wsgiapp
478 def _git_proxy(environ, start_response):
478 def _git_proxy(environ, start_response):
479 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
479 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
480 return app(environ, start_response)
480 return app(environ, start_response)
481 return _git_proxy
481 return _git_proxy
482
482
483 def hg_stream(self):
483 def hg_stream(self):
484 if self._use_echo_app:
484 if self._use_echo_app:
485 @wsgiapp
485 @wsgiapp
486 def _hg_stream(environ, start_response):
486 def _hg_stream(environ, start_response):
487 app = EchoApp('fake_path', 'fake_name', None)
487 app = EchoApp('fake_path', 'fake_name', None)
488 return app(environ, start_response)
488 return app(environ, start_response)
489 return _hg_stream
489 return _hg_stream
490 else:
490 else:
491 @wsgiapp
491 @wsgiapp
492 def _hg_stream(environ, start_response):
492 def _hg_stream(environ, start_response):
493 log.debug('http-app: handling hg stream')
493 log.debug('http-app: handling hg stream')
494 repo_path = environ['HTTP_X_RC_REPO_PATH']
494 repo_path = environ['HTTP_X_RC_REPO_PATH']
495 repo_name = environ['HTTP_X_RC_REPO_NAME']
495 repo_name = environ['HTTP_X_RC_REPO_NAME']
496 packed_config = base64.b64decode(
496 packed_config = base64.b64decode(
497 environ['HTTP_X_RC_REPO_CONFIG'])
497 environ['HTTP_X_RC_REPO_CONFIG'])
498 config = msgpack.unpackb(packed_config)
498 config = msgpack.unpackb(packed_config)
499 app = scm_app.create_hg_wsgi_app(
499 app = scm_app.create_hg_wsgi_app(
500 repo_path, repo_name, config)
500 repo_path, repo_name, config)
501
501
502 # Consistent path information for hgweb
502 # Consistent path information for hgweb
503 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
503 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
504 environ['REPO_NAME'] = repo_name
504 environ['REPO_NAME'] = repo_name
505 self.set_env_from_config(environ, config)
505 self.set_env_from_config(environ, config)
506
506
507 log.debug('http-app: starting app handler '
507 log.debug('http-app: starting app handler '
508 'with %s and process request', app)
508 'with %s and process request', app)
509 return app(environ, ResponseFilter(start_response))
509 return app(environ, ResponseFilter(start_response))
510 return _hg_stream
510 return _hg_stream
511
511
512 def git_stream(self):
512 def git_stream(self):
513 if self._use_echo_app:
513 if self._use_echo_app:
514 @wsgiapp
514 @wsgiapp
515 def _git_stream(environ, start_response):
515 def _git_stream(environ, start_response):
516 app = EchoApp('fake_path', 'fake_name', None)
516 app = EchoApp('fake_path', 'fake_name', None)
517 return app(environ, start_response)
517 return app(environ, start_response)
518 return _git_stream
518 return _git_stream
519 else:
519 else:
520 @wsgiapp
520 @wsgiapp
521 def _git_stream(environ, start_response):
521 def _git_stream(environ, start_response):
522 log.debug('http-app: handling git stream')
522 log.debug('http-app: handling git stream')
523 repo_path = environ['HTTP_X_RC_REPO_PATH']
523 repo_path = environ['HTTP_X_RC_REPO_PATH']
524 repo_name = environ['HTTP_X_RC_REPO_NAME']
524 repo_name = environ['HTTP_X_RC_REPO_NAME']
525 packed_config = base64.b64decode(
525 packed_config = base64.b64decode(
526 environ['HTTP_X_RC_REPO_CONFIG'])
526 environ['HTTP_X_RC_REPO_CONFIG'])
527 config = msgpack.unpackb(packed_config)
527 config = msgpack.unpackb(packed_config)
528
528
529 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
529 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
530 self.set_env_from_config(environ, config)
530 self.set_env_from_config(environ, config)
531
531
532 content_type = environ.get('CONTENT_TYPE', '')
532 content_type = environ.get('CONTENT_TYPE', '')
533
533
534 path = environ['PATH_INFO']
534 path = environ['PATH_INFO']
535 is_lfs_request = GIT_LFS_CONTENT_TYPE in content_type
535 is_lfs_request = GIT_LFS_CONTENT_TYPE in content_type
536 log.debug(
536 log.debug(
537 'LFS: Detecting if request `%s` is LFS server path based '
537 'LFS: Detecting if request `%s` is LFS server path based '
538 'on content type:`%s`, is_lfs:%s',
538 'on content type:`%s`, is_lfs:%s',
539 path, content_type, is_lfs_request)
539 path, content_type, is_lfs_request)
540
540
541 if not is_lfs_request:
541 if not is_lfs_request:
542 # fallback detection by path
542 # fallback detection by path
543 if GIT_LFS_PROTO_PAT.match(path):
543 if GIT_LFS_PROTO_PAT.match(path):
544 is_lfs_request = True
544 is_lfs_request = True
545 log.debug(
545 log.debug(
546 'LFS: fallback detection by path of: `%s`, is_lfs:%s',
546 'LFS: fallback detection by path of: `%s`, is_lfs:%s',
547 path, is_lfs_request)
547 path, is_lfs_request)
548
548
549 if is_lfs_request:
549 if is_lfs_request:
550 app = scm_app.create_git_lfs_wsgi_app(
550 app = scm_app.create_git_lfs_wsgi_app(
551 repo_path, repo_name, config)
551 repo_path, repo_name, config)
552 else:
552 else:
553 app = scm_app.create_git_wsgi_app(
553 app = scm_app.create_git_wsgi_app(
554 repo_path, repo_name, config)
554 repo_path, repo_name, config)
555
555
556 log.debug('http-app: starting app handler '
556 log.debug('http-app: starting app handler '
557 'with %s and process request', app)
557 'with %s and process request', app)
558
558
559 return app(environ, start_response)
559 return app(environ, start_response)
560
560
561 return _git_stream
561 return _git_stream
562
562
563 def handle_vcs_exception(self, exception, request):
563 def handle_vcs_exception(self, exception, request):
564 _vcs_kind = getattr(exception, '_vcs_kind', '')
564 _vcs_kind = getattr(exception, '_vcs_kind', '')
565 if _vcs_kind == 'repo_locked':
565 if _vcs_kind == 'repo_locked':
566 # Get custom repo-locked status code if present.
566 # Get custom repo-locked status code if present.
567 status_code = request.headers.get('X-RC-Locked-Status-Code')
567 status_code = request.headers.get('X-RC-Locked-Status-Code')
568 return HTTPRepoLocked(
568 return HTTPRepoLocked(
569 title=exception.message, status_code=status_code)
569 title=exception.message, status_code=status_code)
570
570
571 elif _vcs_kind == 'repo_branch_protected':
571 elif _vcs_kind == 'repo_branch_protected':
572 # Get custom repo-branch-protected status code if present.
572 # Get custom repo-branch-protected status code if present.
573 return HTTPRepoBranchProtected(title=exception.message)
573 return HTTPRepoBranchProtected(title=exception.message)
574
574
575 exc_info = request.exc_info
575 exc_info = request.exc_info
576 store_exception(id(exc_info), exc_info)
576 store_exception(id(exc_info), exc_info)
577
577
578 traceback_info = 'unavailable'
578 traceback_info = 'unavailable'
579 if request.exc_info:
579 if request.exc_info:
580 exc_type, exc_value, exc_tb = request.exc_info
580 exc_type, exc_value, exc_tb = request.exc_info
581 traceback_info = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb))
581 traceback_info = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb))
582
582
583 log.error(
583 log.error(
584 'error occurred handling this request for path: %s, \n tb: %s',
584 'error occurred handling this request for path: %s, \n tb: %s',
585 request.path, traceback_info)
585 request.path, traceback_info)
586 raise exception
586 raise exception
587
587
588
588
589 class ResponseFilter(object):
589 class ResponseFilter(object):
590
590
591 def __init__(self, start_response):
591 def __init__(self, start_response):
592 self._start_response = start_response
592 self._start_response = start_response
593
593
594 def __call__(self, status, response_headers, exc_info=None):
594 def __call__(self, status, response_headers, exc_info=None):
595 headers = tuple(
595 headers = tuple(
596 (h, v) for h, v in response_headers
596 (h, v) for h, v in response_headers
597 if not wsgiref.util.is_hop_by_hop(h))
597 if not wsgiref.util.is_hop_by_hop(h))
598 return self._start_response(status, headers, exc_info)
598 return self._start_response(status, headers, exc_info)
599
599
600
600
601 def main(global_config, **settings):
601 def main(global_config, **settings):
602 if MercurialFactory:
602 if MercurialFactory:
603 hgpatches.patch_largefiles_capabilities()
603 hgpatches.patch_largefiles_capabilities()
604 hgpatches.patch_subrepo_type_mapping()
604 hgpatches.patch_subrepo_type_mapping()
605
605
606 app = HTTPApplication(settings=settings, global_config=global_config)
606 app = HTTPApplication(settings=settings, global_config=global_config)
607 return app.wsgi_app()
607 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now