##// END OF EJS Templates
mercurial: fix some bytes usage
super-admin -
r1049:7b409ede python3
parent child Browse files
Show More
@@ -1,235 +1,241 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-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 logging
19 import logging
20 import itertools
20 import itertools
21
21
22 import mercurial
22 import mercurial
23 import mercurial.error
23 import mercurial.error
24 import mercurial.wireprotoserver
24 import mercurial.wireprotoserver
25 import mercurial.hgweb.common
25 import mercurial.hgweb.common
26 import mercurial.hgweb.hgweb_mod
26 import mercurial.hgweb.hgweb_mod
27 import webob.exc
27 import webob.exc
28
28
29 from vcsserver import pygrack, exceptions, settings, git_lfs
29 from vcsserver import pygrack, exceptions, settings, git_lfs
30 from vcsserver.utils import ascii_bytes
30 from vcsserver.utils import ascii_bytes, safe_bytes
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 # propagated from mercurial documentation
35 # propagated from mercurial documentation
36 HG_UI_SECTIONS = [
36 HG_UI_SECTIONS = [
37 'alias', 'auth', 'decode/encode', 'defaults', 'diff', 'email', 'extensions',
37 'alias', 'auth', 'decode/encode', 'defaults', 'diff', 'email', 'extensions',
38 'format', 'merge-patterns', 'merge-tools', 'hooks', 'http_proxy', 'smtp',
38 'format', 'merge-patterns', 'merge-tools', 'hooks', 'http_proxy', 'smtp',
39 'patch', 'paths', 'profiling', 'server', 'trusted', 'ui', 'web',
39 'patch', 'paths', 'profiling', 'server', 'trusted', 'ui', 'web',
40 ]
40 ]
41
41
42
42
43 class HgWeb(mercurial.hgweb.hgweb_mod.hgweb):
43 class HgWeb(mercurial.hgweb.hgweb_mod.hgweb):
44 """Extension of hgweb that simplifies some functions."""
44 """Extension of hgweb that simplifies some functions."""
45
45
46 def _get_view(self, repo):
46 def _get_view(self, repo):
47 """Views are not supported."""
47 """Views are not supported."""
48 return repo
48 return repo
49
49
50 def loadsubweb(self):
50 def loadsubweb(self):
51 """The result is only used in the templater method which is not used."""
51 """The result is only used in the templater method which is not used."""
52 return None
52 return None
53
53
54 def run(self):
54 def run(self):
55 """Unused function so raise an exception if accidentally called."""
55 """Unused function so raise an exception if accidentally called."""
56 raise NotImplementedError
56 raise NotImplementedError
57
57
58 def templater(self, req):
58 def templater(self, req):
59 """Function used in an unreachable code path.
59 """Function used in an unreachable code path.
60
60
61 This code is unreachable because we guarantee that the HTTP request,
61 This code is unreachable because we guarantee that the HTTP request,
62 corresponds to a Mercurial command. See the is_hg method. So, we are
62 corresponds to a Mercurial command. See the is_hg method. So, we are
63 never going to get a user-visible url.
63 never going to get a user-visible url.
64 """
64 """
65 raise NotImplementedError
65 raise NotImplementedError
66
66
67 def archivelist(self, nodeid):
67 def archivelist(self, nodeid):
68 """Unused function so raise an exception if accidentally called."""
68 """Unused function so raise an exception if accidentally called."""
69 raise NotImplementedError
69 raise NotImplementedError
70
70
71 def __call__(self, environ, start_response):
71 def __call__(self, environ, start_response):
72 """Run the WSGI application.
72 """Run the WSGI application.
73
73
74 This may be called by multiple threads.
74 This may be called by multiple threads.
75 """
75 """
76 from mercurial.hgweb import request as requestmod
76 from mercurial.hgweb import request as requestmod
77 req = requestmod.parserequestfromenv(environ)
77 req = requestmod.parserequestfromenv(environ)
78 res = requestmod.wsgiresponse(req, start_response)
78 res = requestmod.wsgiresponse(req, start_response)
79 gen = self.run_wsgi(req, res)
79 gen = self.run_wsgi(req, res)
80
80
81 first_chunk = None
81 first_chunk = None
82
82
83 try:
83 try:
84 data = next(gen)
84 data = next(gen)
85
85
86 def first_chunk():
86 def first_chunk():
87 yield data
87 yield data
88 except StopIteration:
88 except StopIteration:
89 pass
89 pass
90
90
91 if first_chunk:
91 if first_chunk:
92 return itertools.chain(first_chunk(), gen)
92 return itertools.chain(first_chunk(), gen)
93 return gen
93 return gen
94
94
95 def _runwsgi(self, req, res, repo):
95 def _runwsgi(self, req, res, repo):
96
96
97 cmd = req.qsparams.get('cmd', '')
97 cmd = req.qsparams.get('cmd', '')
98 if not mercurial.wireprotoserver.iscmd(cmd):
98 if not mercurial.wireprotoserver.iscmd(cmd):
99 # NOTE(marcink): for unsupported commands, we return bad request
99 # NOTE(marcink): for unsupported commands, we return bad request
100 # internally from HG
100 # internally from HG
101 from mercurial.hgweb.common import statusmessage
101 from mercurial.hgweb.common import statusmessage
102 res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST)
102 res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST)
103 res.setbodybytes('')
103 res.setbodybytes('')
104 return res.sendresponse()
104 return res.sendresponse()
105
105
106 return super(HgWeb, self)._runwsgi(req, res, repo)
106 return super(HgWeb, self)._runwsgi(req, res, repo)
107
107
108
108
109 def make_hg_ui_from_config(repo_config):
109 def make_hg_ui_from_config(repo_config):
110 baseui = mercurial.ui.ui()
110 baseui = mercurial.ui.ui()
111
111
112 # clean the baseui object
112 # clean the baseui object
113 baseui._ocfg = mercurial.config.config()
113 baseui._ocfg = mercurial.config.config()
114 baseui._ucfg = mercurial.config.config()
114 baseui._ucfg = mercurial.config.config()
115 baseui._tcfg = mercurial.config.config()
115 baseui._tcfg = mercurial.config.config()
116
116
117 for section, option, value in repo_config:
117 for section, option, value in repo_config:
118 baseui.setconfig(ascii_bytes(section), ascii_bytes(option), ascii_bytes(value))
118 baseui.setconfig(
119 ascii_bytes(section, allow_bytes=True),
120 ascii_bytes(option, allow_bytes=True),
121 ascii_bytes(value, allow_bytes=True))
119
122
120 # make our hgweb quiet so it doesn't print output
123 # make our hgweb quiet so it doesn't print output
121 baseui.setconfig(b'ui', b'quiet', b'true')
124 baseui.setconfig(b'ui', b'quiet', b'true')
122
125
123 return baseui
126 return baseui
124
127
125
128
126 def update_hg_ui_from_hgrc(baseui, repo_path):
129 def update_hg_ui_from_hgrc(baseui, repo_path):
127 path = os.path.join(repo_path, '.hg', 'hgrc')
130 path = os.path.join(repo_path, '.hg', 'hgrc')
128
131
129 if not os.path.isfile(path):
132 if not os.path.isfile(path):
130 log.debug('hgrc file is not present at %s, skipping...', path)
133 log.debug('hgrc file is not present at %s, skipping...', path)
131 return
134 return
132 log.debug('reading hgrc from %s', path)
135 log.debug('reading hgrc from %s', path)
133 cfg = mercurial.config.config()
136 cfg = mercurial.config.config()
134 cfg.read(path)
137 cfg.read(ascii_bytes(path))
135 for section in HG_UI_SECTIONS:
138 for section in HG_UI_SECTIONS:
136 for k, v in cfg.items(section):
139 for k, v in cfg.items(section):
137 log.debug('settings ui from file: [%s] %s=%s', section, k, v)
140 log.debug('settings ui from file: [%s] %s=%s', section, k, v)
138 baseui.setconfig(ascii_bytes(section), ascii_bytes(k), ascii_bytes(v))
141 baseui.setconfig(
142 ascii_bytes(section, allow_bytes=True),
143 ascii_bytes(k, allow_bytes=True),
144 ascii_bytes(v, allow_bytes=True))
139
145
140
146
141 def create_hg_wsgi_app(repo_path, repo_name, config):
147 def create_hg_wsgi_app(repo_path, repo_name, config):
142 """
148 """
143 Prepares a WSGI application to handle Mercurial requests.
149 Prepares a WSGI application to handle Mercurial requests.
144
150
145 :param config: is a list of 3-item tuples representing a ConfigObject
151 :param config: is a list of 3-item tuples representing a ConfigObject
146 (it is the serialized version of the config object).
152 (it is the serialized version of the config object).
147 """
153 """
148 log.debug("Creating Mercurial WSGI application")
154 log.debug("Creating Mercurial WSGI application")
149
155
150 baseui = make_hg_ui_from_config(config)
156 baseui = make_hg_ui_from_config(config)
151 update_hg_ui_from_hgrc(baseui, repo_path)
157 update_hg_ui_from_hgrc(baseui, repo_path)
152
158
153 try:
159 try:
154 return HgWeb(repo_path, name=repo_name, baseui=baseui)
160 return HgWeb(safe_bytes(repo_path), name=safe_bytes(repo_name), baseui=baseui)
155 except mercurial.error.RequirementError as e:
161 except mercurial.error.RequirementError as e:
156 raise exceptions.RequirementException(e)(e)
162 raise exceptions.RequirementException(e)(e)
157
163
158
164
159 class GitHandler(object):
165 class GitHandler(object):
160 """
166 """
161 Handler for Git operations like push/pull etc
167 Handler for Git operations like push/pull etc
162 """
168 """
163 def __init__(self, repo_location, repo_name, git_path, update_server_info,
169 def __init__(self, repo_location, repo_name, git_path, update_server_info,
164 extras):
170 extras):
165 if not os.path.isdir(repo_location):
171 if not os.path.isdir(repo_location):
166 raise OSError(repo_location)
172 raise OSError(repo_location)
167 self.content_path = repo_location
173 self.content_path = repo_location
168 self.repo_name = repo_name
174 self.repo_name = repo_name
169 self.repo_location = repo_location
175 self.repo_location = repo_location
170 self.extras = extras
176 self.extras = extras
171 self.git_path = git_path
177 self.git_path = git_path
172 self.update_server_info = update_server_info
178 self.update_server_info = update_server_info
173
179
174 def __call__(self, environ, start_response):
180 def __call__(self, environ, start_response):
175 app = webob.exc.HTTPNotFound()
181 app = webob.exc.HTTPNotFound()
176 candidate_paths = (
182 candidate_paths = (
177 self.content_path, os.path.join(self.content_path, '.git'))
183 self.content_path, os.path.join(self.content_path, '.git'))
178
184
179 for content_path in candidate_paths:
185 for content_path in candidate_paths:
180 try:
186 try:
181 app = pygrack.GitRepository(
187 app = pygrack.GitRepository(
182 self.repo_name, content_path, self.git_path,
188 self.repo_name, content_path, self.git_path,
183 self.update_server_info, self.extras)
189 self.update_server_info, self.extras)
184 break
190 break
185 except OSError:
191 except OSError:
186 continue
192 continue
187
193
188 return app(environ, start_response)
194 return app(environ, start_response)
189
195
190
196
191 def create_git_wsgi_app(repo_path, repo_name, config):
197 def create_git_wsgi_app(repo_path, repo_name, config):
192 """
198 """
193 Creates a WSGI application to handle Git requests.
199 Creates a WSGI application to handle Git requests.
194
200
195 :param config: is a dictionary holding the extras.
201 :param config: is a dictionary holding the extras.
196 """
202 """
197 git_path = settings.GIT_EXECUTABLE
203 git_path = settings.GIT_EXECUTABLE
198 update_server_info = config.pop('git_update_server_info')
204 update_server_info = config.pop('git_update_server_info')
199 app = GitHandler(
205 app = GitHandler(
200 repo_path, repo_name, git_path, update_server_info, config)
206 repo_path, repo_name, git_path, update_server_info, config)
201
207
202 return app
208 return app
203
209
204
210
205 class GitLFSHandler(object):
211 class GitLFSHandler(object):
206 """
212 """
207 Handler for Git LFS operations
213 Handler for Git LFS operations
208 """
214 """
209
215
210 def __init__(self, repo_location, repo_name, git_path, update_server_info,
216 def __init__(self, repo_location, repo_name, git_path, update_server_info,
211 extras):
217 extras):
212 if not os.path.isdir(repo_location):
218 if not os.path.isdir(repo_location):
213 raise OSError(repo_location)
219 raise OSError(repo_location)
214 self.content_path = repo_location
220 self.content_path = repo_location
215 self.repo_name = repo_name
221 self.repo_name = repo_name
216 self.repo_location = repo_location
222 self.repo_location = repo_location
217 self.extras = extras
223 self.extras = extras
218 self.git_path = git_path
224 self.git_path = git_path
219 self.update_server_info = update_server_info
225 self.update_server_info = update_server_info
220
226
221 def get_app(self, git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme):
227 def get_app(self, git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme):
222 app = git_lfs.create_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
228 app = git_lfs.create_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
223 return app
229 return app
224
230
225
231
226 def create_git_lfs_wsgi_app(repo_path, repo_name, config):
232 def create_git_lfs_wsgi_app(repo_path, repo_name, config):
227 git_path = settings.GIT_EXECUTABLE
233 git_path = settings.GIT_EXECUTABLE
228 update_server_info = config.pop(b'git_update_server_info')
234 update_server_info = config.pop(b'git_update_server_info')
229 git_lfs_enabled = config.pop(b'git_lfs_enabled')
235 git_lfs_enabled = config.pop(b'git_lfs_enabled')
230 git_lfs_store_path = config.pop(b'git_lfs_store_path')
236 git_lfs_store_path = config.pop(b'git_lfs_store_path')
231 git_lfs_http_scheme = config.pop(b'git_lfs_http_scheme', 'http')
237 git_lfs_http_scheme = config.pop(b'git_lfs_http_scheme', 'http')
232 app = GitLFSHandler(
238 app = GitLFSHandler(
233 repo_path, repo_name, git_path, update_server_info, config)
239 repo_path, repo_name, git_path, update_server_info, config)
234
240
235 return app.get_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
241 return app.get_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
General Comments 0
You need to be logged in to leave comments. Login now