|
@@
-1,704
+1,705
|
|
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-2020 RhodeCode GmbH
|
|
2
|
# Copyright (C) 2014-2020 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
|
import psutil
|
|
27
|
import psutil
|
|
28
|
from itertools import chain
|
|
28
|
from itertools import chain
|
|
29
|
from cStringIO import StringIO
|
|
29
|
from cStringIO import StringIO
|
|
30
|
|
|
30
|
|
|
31
|
import simplejson as json
|
|
31
|
import simplejson as json
|
|
32
|
import msgpack
|
|
32
|
import msgpack
|
|
33
|
from pyramid.config import Configurator
|
|
33
|
from pyramid.config import Configurator
|
|
34
|
from pyramid.settings import asbool, aslist
|
|
34
|
from pyramid.settings import asbool, aslist
|
|
35
|
from pyramid.wsgi import wsgiapp
|
|
35
|
from pyramid.wsgi import wsgiapp
|
|
36
|
from pyramid.compat import configparser
|
|
36
|
from pyramid.compat import configparser
|
|
37
|
from pyramid.response import Response
|
|
37
|
from pyramid.response import Response
|
|
38
|
|
|
38
|
|
|
39
|
from vcsserver.utils import safe_int
|
|
39
|
from vcsserver.utils import safe_int
|
|
40
|
|
|
40
|
|
|
41
|
log = logging.getLogger(__name__)
|
|
41
|
log = logging.getLogger(__name__)
|
|
42
|
|
|
42
|
|
|
43
|
# due to Mercurial/glibc2.27 problems we need to detect if locale settings are
|
|
43
|
# due to Mercurial/glibc2.27 problems we need to detect if locale settings are
|
|
44
|
# causing problems and "fix" it in case they do and fallback to LC_ALL = C
|
|
44
|
# causing problems and "fix" it in case they do and fallback to LC_ALL = C
|
|
45
|
|
|
45
|
|
|
46
|
try:
|
|
46
|
try:
|
|
47
|
locale.setlocale(locale.LC_ALL, '')
|
|
47
|
locale.setlocale(locale.LC_ALL, '')
|
|
48
|
except locale.Error as e:
|
|
48
|
except locale.Error as e:
|
|
49
|
log.error(
|
|
49
|
log.error(
|
|
50
|
'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e)
|
|
50
|
'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e)
|
|
51
|
os.environ['LC_ALL'] = 'C'
|
|
51
|
os.environ['LC_ALL'] = 'C'
|
|
52
|
|
|
52
|
|
|
53
|
import vcsserver
|
|
53
|
import vcsserver
|
|
54
|
from vcsserver import remote_wsgi, scm_app, settings, hgpatches
|
|
54
|
from vcsserver import remote_wsgi, scm_app, settings, hgpatches
|
|
55
|
from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
|
|
55
|
from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
|
|
56
|
from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
|
|
56
|
from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
|
|
57
|
from vcsserver.echo_stub.echo_app import EchoApp
|
|
57
|
from vcsserver.echo_stub.echo_app import EchoApp
|
|
58
|
from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
|
|
58
|
from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
|
|
59
|
from vcsserver.lib.exc_tracking import store_exception
|
|
59
|
from vcsserver.lib.exc_tracking import store_exception
|
|
60
|
from vcsserver.server import VcsServer
|
|
60
|
from vcsserver.server import VcsServer
|
|
61
|
|
|
61
|
|
|
62
|
try:
|
|
62
|
try:
|
|
63
|
from vcsserver.git import GitFactory, GitRemote
|
|
63
|
from vcsserver.git import GitFactory, GitRemote
|
|
64
|
except ImportError:
|
|
64
|
except ImportError:
|
|
65
|
GitFactory = None
|
|
65
|
GitFactory = None
|
|
66
|
GitRemote = None
|
|
66
|
GitRemote = None
|
|
67
|
|
|
67
|
|
|
68
|
try:
|
|
68
|
try:
|
|
69
|
from vcsserver.hg import MercurialFactory, HgRemote
|
|
69
|
from vcsserver.hg import MercurialFactory, HgRemote
|
|
70
|
except ImportError:
|
|
70
|
except ImportError:
|
|
71
|
MercurialFactory = None
|
|
71
|
MercurialFactory = None
|
|
72
|
HgRemote = None
|
|
72
|
HgRemote = None
|
|
73
|
|
|
73
|
|
|
74
|
try:
|
|
74
|
try:
|
|
75
|
from vcsserver.svn import SubversionFactory, SvnRemote
|
|
75
|
from vcsserver.svn import SubversionFactory, SvnRemote
|
|
76
|
except ImportError:
|
|
76
|
except ImportError:
|
|
77
|
SubversionFactory = None
|
|
77
|
SubversionFactory = None
|
|
78
|
SvnRemote = None
|
|
78
|
SvnRemote = None
|
|
79
|
|
|
79
|
|
|
80
|
|
|
80
|
|
|
81
|
def _is_request_chunked(environ):
|
|
81
|
def _is_request_chunked(environ):
|
|
82
|
stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
|
|
82
|
stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
|
|
83
|
return stream
|
|
83
|
return stream
|
|
84
|
|
|
84
|
|
|
85
|
|
|
85
|
|
|
86
|
def _int_setting(settings, name, default):
|
|
86
|
def _int_setting(settings, name, default):
|
|
87
|
settings[name] = int(settings.get(name, default))
|
|
87
|
settings[name] = int(settings.get(name, default))
|
|
88
|
return settings[name]
|
|
88
|
return settings[name]
|
|
89
|
|
|
89
|
|
|
90
|
|
|
90
|
|
|
91
|
def _bool_setting(settings, name, default):
|
|
91
|
def _bool_setting(settings, name, default):
|
|
92
|
input_val = settings.get(name, default)
|
|
92
|
input_val = settings.get(name, default)
|
|
93
|
if isinstance(input_val, unicode):
|
|
93
|
if isinstance(input_val, unicode):
|
|
94
|
input_val = input_val.encode('utf8')
|
|
94
|
input_val = input_val.encode('utf8')
|
|
95
|
settings[name] = asbool(input_val)
|
|
95
|
settings[name] = asbool(input_val)
|
|
96
|
return settings[name]
|
|
96
|
return settings[name]
|
|
97
|
|
|
97
|
|
|
98
|
|
|
98
|
|
|
99
|
def _list_setting(settings, name, default):
|
|
99
|
def _list_setting(settings, name, default):
|
|
100
|
raw_value = settings.get(name, default)
|
|
100
|
raw_value = settings.get(name, default)
|
|
101
|
|
|
101
|
|
|
102
|
# Otherwise we assume it uses pyramids space/newline separation.
|
|
102
|
# Otherwise we assume it uses pyramids space/newline separation.
|
|
103
|
settings[name] = aslist(raw_value)
|
|
103
|
settings[name] = aslist(raw_value)
|
|
104
|
return settings[name]
|
|
104
|
return settings[name]
|
|
105
|
|
|
105
|
|
|
106
|
|
|
106
|
|
|
107
|
def _string_setting(settings, name, default, lower=True, default_when_empty=False):
|
|
107
|
def _string_setting(settings, name, default, lower=True, default_when_empty=False):
|
|
108
|
value = settings.get(name, default)
|
|
108
|
value = settings.get(name, default)
|
|
109
|
|
|
109
|
|
|
110
|
if default_when_empty and not value:
|
|
110
|
if default_when_empty and not value:
|
|
111
|
# use default value when value is empty
|
|
111
|
# use default value when value is empty
|
|
112
|
value = default
|
|
112
|
value = default
|
|
113
|
|
|
113
|
|
|
114
|
if lower:
|
|
114
|
if lower:
|
|
115
|
value = value.lower()
|
|
115
|
value = value.lower()
|
|
116
|
settings[name] = value
|
|
116
|
settings[name] = value
|
|
117
|
return settings[name]
|
|
117
|
return settings[name]
|
|
118
|
|
|
118
|
|
|
119
|
|
|
119
|
|
|
120
|
def log_max_fd():
|
|
120
|
def log_max_fd():
|
|
121
|
try:
|
|
121
|
try:
|
|
122
|
maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1]
|
|
122
|
maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1]
|
|
123
|
log.info('Max file descriptors value: %s', maxfd)
|
|
123
|
log.info('Max file descriptors value: %s', maxfd)
|
|
124
|
except Exception:
|
|
124
|
except Exception:
|
|
125
|
pass
|
|
125
|
pass
|
|
126
|
|
|
126
|
|
|
127
|
|
|
127
|
|
|
128
|
class VCS(object):
|
|
128
|
class VCS(object):
|
|
129
|
def __init__(self, locale_conf=None, cache_config=None):
|
|
129
|
def __init__(self, locale_conf=None, cache_config=None):
|
|
130
|
self.locale = locale_conf
|
|
130
|
self.locale = locale_conf
|
|
131
|
self.cache_config = cache_config
|
|
131
|
self.cache_config = cache_config
|
|
132
|
self._configure_locale()
|
|
132
|
self._configure_locale()
|
|
133
|
|
|
133
|
|
|
134
|
log_max_fd()
|
|
134
|
log_max_fd()
|
|
135
|
|
|
135
|
|
|
136
|
if GitFactory and GitRemote:
|
|
136
|
if GitFactory and GitRemote:
|
|
137
|
git_factory = GitFactory()
|
|
137
|
git_factory = GitFactory()
|
|
138
|
self._git_remote = GitRemote(git_factory)
|
|
138
|
self._git_remote = GitRemote(git_factory)
|
|
139
|
else:
|
|
139
|
else:
|
|
140
|
log.info("Git client import failed")
|
|
140
|
log.info("Git client import failed")
|
|
141
|
|
|
141
|
|
|
142
|
if MercurialFactory and HgRemote:
|
|
142
|
if MercurialFactory and HgRemote:
|
|
143
|
hg_factory = MercurialFactory()
|
|
143
|
hg_factory = MercurialFactory()
|
|
144
|
self._hg_remote = HgRemote(hg_factory)
|
|
144
|
self._hg_remote = HgRemote(hg_factory)
|
|
145
|
else:
|
|
145
|
else:
|
|
146
|
log.info("Mercurial client import failed")
|
|
146
|
log.info("Mercurial client import failed")
|
|
147
|
|
|
147
|
|
|
148
|
if SubversionFactory and SvnRemote:
|
|
148
|
if SubversionFactory and SvnRemote:
|
|
149
|
svn_factory = SubversionFactory()
|
|
149
|
svn_factory = SubversionFactory()
|
|
150
|
|
|
150
|
|
|
151
|
# hg factory is used for svn url validation
|
|
151
|
# hg factory is used for svn url validation
|
|
152
|
hg_factory = MercurialFactory()
|
|
152
|
hg_factory = MercurialFactory()
|
|
153
|
self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
|
|
153
|
self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
|
|
154
|
else:
|
|
154
|
else:
|
|
155
|
log.info("Subversion client import failed")
|
|
155
|
log.info("Subversion client import failed")
|
|
156
|
|
|
156
|
|
|
157
|
self._vcsserver = VcsServer()
|
|
157
|
self._vcsserver = VcsServer()
|
|
158
|
|
|
158
|
|
|
159
|
def _configure_locale(self):
|
|
159
|
def _configure_locale(self):
|
|
160
|
if self.locale:
|
|
160
|
if self.locale:
|
|
161
|
log.info('Settings locale: `LC_ALL` to %s', self.locale)
|
|
161
|
log.info('Settings locale: `LC_ALL` to %s', self.locale)
|
|
162
|
else:
|
|
162
|
else:
|
|
163
|
log.info(
|
|
163
|
log.info(
|
|
164
|
'Configuring locale subsystem based on environment variables')
|
|
164
|
'Configuring locale subsystem based on environment variables')
|
|
165
|
try:
|
|
165
|
try:
|
|
166
|
# If self.locale is the empty string, then the locale
|
|
166
|
# If self.locale is the empty string, then the locale
|
|
167
|
# module will use the environment variables. See the
|
|
167
|
# module will use the environment variables. See the
|
|
168
|
# documentation of the package `locale`.
|
|
168
|
# documentation of the package `locale`.
|
|
169
|
locale.setlocale(locale.LC_ALL, self.locale)
|
|
169
|
locale.setlocale(locale.LC_ALL, self.locale)
|
|
170
|
|
|
170
|
|
|
171
|
language_code, encoding = locale.getlocale()
|
|
171
|
language_code, encoding = locale.getlocale()
|
|
172
|
log.info(
|
|
172
|
log.info(
|
|
173
|
'Locale set to language code "%s" with encoding "%s".',
|
|
173
|
'Locale set to language code "%s" with encoding "%s".',
|
|
174
|
language_code, encoding)
|
|
174
|
language_code, encoding)
|
|
175
|
except locale.Error:
|
|
175
|
except locale.Error:
|
|
176
|
log.exception(
|
|
176
|
log.exception(
|
|
177
|
'Cannot set locale, not configuring the locale system')
|
|
177
|
'Cannot set locale, not configuring the locale system')
|
|
178
|
|
|
178
|
|
|
179
|
|
|
179
|
|
|
180
|
class WsgiProxy(object):
|
|
180
|
class WsgiProxy(object):
|
|
181
|
def __init__(self, wsgi):
|
|
181
|
def __init__(self, wsgi):
|
|
182
|
self.wsgi = wsgi
|
|
182
|
self.wsgi = wsgi
|
|
183
|
|
|
183
|
|
|
184
|
def __call__(self, environ, start_response):
|
|
184
|
def __call__(self, environ, start_response):
|
|
185
|
input_data = environ['wsgi.input'].read()
|
|
185
|
input_data = environ['wsgi.input'].read()
|
|
186
|
input_data = msgpack.unpackb(input_data)
|
|
186
|
input_data = msgpack.unpackb(input_data)
|
|
187
|
|
|
187
|
|
|
188
|
error = None
|
|
188
|
error = None
|
|
189
|
try:
|
|
189
|
try:
|
|
190
|
data, status, headers = self.wsgi.handle(
|
|
190
|
data, status, headers = self.wsgi.handle(
|
|
191
|
input_data['environment'], input_data['input_data'],
|
|
191
|
input_data['environment'], input_data['input_data'],
|
|
192
|
*input_data['args'], **input_data['kwargs'])
|
|
192
|
*input_data['args'], **input_data['kwargs'])
|
|
193
|
except Exception as e:
|
|
193
|
except Exception as e:
|
|
194
|
data, status, headers = [], None, None
|
|
194
|
data, status, headers = [], None, None
|
|
195
|
error = {
|
|
195
|
error = {
|
|
196
|
'message': str(e),
|
|
196
|
'message': str(e),
|
|
197
|
'_vcs_kind': getattr(e, '_vcs_kind', None)
|
|
197
|
'_vcs_kind': getattr(e, '_vcs_kind', None)
|
|
198
|
}
|
|
198
|
}
|
|
199
|
|
|
199
|
|
|
200
|
start_response(200, {})
|
|
200
|
start_response(200, {})
|
|
201
|
return self._iterator(error, status, headers, data)
|
|
201
|
return self._iterator(error, status, headers, data)
|
|
202
|
|
|
202
|
|
|
203
|
def _iterator(self, error, status, headers, data):
|
|
203
|
def _iterator(self, error, status, headers, data):
|
|
204
|
initial_data = [
|
|
204
|
initial_data = [
|
|
205
|
error,
|
|
205
|
error,
|
|
206
|
status,
|
|
206
|
status,
|
|
207
|
headers,
|
|
207
|
headers,
|
|
208
|
]
|
|
208
|
]
|
|
209
|
|
|
209
|
|
|
210
|
for d in chain(initial_data, data):
|
|
210
|
for d in chain(initial_data, data):
|
|
211
|
yield msgpack.packb(d)
|
|
211
|
yield msgpack.packb(d)
|
|
212
|
|
|
212
|
|
|
213
|
|
|
213
|
|
|
214
|
def not_found(request):
|
|
214
|
def not_found(request):
|
|
215
|
return {'status': '404 NOT FOUND'}
|
|
215
|
return {'status': '404 NOT FOUND'}
|
|
216
|
|
|
216
|
|
|
217
|
|
|
217
|
|
|
218
|
class VCSViewPredicate(object):
|
|
218
|
class VCSViewPredicate(object):
|
|
219
|
def __init__(self, val, config):
|
|
219
|
def __init__(self, val, config):
|
|
220
|
self.remotes = val
|
|
220
|
self.remotes = val
|
|
221
|
|
|
221
|
|
|
222
|
def text(self):
|
|
222
|
def text(self):
|
|
223
|
return 'vcs view method = %s' % (self.remotes.keys(),)
|
|
223
|
return 'vcs view method = %s' % (self.remotes.keys(),)
|
|
224
|
|
|
224
|
|
|
225
|
phash = text
|
|
225
|
phash = text
|
|
226
|
|
|
226
|
|
|
227
|
def __call__(self, context, request):
|
|
227
|
def __call__(self, context, request):
|
|
228
|
"""
|
|
228
|
"""
|
|
229
|
View predicate that returns true if given backend is supported by
|
|
229
|
View predicate that returns true if given backend is supported by
|
|
230
|
defined remotes.
|
|
230
|
defined remotes.
|
|
231
|
"""
|
|
231
|
"""
|
|
232
|
backend = request.matchdict.get('backend')
|
|
232
|
backend = request.matchdict.get('backend')
|
|
233
|
return backend in self.remotes
|
|
233
|
return backend in self.remotes
|
|
234
|
|
|
234
|
|
|
235
|
|
|
235
|
|
|
236
|
class HTTPApplication(object):
|
|
236
|
class HTTPApplication(object):
|
|
237
|
ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
|
|
237
|
ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
|
|
238
|
|
|
238
|
|
|
239
|
remote_wsgi = remote_wsgi
|
|
239
|
remote_wsgi = remote_wsgi
|
|
240
|
_use_echo_app = False
|
|
240
|
_use_echo_app = False
|
|
241
|
|
|
241
|
|
|
242
|
def __init__(self, settings=None, global_config=None):
|
|
242
|
def __init__(self, settings=None, global_config=None):
|
|
243
|
self._sanitize_settings_and_apply_defaults(settings)
|
|
243
|
self._sanitize_settings_and_apply_defaults(settings)
|
|
244
|
|
|
244
|
|
|
245
|
self.config = Configurator(settings=settings)
|
|
245
|
self.config = Configurator(settings=settings)
|
|
246
|
self.global_config = global_config
|
|
246
|
self.global_config = global_config
|
|
247
|
self.config.include('vcsserver.lib.rc_cache')
|
|
247
|
self.config.include('vcsserver.lib.rc_cache')
|
|
248
|
|
|
248
|
|
|
249
|
settings_locale = settings.get('locale', '') or 'en_US.UTF-8'
|
|
249
|
settings_locale = settings.get('locale', '') or 'en_US.UTF-8'
|
|
250
|
vcs = VCS(locale_conf=settings_locale, cache_config=settings)
|
|
250
|
vcs = VCS(locale_conf=settings_locale, cache_config=settings)
|
|
251
|
self._remotes = {
|
|
251
|
self._remotes = {
|
|
252
|
'hg': vcs._hg_remote,
|
|
252
|
'hg': vcs._hg_remote,
|
|
253
|
'git': vcs._git_remote,
|
|
253
|
'git': vcs._git_remote,
|
|
254
|
'svn': vcs._svn_remote,
|
|
254
|
'svn': vcs._svn_remote,
|
|
255
|
'server': vcs._vcsserver,
|
|
255
|
'server': vcs._vcsserver,
|
|
256
|
}
|
|
256
|
}
|
|
257
|
if settings.get('dev.use_echo_app', 'false').lower() == 'true':
|
|
257
|
if settings.get('dev.use_echo_app', 'false').lower() == 'true':
|
|
258
|
self._use_echo_app = True
|
|
258
|
self._use_echo_app = True
|
|
259
|
log.warning("Using EchoApp for VCS operations.")
|
|
259
|
log.warning("Using EchoApp for VCS operations.")
|
|
260
|
self.remote_wsgi = remote_wsgi_stub
|
|
260
|
self.remote_wsgi = remote_wsgi_stub
|
|
261
|
|
|
261
|
|
|
262
|
self._configure_settings(global_config, settings)
|
|
262
|
self._configure_settings(global_config, settings)
|
|
263
|
|
|
263
|
|
|
264
|
self._configure()
|
|
264
|
self._configure()
|
|
265
|
|
|
265
|
|
|
266
|
def _configure_settings(self, global_config, app_settings):
|
|
266
|
def _configure_settings(self, global_config, app_settings):
|
|
267
|
"""
|
|
267
|
"""
|
|
268
|
Configure the settings module.
|
|
268
|
Configure the settings module.
|
|
269
|
"""
|
|
269
|
"""
|
|
270
|
settings_merged = global_config.copy()
|
|
270
|
settings_merged = global_config.copy()
|
|
271
|
settings_merged.update(app_settings)
|
|
271
|
settings_merged.update(app_settings)
|
|
272
|
|
|
272
|
|
|
273
|
git_path = app_settings.get('git_path', None)
|
|
273
|
git_path = app_settings.get('git_path', None)
|
|
274
|
if git_path:
|
|
274
|
if git_path:
|
|
275
|
settings.GIT_EXECUTABLE = git_path
|
|
275
|
settings.GIT_EXECUTABLE = git_path
|
|
276
|
binary_dir = app_settings.get('core.binary_dir', None)
|
|
276
|
binary_dir = app_settings.get('core.binary_dir', None)
|
|
277
|
if binary_dir:
|
|
277
|
if binary_dir:
|
|
278
|
settings.BINARY_DIR = binary_dir
|
|
278
|
settings.BINARY_DIR = binary_dir
|
|
279
|
|
|
279
|
|
|
280
|
# Store the settings to make them available to other modules.
|
|
280
|
# Store the settings to make them available to other modules.
|
|
281
|
vcsserver.PYRAMID_SETTINGS = settings_merged
|
|
281
|
vcsserver.PYRAMID_SETTINGS = settings_merged
|
|
282
|
vcsserver.CONFIG = settings_merged
|
|
282
|
vcsserver.CONFIG = settings_merged
|
|
283
|
|
|
283
|
|
|
284
|
def _sanitize_settings_and_apply_defaults(self, settings):
|
|
284
|
def _sanitize_settings_and_apply_defaults(self, settings):
|
|
285
|
temp_store = tempfile.gettempdir()
|
|
285
|
temp_store = tempfile.gettempdir()
|
|
286
|
default_cache_dir = os.path.join(temp_store, 'rc_cache')
|
|
286
|
default_cache_dir = os.path.join(temp_store, 'rc_cache')
|
|
287
|
|
|
287
|
|
|
288
|
# save default, cache dir, and use it for all backends later.
|
|
288
|
# save default, cache dir, and use it for all backends later.
|
|
289
|
default_cache_dir = _string_setting(
|
|
289
|
default_cache_dir = _string_setting(
|
|
290
|
settings,
|
|
290
|
settings,
|
|
291
|
'cache_dir',
|
|
291
|
'cache_dir',
|
|
292
|
default_cache_dir, lower=False, default_when_empty=True)
|
|
292
|
default_cache_dir, lower=False, default_when_empty=True)
|
|
293
|
|
|
293
|
|
|
294
|
# ensure we have our dir created
|
|
294
|
# ensure we have our dir created
|
|
295
|
if not os.path.isdir(default_cache_dir):
|
|
295
|
if not os.path.isdir(default_cache_dir):
|
|
296
|
os.makedirs(default_cache_dir, mode=0o755)
|
|
296
|
os.makedirs(default_cache_dir, mode=0o755)
|
|
297
|
|
|
297
|
|
|
298
|
# exception store cache
|
|
298
|
# exception store cache
|
|
299
|
_string_setting(
|
|
299
|
_string_setting(
|
|
300
|
settings,
|
|
300
|
settings,
|
|
301
|
'exception_tracker.store_path',
|
|
301
|
'exception_tracker.store_path',
|
|
302
|
temp_store, lower=False, default_when_empty=True)
|
|
302
|
temp_store, lower=False, default_when_empty=True)
|
|
303
|
|
|
303
|
|
|
304
|
# repo_object cache
|
|
304
|
# repo_object cache
|
|
305
|
_string_setting(
|
|
305
|
_string_setting(
|
|
306
|
settings,
|
|
306
|
settings,
|
|
307
|
'rc_cache.repo_object.backend',
|
|
307
|
'rc_cache.repo_object.backend',
|
|
308
|
'dogpile.cache.rc.file_namespace', lower=False)
|
|
308
|
'dogpile.cache.rc.file_namespace', lower=False)
|
|
309
|
_int_setting(
|
|
309
|
_int_setting(
|
|
310
|
settings,
|
|
310
|
settings,
|
|
311
|
'rc_cache.repo_object.expiration_time',
|
|
311
|
'rc_cache.repo_object.expiration_time',
|
|
312
|
30 * 24 * 60 * 60)
|
|
312
|
30 * 24 * 60 * 60)
|
|
313
|
_string_setting(
|
|
313
|
_string_setting(
|
|
314
|
settings,
|
|
314
|
settings,
|
|
315
|
'rc_cache.repo_object.arguments.filename',
|
|
315
|
'rc_cache.repo_object.arguments.filename',
|
|
316
|
os.path.join(default_cache_dir, 'vcsserver_cache_1'), lower=False)
|
|
316
|
os.path.join(default_cache_dir, 'vcsserver_cache_1'), lower=False)
|
|
317
|
|
|
317
|
|
|
318
|
def _configure(self):
|
|
318
|
def _configure(self):
|
|
319
|
self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
|
|
319
|
self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
|
|
320
|
|
|
320
|
|
|
321
|
self.config.add_route('service', '/_service')
|
|
321
|
self.config.add_route('service', '/_service')
|
|
322
|
self.config.add_route('status', '/status')
|
|
322
|
self.config.add_route('status', '/status')
|
|
323
|
self.config.add_route('hg_proxy', '/proxy/hg')
|
|
323
|
self.config.add_route('hg_proxy', '/proxy/hg')
|
|
324
|
self.config.add_route('git_proxy', '/proxy/git')
|
|
324
|
self.config.add_route('git_proxy', '/proxy/git')
|
|
325
|
|
|
325
|
|
|
326
|
# rpc methods
|
|
326
|
# rpc methods
|
|
327
|
self.config.add_route('vcs', '/{backend}')
|
|
327
|
self.config.add_route('vcs', '/{backend}')
|
|
328
|
|
|
328
|
|
|
329
|
# streaming rpc remote methods
|
|
329
|
# streaming rpc remote methods
|
|
330
|
self.config.add_route('vcs_stream', '/{backend}/stream')
|
|
330
|
self.config.add_route('vcs_stream', '/{backend}/stream')
|
|
331
|
|
|
331
|
|
|
332
|
# vcs operations clone/push as streaming
|
|
332
|
# vcs operations clone/push as streaming
|
|
333
|
self.config.add_route('stream_git', '/stream/git/*repo_name')
|
|
333
|
self.config.add_route('stream_git', '/stream/git/*repo_name')
|
|
334
|
self.config.add_route('stream_hg', '/stream/hg/*repo_name')
|
|
334
|
self.config.add_route('stream_hg', '/stream/hg/*repo_name')
|
|
335
|
|
|
335
|
|
|
336
|
self.config.add_view(self.status_view, route_name='status', renderer='json')
|
|
336
|
self.config.add_view(self.status_view, route_name='status', renderer='json')
|
|
337
|
self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
|
|
337
|
self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
|
|
338
|
|
|
338
|
|
|
339
|
self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
|
|
339
|
self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
|
|
340
|
self.config.add_view(self.git_proxy(), route_name='git_proxy')
|
|
340
|
self.config.add_view(self.git_proxy(), route_name='git_proxy')
|
|
341
|
self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
|
|
341
|
self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
|
|
342
|
vcs_view=self._remotes)
|
|
342
|
vcs_view=self._remotes)
|
|
343
|
self.config.add_view(self.vcs_stream_view, route_name='vcs_stream',
|
|
343
|
self.config.add_view(self.vcs_stream_view, route_name='vcs_stream',
|
|
344
|
vcs_view=self._remotes)
|
|
344
|
vcs_view=self._remotes)
|
|
345
|
|
|
345
|
|
|
346
|
self.config.add_view(self.hg_stream(), route_name='stream_hg')
|
|
346
|
self.config.add_view(self.hg_stream(), route_name='stream_hg')
|
|
347
|
self.config.add_view(self.git_stream(), route_name='stream_git')
|
|
347
|
self.config.add_view(self.git_stream(), route_name='stream_git')
|
|
348
|
|
|
348
|
|
|
349
|
self.config.add_view_predicate('vcs_view', VCSViewPredicate)
|
|
349
|
self.config.add_view_predicate('vcs_view', VCSViewPredicate)
|
|
350
|
|
|
350
|
|
|
351
|
self.config.add_notfound_view(not_found, renderer='json')
|
|
351
|
self.config.add_notfound_view(not_found, renderer='json')
|
|
352
|
|
|
352
|
|
|
353
|
self.config.add_view(self.handle_vcs_exception, context=Exception)
|
|
353
|
self.config.add_view(self.handle_vcs_exception, context=Exception)
|
|
354
|
|
|
354
|
|
|
355
|
self.config.add_tween(
|
|
355
|
self.config.add_tween(
|
|
356
|
'vcsserver.tweens.request_wrapper.RequestWrapperTween',
|
|
356
|
'vcsserver.tweens.request_wrapper.RequestWrapperTween',
|
|
357
|
)
|
|
357
|
)
|
|
358
|
self.config.add_request_method(
|
|
358
|
self.config.add_request_method(
|
|
359
|
'vcsserver.lib.request_counter.get_request_counter',
|
|
359
|
'vcsserver.lib.request_counter.get_request_counter',
|
|
360
|
'request_count')
|
|
360
|
'request_count')
|
|
361
|
|
|
361
|
|
|
362
|
self.config.add_request_method(
|
|
362
|
self.config.add_request_method(
|
|
363
|
'vcsserver.lib._vendor.statsd.get_statsd_client',
|
|
363
|
'vcsserver.lib._vendor.statsd.get_statsd_client',
|
|
364
|
'statsd', reify=True)
|
|
364
|
'statsd', reify=True)
|
|
365
|
|
|
365
|
|
|
366
|
def wsgi_app(self):
|
|
366
|
def wsgi_app(self):
|
|
367
|
return self.config.make_wsgi_app()
|
|
367
|
return self.config.make_wsgi_app()
|
|
368
|
|
|
368
|
|
|
369
|
def _vcs_view_params(self, request):
|
|
369
|
def _vcs_view_params(self, request):
|
|
370
|
remote = self._remotes[request.matchdict['backend']]
|
|
370
|
remote = self._remotes[request.matchdict['backend']]
|
|
371
|
payload = msgpack.unpackb(request.body, use_list=True)
|
|
371
|
payload = msgpack.unpackb(request.body, use_list=True)
|
|
372
|
method = payload.get('method')
|
|
372
|
method = payload.get('method')
|
|
373
|
params = payload['params']
|
|
373
|
params = payload['params']
|
|
374
|
wire = params.get('wire')
|
|
374
|
wire = params.get('wire')
|
|
375
|
args = params.get('args')
|
|
375
|
args = params.get('args')
|
|
376
|
kwargs = params.get('kwargs')
|
|
376
|
kwargs = params.get('kwargs')
|
|
377
|
context_uid = None
|
|
377
|
context_uid = None
|
|
378
|
|
|
378
|
|
|
379
|
if wire:
|
|
379
|
if wire:
|
|
380
|
try:
|
|
380
|
try:
|
|
381
|
wire['context'] = context_uid = uuid.UUID(wire['context'])
|
|
381
|
wire['context'] = context_uid = uuid.UUID(wire['context'])
|
|
382
|
except KeyError:
|
|
382
|
except KeyError:
|
|
383
|
pass
|
|
383
|
pass
|
|
384
|
args.insert(0, wire)
|
|
384
|
args.insert(0, wire)
|
|
385
|
repo_state_uid = wire.get('repo_state_uid') if wire else None
|
|
385
|
repo_state_uid = wire.get('repo_state_uid') if wire else None
|
|
386
|
|
|
386
|
|
|
387
|
# NOTE(marcink): trading complexity for slight performance
|
|
387
|
# NOTE(marcink): trading complexity for slight performance
|
|
388
|
if log.isEnabledFor(logging.DEBUG):
|
|
388
|
if log.isEnabledFor(logging.DEBUG):
|
|
389
|
no_args_methods = [
|
|
389
|
no_args_methods = [
|
|
390
|
|
|
390
|
|
|
391
|
]
|
|
391
|
]
|
|
392
|
if method in no_args_methods:
|
|
392
|
if method in no_args_methods:
|
|
393
|
call_args = ''
|
|
393
|
call_args = ''
|
|
394
|
else:
|
|
394
|
else:
|
|
395
|
call_args = args[1:]
|
|
395
|
call_args = args[1:]
|
|
396
|
|
|
396
|
|
|
397
|
log.debug('method requested:%s with args:%s kwargs:%s context_uid: %s, repo_state_uid:%s',
|
|
397
|
log.debug('method requested:%s with args:%s kwargs:%s context_uid: %s, repo_state_uid:%s',
|
|
398
|
method, call_args, kwargs, context_uid, repo_state_uid)
|
|
398
|
method, call_args, kwargs, context_uid, repo_state_uid)
|
|
399
|
|
|
399
|
|
|
400
|
return payload, remote, method, args, kwargs
|
|
400
|
return payload, remote, method, args, kwargs
|
|
401
|
|
|
401
|
|
|
402
|
def vcs_view(self, request):
|
|
402
|
def vcs_view(self, request):
|
|
403
|
|
|
403
|
|
|
404
|
payload, remote, method, args, kwargs = self._vcs_view_params(request)
|
|
404
|
payload, remote, method, args, kwargs = self._vcs_view_params(request)
|
|
405
|
payload_id = payload.get('id')
|
|
405
|
payload_id = payload.get('id')
|
|
406
|
|
|
406
|
|
|
407
|
try:
|
|
407
|
try:
|
|
408
|
resp = getattr(remote, method)(*args, **kwargs)
|
|
408
|
resp = getattr(remote, method)(*args, **kwargs)
|
|
409
|
except Exception as e:
|
|
409
|
except Exception as e:
|
|
410
|
exc_info = list(sys.exc_info())
|
|
410
|
exc_info = list(sys.exc_info())
|
|
411
|
exc_type, exc_value, exc_traceback = exc_info
|
|
411
|
exc_type, exc_value, exc_traceback = exc_info
|
|
412
|
|
|
412
|
|
|
413
|
org_exc = getattr(e, '_org_exc', None)
|
|
413
|
org_exc = getattr(e, '_org_exc', None)
|
|
414
|
org_exc_name = None
|
|
414
|
org_exc_name = None
|
|
415
|
org_exc_tb = ''
|
|
415
|
org_exc_tb = ''
|
|
416
|
if org_exc:
|
|
416
|
if org_exc:
|
|
417
|
org_exc_name = org_exc.__class__.__name__
|
|
417
|
org_exc_name = org_exc.__class__.__name__
|
|
418
|
org_exc_tb = getattr(e, '_org_exc_tb', '')
|
|
418
|
org_exc_tb = getattr(e, '_org_exc_tb', '')
|
|
419
|
# replace our "faked" exception with our org
|
|
419
|
# replace our "faked" exception with our org
|
|
420
|
exc_info[0] = org_exc.__class__
|
|
420
|
exc_info[0] = org_exc.__class__
|
|
421
|
exc_info[1] = org_exc
|
|
421
|
exc_info[1] = org_exc
|
|
422
|
|
|
422
|
|
|
423
|
should_store_exc = True
|
|
423
|
should_store_exc = True
|
|
424
|
if org_exc:
|
|
424
|
if org_exc:
|
|
425
|
def get_exc_fqn(_exc_obj):
|
|
425
|
def get_exc_fqn(_exc_obj):
|
|
426
|
module_name = getattr(org_exc.__class__, '__module__', 'UNKNOWN')
|
|
426
|
module_name = getattr(org_exc.__class__, '__module__', 'UNKNOWN')
|
|
427
|
return module_name + '.' + org_exc_name
|
|
427
|
return module_name + '.' + org_exc_name
|
|
428
|
|
|
428
|
|
|
429
|
exc_fqn = get_exc_fqn(org_exc)
|
|
429
|
exc_fqn = get_exc_fqn(org_exc)
|
|
430
|
|
|
430
|
|
|
431
|
if exc_fqn in ['mercurial.error.RepoLookupError',
|
|
431
|
if exc_fqn in ['mercurial.error.RepoLookupError',
|
|
432
|
'vcsserver.exceptions.RefNotFoundException']:
|
|
432
|
'vcsserver.exceptions.RefNotFoundException']:
|
|
433
|
should_store_exc = False
|
|
433
|
should_store_exc = False
|
|
434
|
|
|
434
|
|
|
435
|
if should_store_exc:
|
|
435
|
if should_store_exc:
|
|
436
|
store_exception(id(exc_info), exc_info)
|
|
436
|
store_exception(id(exc_info), exc_info, request_path=request.path)
|
|
437
|
|
|
437
|
|
|
438
|
tb_info = ''.join(
|
|
438
|
tb_info = ''.join(
|
|
439
|
traceback.format_exception(exc_type, exc_value, exc_traceback))
|
|
439
|
traceback.format_exception(exc_type, exc_value, exc_traceback))
|
|
440
|
|
|
440
|
|
|
441
|
type_ = e.__class__.__name__
|
|
441
|
type_ = e.__class__.__name__
|
|
442
|
if type_ not in self.ALLOWED_EXCEPTIONS:
|
|
442
|
if type_ not in self.ALLOWED_EXCEPTIONS:
|
|
443
|
type_ = None
|
|
443
|
type_ = None
|
|
444
|
|
|
444
|
|
|
445
|
resp = {
|
|
445
|
resp = {
|
|
446
|
'id': payload_id,
|
|
446
|
'id': payload_id,
|
|
447
|
'error': {
|
|
447
|
'error': {
|
|
448
|
'message': e.message,
|
|
448
|
'message': e.message,
|
|
449
|
'traceback': tb_info,
|
|
449
|
'traceback': tb_info,
|
|
450
|
'org_exc': org_exc_name,
|
|
450
|
'org_exc': org_exc_name,
|
|
451
|
'org_exc_tb': org_exc_tb,
|
|
451
|
'org_exc_tb': org_exc_tb,
|
|
452
|
'type': type_
|
|
452
|
'type': type_
|
|
453
|
}
|
|
453
|
}
|
|
454
|
}
|
|
454
|
}
|
|
|
|
|
455
|
|
|
455
|
try:
|
|
456
|
try:
|
|
456
|
resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None)
|
|
457
|
resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None)
|
|
457
|
except AttributeError:
|
|
458
|
except AttributeError:
|
|
458
|
pass
|
|
459
|
pass
|
|
459
|
else:
|
|
460
|
else:
|
|
460
|
resp = {
|
|
461
|
resp = {
|
|
461
|
'id': payload_id,
|
|
462
|
'id': payload_id,
|
|
462
|
'result': resp
|
|
463
|
'result': resp
|
|
463
|
}
|
|
464
|
}
|
|
464
|
|
|
465
|
|
|
465
|
return resp
|
|
466
|
return resp
|
|
466
|
|
|
467
|
|
|
467
|
def vcs_stream_view(self, request):
|
|
468
|
def vcs_stream_view(self, request):
|
|
468
|
payload, remote, method, args, kwargs = self._vcs_view_params(request)
|
|
469
|
payload, remote, method, args, kwargs = self._vcs_view_params(request)
|
|
469
|
# this method has a stream: marker we remove it here
|
|
470
|
# this method has a stream: marker we remove it here
|
|
470
|
method = method.split('stream:')[-1]
|
|
471
|
method = method.split('stream:')[-1]
|
|
471
|
chunk_size = safe_int(payload.get('chunk_size')) or 4096
|
|
472
|
chunk_size = safe_int(payload.get('chunk_size')) or 4096
|
|
472
|
|
|
473
|
|
|
473
|
try:
|
|
474
|
try:
|
|
474
|
resp = getattr(remote, method)(*args, **kwargs)
|
|
475
|
resp = getattr(remote, method)(*args, **kwargs)
|
|
475
|
except Exception as e:
|
|
476
|
except Exception as e:
|
|
476
|
raise
|
|
477
|
raise
|
|
477
|
|
|
478
|
|
|
478
|
def get_chunked_data(method_resp):
|
|
479
|
def get_chunked_data(method_resp):
|
|
479
|
stream = StringIO(method_resp)
|
|
480
|
stream = StringIO(method_resp)
|
|
480
|
while 1:
|
|
481
|
while 1:
|
|
481
|
chunk = stream.read(chunk_size)
|
|
482
|
chunk = stream.read(chunk_size)
|
|
482
|
if not chunk:
|
|
483
|
if not chunk:
|
|
483
|
break
|
|
484
|
break
|
|
484
|
yield chunk
|
|
485
|
yield chunk
|
|
485
|
|
|
486
|
|
|
486
|
response = Response(app_iter=get_chunked_data(resp))
|
|
487
|
response = Response(app_iter=get_chunked_data(resp))
|
|
487
|
response.content_type = 'application/octet-stream'
|
|
488
|
response.content_type = 'application/octet-stream'
|
|
488
|
|
|
489
|
|
|
489
|
return response
|
|
490
|
return response
|
|
490
|
|
|
491
|
|
|
491
|
def status_view(self, request):
|
|
492
|
def status_view(self, request):
|
|
492
|
import vcsserver
|
|
493
|
import vcsserver
|
|
493
|
return {'status': 'OK', 'vcsserver_version': vcsserver.__version__,
|
|
494
|
return {'status': 'OK', 'vcsserver_version': vcsserver.__version__,
|
|
494
|
'pid': os.getpid()}
|
|
495
|
'pid': os.getpid()}
|
|
495
|
|
|
496
|
|
|
496
|
def service_view(self, request):
|
|
497
|
def service_view(self, request):
|
|
497
|
import vcsserver
|
|
498
|
import vcsserver
|
|
498
|
|
|
499
|
|
|
499
|
payload = msgpack.unpackb(request.body, use_list=True)
|
|
500
|
payload = msgpack.unpackb(request.body, use_list=True)
|
|
500
|
server_config, app_config = {}, {}
|
|
501
|
server_config, app_config = {}, {}
|
|
501
|
|
|
502
|
|
|
502
|
try:
|
|
503
|
try:
|
|
503
|
path = self.global_config['__file__']
|
|
504
|
path = self.global_config['__file__']
|
|
504
|
config = configparser.RawConfigParser()
|
|
505
|
config = configparser.RawConfigParser()
|
|
505
|
|
|
506
|
|
|
506
|
config.read(path)
|
|
507
|
config.read(path)
|
|
507
|
|
|
508
|
|
|
508
|
if config.has_section('server:main'):
|
|
509
|
if config.has_section('server:main'):
|
|
509
|
server_config = dict(config.items('server:main'))
|
|
510
|
server_config = dict(config.items('server:main'))
|
|
510
|
if config.has_section('app:main'):
|
|
511
|
if config.has_section('app:main'):
|
|
511
|
app_config = dict(config.items('app:main'))
|
|
512
|
app_config = dict(config.items('app:main'))
|
|
512
|
|
|
513
|
|
|
513
|
except Exception:
|
|
514
|
except Exception:
|
|
514
|
log.exception('Failed to read .ini file for display')
|
|
515
|
log.exception('Failed to read .ini file for display')
|
|
515
|
|
|
516
|
|
|
516
|
environ = os.environ.items()
|
|
517
|
environ = os.environ.items()
|
|
517
|
|
|
518
|
|
|
518
|
resp = {
|
|
519
|
resp = {
|
|
519
|
'id': payload.get('id'),
|
|
520
|
'id': payload.get('id'),
|
|
520
|
'result': dict(
|
|
521
|
'result': dict(
|
|
521
|
version=vcsserver.__version__,
|
|
522
|
version=vcsserver.__version__,
|
|
522
|
config=server_config,
|
|
523
|
config=server_config,
|
|
523
|
app_config=app_config,
|
|
524
|
app_config=app_config,
|
|
524
|
environ=environ,
|
|
525
|
environ=environ,
|
|
525
|
payload=payload,
|
|
526
|
payload=payload,
|
|
526
|
)
|
|
527
|
)
|
|
527
|
}
|
|
528
|
}
|
|
528
|
return resp
|
|
529
|
return resp
|
|
529
|
|
|
530
|
|
|
530
|
def _msgpack_renderer_factory(self, info):
|
|
531
|
def _msgpack_renderer_factory(self, info):
|
|
531
|
def _render(value, system):
|
|
532
|
def _render(value, system):
|
|
532
|
request = system.get('request')
|
|
533
|
request = system.get('request')
|
|
533
|
if request is not None:
|
|
534
|
if request is not None:
|
|
534
|
response = request.response
|
|
535
|
response = request.response
|
|
535
|
ct = response.content_type
|
|
536
|
ct = response.content_type
|
|
536
|
if ct == response.default_content_type:
|
|
537
|
if ct == response.default_content_type:
|
|
537
|
response.content_type = 'application/x-msgpack'
|
|
538
|
response.content_type = 'application/x-msgpack'
|
|
538
|
return msgpack.packb(value)
|
|
539
|
return msgpack.packb(value)
|
|
539
|
return _render
|
|
540
|
return _render
|
|
540
|
|
|
541
|
|
|
541
|
def set_env_from_config(self, environ, config):
|
|
542
|
def set_env_from_config(self, environ, config):
|
|
542
|
dict_conf = {}
|
|
543
|
dict_conf = {}
|
|
543
|
try:
|
|
544
|
try:
|
|
544
|
for elem in config:
|
|
545
|
for elem in config:
|
|
545
|
if elem[0] == 'rhodecode':
|
|
546
|
if elem[0] == 'rhodecode':
|
|
546
|
dict_conf = json.loads(elem[2])
|
|
547
|
dict_conf = json.loads(elem[2])
|
|
547
|
break
|
|
548
|
break
|
|
548
|
except Exception:
|
|
549
|
except Exception:
|
|
549
|
log.exception('Failed to fetch SCM CONFIG')
|
|
550
|
log.exception('Failed to fetch SCM CONFIG')
|
|
550
|
return
|
|
551
|
return
|
|
551
|
|
|
552
|
|
|
552
|
username = dict_conf.get('username')
|
|
553
|
username = dict_conf.get('username')
|
|
553
|
if username:
|
|
554
|
if username:
|
|
554
|
environ['REMOTE_USER'] = username
|
|
555
|
environ['REMOTE_USER'] = username
|
|
555
|
# mercurial specific, some extension api rely on this
|
|
556
|
# mercurial specific, some extension api rely on this
|
|
556
|
environ['HGUSER'] = username
|
|
557
|
environ['HGUSER'] = username
|
|
557
|
|
|
558
|
|
|
558
|
ip = dict_conf.get('ip')
|
|
559
|
ip = dict_conf.get('ip')
|
|
559
|
if ip:
|
|
560
|
if ip:
|
|
560
|
environ['REMOTE_HOST'] = ip
|
|
561
|
environ['REMOTE_HOST'] = ip
|
|
561
|
|
|
562
|
|
|
562
|
if _is_request_chunked(environ):
|
|
563
|
if _is_request_chunked(environ):
|
|
563
|
# set the compatibility flag for webob
|
|
564
|
# set the compatibility flag for webob
|
|
564
|
environ['wsgi.input_terminated'] = True
|
|
565
|
environ['wsgi.input_terminated'] = True
|
|
565
|
|
|
566
|
|
|
566
|
def hg_proxy(self):
|
|
567
|
def hg_proxy(self):
|
|
567
|
@wsgiapp
|
|
568
|
@wsgiapp
|
|
568
|
def _hg_proxy(environ, start_response):
|
|
569
|
def _hg_proxy(environ, start_response):
|
|
569
|
app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
|
|
570
|
app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
|
|
570
|
return app(environ, start_response)
|
|
571
|
return app(environ, start_response)
|
|
571
|
return _hg_proxy
|
|
572
|
return _hg_proxy
|
|
572
|
|
|
573
|
|
|
573
|
def git_proxy(self):
|
|
574
|
def git_proxy(self):
|
|
574
|
@wsgiapp
|
|
575
|
@wsgiapp
|
|
575
|
def _git_proxy(environ, start_response):
|
|
576
|
def _git_proxy(environ, start_response):
|
|
576
|
app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
|
|
577
|
app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
|
|
577
|
return app(environ, start_response)
|
|
578
|
return app(environ, start_response)
|
|
578
|
return _git_proxy
|
|
579
|
return _git_proxy
|
|
579
|
|
|
580
|
|
|
580
|
def hg_stream(self):
|
|
581
|
def hg_stream(self):
|
|
581
|
if self._use_echo_app:
|
|
582
|
if self._use_echo_app:
|
|
582
|
@wsgiapp
|
|
583
|
@wsgiapp
|
|
583
|
def _hg_stream(environ, start_response):
|
|
584
|
def _hg_stream(environ, start_response):
|
|
584
|
app = EchoApp('fake_path', 'fake_name', None)
|
|
585
|
app = EchoApp('fake_path', 'fake_name', None)
|
|
585
|
return app(environ, start_response)
|
|
586
|
return app(environ, start_response)
|
|
586
|
return _hg_stream
|
|
587
|
return _hg_stream
|
|
587
|
else:
|
|
588
|
else:
|
|
588
|
@wsgiapp
|
|
589
|
@wsgiapp
|
|
589
|
def _hg_stream(environ, start_response):
|
|
590
|
def _hg_stream(environ, start_response):
|
|
590
|
log.debug('http-app: handling hg stream')
|
|
591
|
log.debug('http-app: handling hg stream')
|
|
591
|
repo_path = environ['HTTP_X_RC_REPO_PATH']
|
|
592
|
repo_path = environ['HTTP_X_RC_REPO_PATH']
|
|
592
|
repo_name = environ['HTTP_X_RC_REPO_NAME']
|
|
593
|
repo_name = environ['HTTP_X_RC_REPO_NAME']
|
|
593
|
packed_config = base64.b64decode(
|
|
594
|
packed_config = base64.b64decode(
|
|
594
|
environ['HTTP_X_RC_REPO_CONFIG'])
|
|
595
|
environ['HTTP_X_RC_REPO_CONFIG'])
|
|
595
|
config = msgpack.unpackb(packed_config)
|
|
596
|
config = msgpack.unpackb(packed_config)
|
|
596
|
|