##// 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 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2020 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import os
19 19 import logging
20 20 import itertools
21 21
22 22 import mercurial
23 23 import mercurial.error
24 24 import mercurial.wireprotoserver
25 25 import mercurial.hgweb.common
26 26 import mercurial.hgweb.hgweb_mod
27 27 import webob.exc
28 28
29 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 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 # propagated from mercurial documentation
36 36 HG_UI_SECTIONS = [
37 37 'alias', 'auth', 'decode/encode', 'defaults', 'diff', 'email', 'extensions',
38 38 'format', 'merge-patterns', 'merge-tools', 'hooks', 'http_proxy', 'smtp',
39 39 'patch', 'paths', 'profiling', 'server', 'trusted', 'ui', 'web',
40 40 ]
41 41
42 42
43 43 class HgWeb(mercurial.hgweb.hgweb_mod.hgweb):
44 44 """Extension of hgweb that simplifies some functions."""
45 45
46 46 def _get_view(self, repo):
47 47 """Views are not supported."""
48 48 return repo
49 49
50 50 def loadsubweb(self):
51 51 """The result is only used in the templater method which is not used."""
52 52 return None
53 53
54 54 def run(self):
55 55 """Unused function so raise an exception if accidentally called."""
56 56 raise NotImplementedError
57 57
58 58 def templater(self, req):
59 59 """Function used in an unreachable code path.
60 60
61 61 This code is unreachable because we guarantee that the HTTP request,
62 62 corresponds to a Mercurial command. See the is_hg method. So, we are
63 63 never going to get a user-visible url.
64 64 """
65 65 raise NotImplementedError
66 66
67 67 def archivelist(self, nodeid):
68 68 """Unused function so raise an exception if accidentally called."""
69 69 raise NotImplementedError
70 70
71 71 def __call__(self, environ, start_response):
72 72 """Run the WSGI application.
73 73
74 74 This may be called by multiple threads.
75 75 """
76 76 from mercurial.hgweb import request as requestmod
77 77 req = requestmod.parserequestfromenv(environ)
78 78 res = requestmod.wsgiresponse(req, start_response)
79 79 gen = self.run_wsgi(req, res)
80 80
81 81 first_chunk = None
82 82
83 83 try:
84 84 data = next(gen)
85 85
86 86 def first_chunk():
87 87 yield data
88 88 except StopIteration:
89 89 pass
90 90
91 91 if first_chunk:
92 92 return itertools.chain(first_chunk(), gen)
93 93 return gen
94 94
95 95 def _runwsgi(self, req, res, repo):
96 96
97 97 cmd = req.qsparams.get('cmd', '')
98 98 if not mercurial.wireprotoserver.iscmd(cmd):
99 99 # NOTE(marcink): for unsupported commands, we return bad request
100 100 # internally from HG
101 101 from mercurial.hgweb.common import statusmessage
102 102 res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST)
103 103 res.setbodybytes('')
104 104 return res.sendresponse()
105 105
106 106 return super(HgWeb, self)._runwsgi(req, res, repo)
107 107
108 108
109 109 def make_hg_ui_from_config(repo_config):
110 110 baseui = mercurial.ui.ui()
111 111
112 112 # clean the baseui object
113 113 baseui._ocfg = mercurial.config.config()
114 114 baseui._ucfg = mercurial.config.config()
115 115 baseui._tcfg = mercurial.config.config()
116 116
117 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 123 # make our hgweb quiet so it doesn't print output
121 124 baseui.setconfig(b'ui', b'quiet', b'true')
122 125
123 126 return baseui
124 127
125 128
126 129 def update_hg_ui_from_hgrc(baseui, repo_path):
127 130 path = os.path.join(repo_path, '.hg', 'hgrc')
128 131
129 132 if not os.path.isfile(path):
130 133 log.debug('hgrc file is not present at %s, skipping...', path)
131 134 return
132 135 log.debug('reading hgrc from %s', path)
133 136 cfg = mercurial.config.config()
134 cfg.read(path)
137 cfg.read(ascii_bytes(path))
135 138 for section in HG_UI_SECTIONS:
136 139 for k, v in cfg.items(section):
137 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 147 def create_hg_wsgi_app(repo_path, repo_name, config):
142 148 """
143 149 Prepares a WSGI application to handle Mercurial requests.
144 150
145 151 :param config: is a list of 3-item tuples representing a ConfigObject
146 152 (it is the serialized version of the config object).
147 153 """
148 154 log.debug("Creating Mercurial WSGI application")
149 155
150 156 baseui = make_hg_ui_from_config(config)
151 157 update_hg_ui_from_hgrc(baseui, repo_path)
152 158
153 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 161 except mercurial.error.RequirementError as e:
156 162 raise exceptions.RequirementException(e)(e)
157 163
158 164
159 165 class GitHandler(object):
160 166 """
161 167 Handler for Git operations like push/pull etc
162 168 """
163 169 def __init__(self, repo_location, repo_name, git_path, update_server_info,
164 170 extras):
165 171 if not os.path.isdir(repo_location):
166 172 raise OSError(repo_location)
167 173 self.content_path = repo_location
168 174 self.repo_name = repo_name
169 175 self.repo_location = repo_location
170 176 self.extras = extras
171 177 self.git_path = git_path
172 178 self.update_server_info = update_server_info
173 179
174 180 def __call__(self, environ, start_response):
175 181 app = webob.exc.HTTPNotFound()
176 182 candidate_paths = (
177 183 self.content_path, os.path.join(self.content_path, '.git'))
178 184
179 185 for content_path in candidate_paths:
180 186 try:
181 187 app = pygrack.GitRepository(
182 188 self.repo_name, content_path, self.git_path,
183 189 self.update_server_info, self.extras)
184 190 break
185 191 except OSError:
186 192 continue
187 193
188 194 return app(environ, start_response)
189 195
190 196
191 197 def create_git_wsgi_app(repo_path, repo_name, config):
192 198 """
193 199 Creates a WSGI application to handle Git requests.
194 200
195 201 :param config: is a dictionary holding the extras.
196 202 """
197 203 git_path = settings.GIT_EXECUTABLE
198 204 update_server_info = config.pop('git_update_server_info')
199 205 app = GitHandler(
200 206 repo_path, repo_name, git_path, update_server_info, config)
201 207
202 208 return app
203 209
204 210
205 211 class GitLFSHandler(object):
206 212 """
207 213 Handler for Git LFS operations
208 214 """
209 215
210 216 def __init__(self, repo_location, repo_name, git_path, update_server_info,
211 217 extras):
212 218 if not os.path.isdir(repo_location):
213 219 raise OSError(repo_location)
214 220 self.content_path = repo_location
215 221 self.repo_name = repo_name
216 222 self.repo_location = repo_location
217 223 self.extras = extras
218 224 self.git_path = git_path
219 225 self.update_server_info = update_server_info
220 226
221 227 def get_app(self, git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme):
222 228 app = git_lfs.create_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
223 229 return app
224 230
225 231
226 232 def create_git_lfs_wsgi_app(repo_path, repo_name, config):
227 233 git_path = settings.GIT_EXECUTABLE
228 234 update_server_info = config.pop(b'git_update_server_info')
229 235 git_lfs_enabled = config.pop(b'git_lfs_enabled')
230 236 git_lfs_store_path = config.pop(b'git_lfs_store_path')
231 237 git_lfs_http_scheme = config.pop(b'git_lfs_http_scheme', 'http')
232 238 app = GitLFSHandler(
233 239 repo_path, repo_name, git_path, update_server_info, config)
234 240
235 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