##// END OF EJS Templates
mercurial: expose function to check for unresolved files
marcink -
r798:a5646341 default
parent child Browse files
Show More
@@ -1,969 +1,990 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-2019 RhodeCode GmbH
2 # Copyright (C) 2014-2019 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 io
18 import io
19 import logging
19 import logging
20 import stat
20 import stat
21 import urllib
21 import urllib
22 import urllib2
22 import urllib2
23 import traceback
23 import traceback
24
24
25 from hgext import largefiles, rebase
25 from hgext import largefiles, rebase, purge
26 from hgext.strip import strip as hgext_strip
26 from hgext.strip import strip as hgext_strip
27 from mercurial import commands
27 from mercurial import commands
28 from mercurial import unionrepo
28 from mercurial import unionrepo
29 from mercurial import verify
29 from mercurial import verify
30
30
31 import vcsserver
31 import vcsserver
32 from vcsserver import exceptions
32 from vcsserver import exceptions
33 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
33 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
34 from vcsserver.hgcompat import (
34 from vcsserver.hgcompat import (
35 archival, bin, clone, config as hgconfig, diffopts, hex, get_ctx,
35 archival, bin, clone, config as hgconfig, diffopts, hex, get_ctx,
36 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
36 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
37 makepeer, instance, match, memctx, exchange, memfilectx, nullrev, hg_merge,
37 makepeer, instance, match, memctx, exchange, memfilectx, nullrev, hg_merge,
38 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
38 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
39 RepoLookupError, InterventionRequired, RequirementError)
39 RepoLookupError, InterventionRequired, RequirementError)
40 from vcsserver.vcs_base import RemoteBase
40 from vcsserver.vcs_base import RemoteBase
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 def make_ui_from_config(repo_config):
45 def make_ui_from_config(repo_config):
46
46
47 class LoggingUI(ui.ui):
47 class LoggingUI(ui.ui):
48 def status(self, *msg, **opts):
48 def status(self, *msg, **opts):
49 log.info(' '.join(msg).rstrip('\n'))
49 log.info(' '.join(msg).rstrip('\n'))
50 super(LoggingUI, self).status(*msg, **opts)
50 super(LoggingUI, self).status(*msg, **opts)
51
51
52 def warn(self, *msg, **opts):
52 def warn(self, *msg, **opts):
53 log.warn(' '.join(msg).rstrip('\n'))
53 log.warn(' '.join(msg).rstrip('\n'))
54 super(LoggingUI, self).warn(*msg, **opts)
54 super(LoggingUI, self).warn(*msg, **opts)
55
55
56 def error(self, *msg, **opts):
56 def error(self, *msg, **opts):
57 log.error(' '.join(msg).rstrip('\n'))
57 log.error(' '.join(msg).rstrip('\n'))
58 super(LoggingUI, self).error(*msg, **opts)
58 super(LoggingUI, self).error(*msg, **opts)
59
59
60 def note(self, *msg, **opts):
60 def note(self, *msg, **opts):
61 log.info(' '.join(msg).rstrip('\n'))
61 log.info(' '.join(msg).rstrip('\n'))
62 super(LoggingUI, self).note(*msg, **opts)
62 super(LoggingUI, self).note(*msg, **opts)
63
63
64 def debug(self, *msg, **opts):
64 def debug(self, *msg, **opts):
65 log.debug(' '.join(msg).rstrip('\n'))
65 log.debug(' '.join(msg).rstrip('\n'))
66 super(LoggingUI, self).debug(*msg, **opts)
66 super(LoggingUI, self).debug(*msg, **opts)
67
67
68 baseui = LoggingUI()
68 baseui = LoggingUI()
69
69
70 # clean the baseui object
70 # clean the baseui object
71 baseui._ocfg = hgconfig.config()
71 baseui._ocfg = hgconfig.config()
72 baseui._ucfg = hgconfig.config()
72 baseui._ucfg = hgconfig.config()
73 baseui._tcfg = hgconfig.config()
73 baseui._tcfg = hgconfig.config()
74
74
75 for section, option, value in repo_config:
75 for section, option, value in repo_config:
76 baseui.setconfig(section, option, value)
76 baseui.setconfig(section, option, value)
77
77
78 # make our hgweb quiet so it doesn't print output
78 # make our hgweb quiet so it doesn't print output
79 baseui.setconfig('ui', 'quiet', 'true')
79 baseui.setconfig('ui', 'quiet', 'true')
80
80
81 baseui.setconfig('ui', 'paginate', 'never')
81 baseui.setconfig('ui', 'paginate', 'never')
82 # for better Error reporting of Mercurial
82 # for better Error reporting of Mercurial
83 baseui.setconfig('ui', 'message-output', 'stderr')
83 baseui.setconfig('ui', 'message-output', 'stderr')
84
84
85 # force mercurial to only use 1 thread, otherwise it may try to set a
85 # force mercurial to only use 1 thread, otherwise it may try to set a
86 # signal in a non-main thread, thus generating a ValueError.
86 # signal in a non-main thread, thus generating a ValueError.
87 baseui.setconfig('worker', 'numcpus', 1)
87 baseui.setconfig('worker', 'numcpus', 1)
88
88
89 # If there is no config for the largefiles extension, we explicitly disable
89 # If there is no config for the largefiles extension, we explicitly disable
90 # it here. This overrides settings from repositories hgrc file. Recent
90 # it here. This overrides settings from repositories hgrc file. Recent
91 # mercurial versions enable largefiles in hgrc on clone from largefile
91 # mercurial versions enable largefiles in hgrc on clone from largefile
92 # repo.
92 # repo.
93 if not baseui.hasconfig('extensions', 'largefiles'):
93 if not baseui.hasconfig('extensions', 'largefiles'):
94 log.debug('Explicitly disable largefiles extension for repo.')
94 log.debug('Explicitly disable largefiles extension for repo.')
95 baseui.setconfig('extensions', 'largefiles', '!')
95 baseui.setconfig('extensions', 'largefiles', '!')
96
96
97 return baseui
97 return baseui
98
98
99
99
100 def reraise_safe_exceptions(func):
100 def reraise_safe_exceptions(func):
101 """Decorator for converting mercurial exceptions to something neutral."""
101 """Decorator for converting mercurial exceptions to something neutral."""
102
102
103 def wrapper(*args, **kwargs):
103 def wrapper(*args, **kwargs):
104 try:
104 try:
105 return func(*args, **kwargs)
105 return func(*args, **kwargs)
106 except (Abort, InterventionRequired) as e:
106 except (Abort, InterventionRequired) as e:
107 raise_from_original(exceptions.AbortException(e))
107 raise_from_original(exceptions.AbortException(e))
108 except RepoLookupError as e:
108 except RepoLookupError as e:
109 raise_from_original(exceptions.LookupException(e))
109 raise_from_original(exceptions.LookupException(e))
110 except RequirementError as e:
110 except RequirementError as e:
111 raise_from_original(exceptions.RequirementException(e))
111 raise_from_original(exceptions.RequirementException(e))
112 except RepoError as e:
112 except RepoError as e:
113 raise_from_original(exceptions.VcsException(e))
113 raise_from_original(exceptions.VcsException(e))
114 except LookupError as e:
114 except LookupError as e:
115 raise_from_original(exceptions.LookupException(e))
115 raise_from_original(exceptions.LookupException(e))
116 except Exception as e:
116 except Exception as e:
117 if not hasattr(e, '_vcs_kind'):
117 if not hasattr(e, '_vcs_kind'):
118 log.exception("Unhandled exception in hg remote call")
118 log.exception("Unhandled exception in hg remote call")
119 raise_from_original(exceptions.UnhandledException(e))
119 raise_from_original(exceptions.UnhandledException(e))
120
120
121 raise
121 raise
122 return wrapper
122 return wrapper
123
123
124
124
125 class MercurialFactory(RepoFactory):
125 class MercurialFactory(RepoFactory):
126 repo_type = 'hg'
126 repo_type = 'hg'
127
127
128 def _create_config(self, config, hooks=True):
128 def _create_config(self, config, hooks=True):
129 if not hooks:
129 if not hooks:
130 hooks_to_clean = frozenset((
130 hooks_to_clean = frozenset((
131 'changegroup.repo_size', 'preoutgoing.pre_pull',
131 'changegroup.repo_size', 'preoutgoing.pre_pull',
132 'outgoing.pull_logger', 'prechangegroup.pre_push'))
132 'outgoing.pull_logger', 'prechangegroup.pre_push'))
133 new_config = []
133 new_config = []
134 for section, option, value in config:
134 for section, option, value in config:
135 if section == 'hooks' and option in hooks_to_clean:
135 if section == 'hooks' and option in hooks_to_clean:
136 continue
136 continue
137 new_config.append((section, option, value))
137 new_config.append((section, option, value))
138 config = new_config
138 config = new_config
139
139
140 baseui = make_ui_from_config(config)
140 baseui = make_ui_from_config(config)
141 return baseui
141 return baseui
142
142
143 def _create_repo(self, wire, create):
143 def _create_repo(self, wire, create):
144 baseui = self._create_config(wire["config"])
144 baseui = self._create_config(wire["config"])
145 return instance(baseui, wire["path"], create)
145 return instance(baseui, wire["path"], create)
146
146
147 def repo(self, wire, create=False):
147 def repo(self, wire, create=False):
148 """
148 """
149 Get a repository instance for the given path.
149 Get a repository instance for the given path.
150 """
150 """
151 return self._create_repo(wire, create)
151 return self._create_repo(wire, create)
152
152
153
153
154 class HgRemote(RemoteBase):
154 class HgRemote(RemoteBase):
155
155
156 def __init__(self, factory):
156 def __init__(self, factory):
157 self._factory = factory
157 self._factory = factory
158 self._bulk_methods = {
158 self._bulk_methods = {
159 "affected_files": self.ctx_files,
159 "affected_files": self.ctx_files,
160 "author": self.ctx_user,
160 "author": self.ctx_user,
161 "branch": self.ctx_branch,
161 "branch": self.ctx_branch,
162 "children": self.ctx_children,
162 "children": self.ctx_children,
163 "date": self.ctx_date,
163 "date": self.ctx_date,
164 "message": self.ctx_description,
164 "message": self.ctx_description,
165 "parents": self.ctx_parents,
165 "parents": self.ctx_parents,
166 "status": self.ctx_status,
166 "status": self.ctx_status,
167 "obsolete": self.ctx_obsolete,
167 "obsolete": self.ctx_obsolete,
168 "phase": self.ctx_phase,
168 "phase": self.ctx_phase,
169 "hidden": self.ctx_hidden,
169 "hidden": self.ctx_hidden,
170 "_file_paths": self.ctx_list,
170 "_file_paths": self.ctx_list,
171 }
171 }
172
172
173 def _get_ctx(self, repo, ref):
173 def _get_ctx(self, repo, ref):
174 return get_ctx(repo, ref)
174 return get_ctx(repo, ref)
175
175
176 @reraise_safe_exceptions
176 @reraise_safe_exceptions
177 def discover_hg_version(self):
177 def discover_hg_version(self):
178 from mercurial import util
178 from mercurial import util
179 return util.version()
179 return util.version()
180
180
181 @reraise_safe_exceptions
181 @reraise_safe_exceptions
182 def is_empty(self, wire):
182 def is_empty(self, wire):
183 repo = self._factory.repo(wire)
183 repo = self._factory.repo(wire)
184
184
185 try:
185 try:
186 return len(repo) == 0
186 return len(repo) == 0
187 except Exception:
187 except Exception:
188 log.exception("failed to read object_store")
188 log.exception("failed to read object_store")
189 return False
189 return False
190
190
191 @reraise_safe_exceptions
191 @reraise_safe_exceptions
192 def archive_repo(self, archive_path, mtime, file_info, kind):
192 def archive_repo(self, archive_path, mtime, file_info, kind):
193 if kind == "tgz":
193 if kind == "tgz":
194 archiver = archival.tarit(archive_path, mtime, "gz")
194 archiver = archival.tarit(archive_path, mtime, "gz")
195 elif kind == "tbz2":
195 elif kind == "tbz2":
196 archiver = archival.tarit(archive_path, mtime, "bz2")
196 archiver = archival.tarit(archive_path, mtime, "bz2")
197 elif kind == 'zip':
197 elif kind == 'zip':
198 archiver = archival.zipit(archive_path, mtime)
198 archiver = archival.zipit(archive_path, mtime)
199 else:
199 else:
200 raise exceptions.ArchiveException()(
200 raise exceptions.ArchiveException()(
201 'Remote does not support: "%s".' % kind)
201 'Remote does not support: "%s".' % kind)
202
202
203 for f_path, f_mode, f_is_link, f_content in file_info:
203 for f_path, f_mode, f_is_link, f_content in file_info:
204 archiver.addfile(f_path, f_mode, f_is_link, f_content)
204 archiver.addfile(f_path, f_mode, f_is_link, f_content)
205 archiver.done()
205 archiver.done()
206
206
207 @reraise_safe_exceptions
207 @reraise_safe_exceptions
208 def bookmarks(self, wire):
208 def bookmarks(self, wire):
209 cache_on, context_uid, repo_id = self._cache_on(wire)
209 cache_on, context_uid, repo_id = self._cache_on(wire)
210 @self.region.conditional_cache_on_arguments(condition=cache_on)
210 @self.region.conditional_cache_on_arguments(condition=cache_on)
211 def _bookmarks(_context_uid, _repo_id):
211 def _bookmarks(_context_uid, _repo_id):
212 repo = self._factory.repo(wire)
212 repo = self._factory.repo(wire)
213 return dict(repo._bookmarks)
213 return dict(repo._bookmarks)
214
214
215 return _bookmarks(context_uid, repo_id)
215 return _bookmarks(context_uid, repo_id)
216
216
217 @reraise_safe_exceptions
217 @reraise_safe_exceptions
218 def branches(self, wire, normal, closed):
218 def branches(self, wire, normal, closed):
219 cache_on, context_uid, repo_id = self._cache_on(wire)
219 cache_on, context_uid, repo_id = self._cache_on(wire)
220 @self.region.conditional_cache_on_arguments(condition=cache_on)
220 @self.region.conditional_cache_on_arguments(condition=cache_on)
221 def _branches(_context_uid, _repo_id, _normal, _closed):
221 def _branches(_context_uid, _repo_id, _normal, _closed):
222 repo = self._factory.repo(wire)
222 repo = self._factory.repo(wire)
223 iter_branches = repo.branchmap().iterbranches()
223 iter_branches = repo.branchmap().iterbranches()
224 bt = {}
224 bt = {}
225 for branch_name, _heads, tip, is_closed in iter_branches:
225 for branch_name, _heads, tip, is_closed in iter_branches:
226 if normal and not is_closed:
226 if normal and not is_closed:
227 bt[branch_name] = tip
227 bt[branch_name] = tip
228 if closed and is_closed:
228 if closed and is_closed:
229 bt[branch_name] = tip
229 bt[branch_name] = tip
230
230
231 return bt
231 return bt
232
232
233 return _branches(context_uid, repo_id, normal, closed)
233 return _branches(context_uid, repo_id, normal, closed)
234
234
235 @reraise_safe_exceptions
235 @reraise_safe_exceptions
236 def bulk_request(self, wire, commit_id, pre_load):
236 def bulk_request(self, wire, commit_id, pre_load):
237 cache_on, context_uid, repo_id = self._cache_on(wire)
237 cache_on, context_uid, repo_id = self._cache_on(wire)
238 @self.region.conditional_cache_on_arguments(condition=cache_on)
238 @self.region.conditional_cache_on_arguments(condition=cache_on)
239 def _bulk_request(_repo_id, _commit_id, _pre_load):
239 def _bulk_request(_repo_id, _commit_id, _pre_load):
240 result = {}
240 result = {}
241 for attr in pre_load:
241 for attr in pre_load:
242 try:
242 try:
243 method = self._bulk_methods[attr]
243 method = self._bulk_methods[attr]
244 result[attr] = method(wire, commit_id)
244 result[attr] = method(wire, commit_id)
245 except KeyError as e:
245 except KeyError as e:
246 raise exceptions.VcsException(e)(
246 raise exceptions.VcsException(e)(
247 'Unknown bulk attribute: "%s"' % attr)
247 'Unknown bulk attribute: "%s"' % attr)
248 return result
248 return result
249
249
250 return _bulk_request(repo_id, commit_id, sorted(pre_load))
250 return _bulk_request(repo_id, commit_id, sorted(pre_load))
251
251
252 @reraise_safe_exceptions
252 @reraise_safe_exceptions
253 def ctx_branch(self, wire, commit_id):
253 def ctx_branch(self, wire, commit_id):
254 cache_on, context_uid, repo_id = self._cache_on(wire)
254 cache_on, context_uid, repo_id = self._cache_on(wire)
255 @self.region.conditional_cache_on_arguments(condition=cache_on)
255 @self.region.conditional_cache_on_arguments(condition=cache_on)
256 def _ctx_branch(_repo_id, _commit_id):
256 def _ctx_branch(_repo_id, _commit_id):
257 repo = self._factory.repo(wire)
257 repo = self._factory.repo(wire)
258 ctx = self._get_ctx(repo, commit_id)
258 ctx = self._get_ctx(repo, commit_id)
259 return ctx.branch()
259 return ctx.branch()
260 return _ctx_branch(repo_id, commit_id)
260 return _ctx_branch(repo_id, commit_id)
261
261
262 @reraise_safe_exceptions
262 @reraise_safe_exceptions
263 def ctx_date(self, wire, commit_id):
263 def ctx_date(self, wire, commit_id):
264 cache_on, context_uid, repo_id = self._cache_on(wire)
264 cache_on, context_uid, repo_id = self._cache_on(wire)
265 @self.region.conditional_cache_on_arguments(condition=cache_on)
265 @self.region.conditional_cache_on_arguments(condition=cache_on)
266 def _ctx_date(_repo_id, _commit_id):
266 def _ctx_date(_repo_id, _commit_id):
267 repo = self._factory.repo(wire)
267 repo = self._factory.repo(wire)
268 ctx = self._get_ctx(repo, commit_id)
268 ctx = self._get_ctx(repo, commit_id)
269 return ctx.date()
269 return ctx.date()
270 return _ctx_date(repo_id, commit_id)
270 return _ctx_date(repo_id, commit_id)
271
271
272 @reraise_safe_exceptions
272 @reraise_safe_exceptions
273 def ctx_description(self, wire, revision):
273 def ctx_description(self, wire, revision):
274 repo = self._factory.repo(wire)
274 repo = self._factory.repo(wire)
275 ctx = self._get_ctx(repo, revision)
275 ctx = self._get_ctx(repo, revision)
276 return ctx.description()
276 return ctx.description()
277
277
278 @reraise_safe_exceptions
278 @reraise_safe_exceptions
279 def ctx_files(self, wire, commit_id):
279 def ctx_files(self, wire, commit_id):
280 cache_on, context_uid, repo_id = self._cache_on(wire)
280 cache_on, context_uid, repo_id = self._cache_on(wire)
281 @self.region.conditional_cache_on_arguments(condition=cache_on)
281 @self.region.conditional_cache_on_arguments(condition=cache_on)
282 def _ctx_files(_repo_id, _commit_id):
282 def _ctx_files(_repo_id, _commit_id):
283 repo = self._factory.repo(wire)
283 repo = self._factory.repo(wire)
284 ctx = self._get_ctx(repo, commit_id)
284 ctx = self._get_ctx(repo, commit_id)
285 return ctx.files()
285 return ctx.files()
286
286
287 return _ctx_files(repo_id, commit_id)
287 return _ctx_files(repo_id, commit_id)
288
288
289 @reraise_safe_exceptions
289 @reraise_safe_exceptions
290 def ctx_list(self, path, revision):
290 def ctx_list(self, path, revision):
291 repo = self._factory.repo(path)
291 repo = self._factory.repo(path)
292 ctx = self._get_ctx(repo, revision)
292 ctx = self._get_ctx(repo, revision)
293 return list(ctx)
293 return list(ctx)
294
294
295 @reraise_safe_exceptions
295 @reraise_safe_exceptions
296 def ctx_parents(self, wire, commit_id):
296 def ctx_parents(self, wire, commit_id):
297 cache_on, context_uid, repo_id = self._cache_on(wire)
297 cache_on, context_uid, repo_id = self._cache_on(wire)
298 @self.region.conditional_cache_on_arguments(condition=cache_on)
298 @self.region.conditional_cache_on_arguments(condition=cache_on)
299 def _ctx_parents(_repo_id, _commit_id):
299 def _ctx_parents(_repo_id, _commit_id):
300 repo = self._factory.repo(wire)
300 repo = self._factory.repo(wire)
301 ctx = self._get_ctx(repo, commit_id)
301 ctx = self._get_ctx(repo, commit_id)
302 return [parent.hex() for parent in ctx.parents()
302 return [parent.hex() for parent in ctx.parents()
303 if not (parent.hidden() or parent.obsolete())]
303 if not (parent.hidden() or parent.obsolete())]
304
304
305 return _ctx_parents(repo_id, commit_id)
305 return _ctx_parents(repo_id, commit_id)
306
306
307 @reraise_safe_exceptions
307 @reraise_safe_exceptions
308 def ctx_children(self, wire, commit_id):
308 def ctx_children(self, wire, commit_id):
309 cache_on, context_uid, repo_id = self._cache_on(wire)
309 cache_on, context_uid, repo_id = self._cache_on(wire)
310 @self.region.conditional_cache_on_arguments(condition=cache_on)
310 @self.region.conditional_cache_on_arguments(condition=cache_on)
311 def _ctx_children(_repo_id, _commit_id):
311 def _ctx_children(_repo_id, _commit_id):
312 repo = self._factory.repo(wire)
312 repo = self._factory.repo(wire)
313 ctx = self._get_ctx(repo, commit_id)
313 ctx = self._get_ctx(repo, commit_id)
314 return [child.hex() for child in ctx.children()
314 return [child.hex() for child in ctx.children()
315 if not (child.hidden() or child.obsolete())]
315 if not (child.hidden() or child.obsolete())]
316
316
317 return _ctx_children(repo_id, commit_id)
317 return _ctx_children(repo_id, commit_id)
318
318
319 @reraise_safe_exceptions
319 @reraise_safe_exceptions
320 def ctx_phase(self, wire, commit_id):
320 def ctx_phase(self, wire, commit_id):
321 cache_on, context_uid, repo_id = self._cache_on(wire)
321 cache_on, context_uid, repo_id = self._cache_on(wire)
322 @self.region.conditional_cache_on_arguments(condition=cache_on)
322 @self.region.conditional_cache_on_arguments(condition=cache_on)
323 def _ctx_phase(_context_uid, _repo_id, _commit_id):
323 def _ctx_phase(_context_uid, _repo_id, _commit_id):
324 repo = self._factory.repo(wire)
324 repo = self._factory.repo(wire)
325 ctx = self._get_ctx(repo, commit_id)
325 ctx = self._get_ctx(repo, commit_id)
326 # public=0, draft=1, secret=3
326 # public=0, draft=1, secret=3
327 return ctx.phase()
327 return ctx.phase()
328 return _ctx_phase(context_uid, repo_id, commit_id)
328 return _ctx_phase(context_uid, repo_id, commit_id)
329
329
330 @reraise_safe_exceptions
330 @reraise_safe_exceptions
331 def ctx_obsolete(self, wire, commit_id):
331 def ctx_obsolete(self, wire, commit_id):
332 cache_on, context_uid, repo_id = self._cache_on(wire)
332 cache_on, context_uid, repo_id = self._cache_on(wire)
333 @self.region.conditional_cache_on_arguments(condition=cache_on)
333 @self.region.conditional_cache_on_arguments(condition=cache_on)
334 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
334 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
335 repo = self._factory.repo(wire)
335 repo = self._factory.repo(wire)
336 ctx = self._get_ctx(repo, commit_id)
336 ctx = self._get_ctx(repo, commit_id)
337 return ctx.obsolete()
337 return ctx.obsolete()
338 return _ctx_obsolete(context_uid, repo_id, commit_id)
338 return _ctx_obsolete(context_uid, repo_id, commit_id)
339
339
340 @reraise_safe_exceptions
340 @reraise_safe_exceptions
341 def ctx_hidden(self, wire, commit_id):
341 def ctx_hidden(self, wire, commit_id):
342 cache_on, context_uid, repo_id = self._cache_on(wire)
342 cache_on, context_uid, repo_id = self._cache_on(wire)
343 @self.region.conditional_cache_on_arguments(condition=cache_on)
343 @self.region.conditional_cache_on_arguments(condition=cache_on)
344 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
344 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
345 repo = self._factory.repo(wire)
345 repo = self._factory.repo(wire)
346 ctx = self._get_ctx(repo, commit_id)
346 ctx = self._get_ctx(repo, commit_id)
347 return ctx.hidden()
347 return ctx.hidden()
348 return _ctx_hidden(context_uid, repo_id, commit_id)
348 return _ctx_hidden(context_uid, repo_id, commit_id)
349
349
350 @reraise_safe_exceptions
350 @reraise_safe_exceptions
351 def ctx_substate(self, wire, revision):
351 def ctx_substate(self, wire, revision):
352 repo = self._factory.repo(wire)
352 repo = self._factory.repo(wire)
353 ctx = self._get_ctx(repo, revision)
353 ctx = self._get_ctx(repo, revision)
354 return ctx.substate
354 return ctx.substate
355
355
356 @reraise_safe_exceptions
356 @reraise_safe_exceptions
357 def ctx_status(self, wire, revision):
357 def ctx_status(self, wire, revision):
358 repo = self._factory.repo(wire)
358 repo = self._factory.repo(wire)
359 ctx = self._get_ctx(repo, revision)
359 ctx = self._get_ctx(repo, revision)
360 status = repo[ctx.p1().node()].status(other=ctx.node())
360 status = repo[ctx.p1().node()].status(other=ctx.node())
361 # object of status (odd, custom named tuple in mercurial) is not
361 # object of status (odd, custom named tuple in mercurial) is not
362 # correctly serializable, we make it a list, as the underling
362 # correctly serializable, we make it a list, as the underling
363 # API expects this to be a list
363 # API expects this to be a list
364 return list(status)
364 return list(status)
365
365
366 @reraise_safe_exceptions
366 @reraise_safe_exceptions
367 def ctx_user(self, wire, revision):
367 def ctx_user(self, wire, revision):
368 repo = self._factory.repo(wire)
368 repo = self._factory.repo(wire)
369 ctx = self._get_ctx(repo, revision)
369 ctx = self._get_ctx(repo, revision)
370 return ctx.user()
370 return ctx.user()
371
371
372 @reraise_safe_exceptions
372 @reraise_safe_exceptions
373 def check_url(self, url, config):
373 def check_url(self, url, config):
374 _proto = None
374 _proto = None
375 if '+' in url[:url.find('://')]:
375 if '+' in url[:url.find('://')]:
376 _proto = url[0:url.find('+')]
376 _proto = url[0:url.find('+')]
377 url = url[url.find('+') + 1:]
377 url = url[url.find('+') + 1:]
378 handlers = []
378 handlers = []
379 url_obj = url_parser(url)
379 url_obj = url_parser(url)
380 test_uri, authinfo = url_obj.authinfo()
380 test_uri, authinfo = url_obj.authinfo()
381 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
381 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
382 url_obj.query = obfuscate_qs(url_obj.query)
382 url_obj.query = obfuscate_qs(url_obj.query)
383
383
384 cleaned_uri = str(url_obj)
384 cleaned_uri = str(url_obj)
385 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
385 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
386
386
387 if authinfo:
387 if authinfo:
388 # create a password manager
388 # create a password manager
389 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
389 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
390 passmgr.add_password(*authinfo)
390 passmgr.add_password(*authinfo)
391
391
392 handlers.extend((httpbasicauthhandler(passmgr),
392 handlers.extend((httpbasicauthhandler(passmgr),
393 httpdigestauthhandler(passmgr)))
393 httpdigestauthhandler(passmgr)))
394
394
395 o = urllib2.build_opener(*handlers)
395 o = urllib2.build_opener(*handlers)
396 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
396 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
397 ('Accept', 'application/mercurial-0.1')]
397 ('Accept', 'application/mercurial-0.1')]
398
398
399 q = {"cmd": 'between'}
399 q = {"cmd": 'between'}
400 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
400 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
401 qs = '?%s' % urllib.urlencode(q)
401 qs = '?%s' % urllib.urlencode(q)
402 cu = "%s%s" % (test_uri, qs)
402 cu = "%s%s" % (test_uri, qs)
403 req = urllib2.Request(cu, None, {})
403 req = urllib2.Request(cu, None, {})
404
404
405 try:
405 try:
406 log.debug("Trying to open URL %s", cleaned_uri)
406 log.debug("Trying to open URL %s", cleaned_uri)
407 resp = o.open(req)
407 resp = o.open(req)
408 if resp.code != 200:
408 if resp.code != 200:
409 raise exceptions.URLError()('Return Code is not 200')
409 raise exceptions.URLError()('Return Code is not 200')
410 except Exception as e:
410 except Exception as e:
411 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
411 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
412 # means it cannot be cloned
412 # means it cannot be cloned
413 raise exceptions.URLError(e)("[%s] org_exc: %s" % (cleaned_uri, e))
413 raise exceptions.URLError(e)("[%s] org_exc: %s" % (cleaned_uri, e))
414
414
415 # now check if it's a proper hg repo, but don't do it for svn
415 # now check if it's a proper hg repo, but don't do it for svn
416 try:
416 try:
417 if _proto == 'svn':
417 if _proto == 'svn':
418 pass
418 pass
419 else:
419 else:
420 # check for pure hg repos
420 # check for pure hg repos
421 log.debug(
421 log.debug(
422 "Verifying if URL is a Mercurial repository: %s",
422 "Verifying if URL is a Mercurial repository: %s",
423 cleaned_uri)
423 cleaned_uri)
424 ui = make_ui_from_config(config)
424 ui = make_ui_from_config(config)
425 peer_checker = makepeer(ui, url)
425 peer_checker = makepeer(ui, url)
426 peer_checker.lookup('tip')
426 peer_checker.lookup('tip')
427 except Exception as e:
427 except Exception as e:
428 log.warning("URL is not a valid Mercurial repository: %s",
428 log.warning("URL is not a valid Mercurial repository: %s",
429 cleaned_uri)
429 cleaned_uri)
430 raise exceptions.URLError(e)(
430 raise exceptions.URLError(e)(
431 "url [%s] does not look like an hg repo org_exc: %s"
431 "url [%s] does not look like an hg repo org_exc: %s"
432 % (cleaned_uri, e))
432 % (cleaned_uri, e))
433
433
434 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
434 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
435 return True
435 return True
436
436
437 @reraise_safe_exceptions
437 @reraise_safe_exceptions
438 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
438 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
439 repo = self._factory.repo(wire)
439 repo = self._factory.repo(wire)
440
440
441 if file_filter:
441 if file_filter:
442 match_filter = match(file_filter[0], '', [file_filter[1]])
442 match_filter = match(file_filter[0], '', [file_filter[1]])
443 else:
443 else:
444 match_filter = file_filter
444 match_filter = file_filter
445 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
445 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
446
446
447 try:
447 try:
448 return "".join(patch.diff(
448 return "".join(patch.diff(
449 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts))
449 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts))
450 except RepoLookupError as e:
450 except RepoLookupError as e:
451 raise exceptions.LookupException(e)()
451 raise exceptions.LookupException(e)()
452
452
453 @reraise_safe_exceptions
453 @reraise_safe_exceptions
454 def node_history(self, wire, revision, path, limit):
454 def node_history(self, wire, revision, path, limit):
455 cache_on, context_uid, repo_id = self._cache_on(wire)
455 cache_on, context_uid, repo_id = self._cache_on(wire)
456 @self.region.conditional_cache_on_arguments(condition=cache_on)
456 @self.region.conditional_cache_on_arguments(condition=cache_on)
457 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
457 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
458 repo = self._factory.repo(wire)
458 repo = self._factory.repo(wire)
459
459
460 ctx = self._get_ctx(repo, revision)
460 ctx = self._get_ctx(repo, revision)
461 fctx = ctx.filectx(path)
461 fctx = ctx.filectx(path)
462
462
463 def history_iter():
463 def history_iter():
464 limit_rev = fctx.rev()
464 limit_rev = fctx.rev()
465 for obj in reversed(list(fctx.filelog())):
465 for obj in reversed(list(fctx.filelog())):
466 obj = fctx.filectx(obj)
466 obj = fctx.filectx(obj)
467 ctx = obj.changectx()
467 ctx = obj.changectx()
468 if ctx.hidden() or ctx.obsolete():
468 if ctx.hidden() or ctx.obsolete():
469 continue
469 continue
470
470
471 if limit_rev >= obj.rev():
471 if limit_rev >= obj.rev():
472 yield obj
472 yield obj
473
473
474 history = []
474 history = []
475 for cnt, obj in enumerate(history_iter()):
475 for cnt, obj in enumerate(history_iter()):
476 if limit and cnt >= limit:
476 if limit and cnt >= limit:
477 break
477 break
478 history.append(hex(obj.node()))
478 history.append(hex(obj.node()))
479
479
480 return [x for x in history]
480 return [x for x in history]
481 return _node_history(context_uid, repo_id, revision, path, limit)
481 return _node_history(context_uid, repo_id, revision, path, limit)
482
482
483 @reraise_safe_exceptions
483 @reraise_safe_exceptions
484 def node_history_untill(self, wire, revision, path, limit):
484 def node_history_untill(self, wire, revision, path, limit):
485 cache_on, context_uid, repo_id = self._cache_on(wire)
485 cache_on, context_uid, repo_id = self._cache_on(wire)
486 @self.region.conditional_cache_on_arguments(condition=cache_on)
486 @self.region.conditional_cache_on_arguments(condition=cache_on)
487 def _node_history_until(_context_uid, _repo_id):
487 def _node_history_until(_context_uid, _repo_id):
488 repo = self._factory.repo(wire)
488 repo = self._factory.repo(wire)
489 ctx = self._get_ctx(repo, revision)
489 ctx = self._get_ctx(repo, revision)
490 fctx = ctx.filectx(path)
490 fctx = ctx.filectx(path)
491
491
492 file_log = list(fctx.filelog())
492 file_log = list(fctx.filelog())
493 if limit:
493 if limit:
494 # Limit to the last n items
494 # Limit to the last n items
495 file_log = file_log[-limit:]
495 file_log = file_log[-limit:]
496
496
497 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
497 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
498 return _node_history_until(context_uid, repo_id, revision, path, limit)
498 return _node_history_until(context_uid, repo_id, revision, path, limit)
499
499
500 @reraise_safe_exceptions
500 @reraise_safe_exceptions
501 def fctx_annotate(self, wire, revision, path):
501 def fctx_annotate(self, wire, revision, path):
502 repo = self._factory.repo(wire)
502 repo = self._factory.repo(wire)
503 ctx = self._get_ctx(repo, revision)
503 ctx = self._get_ctx(repo, revision)
504 fctx = ctx.filectx(path)
504 fctx = ctx.filectx(path)
505
505
506 result = []
506 result = []
507 for i, annotate_obj in enumerate(fctx.annotate(), 1):
507 for i, annotate_obj in enumerate(fctx.annotate(), 1):
508 ln_no = i
508 ln_no = i
509 sha = hex(annotate_obj.fctx.node())
509 sha = hex(annotate_obj.fctx.node())
510 content = annotate_obj.text
510 content = annotate_obj.text
511 result.append((ln_no, sha, content))
511 result.append((ln_no, sha, content))
512 return result
512 return result
513
513
514 @reraise_safe_exceptions
514 @reraise_safe_exceptions
515 def fctx_node_data(self, wire, revision, path):
515 def fctx_node_data(self, wire, revision, path):
516 repo = self._factory.repo(wire)
516 repo = self._factory.repo(wire)
517 ctx = self._get_ctx(repo, revision)
517 ctx = self._get_ctx(repo, revision)
518 fctx = ctx.filectx(path)
518 fctx = ctx.filectx(path)
519 return fctx.data()
519 return fctx.data()
520
520
521 @reraise_safe_exceptions
521 @reraise_safe_exceptions
522 def fctx_flags(self, wire, commit_id, path):
522 def fctx_flags(self, wire, commit_id, path):
523 cache_on, context_uid, repo_id = self._cache_on(wire)
523 cache_on, context_uid, repo_id = self._cache_on(wire)
524 @self.region.conditional_cache_on_arguments(condition=cache_on)
524 @self.region.conditional_cache_on_arguments(condition=cache_on)
525 def _fctx_flags(_repo_id, _commit_id, _path):
525 def _fctx_flags(_repo_id, _commit_id, _path):
526 repo = self._factory.repo(wire)
526 repo = self._factory.repo(wire)
527 ctx = self._get_ctx(repo, commit_id)
527 ctx = self._get_ctx(repo, commit_id)
528 fctx = ctx.filectx(path)
528 fctx = ctx.filectx(path)
529 return fctx.flags()
529 return fctx.flags()
530
530
531 return _fctx_flags(repo_id, commit_id, path)
531 return _fctx_flags(repo_id, commit_id, path)
532
532
533 @reraise_safe_exceptions
533 @reraise_safe_exceptions
534 def fctx_size(self, wire, commit_id, path):
534 def fctx_size(self, wire, commit_id, path):
535 cache_on, context_uid, repo_id = self._cache_on(wire)
535 cache_on, context_uid, repo_id = self._cache_on(wire)
536 @self.region.conditional_cache_on_arguments(condition=cache_on)
536 @self.region.conditional_cache_on_arguments(condition=cache_on)
537 def _fctx_size(_repo_id, _revision, _path):
537 def _fctx_size(_repo_id, _revision, _path):
538 repo = self._factory.repo(wire)
538 repo = self._factory.repo(wire)
539 ctx = self._get_ctx(repo, commit_id)
539 ctx = self._get_ctx(repo, commit_id)
540 fctx = ctx.filectx(path)
540 fctx = ctx.filectx(path)
541 return fctx.size()
541 return fctx.size()
542 return _fctx_size(repo_id, commit_id, path)
542 return _fctx_size(repo_id, commit_id, path)
543
543
544 @reraise_safe_exceptions
544 @reraise_safe_exceptions
545 def get_all_commit_ids(self, wire, name):
545 def get_all_commit_ids(self, wire, name):
546 cache_on, context_uid, repo_id = self._cache_on(wire)
546 cache_on, context_uid, repo_id = self._cache_on(wire)
547 @self.region.conditional_cache_on_arguments(condition=cache_on)
547 @self.region.conditional_cache_on_arguments(condition=cache_on)
548 def _get_all_commit_ids(_context_uid, _repo_id, _name):
548 def _get_all_commit_ids(_context_uid, _repo_id, _name):
549 repo = self._factory.repo(wire)
549 repo = self._factory.repo(wire)
550 repo = repo.filtered(name)
550 repo = repo.filtered(name)
551 revs = map(lambda x: hex(x[7]), repo.changelog.index)
551 revs = map(lambda x: hex(x[7]), repo.changelog.index)
552 return revs
552 return revs
553 return _get_all_commit_ids(context_uid, repo_id, name)
553 return _get_all_commit_ids(context_uid, repo_id, name)
554
554
555 @reraise_safe_exceptions
555 @reraise_safe_exceptions
556 def get_config_value(self, wire, section, name, untrusted=False):
556 def get_config_value(self, wire, section, name, untrusted=False):
557 repo = self._factory.repo(wire)
557 repo = self._factory.repo(wire)
558 return repo.ui.config(section, name, untrusted=untrusted)
558 return repo.ui.config(section, name, untrusted=untrusted)
559
559
560 @reraise_safe_exceptions
560 @reraise_safe_exceptions
561 def is_large_file(self, wire, commit_id, path):
561 def is_large_file(self, wire, commit_id, path):
562 cache_on, context_uid, repo_id = self._cache_on(wire)
562 cache_on, context_uid, repo_id = self._cache_on(wire)
563 @self.region.conditional_cache_on_arguments(condition=cache_on)
563 @self.region.conditional_cache_on_arguments(condition=cache_on)
564 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
564 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
565 return largefiles.lfutil.isstandin(path)
565 return largefiles.lfutil.isstandin(path)
566
566
567 return _is_large_file(context_uid, repo_id, commit_id, path)
567 return _is_large_file(context_uid, repo_id, commit_id, path)
568
568
569 @reraise_safe_exceptions
569 @reraise_safe_exceptions
570 def is_binary(self, wire, revision, path):
570 def is_binary(self, wire, revision, path):
571 cache_on, context_uid, repo_id = self._cache_on(wire)
571 cache_on, context_uid, repo_id = self._cache_on(wire)
572
572
573 @self.region.conditional_cache_on_arguments(condition=cache_on)
573 @self.region.conditional_cache_on_arguments(condition=cache_on)
574 def _is_binary(_repo_id, _sha, _path):
574 def _is_binary(_repo_id, _sha, _path):
575 repo = self._factory.repo(wire)
575 repo = self._factory.repo(wire)
576 ctx = self._get_ctx(repo, revision)
576 ctx = self._get_ctx(repo, revision)
577 fctx = ctx.filectx(path)
577 fctx = ctx.filectx(path)
578 return fctx.isbinary()
578 return fctx.isbinary()
579
579
580 return _is_binary(repo_id, revision, path)
580 return _is_binary(repo_id, revision, path)
581
581
582 @reraise_safe_exceptions
582 @reraise_safe_exceptions
583 def in_largefiles_store(self, wire, sha):
583 def in_largefiles_store(self, wire, sha):
584 repo = self._factory.repo(wire)
584 repo = self._factory.repo(wire)
585 return largefiles.lfutil.instore(repo, sha)
585 return largefiles.lfutil.instore(repo, sha)
586
586
587 @reraise_safe_exceptions
587 @reraise_safe_exceptions
588 def in_user_cache(self, wire, sha):
588 def in_user_cache(self, wire, sha):
589 repo = self._factory.repo(wire)
589 repo = self._factory.repo(wire)
590 return largefiles.lfutil.inusercache(repo.ui, sha)
590 return largefiles.lfutil.inusercache(repo.ui, sha)
591
591
592 @reraise_safe_exceptions
592 @reraise_safe_exceptions
593 def store_path(self, wire, sha):
593 def store_path(self, wire, sha):
594 repo = self._factory.repo(wire)
594 repo = self._factory.repo(wire)
595 return largefiles.lfutil.storepath(repo, sha)
595 return largefiles.lfutil.storepath(repo, sha)
596
596
597 @reraise_safe_exceptions
597 @reraise_safe_exceptions
598 def link(self, wire, sha, path):
598 def link(self, wire, sha, path):
599 repo = self._factory.repo(wire)
599 repo = self._factory.repo(wire)
600 largefiles.lfutil.link(
600 largefiles.lfutil.link(
601 largefiles.lfutil.usercachepath(repo.ui, sha), path)
601 largefiles.lfutil.usercachepath(repo.ui, sha), path)
602
602
603 @reraise_safe_exceptions
603 @reraise_safe_exceptions
604 def localrepository(self, wire, create=False):
604 def localrepository(self, wire, create=False):
605 self._factory.repo(wire, create=create)
605 self._factory.repo(wire, create=create)
606
606
607 @reraise_safe_exceptions
607 @reraise_safe_exceptions
608 def lookup(self, wire, revision, both):
608 def lookup(self, wire, revision, both):
609 cache_on, context_uid, repo_id = self._cache_on(wire)
609 cache_on, context_uid, repo_id = self._cache_on(wire)
610 @self.region.conditional_cache_on_arguments(condition=cache_on)
610 @self.region.conditional_cache_on_arguments(condition=cache_on)
611 def _lookup(_context_uid, _repo_id, _revision, _both):
611 def _lookup(_context_uid, _repo_id, _revision, _both):
612
612
613 repo = self._factory.repo(wire)
613 repo = self._factory.repo(wire)
614 rev = _revision
614 rev = _revision
615 if isinstance(rev, int):
615 if isinstance(rev, int):
616 # NOTE(marcink):
616 # NOTE(marcink):
617 # since Mercurial doesn't support negative indexes properly
617 # since Mercurial doesn't support negative indexes properly
618 # we need to shift accordingly by one to get proper index, e.g
618 # we need to shift accordingly by one to get proper index, e.g
619 # repo[-1] => repo[-2]
619 # repo[-1] => repo[-2]
620 # repo[0] => repo[-1]
620 # repo[0] => repo[-1]
621 if rev <= 0:
621 if rev <= 0:
622 rev = rev + -1
622 rev = rev + -1
623 try:
623 try:
624 ctx = self._get_ctx(repo, rev)
624 ctx = self._get_ctx(repo, rev)
625 except (TypeError, RepoLookupError) as e:
625 except (TypeError, RepoLookupError) as e:
626 e._org_exc_tb = traceback.format_exc()
626 e._org_exc_tb = traceback.format_exc()
627 raise exceptions.LookupException(e)(rev)
627 raise exceptions.LookupException(e)(rev)
628 except LookupError as e:
628 except LookupError as e:
629 e._org_exc_tb = traceback.format_exc()
629 e._org_exc_tb = traceback.format_exc()
630 raise exceptions.LookupException(e)(e.name)
630 raise exceptions.LookupException(e)(e.name)
631
631
632 if not both:
632 if not both:
633 return ctx.hex()
633 return ctx.hex()
634
634
635 ctx = repo[ctx.hex()]
635 ctx = repo[ctx.hex()]
636 return ctx.hex(), ctx.rev()
636 return ctx.hex(), ctx.rev()
637
637
638 return _lookup(context_uid, repo_id, revision, both)
638 return _lookup(context_uid, repo_id, revision, both)
639
639
640 @reraise_safe_exceptions
640 @reraise_safe_exceptions
641 def sync_push(self, wire, url):
641 def sync_push(self, wire, url):
642 if not self.check_url(url, wire['config']):
642 if not self.check_url(url, wire['config']):
643 return
643 return
644
644
645 repo = self._factory.repo(wire)
645 repo = self._factory.repo(wire)
646
646
647 # Disable any prompts for this repo
647 # Disable any prompts for this repo
648 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
648 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
649
649
650 bookmarks = dict(repo._bookmarks).keys()
650 bookmarks = dict(repo._bookmarks).keys()
651 remote = peer(repo, {}, url)
651 remote = peer(repo, {}, url)
652 # Disable any prompts for this remote
652 # Disable any prompts for this remote
653 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
653 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
654
654
655 return exchange.push(
655 return exchange.push(
656 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
656 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
657
657
658 @reraise_safe_exceptions
658 @reraise_safe_exceptions
659 def revision(self, wire, rev):
659 def revision(self, wire, rev):
660 repo = self._factory.repo(wire)
660 repo = self._factory.repo(wire)
661 ctx = self._get_ctx(repo, rev)
661 ctx = self._get_ctx(repo, rev)
662 return ctx.rev()
662 return ctx.rev()
663
663
664 @reraise_safe_exceptions
664 @reraise_safe_exceptions
665 def rev_range(self, wire, commit_filter):
665 def rev_range(self, wire, commit_filter):
666 cache_on, context_uid, repo_id = self._cache_on(wire)
666 cache_on, context_uid, repo_id = self._cache_on(wire)
667
667
668 @self.region.conditional_cache_on_arguments(condition=cache_on)
668 @self.region.conditional_cache_on_arguments(condition=cache_on)
669 def _rev_range(_context_uid, _repo_id, _filter):
669 def _rev_range(_context_uid, _repo_id, _filter):
670 repo = self._factory.repo(wire)
670 repo = self._factory.repo(wire)
671 revisions = [rev for rev in revrange(repo, commit_filter)]
671 revisions = [rev for rev in revrange(repo, commit_filter)]
672 return revisions
672 return revisions
673
673
674 return _rev_range(context_uid, repo_id, sorted(commit_filter))
674 return _rev_range(context_uid, repo_id, sorted(commit_filter))
675
675
676 @reraise_safe_exceptions
676 @reraise_safe_exceptions
677 def rev_range_hash(self, wire, node):
677 def rev_range_hash(self, wire, node):
678 repo = self._factory.repo(wire)
678 repo = self._factory.repo(wire)
679
679
680 def get_revs(repo, rev_opt):
680 def get_revs(repo, rev_opt):
681 if rev_opt:
681 if rev_opt:
682 revs = revrange(repo, rev_opt)
682 revs = revrange(repo, rev_opt)
683 if len(revs) == 0:
683 if len(revs) == 0:
684 return (nullrev, nullrev)
684 return (nullrev, nullrev)
685 return max(revs), min(revs)
685 return max(revs), min(revs)
686 else:
686 else:
687 return len(repo) - 1, 0
687 return len(repo) - 1, 0
688
688
689 stop, start = get_revs(repo, [node + ':'])
689 stop, start = get_revs(repo, [node + ':'])
690 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
690 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
691 return revs
691 return revs
692
692
693 @reraise_safe_exceptions
693 @reraise_safe_exceptions
694 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
694 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
695 other_path = kwargs.pop('other_path', None)
695 other_path = kwargs.pop('other_path', None)
696
696
697 # case when we want to compare two independent repositories
697 # case when we want to compare two independent repositories
698 if other_path and other_path != wire["path"]:
698 if other_path and other_path != wire["path"]:
699 baseui = self._factory._create_config(wire["config"])
699 baseui = self._factory._create_config(wire["config"])
700 repo = unionrepo.makeunionrepository(baseui, other_path, wire["path"])
700 repo = unionrepo.makeunionrepository(baseui, other_path, wire["path"])
701 else:
701 else:
702 repo = self._factory.repo(wire)
702 repo = self._factory.repo(wire)
703 return list(repo.revs(rev_spec, *args))
703 return list(repo.revs(rev_spec, *args))
704
704
705 @reraise_safe_exceptions
705 @reraise_safe_exceptions
706 def verify(self, wire,):
706 def verify(self, wire,):
707 repo = self._factory.repo(wire)
707 repo = self._factory.repo(wire)
708 baseui = self._factory._create_config(wire['config'])
708 baseui = self._factory._create_config(wire['config'])
709 baseui.setconfig('ui', 'quiet', 'false')
709 baseui.setconfig('ui', 'quiet', 'false')
710 output = io.BytesIO()
710 output = io.BytesIO()
711
711
712 def write(data, **unused_kwargs):
712 def write(data, **unused_kwargs):
713 output.write(data)
713 output.write(data)
714 baseui.write = write
714 baseui.write = write
715
715
716 repo.ui = baseui
716 repo.ui = baseui
717 verify.verify(repo)
717 verify.verify(repo)
718 return output.getvalue()
718 return output.getvalue()
719
719
720 @reraise_safe_exceptions
720 @reraise_safe_exceptions
721 def hg_update_cache(self, wire,):
721 def hg_update_cache(self, wire,):
722 repo = self._factory.repo(wire)
722 repo = self._factory.repo(wire)
723 baseui = self._factory._create_config(wire['config'])
723 baseui = self._factory._create_config(wire['config'])
724 baseui.setconfig('ui', 'quiet', 'false')
724 baseui.setconfig('ui', 'quiet', 'false')
725 output = io.BytesIO()
725 output = io.BytesIO()
726
726
727 def write(data, **unused_kwargs):
727 def write(data, **unused_kwargs):
728 output.write(data)
728 output.write(data)
729 baseui.write = write
729 baseui.write = write
730
730
731 repo.ui = baseui
731 repo.ui = baseui
732 with repo.wlock(), repo.lock():
732 with repo.wlock(), repo.lock():
733 repo.updatecaches(full=True)
733 repo.updatecaches(full=True)
734
734
735 return output.getvalue()
735 return output.getvalue()
736
736
737 @reraise_safe_exceptions
737 @reraise_safe_exceptions
738 def tags(self, wire):
738 def tags(self, wire):
739 cache_on, context_uid, repo_id = self._cache_on(wire)
739 cache_on, context_uid, repo_id = self._cache_on(wire)
740 @self.region.conditional_cache_on_arguments(condition=cache_on)
740 @self.region.conditional_cache_on_arguments(condition=cache_on)
741 def _tags(_context_uid, _repo_id):
741 def _tags(_context_uid, _repo_id):
742 repo = self._factory.repo(wire)
742 repo = self._factory.repo(wire)
743 return repo.tags()
743 return repo.tags()
744
744
745 return _tags(context_uid, repo_id)
745 return _tags(context_uid, repo_id)
746
746
747 @reraise_safe_exceptions
747 @reraise_safe_exceptions
748 def update(self, wire, node=None, clean=False):
748 def update(self, wire, node=None, clean=False):
749 repo = self._factory.repo(wire)
749 repo = self._factory.repo(wire)
750 baseui = self._factory._create_config(wire['config'])
750 baseui = self._factory._create_config(wire['config'])
751 commands.update(baseui, repo, node=node, clean=clean)
751 commands.update(baseui, repo, node=node, clean=clean)
752
752
753 @reraise_safe_exceptions
753 @reraise_safe_exceptions
754 def identify(self, wire):
754 def identify(self, wire):
755 repo = self._factory.repo(wire)
755 repo = self._factory.repo(wire)
756 baseui = self._factory._create_config(wire['config'])
756 baseui = self._factory._create_config(wire['config'])
757 output = io.BytesIO()
757 output = io.BytesIO()
758 baseui.write = output.write
758 baseui.write = output.write
759 # This is required to get a full node id
759 # This is required to get a full node id
760 baseui.debugflag = True
760 baseui.debugflag = True
761 commands.identify(baseui, repo, id=True)
761 commands.identify(baseui, repo, id=True)
762
762
763 return output.getvalue()
763 return output.getvalue()
764
764
765 @reraise_safe_exceptions
765 @reraise_safe_exceptions
766 def heads(self, wire, branch=None):
766 def heads(self, wire, branch=None):
767 repo = self._factory.repo(wire)
767 repo = self._factory.repo(wire)
768 baseui = self._factory._create_config(wire['config'])
768 baseui = self._factory._create_config(wire['config'])
769 output = io.BytesIO()
769 output = io.BytesIO()
770
770
771 def write(data, **unused_kwargs):
771 def write(data, **unused_kwargs):
772 output.write(data)
772 output.write(data)
773
773
774 baseui.write = write
774 baseui.write = write
775 if branch:
775 if branch:
776 args = [branch]
776 args = [branch]
777 else:
777 else:
778 args = []
778 args = []
779 commands.heads(baseui, repo, template='{node} ', *args)
779 commands.heads(baseui, repo, template='{node} ', *args)
780
780
781 return output.getvalue()
781 return output.getvalue()
782
782
783 @reraise_safe_exceptions
783 @reraise_safe_exceptions
784 def ancestor(self, wire, revision1, revision2):
784 def ancestor(self, wire, revision1, revision2):
785 repo = self._factory.repo(wire)
785 repo = self._factory.repo(wire)
786 changelog = repo.changelog
786 changelog = repo.changelog
787 lookup = repo.lookup
787 lookup = repo.lookup
788 a = changelog.ancestor(lookup(revision1), lookup(revision2))
788 a = changelog.ancestor(lookup(revision1), lookup(revision2))
789 return hex(a)
789 return hex(a)
790
790
791 @reraise_safe_exceptions
791 @reraise_safe_exceptions
792 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
792 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
793 baseui = self._factory._create_config(wire["config"], hooks=hooks)
793 baseui = self._factory._create_config(wire["config"], hooks=hooks)
794 clone(baseui, source, dest, noupdate=not update_after_clone)
794 clone(baseui, source, dest, noupdate=not update_after_clone)
795
795
796 @reraise_safe_exceptions
796 @reraise_safe_exceptions
797 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
797 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
798
798
799 repo = self._factory.repo(wire)
799 repo = self._factory.repo(wire)
800 baseui = self._factory._create_config(wire['config'])
800 baseui = self._factory._create_config(wire['config'])
801 publishing = baseui.configbool('phases', 'publish')
801 publishing = baseui.configbool('phases', 'publish')
802 if publishing:
802 if publishing:
803 new_commit = 'public'
803 new_commit = 'public'
804 else:
804 else:
805 new_commit = 'draft'
805 new_commit = 'draft'
806
806
807 def _filectxfn(_repo, ctx, path):
807 def _filectxfn(_repo, ctx, path):
808 """
808 """
809 Marks given path as added/changed/removed in a given _repo. This is
809 Marks given path as added/changed/removed in a given _repo. This is
810 for internal mercurial commit function.
810 for internal mercurial commit function.
811 """
811 """
812
812
813 # check if this path is removed
813 # check if this path is removed
814 if path in removed:
814 if path in removed:
815 # returning None is a way to mark node for removal
815 # returning None is a way to mark node for removal
816 return None
816 return None
817
817
818 # check if this path is added
818 # check if this path is added
819 for node in updated:
819 for node in updated:
820 if node['path'] == path:
820 if node['path'] == path:
821 return memfilectx(
821 return memfilectx(
822 _repo,
822 _repo,
823 changectx=ctx,
823 changectx=ctx,
824 path=node['path'],
824 path=node['path'],
825 data=node['content'],
825 data=node['content'],
826 islink=False,
826 islink=False,
827 isexec=bool(node['mode'] & stat.S_IXUSR),
827 isexec=bool(node['mode'] & stat.S_IXUSR),
828 copysource=False)
828 copysource=False)
829
829
830 raise exceptions.AbortException()(
830 raise exceptions.AbortException()(
831 "Given path haven't been marked as added, "
831 "Given path haven't been marked as added, "
832 "changed or removed (%s)" % path)
832 "changed or removed (%s)" % path)
833
833
834 with repo.ui.configoverride({('phases', 'new-commit'): new_commit}):
834 with repo.ui.configoverride({('phases', 'new-commit'): new_commit}):
835
835
836 commit_ctx = memctx(
836 commit_ctx = memctx(
837 repo=repo,
837 repo=repo,
838 parents=parents,
838 parents=parents,
839 text=message,
839 text=message,
840 files=files,
840 files=files,
841 filectxfn=_filectxfn,
841 filectxfn=_filectxfn,
842 user=user,
842 user=user,
843 date=(commit_time, commit_timezone),
843 date=(commit_time, commit_timezone),
844 extra=extra)
844 extra=extra)
845
845
846 n = repo.commitctx(commit_ctx)
846 n = repo.commitctx(commit_ctx)
847 new_id = hex(n)
847 new_id = hex(n)
848
848
849 return new_id
849 return new_id
850
850
851 @reraise_safe_exceptions
851 @reraise_safe_exceptions
852 def pull(self, wire, url, commit_ids=None):
852 def pull(self, wire, url, commit_ids=None):
853 repo = self._factory.repo(wire)
853 repo = self._factory.repo(wire)
854 # Disable any prompts for this repo
854 # Disable any prompts for this repo
855 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
855 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
856
856
857 remote = peer(repo, {}, url)
857 remote = peer(repo, {}, url)
858 # Disable any prompts for this remote
858 # Disable any prompts for this remote
859 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
859 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
860
860
861 if commit_ids:
861 if commit_ids:
862 commit_ids = [bin(commit_id) for commit_id in commit_ids]
862 commit_ids = [bin(commit_id) for commit_id in commit_ids]
863
863
864 return exchange.pull(
864 return exchange.pull(
865 repo, remote, heads=commit_ids, force=None).cgresult
865 repo, remote, heads=commit_ids, force=None).cgresult
866
866
867 @reraise_safe_exceptions
867 @reraise_safe_exceptions
868 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None, hooks=True):
868 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None, hooks=True):
869 repo = self._factory.repo(wire)
869 repo = self._factory.repo(wire)
870 baseui = self._factory._create_config(wire['config'], hooks=hooks)
870 baseui = self._factory._create_config(wire['config'], hooks=hooks)
871
871
872 # Mercurial internally has a lot of logic that checks ONLY if
872 # Mercurial internally has a lot of logic that checks ONLY if
873 # option is defined, we just pass those if they are defined then
873 # option is defined, we just pass those if they are defined then
874 opts = {}
874 opts = {}
875 if bookmark:
875 if bookmark:
876 opts['bookmark'] = bookmark
876 opts['bookmark'] = bookmark
877 if branch:
877 if branch:
878 opts['branch'] = branch
878 opts['branch'] = branch
879 if revision:
879 if revision:
880 opts['rev'] = revision
880 opts['rev'] = revision
881
881
882 commands.pull(baseui, repo, source, **opts)
882 commands.pull(baseui, repo, source, **opts)
883
883
884 @reraise_safe_exceptions
884 @reraise_safe_exceptions
885 def push(self, wire, revisions, dest_path, hooks=True, push_branches=False):
885 def push(self, wire, revisions, dest_path, hooks=True, push_branches=False):
886 repo = self._factory.repo(wire)
886 repo = self._factory.repo(wire)
887 baseui = self._factory._create_config(wire['config'], hooks=hooks)
887 baseui = self._factory._create_config(wire['config'], hooks=hooks)
888 commands.push(baseui, repo, dest=dest_path, rev=revisions,
888 commands.push(baseui, repo, dest=dest_path, rev=revisions,
889 new_branch=push_branches)
889 new_branch=push_branches)
890
890
891 @reraise_safe_exceptions
891 @reraise_safe_exceptions
892 def strip(self, wire, revision, update, backup):
892 def strip(self, wire, revision, update, backup):
893 repo = self._factory.repo(wire)
893 repo = self._factory.repo(wire)
894 ctx = self._get_ctx(repo, revision)
894 ctx = self._get_ctx(repo, revision)
895 hgext_strip(
895 hgext_strip(
896 repo.baseui, repo, ctx.node(), update=update, backup=backup)
896 repo.baseui, repo, ctx.node(), update=update, backup=backup)
897
897
898 @reraise_safe_exceptions
898 @reraise_safe_exceptions
899 def get_unresolved_files(self, wire):
900 repo = self._factory.repo(wire)
901
902 log.debug('Calculating unresolved files for repo: %s', repo)
903 output = io.BytesIO()
904
905 def write(data, **unused_kwargs):
906 output.write(data)
907
908 baseui = self._factory._create_config(wire['config'])
909 baseui.write = write
910
911 commands.resolve(baseui, repo, list=True)
912 unresolved = output.getvalue().splitlines(0)
913 return unresolved
914
915 @reraise_safe_exceptions
899 def merge(self, wire, revision):
916 def merge(self, wire, revision):
900 repo = self._factory.repo(wire)
917 repo = self._factory.repo(wire)
901 baseui = self._factory._create_config(wire['config'])
918 baseui = self._factory._create_config(wire['config'])
902 repo.ui.setconfig('ui', 'merge', 'internal:dump')
919 repo.ui.setconfig('ui', 'merge', 'internal:dump')
903
920
904 # In case of sub repositories are used mercurial prompts the user in
921 # In case of sub repositories are used mercurial prompts the user in
905 # case of merge conflicts or different sub repository sources. By
922 # case of merge conflicts or different sub repository sources. By
906 # setting the interactive flag to `False` mercurial doesn't prompt the
923 # setting the interactive flag to `False` mercurial doesn't prompt the
907 # used but instead uses a default value.
924 # used but instead uses a default value.
908 repo.ui.setconfig('ui', 'interactive', False)
925 repo.ui.setconfig('ui', 'interactive', False)
909 commands.merge(baseui, repo, rev=revision)
926 commands.merge(baseui, repo, rev=revision)
910
927
911 @reraise_safe_exceptions
928 @reraise_safe_exceptions
912 def merge_state(self, wire):
929 def merge_state(self, wire):
913 repo = self._factory.repo(wire)
930 repo = self._factory.repo(wire)
914 repo.ui.setconfig('ui', 'merge', 'internal:dump')
931 repo.ui.setconfig('ui', 'merge', 'internal:dump')
915
932
916 # In case of sub repositories are used mercurial prompts the user in
933 # In case of sub repositories are used mercurial prompts the user in
917 # case of merge conflicts or different sub repository sources. By
934 # case of merge conflicts or different sub repository sources. By
918 # setting the interactive flag to `False` mercurial doesn't prompt the
935 # setting the interactive flag to `False` mercurial doesn't prompt the
919 # used but instead uses a default value.
936 # used but instead uses a default value.
920 repo.ui.setconfig('ui', 'interactive', False)
937 repo.ui.setconfig('ui', 'interactive', False)
921 ms = hg_merge.mergestate(repo)
938 ms = hg_merge.mergestate(repo)
922 return [x for x in ms.unresolved()]
939 return [x for x in ms.unresolved()]
923
940
924 @reraise_safe_exceptions
941 @reraise_safe_exceptions
925 def commit(self, wire, message, username, close_branch=False):
942 def commit(self, wire, message, username, close_branch=False):
926 repo = self._factory.repo(wire)
943 repo = self._factory.repo(wire)
927 baseui = self._factory._create_config(wire['config'])
944 baseui = self._factory._create_config(wire['config'])
928 repo.ui.setconfig('ui', 'username', username)
945 repo.ui.setconfig('ui', 'username', username)
929 commands.commit(baseui, repo, message=message, close_branch=close_branch)
946 commands.commit(baseui, repo, message=message, close_branch=close_branch)
930
947
931 @reraise_safe_exceptions
948 @reraise_safe_exceptions
932 def rebase(self, wire, source=None, dest=None, abort=False):
949 def rebase(self, wire, source=None, dest=None, abort=False):
933 repo = self._factory.repo(wire)
950 repo = self._factory.repo(wire)
934 baseui = self._factory._create_config(wire['config'])
951 baseui = self._factory._create_config(wire['config'])
935 repo.ui.setconfig('ui', 'merge', 'internal:dump')
952 repo.ui.setconfig('ui', 'merge', 'internal:dump')
936 rebase.rebase(
953 # In case of sub repositories are used mercurial prompts the user in
937 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
954 # case of merge conflicts or different sub repository sources. By
955 # setting the interactive flag to `False` mercurial doesn't prompt the
956 # used but instead uses a default value.
957 repo.ui.setconfig('ui', 'interactive', False)
958 rebase.rebase(baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
938
959
939 @reraise_safe_exceptions
960 @reraise_safe_exceptions
940 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
961 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
941 repo = self._factory.repo(wire)
962 repo = self._factory.repo(wire)
942 ctx = self._get_ctx(repo, revision)
963 ctx = self._get_ctx(repo, revision)
943 node = ctx.node()
964 node = ctx.node()
944
965
945 date = (tag_time, tag_timezone)
966 date = (tag_time, tag_timezone)
946 try:
967 try:
947 hg_tag.tag(repo, name, node, message, local, user, date)
968 hg_tag.tag(repo, name, node, message, local, user, date)
948 except Abort as e:
969 except Abort as e:
949 log.exception("Tag operation aborted")
970 log.exception("Tag operation aborted")
950 # Exception can contain unicode which we convert
971 # Exception can contain unicode which we convert
951 raise exceptions.AbortException(e)(repr(e))
972 raise exceptions.AbortException(e)(repr(e))
952
973
953 @reraise_safe_exceptions
974 @reraise_safe_exceptions
954 def bookmark(self, wire, bookmark, revision=None):
975 def bookmark(self, wire, bookmark, revision=None):
955 repo = self._factory.repo(wire)
976 repo = self._factory.repo(wire)
956 baseui = self._factory._create_config(wire['config'])
977 baseui = self._factory._create_config(wire['config'])
957 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
978 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
958
979
959 @reraise_safe_exceptions
980 @reraise_safe_exceptions
960 def install_hooks(self, wire, force=False):
981 def install_hooks(self, wire, force=False):
961 # we don't need any special hooks for Mercurial
982 # we don't need any special hooks for Mercurial
962 pass
983 pass
963
984
964 @reraise_safe_exceptions
985 @reraise_safe_exceptions
965 def get_hooks_info(self, wire):
986 def get_hooks_info(self, wire):
966 return {
987 return {
967 'pre_version': vcsserver.__version__,
988 'pre_version': vcsserver.__version__,
968 'post_version': vcsserver.__version__,
989 'post_version': vcsserver.__version__,
969 }
990 }
General Comments 0
You need to be logged in to leave comments. Login now