Show More
@@ -211,12 +211,12 b' class HgRemote(object):' | |||
|
211 | 211 | if node['path'] == path: |
|
212 | 212 | return memfilectx( |
|
213 | 213 | _repo, |
|
214 | changectx=memctx, | |
|
214 | 215 | path=node['path'], |
|
215 | 216 | data=node['content'], |
|
216 | 217 | islink=False, |
|
217 | 218 | isexec=bool(node['mode'] & stat.S_IXUSR), |
|
218 |
copied=False |
|
|
219 | memctx=memctx) | |
|
219 | copied=False) | |
|
220 | 220 | |
|
221 | 221 | raise exceptions.AbortException( |
|
222 | 222 | "Given path haven't been marked as added, " |
@@ -454,9 +454,10 b' class HgRemote(object):' | |||
|
454 | 454 | fctx = ctx.filectx(path) |
|
455 | 455 | |
|
456 | 456 | result = [] |
|
457 |
for i, |
|
|
458 |
ln_no = i |
|
|
459 |
sha = hex(a |
|
|
457 | for i, annotate_obj in enumerate(fctx.annotate(), 1): | |
|
458 | ln_no = i | |
|
459 | sha = hex(annotate_obj.fctx.node()) | |
|
460 | content = annotate_obj.text | |
|
460 | 461 | result.append((ln_no, sha, content)) |
|
461 | 462 | return result |
|
462 | 463 | |
@@ -533,10 +534,22 b' class HgRemote(object):' | |||
|
533 | 534 | |
|
534 | 535 | @reraise_safe_exceptions |
|
535 | 536 | def lookup(self, wire, revision, both): |
|
536 | # TODO Paris: Ugly hack to "deserialize" long for msgpack | |
|
537 | if isinstance(revision, float): | |
|
538 | revision = long(revision) | |
|
537 | ||
|
539 | 538 | repo = self._factory.repo(wire) |
|
539 | ||
|
540 | if isinstance(revision, int): | |
|
541 | # NOTE(marcink): | |
|
542 | # since Mercurial doesn't support indexes properly | |
|
543 | # we need to shift accordingly by one to get proper index, e.g | |
|
544 | # repo[-1] => repo[-2] | |
|
545 | # repo[0] => repo[-1] | |
|
546 | # repo[1] => repo[2] we also never call repo[0] because | |
|
547 | # it's actually second commit | |
|
548 | if revision <= 0: | |
|
549 | revision = revision + -1 | |
|
550 | else: | |
|
551 | revision = revision + 1 | |
|
552 | ||
|
540 | 553 | try: |
|
541 | 554 | ctx = repo[revision] |
|
542 | 555 | except RepoLookupError: |
@@ -36,15 +36,15 b' def patch_largefiles_capabilities():' | |||
|
36 | 36 | lfproto = hgcompat.largefiles.proto |
|
37 | 37 | wrapper = _dynamic_capabilities_wrapper( |
|
38 | 38 | lfproto, hgcompat.extensions.extensions) |
|
39 | lfproto.capabilities = wrapper | |
|
39 | lfproto._capabilities = wrapper | |
|
40 | 40 | |
|
41 | 41 | |
|
42 | 42 | def _dynamic_capabilities_wrapper(lfproto, extensions): |
|
43 | 43 | |
|
44 | wrapped_capabilities = lfproto.capabilities | |
|
44 | wrapped_capabilities = lfproto._capabilities | |
|
45 | 45 | logger = logging.getLogger('vcsserver.hg') |
|
46 | 46 | |
|
47 | def _dynamic_capabilities(repo, proto): | |
|
47 | def _dynamic_capabilities(orig, repo, proto): | |
|
48 | 48 | """ |
|
49 | 49 | Adds dynamic behavior, so that the capability is only added if the |
|
50 | 50 | extension is enabled in the current ui object. |
@@ -52,10 +52,10 b' def _dynamic_capabilities_wrapper(lfprot' | |||
|
52 | 52 | if 'largefiles' in dict(extensions(repo.ui)): |
|
53 | 53 | logger.debug('Extension largefiles enabled') |
|
54 | 54 | calc_capabilities = wrapped_capabilities |
|
55 | return calc_capabilities(orig, repo, proto) | |
|
55 | 56 | else: |
|
56 | 57 | logger.debug('Extension largefiles disabled') |
|
57 | calc_capabilities = lfproto.capabilitiesorig | |
|
58 | return calc_capabilities(repo, proto) | |
|
58 | return orig(repo, proto) | |
|
59 | 59 | |
|
60 | 60 | return _dynamic_capabilities |
|
61 | 61 |
@@ -164,7 +164,8 b' def _extras_from_ui(ui):' | |||
|
164 | 164 | def _rev_range_hash(repo, node): |
|
165 | 165 | |
|
166 | 166 | commits = [] |
|
167 | for rev in xrange(repo[node], len(repo)): | |
|
167 | start = repo[node].rev() | |
|
168 | for rev in xrange(start, len(repo)): | |
|
168 | 169 | ctx = repo[rev] |
|
169 | 170 | commit_id = mercurial.node.hex(ctx.node()) |
|
170 | 171 | branch = ctx.branch() |
@@ -21,9 +21,9 b' import itertools' | |||
|
21 | 21 | |
|
22 | 22 | import mercurial |
|
23 | 23 | import mercurial.error |
|
24 | import mercurial.wireprotoserver | |
|
24 | 25 | import mercurial.hgweb.common |
|
25 | 26 | import mercurial.hgweb.hgweb_mod |
|
26 | import mercurial.hgweb.protocol | |
|
27 | 27 | import webob.exc |
|
28 | 28 | |
|
29 | 29 | from vcsserver import pygrack, exceptions, settings, git_lfs |
@@ -73,14 +73,18 b' class HgWeb(mercurial.hgweb.hgweb_mod.hg' | |||
|
73 | 73 | |
|
74 | 74 | This may be called by multiple threads. |
|
75 | 75 | """ |
|
76 |
|
|
|
77 | gen = self.run_wsgi(req) | |
|
76 | from mercurial.hgweb import request as requestmod | |
|
77 | req = requestmod.parserequestfromenv(environ) | |
|
78 | res = requestmod.wsgiresponse(req, start_response) | |
|
79 | gen = self.run_wsgi(req, res) | |
|
78 | 80 | |
|
79 | 81 | first_chunk = None |
|
80 | 82 | |
|
81 | 83 | try: |
|
82 | 84 | data = gen.next() |
|
83 | def first_chunk(): yield data | |
|
85 | ||
|
86 | def first_chunk(): | |
|
87 | yield data | |
|
84 | 88 | except StopIteration: |
|
85 | 89 | pass |
|
86 | 90 | |
@@ -88,17 +92,18 b' class HgWeb(mercurial.hgweb.hgweb_mod.hg' | |||
|
88 | 92 | return itertools.chain(first_chunk(), gen) |
|
89 | 93 | return gen |
|
90 | 94 | |
|
91 | def _runwsgi(self, req, repo): | |
|
92 | cmd = req.form.get('cmd', [''])[0] | |
|
93 | if not mercurial.hgweb.protocol.iscmd(cmd): | |
|
94 | req.respond( | |
|
95 | mercurial.hgweb.common.ErrorResponse( | |
|
96 | mercurial.hgweb.common.HTTP_BAD_REQUEST), | |
|
97 | mercurial.hgweb.protocol.HGTYPE | |
|
98 | ) | |
|
99 | return [''] | |
|
95 | def _runwsgi(self, req, res, repo): | |
|
100 | 96 | |
|
101 | return super(HgWeb, self)._runwsgi(req, repo) | |
|
97 | cmd = req.qsparams.get('cmd', '') | |
|
98 | if not mercurial.wireprotoserver.iscmd(cmd): | |
|
99 | # NOTE(marcink): for unsupported commands, we return bad request | |
|
100 | # internally from HG | |
|
101 | from mercurial.hgweb.common import statusmessage | |
|
102 | res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST) | |
|
103 | res.setbodybytes('') | |
|
104 | return res.sendresponse() | |
|
105 | ||
|
106 | return super(HgWeb, self)._runwsgi(req, res, repo) | |
|
102 | 107 | |
|
103 | 108 | |
|
104 | 109 | def make_hg_ui_from_config(repo_config): |
@@ -28,56 +28,45 b' def test_patch_largefiles_capabilities_a' | |||
|
28 | 28 | patched_capabilities): |
|
29 | 29 | lfproto = hgcompat.largefiles.proto |
|
30 | 30 | hgpatches.patch_largefiles_capabilities() |
|
31 | assert lfproto.capabilities.func_name == '_dynamic_capabilities' | |
|
31 | assert lfproto._capabilities.func_name == '_dynamic_capabilities' | |
|
32 | 32 | |
|
33 | 33 | |
|
34 | 34 | def test_dynamic_capabilities_uses_original_function_if_not_enabled( |
|
35 |
stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities |
|
|
35 | stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, | |
|
36 | orig_capabilities): | |
|
36 | 37 | dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( |
|
37 | 38 | hgcompat.largefiles.proto, stub_extensions) |
|
38 | 39 | |
|
39 | caps = dynamic_capabilities(stub_repo, stub_proto) | |
|
40 | caps = dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) | |
|
40 | 41 | |
|
41 | 42 | stub_extensions.assert_called_once_with(stub_ui) |
|
42 | 43 | assert LARGEFILES_CAPABILITY not in caps |
|
43 | 44 | |
|
44 | 45 | |
|
45 | def test_dynamic_capabilities_uses_updated_capabilitiesorig( | |
|
46 | stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities): | |
|
47 | dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( | |
|
48 | hgcompat.largefiles.proto, stub_extensions) | |
|
49 | ||
|
50 | # This happens when the extension is loaded for the first time, important | |
|
51 | # to ensure that an updated function is correctly picked up. | |
|
52 | hgcompat.largefiles.proto.capabilitiesorig = mock.Mock( | |
|
53 | return_value='REPLACED') | |
|
54 | ||
|
55 | caps = dynamic_capabilities(stub_repo, stub_proto) | |
|
56 | assert 'REPLACED' == caps | |
|
57 | ||
|
58 | ||
|
59 | 46 | def test_dynamic_capabilities_ignores_updated_capabilities( |
|
60 |
stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities |
|
|
47 | stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, | |
|
48 | orig_capabilities): | |
|
61 | 49 | stub_extensions.return_value = [('largefiles', mock.Mock())] |
|
62 | 50 | dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( |
|
63 | 51 | hgcompat.largefiles.proto, stub_extensions) |
|
64 | 52 | |
|
65 | 53 | # This happens when the extension is loaded for the first time, important |
|
66 | 54 | # to ensure that an updated function is correctly picked up. |
|
67 | hgcompat.largefiles.proto.capabilities = mock.Mock( | |
|
55 | hgcompat.largefiles.proto._capabilities = mock.Mock( | |
|
68 | 56 | side_effect=Exception('Must not be called')) |
|
69 | 57 | |
|
70 | dynamic_capabilities(stub_repo, stub_proto) | |
|
58 | dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) | |
|
71 | 59 | |
|
72 | 60 | |
|
73 | 61 | def test_dynamic_capabilities_uses_largefiles_if_enabled( |
|
74 |
stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities |
|
|
62 | stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, | |
|
63 | orig_capabilities): | |
|
75 | 64 | stub_extensions.return_value = [('largefiles', mock.Mock())] |
|
76 | 65 | |
|
77 | 66 | dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( |
|
78 | 67 | hgcompat.largefiles.proto, stub_extensions) |
|
79 | 68 | |
|
80 | caps = dynamic_capabilities(stub_repo, stub_proto) | |
|
69 | caps = dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) | |
|
81 | 70 | |
|
82 | 71 | stub_extensions.assert_called_once_with(stub_ui) |
|
83 | 72 | assert LARGEFILES_CAPABILITY in caps |
@@ -94,15 +83,11 b' def patched_capabilities(request):' | |||
|
94 | 83 | Patch in `capabilitiesorig` and restore both capability functions. |
|
95 | 84 | """ |
|
96 | 85 | lfproto = hgcompat.largefiles.proto |
|
97 | orig_capabilities = lfproto.capabilities | |
|
98 | orig_capabilitiesorig = lfproto.capabilitiesorig | |
|
99 | ||
|
100 | lfproto.capabilitiesorig = mock.Mock(return_value='ORIG') | |
|
86 | orig_capabilities = lfproto._capabilities | |
|
101 | 87 | |
|
102 | 88 | @request.addfinalizer |
|
103 | 89 | def restore(): |
|
104 | lfproto.capabilities = orig_capabilities | |
|
105 | lfproto.capabilitiesorig = orig_capabilitiesorig | |
|
90 | lfproto._capabilities = orig_capabilities | |
|
106 | 91 | |
|
107 | 92 | |
|
108 | 93 | @pytest.fixture |
@@ -120,6 +105,15 b' def stub_proto(stub_ui):' | |||
|
120 | 105 | |
|
121 | 106 | |
|
122 | 107 | @pytest.fixture |
|
108 | def orig_capabilities(): | |
|
109 | from mercurial.wireprotov1server import wireprotocaps | |
|
110 | ||
|
111 | def _capabilities(repo, proto): | |
|
112 | return wireprotocaps | |
|
113 | return _capabilities | |
|
114 | ||
|
115 | ||
|
116 | @pytest.fixture | |
|
123 | 117 | def stub_ui(): |
|
124 | 118 | return hgcompat.ui.ui() |
|
125 | 119 |
General Comments 0
You need to be logged in to leave comments.
Login now