##// END OF EJS Templates
chore(deps): bumped mercurial to 6.7.4, hg-evolve to 11.1.3, fixed related issues
andverb -
r1248:8cfec191 default
parent child Browse files
Show More
@@ -1,73 +1,73 b''
1 # deps, generated via pipdeptree --exclude setuptools,wheel,pipdeptree,pip -f | tr '[:upper:]' '[:lower:]'
1 # deps, generated via pipdeptree --exclude setuptools,wheel,pipdeptree,pip -f | tr '[:upper:]' '[:lower:]'
2
2
3 async-timeout==4.0.3
3 async-timeout==4.0.3
4 atomicwrites==1.4.1
4 atomicwrites==1.4.1
5 celery==5.3.6
5 celery==5.3.6
6 billiard==4.2.0
6 billiard==4.2.0
7 click==8.1.3
7 click==8.1.3
8 click-didyoumean==0.3.0
8 click-didyoumean==0.3.0
9 click==8.1.3
9 click==8.1.3
10 click-plugins==1.1.1
10 click-plugins==1.1.1
11 click==8.1.3
11 click==8.1.3
12 click-repl==0.2.0
12 click-repl==0.2.0
13 click==8.1.3
13 click==8.1.3
14 prompt-toolkit==3.0.38
14 prompt-toolkit==3.0.38
15 wcwidth==0.2.6
15 wcwidth==0.2.6
16 six==1.16.0
16 six==1.16.0
17 kombu==5.3.5
17 kombu==5.3.5
18 amqp==5.2.0
18 amqp==5.2.0
19 vine==5.1.0
19 vine==5.1.0
20 vine==5.1.0
20 vine==5.1.0
21 python-dateutil==2.8.2
21 python-dateutil==2.8.2
22 six==1.16.0
22 six==1.16.0
23 tzdata==2024.1
23 tzdata==2024.1
24 vine==5.1.0
24 vine==5.1.0
25 contextlib2==21.6.0
25 contextlib2==21.6.0
26 dogpile.cache==1.3.3
26 dogpile.cache==1.3.3
27 decorator==5.1.1
27 decorator==5.1.1
28 stevedore==5.1.0
28 stevedore==5.1.0
29 pbr==5.11.1
29 pbr==5.11.1
30 dulwich==0.21.6
30 dulwich==0.21.6
31 urllib3==1.26.14
31 urllib3==1.26.14
32 gunicorn==21.2.0
32 gunicorn==21.2.0
33 packaging==24.0
33 packaging==24.0
34 hg-evolve==11.0.2
34 hg-evolve==11.1.3
35 importlib-metadata==6.0.0
35 importlib-metadata==6.0.0
36 zipp==3.15.0
36 zipp==3.15.0
37 mercurial==6.3.3
37 mercurial==6.7.4
38 more-itertools==9.1.0
38 more-itertools==9.1.0
39 msgpack==1.0.8
39 msgpack==1.0.8
40 orjson==3.10.3
40 orjson==3.10.3
41 psutil==5.9.8
41 psutil==5.9.8
42 py==1.11.0
42 py==1.11.0
43 pygit2==1.13.3
43 pygit2==1.13.3
44 cffi==1.16.0
44 cffi==1.16.0
45 pycparser==2.21
45 pycparser==2.21
46 pygments==2.15.1
46 pygments==2.15.1
47 pyparsing==3.1.1
47 pyparsing==3.1.1
48 pyramid==2.0.2
48 pyramid==2.0.2
49 hupper==1.12
49 hupper==1.12
50 plaster==1.1.2
50 plaster==1.1.2
51 plaster-pastedeploy==1.0.1
51 plaster-pastedeploy==1.0.1
52 pastedeploy==3.1.0
52 pastedeploy==3.1.0
53 plaster==1.1.2
53 plaster==1.1.2
54 translationstring==1.4
54 translationstring==1.4
55 venusian==3.0.0
55 venusian==3.0.0
56 webob==1.8.7
56 webob==1.8.7
57 zope.deprecation==5.0.0
57 zope.deprecation==5.0.0
58 zope.interface==6.3.0
58 zope.interface==6.3.0
59 redis==5.0.4
59 redis==5.0.4
60 async-timeout==4.0.3
60 async-timeout==4.0.3
61 repoze.lru==0.7
61 repoze.lru==0.7
62 scandir==1.10.0
62 scandir==1.10.0
63 setproctitle==1.3.3
63 setproctitle==1.3.3
64 subvertpy==0.11.0
64 subvertpy==0.11.0
65 waitress==3.0.0
65 waitress==3.0.0
66 wcwidth==0.2.6
66 wcwidth==0.2.6
67
67
68
68
69 ## test related requirements
69 ## test related requirements
70 #-r requirements_test.txt
70 #-r requirements_test.txt
71
71
72 ## uncomment to add the debug libraries
72 ## uncomment to add the debug libraries
73 #-r requirements_debug.txt
73 #-r requirements_debug.txt
@@ -1,92 +1,92 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-2023 RhodeCode GmbH
2 # Copyright (C) 2014-2023 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 """
18 """
19 Mercurial libs compatibility
19 Mercurial libs compatibility
20 """
20 """
21
21
22 import mercurial
22 import mercurial
23 from mercurial import demandimport
23 from mercurial import demandimport
24
24
25 # patch demandimport, due to bug in mercurial when it always triggers
25 # patch demandimport, due to bug in mercurial when it always triggers
26 # demandimport.enable()
26 # demandimport.enable()
27 from vcsserver.str_utils import safe_bytes
27 from vcsserver.str_utils import safe_bytes
28
28
29 demandimport.enable = lambda *args, **kwargs: 1
29 demandimport.enable = lambda *args, **kwargs: 1
30
30
31 from mercurial import ui
31 from mercurial import ui
32 from mercurial import patch
32 from mercurial import patch
33 from mercurial import config
33 from mercurial import config
34 from mercurial import extensions
34 from mercurial import extensions
35 from mercurial import scmutil
35 from mercurial import scmutil
36 from mercurial import archival
36 from mercurial import archival
37 from mercurial import discovery
37 from mercurial import discovery
38 from mercurial import unionrepo
38 from mercurial import unionrepo
39 from mercurial import localrepo
39 from mercurial import localrepo
40 from mercurial import merge as hg_merge
40 from mercurial import merge as hg_merge
41 from mercurial import subrepo
41 from mercurial import subrepo
42 from mercurial import subrepoutil
42 from mercurial import subrepoutil
43 from mercurial import tags as hg_tag
43 from mercurial import tags as hg_tag
44 from mercurial import util as hgutil
44 from mercurial import util as hgutil
45 from mercurial.commands import clone, pull
45 from mercurial.commands import clone, pull
46 from mercurial.node import nullid
46 from mercurial.node import nullid
47 from mercurial.context import memctx, memfilectx
47 from mercurial.context import memctx, memfilectx
48 from mercurial.error import (
48 from mercurial.error import (
49 LookupError, RepoError, RepoLookupError, Abort, InterventionRequired,
49 LookupError, RepoError, RepoLookupError, Abort, InterventionRequired,
50 RequirementError, ProgrammingError)
50 RequirementError, ProgrammingError)
51 from mercurial.hgweb import hgweb_mod
51 from mercurial.hgweb import hgweb_mod
52 from mercurial.localrepo import instance
52 from mercurial.localrepo import instance
53 from mercurial.match import match, alwaysmatcher, patternmatcher
53 from mercurial.match import match, alwaysmatcher, patternmatcher
54 from mercurial.mdiff import diffopts
54 from mercurial.mdiff import diffopts
55 from mercurial.node import bin, hex
55 from mercurial.node import bin, hex
56 from mercurial.encoding import tolocal
56 from mercurial.encoding import tolocal
57 from mercurial.discovery import findcommonoutgoing
57 from mercurial.discovery import findcommonoutgoing
58 from mercurial.hg import peer
58 from mercurial.hg import peer
59 from mercurial.httppeer import makepeer
59 from mercurial.httppeer import make_peer
60 from mercurial.utils.urlutil import url as hg_url
60 from mercurial.utils.urlutil import url as hg_url
61 from mercurial.scmutil import revrange, revsymbol
61 from mercurial.scmutil import revrange, revsymbol
62 from mercurial.node import nullrev
62 from mercurial.node import nullrev
63 from mercurial import exchange
63 from mercurial import exchange
64 from hgext import largefiles
64 from hgext import largefiles
65
65
66 # those authnadlers are patched for python 2.6.5 bug an
66 # those authnadlers are patched for python 2.6.5 bug an
67 # infinit looping when given invalid resources
67 # infinit looping when given invalid resources
68 from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
68 from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
69
69
70 # hg strip is in core now
70 # hg strip is in core now
71 from mercurial import strip as hgext_strip
71 from mercurial import strip as hgext_strip
72
72
73
73
74 def get_ctx(repo, ref):
74 def get_ctx(repo, ref):
75 if not isinstance(ref, int):
75 if not isinstance(ref, int):
76 ref = safe_bytes(ref)
76 ref = safe_bytes(ref)
77
77
78 try:
78 try:
79 ctx = repo[ref]
79 ctx = repo[ref]
80 return ctx
80 return ctx
81 except (ProgrammingError, TypeError):
81 except (ProgrammingError, TypeError):
82 # we're unable to find the rev using a regular lookup, we fallback
82 # we're unable to find the rev using a regular lookup, we fallback
83 # to slower, but backward compat revsymbol usage
83 # to slower, but backward compat revsymbol usage
84 pass
84 pass
85 except (LookupError, RepoLookupError):
85 except (LookupError, RepoLookupError):
86 # Similar case as above but only for refs that are not numeric
86 # Similar case as above but only for refs that are not numeric
87 if isinstance(ref, int):
87 if isinstance(ref, int):
88 raise
88 raise
89
89
90 ctx = revsymbol(repo, ref)
90 ctx = revsymbol(repo, ref)
91
91
92 return ctx
92 return ctx
@@ -1,1213 +1,1216 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-2023 RhodeCode GmbH
2 # Copyright (C) 2014-2023 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 binascii
18 import binascii
19 import io
19 import io
20 import logging
20 import logging
21 import stat
21 import stat
22 import sys
22 import sys
23 import urllib.request
23 import urllib.request
24 import urllib.parse
24 import urllib.parse
25 import hashlib
25 import hashlib
26
26
27 from hgext import largefiles, rebase
27 from hgext import largefiles, rebase
28
28
29 from mercurial import commands
29 from mercurial import commands
30 from mercurial import unionrepo
30 from mercurial import unionrepo
31 from mercurial import verify
31 from mercurial import verify
32 from mercurial import repair
32 from mercurial import repair
33 from mercurial.error import AmbiguousPrefixLookupError
33 from mercurial.error import AmbiguousPrefixLookupError
34 from mercurial.utils.urlutil import path as hg_path
34
35
35 import vcsserver
36 import vcsserver
36 from vcsserver import exceptions
37 from vcsserver import exceptions
37 from vcsserver.base import (
38 from vcsserver.base import (
38 RepoFactory,
39 RepoFactory,
39 obfuscate_qs,
40 obfuscate_qs,
40 raise_from_original,
41 raise_from_original,
41 store_archive_in_cache,
42 store_archive_in_cache,
42 ArchiveNode,
43 ArchiveNode,
43 BytesEnvelope,
44 BytesEnvelope,
44 BinaryEnvelope,
45 BinaryEnvelope,
45 )
46 )
46 from vcsserver.hgcompat import (
47 from vcsserver.hgcompat import (
47 archival,
48 archival,
48 bin,
49 bin,
49 clone,
50 clone,
50 config as hgconfig,
51 config as hgconfig,
51 diffopts,
52 diffopts,
52 hex,
53 hex,
53 get_ctx,
54 get_ctx,
54 hg_url as url_parser,
55 hg_url as url_parser,
55 httpbasicauthhandler,
56 httpbasicauthhandler,
56 httpdigestauthhandler,
57 httpdigestauthhandler,
57 makepeer,
58 make_peer,
58 instance,
59 instance,
59 match,
60 match,
60 memctx,
61 memctx,
61 exchange,
62 exchange,
62 memfilectx,
63 memfilectx,
63 nullrev,
64 nullrev,
64 hg_merge,
65 hg_merge,
65 patch,
66 patch,
66 peer,
67 peer,
67 revrange,
68 revrange,
68 ui,
69 ui,
69 hg_tag,
70 hg_tag,
70 Abort,
71 Abort,
71 LookupError,
72 LookupError,
72 RepoError,
73 RepoError,
73 RepoLookupError,
74 RepoLookupError,
74 InterventionRequired,
75 InterventionRequired,
75 RequirementError,
76 RequirementError,
76 alwaysmatcher,
77 alwaysmatcher,
77 patternmatcher,
78 patternmatcher,
78 hgext_strip,
79 hgext_strip,
79 )
80 )
80 from vcsserver.str_utils import ascii_bytes, ascii_str, safe_str, safe_bytes, convert_to_str
81 from vcsserver.str_utils import ascii_bytes, ascii_str, safe_str, safe_bytes, convert_to_str
81 from vcsserver.vcs_base import RemoteBase
82 from vcsserver.vcs_base import RemoteBase
82 from vcsserver.config import hooks as hooks_config
83 from vcsserver.config import hooks as hooks_config
83 from vcsserver.lib.exc_tracking import format_exc
84 from vcsserver.lib.exc_tracking import format_exc
84
85
85 log = logging.getLogger(__name__)
86 log = logging.getLogger(__name__)
86
87
87
88
88 def make_ui_from_config(repo_config):
89 def make_ui_from_config(repo_config):
89
90
90 class LoggingUI(ui.ui):
91 class LoggingUI(ui.ui):
91
92
92 def status(self, *msg, **opts):
93 def status(self, *msg, **opts):
93 str_msg = map(safe_str, msg)
94 str_msg = map(safe_str, msg)
94 log.info(' '.join(str_msg).rstrip('\n'))
95 log.info(' '.join(str_msg).rstrip('\n'))
95 #super(LoggingUI, self).status(*msg, **opts)
96 #super(LoggingUI, self).status(*msg, **opts)
96
97
97 def warn(self, *msg, **opts):
98 def warn(self, *msg, **opts):
98 str_msg = map(safe_str, msg)
99 str_msg = map(safe_str, msg)
99 log.warning('ui_logger:'+' '.join(str_msg).rstrip('\n'))
100 log.warning('ui_logger:'+' '.join(str_msg).rstrip('\n'))
100 #super(LoggingUI, self).warn(*msg, **opts)
101 #super(LoggingUI, self).warn(*msg, **opts)
101
102
102 def error(self, *msg, **opts):
103 def error(self, *msg, **opts):
103 str_msg = map(safe_str, msg)
104 str_msg = map(safe_str, msg)
104 log.error('ui_logger:'+' '.join(str_msg).rstrip('\n'))
105 log.error('ui_logger:'+' '.join(str_msg).rstrip('\n'))
105 #super(LoggingUI, self).error(*msg, **opts)
106 #super(LoggingUI, self).error(*msg, **opts)
106
107
107 def note(self, *msg, **opts):
108 def note(self, *msg, **opts):
108 str_msg = map(safe_str, msg)
109 str_msg = map(safe_str, msg)
109 log.info('ui_logger:'+' '.join(str_msg).rstrip('\n'))
110 log.info('ui_logger:'+' '.join(str_msg).rstrip('\n'))
110 #super(LoggingUI, self).note(*msg, **opts)
111 #super(LoggingUI, self).note(*msg, **opts)
111
112
112 def debug(self, *msg, **opts):
113 def debug(self, *msg, **opts):
113 str_msg = map(safe_str, msg)
114 str_msg = map(safe_str, msg)
114 log.debug('ui_logger:'+' '.join(str_msg).rstrip('\n'))
115 log.debug('ui_logger:'+' '.join(str_msg).rstrip('\n'))
115 #super(LoggingUI, self).debug(*msg, **opts)
116 #super(LoggingUI, self).debug(*msg, **opts)
116
117
117 baseui = LoggingUI()
118 baseui = LoggingUI()
118
119
119 # clean the baseui object
120 # clean the baseui object
120 baseui._ocfg = hgconfig.config()
121 baseui._ocfg = hgconfig.config()
121 baseui._ucfg = hgconfig.config()
122 baseui._ucfg = hgconfig.config()
122 baseui._tcfg = hgconfig.config()
123 baseui._tcfg = hgconfig.config()
123
124
124 for section, option, value in repo_config:
125 for section, option, value in repo_config:
125 baseui.setconfig(ascii_bytes(section), ascii_bytes(option), ascii_bytes(value))
126 baseui.setconfig(ascii_bytes(section), ascii_bytes(option), ascii_bytes(value))
126
127
127 # make our hgweb quiet so it doesn't print output
128 # make our hgweb quiet so it doesn't print output
128 baseui.setconfig(b'ui', b'quiet', b'true')
129 baseui.setconfig(b'ui', b'quiet', b'true')
129
130
130 baseui.setconfig(b'ui', b'paginate', b'never')
131 baseui.setconfig(b'ui', b'paginate', b'never')
131 # for better Error reporting of Mercurial
132 # for better Error reporting of Mercurial
132 baseui.setconfig(b'ui', b'message-output', b'stderr')
133 baseui.setconfig(b'ui', b'message-output', b'stderr')
133
134
134 # force mercurial to only use 1 thread, otherwise it may try to set a
135 # force mercurial to only use 1 thread, otherwise it may try to set a
135 # signal in a non-main thread, thus generating a ValueError.
136 # signal in a non-main thread, thus generating a ValueError.
136 baseui.setconfig(b'worker', b'numcpus', 1)
137 baseui.setconfig(b'worker', b'numcpus', 1)
137
138
138 # If there is no config for the largefiles extension, we explicitly disable
139 # If there is no config for the largefiles extension, we explicitly disable
139 # it here. This overrides settings from repositories hgrc file. Recent
140 # it here. This overrides settings from repositories hgrc file. Recent
140 # mercurial versions enable largefiles in hgrc on clone from largefile
141 # mercurial versions enable largefiles in hgrc on clone from largefile
141 # repo.
142 # repo.
142 if not baseui.hasconfig(b'extensions', b'largefiles'):
143 if not baseui.hasconfig(b'extensions', b'largefiles'):
143 log.debug('Explicitly disable largefiles extension for repo.')
144 log.debug('Explicitly disable largefiles extension for repo.')
144 baseui.setconfig(b'extensions', b'largefiles', b'!')
145 baseui.setconfig(b'extensions', b'largefiles', b'!')
145
146
146 return baseui
147 return baseui
147
148
148
149
149 def reraise_safe_exceptions(func):
150 def reraise_safe_exceptions(func):
150 """Decorator for converting mercurial exceptions to something neutral."""
151 """Decorator for converting mercurial exceptions to something neutral."""
151
152
152 def wrapper(*args, **kwargs):
153 def wrapper(*args, **kwargs):
153 try:
154 try:
154 return func(*args, **kwargs)
155 return func(*args, **kwargs)
155 except (Abort, InterventionRequired) as e:
156 except (Abort, InterventionRequired) as e:
156 raise_from_original(exceptions.AbortException(e), e)
157 raise_from_original(exceptions.AbortException(e), e)
157 except RepoLookupError as e:
158 except RepoLookupError as e:
158 raise_from_original(exceptions.LookupException(e), e)
159 raise_from_original(exceptions.LookupException(e), e)
159 except RequirementError as e:
160 except RequirementError as e:
160 raise_from_original(exceptions.RequirementException(e), e)
161 raise_from_original(exceptions.RequirementException(e), e)
161 except RepoError as e:
162 except RepoError as e:
162 raise_from_original(exceptions.VcsException(e), e)
163 raise_from_original(exceptions.VcsException(e), e)
163 except LookupError as e:
164 except LookupError as e:
164 raise_from_original(exceptions.LookupException(e), e)
165 raise_from_original(exceptions.LookupException(e), e)
165 except Exception as e:
166 except Exception as e:
166 if not hasattr(e, '_vcs_kind'):
167 if not hasattr(e, '_vcs_kind'):
167 log.exception("Unhandled exception in hg remote call")
168 log.exception("Unhandled exception in hg remote call")
168 raise_from_original(exceptions.UnhandledException(e), e)
169 raise_from_original(exceptions.UnhandledException(e), e)
169
170
170 raise
171 raise
171 return wrapper
172 return wrapper
172
173
173
174
174 class MercurialFactory(RepoFactory):
175 class MercurialFactory(RepoFactory):
175 repo_type = 'hg'
176 repo_type = 'hg'
176
177
177 def _create_config(self, config, hooks=True):
178 def _create_config(self, config, hooks=True):
178 if not hooks:
179 if not hooks:
179
180
180 hooks_to_clean = {
181 hooks_to_clean = {
181
182
182 hooks_config.HOOK_REPO_SIZE,
183 hooks_config.HOOK_REPO_SIZE,
183 hooks_config.HOOK_PRE_PULL,
184 hooks_config.HOOK_PRE_PULL,
184 hooks_config.HOOK_PULL,
185 hooks_config.HOOK_PULL,
185
186
186 hooks_config.HOOK_PRE_PUSH,
187 hooks_config.HOOK_PRE_PUSH,
187 # TODO: what about PRETXT, this was disabled in pre 5.0.0
188 # TODO: what about PRETXT, this was disabled in pre 5.0.0
188 hooks_config.HOOK_PRETX_PUSH,
189 hooks_config.HOOK_PRETX_PUSH,
189
190
190 }
191 }
191 new_config = []
192 new_config = []
192 for section, option, value in config:
193 for section, option, value in config:
193 if section == 'hooks' and option in hooks_to_clean:
194 if section == 'hooks' and option in hooks_to_clean:
194 continue
195 continue
195 new_config.append((section, option, value))
196 new_config.append((section, option, value))
196 config = new_config
197 config = new_config
197
198
198 baseui = make_ui_from_config(config)
199 baseui = make_ui_from_config(config)
199 return baseui
200 return baseui
200
201
201 def _create_repo(self, wire, create):
202 def _create_repo(self, wire, create):
202 baseui = self._create_config(wire["config"])
203 baseui = self._create_config(wire["config"])
203 repo = instance(baseui, safe_bytes(wire["path"]), create)
204 repo = instance(baseui, safe_bytes(wire["path"]), create)
204 log.debug('repository created: got HG object: %s', repo)
205 log.debug('repository created: got HG object: %s', repo)
205 return repo
206 return repo
206
207
207 def repo(self, wire, create=False):
208 def repo(self, wire, create=False):
208 """
209 """
209 Get a repository instance for the given path.
210 Get a repository instance for the given path.
210 """
211 """
211 return self._create_repo(wire, create)
212 return self._create_repo(wire, create)
212
213
213
214
214 def patch_ui_message_output(baseui):
215 def patch_ui_message_output(baseui):
215 baseui.setconfig(b'ui', b'quiet', b'false')
216 baseui.setconfig(b'ui', b'quiet', b'false')
216 output = io.BytesIO()
217 output = io.BytesIO()
217
218
218 def write(data, **unused_kwargs):
219 def write(data, **unused_kwargs):
219 output.write(data)
220 output.write(data)
220
221
221 baseui.status = write
222 baseui.status = write
222 baseui.write = write
223 baseui.write = write
223 baseui.warn = write
224 baseui.warn = write
224 baseui.debug = write
225 baseui.debug = write
225
226
226 return baseui, output
227 return baseui, output
227
228
228
229
229 def get_obfuscated_url(url_obj):
230 def get_obfuscated_url(url_obj):
230 url_obj.passwd = b'*****' if url_obj.passwd else url_obj.passwd
231 url_obj.passwd = b'*****' if url_obj.passwd else url_obj.passwd
231 url_obj.query = obfuscate_qs(url_obj.query)
232 url_obj.query = obfuscate_qs(url_obj.query)
232 obfuscated_uri = str(url_obj)
233 obfuscated_uri = str(url_obj)
233 return obfuscated_uri
234 return obfuscated_uri
234
235
235
236
236 def normalize_url_for_hg(url: str):
237 def normalize_url_for_hg(url: str):
237 _proto = None
238 _proto = None
238
239
239 if '+' in url[:url.find('://')]:
240 if '+' in url[:url.find('://')]:
240 _proto = url[0:url.find('+')]
241 _proto = url[0:url.find('+')]
241 url = url[url.find('+') + 1:]
242 url = url[url.find('+') + 1:]
242 return url, _proto
243 return url, _proto
243
244
244
245
245 class HgRemote(RemoteBase):
246 class HgRemote(RemoteBase):
246
247
247 def __init__(self, factory):
248 def __init__(self, factory):
248 self._factory = factory
249 self._factory = factory
249 self._bulk_methods = {
250 self._bulk_methods = {
250 "affected_files": self.ctx_files,
251 "affected_files": self.ctx_files,
251 "author": self.ctx_user,
252 "author": self.ctx_user,
252 "branch": self.ctx_branch,
253 "branch": self.ctx_branch,
253 "children": self.ctx_children,
254 "children": self.ctx_children,
254 "date": self.ctx_date,
255 "date": self.ctx_date,
255 "message": self.ctx_description,
256 "message": self.ctx_description,
256 "parents": self.ctx_parents,
257 "parents": self.ctx_parents,
257 "status": self.ctx_status,
258 "status": self.ctx_status,
258 "obsolete": self.ctx_obsolete,
259 "obsolete": self.ctx_obsolete,
259 "phase": self.ctx_phase,
260 "phase": self.ctx_phase,
260 "hidden": self.ctx_hidden,
261 "hidden": self.ctx_hidden,
261 "_file_paths": self.ctx_list,
262 "_file_paths": self.ctx_list,
262 }
263 }
263 self._bulk_file_methods = {
264 self._bulk_file_methods = {
264 "size": self.fctx_size,
265 "size": self.fctx_size,
265 "data": self.fctx_node_data,
266 "data": self.fctx_node_data,
266 "flags": self.fctx_flags,
267 "flags": self.fctx_flags,
267 "is_binary": self.is_binary,
268 "is_binary": self.is_binary,
268 "md5": self.md5_hash,
269 "md5": self.md5_hash,
269 }
270 }
270
271
271 def _get_ctx(self, repo, ref):
272 def _get_ctx(self, repo, ref):
272 return get_ctx(repo, ref)
273 return get_ctx(repo, ref)
273
274
274 @reraise_safe_exceptions
275 @reraise_safe_exceptions
275 def discover_hg_version(self):
276 def discover_hg_version(self):
276 from mercurial import util
277 from mercurial import util
277 return safe_str(util.version())
278 return safe_str(util.version())
278
279
279 @reraise_safe_exceptions
280 @reraise_safe_exceptions
280 def is_empty(self, wire):
281 def is_empty(self, wire):
281 repo = self._factory.repo(wire)
282 repo = self._factory.repo(wire)
282
283
283 try:
284 try:
284 return len(repo) == 0
285 return len(repo) == 0
285 except Exception:
286 except Exception:
286 log.exception("failed to read object_store")
287 log.exception("failed to read object_store")
287 return False
288 return False
288
289
289 @reraise_safe_exceptions
290 @reraise_safe_exceptions
290 def bookmarks(self, wire):
291 def bookmarks(self, wire):
291 cache_on, context_uid, repo_id = self._cache_on(wire)
292 cache_on, context_uid, repo_id = self._cache_on(wire)
292 region = self._region(wire)
293 region = self._region(wire)
293
294
294 @region.conditional_cache_on_arguments(condition=cache_on)
295 @region.conditional_cache_on_arguments(condition=cache_on)
295 def _bookmarks(_context_uid, _repo_id):
296 def _bookmarks(_context_uid, _repo_id):
296 repo = self._factory.repo(wire)
297 repo = self._factory.repo(wire)
297 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo._bookmarks.items()}
298 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo._bookmarks.items()}
298
299
299 return _bookmarks(context_uid, repo_id)
300 return _bookmarks(context_uid, repo_id)
300
301
301 @reraise_safe_exceptions
302 @reraise_safe_exceptions
302 def branches(self, wire, normal, closed):
303 def branches(self, wire, normal, closed):
303 cache_on, context_uid, repo_id = self._cache_on(wire)
304 cache_on, context_uid, repo_id = self._cache_on(wire)
304 region = self._region(wire)
305 region = self._region(wire)
305
306
306 @region.conditional_cache_on_arguments(condition=cache_on)
307 @region.conditional_cache_on_arguments(condition=cache_on)
307 def _branches(_context_uid, _repo_id, _normal, _closed):
308 def _branches(_context_uid, _repo_id, _normal, _closed):
308 repo = self._factory.repo(wire)
309 repo = self._factory.repo(wire)
309 iter_branches = repo.branchmap().iterbranches()
310 iter_branches = repo.branchmap().iterbranches()
310 bt = {}
311 bt = {}
311 for branch_name, _heads, tip_node, is_closed in iter_branches:
312 for branch_name, _heads, tip_node, is_closed in iter_branches:
312 if normal and not is_closed:
313 if normal and not is_closed:
313 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
314 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
314 if closed and is_closed:
315 if closed and is_closed:
315 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
316 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
316
317
317 return bt
318 return bt
318
319
319 return _branches(context_uid, repo_id, normal, closed)
320 return _branches(context_uid, repo_id, normal, closed)
320
321
321 @reraise_safe_exceptions
322 @reraise_safe_exceptions
322 def bulk_request(self, wire, commit_id, pre_load):
323 def bulk_request(self, wire, commit_id, pre_load):
323 cache_on, context_uid, repo_id = self._cache_on(wire)
324 cache_on, context_uid, repo_id = self._cache_on(wire)
324 region = self._region(wire)
325 region = self._region(wire)
325
326
326 @region.conditional_cache_on_arguments(condition=cache_on)
327 @region.conditional_cache_on_arguments(condition=cache_on)
327 def _bulk_request(_repo_id, _commit_id, _pre_load):
328 def _bulk_request(_repo_id, _commit_id, _pre_load):
328 result = {}
329 result = {}
329 for attr in pre_load:
330 for attr in pre_load:
330 try:
331 try:
331 method = self._bulk_methods[attr]
332 method = self._bulk_methods[attr]
332 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
333 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
333 result[attr] = method(wire, commit_id)
334 result[attr] = method(wire, commit_id)
334 except KeyError as e:
335 except KeyError as e:
335 raise exceptions.VcsException(e)(
336 raise exceptions.VcsException(e)(
336 f'Unknown bulk attribute: "{attr}"')
337 f'Unknown bulk attribute: "{attr}"')
337 return result
338 return result
338
339
339 return _bulk_request(repo_id, commit_id, sorted(pre_load))
340 return _bulk_request(repo_id, commit_id, sorted(pre_load))
340
341
341 @reraise_safe_exceptions
342 @reraise_safe_exceptions
342 def ctx_branch(self, wire, commit_id):
343 def ctx_branch(self, wire, commit_id):
343 cache_on, context_uid, repo_id = self._cache_on(wire)
344 cache_on, context_uid, repo_id = self._cache_on(wire)
344 region = self._region(wire)
345 region = self._region(wire)
345
346
346 @region.conditional_cache_on_arguments(condition=cache_on)
347 @region.conditional_cache_on_arguments(condition=cache_on)
347 def _ctx_branch(_repo_id, _commit_id):
348 def _ctx_branch(_repo_id, _commit_id):
348 repo = self._factory.repo(wire)
349 repo = self._factory.repo(wire)
349 ctx = self._get_ctx(repo, commit_id)
350 ctx = self._get_ctx(repo, commit_id)
350 return ctx.branch()
351 return ctx.branch()
351 return _ctx_branch(repo_id, commit_id)
352 return _ctx_branch(repo_id, commit_id)
352
353
353 @reraise_safe_exceptions
354 @reraise_safe_exceptions
354 def ctx_date(self, wire, commit_id):
355 def ctx_date(self, wire, commit_id):
355 cache_on, context_uid, repo_id = self._cache_on(wire)
356 cache_on, context_uid, repo_id = self._cache_on(wire)
356 region = self._region(wire)
357 region = self._region(wire)
357
358
358 @region.conditional_cache_on_arguments(condition=cache_on)
359 @region.conditional_cache_on_arguments(condition=cache_on)
359 def _ctx_date(_repo_id, _commit_id):
360 def _ctx_date(_repo_id, _commit_id):
360 repo = self._factory.repo(wire)
361 repo = self._factory.repo(wire)
361 ctx = self._get_ctx(repo, commit_id)
362 ctx = self._get_ctx(repo, commit_id)
362 return ctx.date()
363 return ctx.date()
363 return _ctx_date(repo_id, commit_id)
364 return _ctx_date(repo_id, commit_id)
364
365
365 @reraise_safe_exceptions
366 @reraise_safe_exceptions
366 def ctx_description(self, wire, revision):
367 def ctx_description(self, wire, revision):
367 repo = self._factory.repo(wire)
368 repo = self._factory.repo(wire)
368 ctx = self._get_ctx(repo, revision)
369 ctx = self._get_ctx(repo, revision)
369 return ctx.description()
370 return ctx.description()
370
371
371 @reraise_safe_exceptions
372 @reraise_safe_exceptions
372 def ctx_files(self, wire, commit_id):
373 def ctx_files(self, wire, commit_id):
373 cache_on, context_uid, repo_id = self._cache_on(wire)
374 cache_on, context_uid, repo_id = self._cache_on(wire)
374 region = self._region(wire)
375 region = self._region(wire)
375
376
376 @region.conditional_cache_on_arguments(condition=cache_on)
377 @region.conditional_cache_on_arguments(condition=cache_on)
377 def _ctx_files(_repo_id, _commit_id):
378 def _ctx_files(_repo_id, _commit_id):
378 repo = self._factory.repo(wire)
379 repo = self._factory.repo(wire)
379 ctx = self._get_ctx(repo, commit_id)
380 ctx = self._get_ctx(repo, commit_id)
380 return ctx.files()
381 return ctx.files()
381
382
382 return _ctx_files(repo_id, commit_id)
383 return _ctx_files(repo_id, commit_id)
383
384
384 @reraise_safe_exceptions
385 @reraise_safe_exceptions
385 def ctx_list(self, path, revision):
386 def ctx_list(self, path, revision):
386 repo = self._factory.repo(path)
387 repo = self._factory.repo(path)
387 ctx = self._get_ctx(repo, revision)
388 ctx = self._get_ctx(repo, revision)
388 return list(ctx)
389 return list(ctx)
389
390
390 @reraise_safe_exceptions
391 @reraise_safe_exceptions
391 def ctx_parents(self, wire, commit_id):
392 def ctx_parents(self, wire, commit_id):
392 cache_on, context_uid, repo_id = self._cache_on(wire)
393 cache_on, context_uid, repo_id = self._cache_on(wire)
393 region = self._region(wire)
394 region = self._region(wire)
394
395
395 @region.conditional_cache_on_arguments(condition=cache_on)
396 @region.conditional_cache_on_arguments(condition=cache_on)
396 def _ctx_parents(_repo_id, _commit_id):
397 def _ctx_parents(_repo_id, _commit_id):
397 repo = self._factory.repo(wire)
398 repo = self._factory.repo(wire)
398 ctx = self._get_ctx(repo, commit_id)
399 ctx = self._get_ctx(repo, commit_id)
399 return [parent.hex() for parent in ctx.parents()
400 return [parent.hex() for parent in ctx.parents()
400 if not (parent.hidden() or parent.obsolete())]
401 if not (parent.hidden() or parent.obsolete())]
401
402
402 return _ctx_parents(repo_id, commit_id)
403 return _ctx_parents(repo_id, commit_id)
403
404
404 @reraise_safe_exceptions
405 @reraise_safe_exceptions
405 def ctx_children(self, wire, commit_id):
406 def ctx_children(self, wire, commit_id):
406 cache_on, context_uid, repo_id = self._cache_on(wire)
407 cache_on, context_uid, repo_id = self._cache_on(wire)
407 region = self._region(wire)
408 region = self._region(wire)
408
409
409 @region.conditional_cache_on_arguments(condition=cache_on)
410 @region.conditional_cache_on_arguments(condition=cache_on)
410 def _ctx_children(_repo_id, _commit_id):
411 def _ctx_children(_repo_id, _commit_id):
411 repo = self._factory.repo(wire)
412 repo = self._factory.repo(wire)
412 ctx = self._get_ctx(repo, commit_id)
413 ctx = self._get_ctx(repo, commit_id)
413 return [child.hex() for child in ctx.children()
414 return [child.hex() for child in ctx.children()
414 if not (child.hidden() or child.obsolete())]
415 if not (child.hidden() or child.obsolete())]
415
416
416 return _ctx_children(repo_id, commit_id)
417 return _ctx_children(repo_id, commit_id)
417
418
418 @reraise_safe_exceptions
419 @reraise_safe_exceptions
419 def ctx_phase(self, wire, commit_id):
420 def ctx_phase(self, wire, commit_id):
420 cache_on, context_uid, repo_id = self._cache_on(wire)
421 cache_on, context_uid, repo_id = self._cache_on(wire)
421 region = self._region(wire)
422 region = self._region(wire)
422
423
423 @region.conditional_cache_on_arguments(condition=cache_on)
424 @region.conditional_cache_on_arguments(condition=cache_on)
424 def _ctx_phase(_context_uid, _repo_id, _commit_id):
425 def _ctx_phase(_context_uid, _repo_id, _commit_id):
425 repo = self._factory.repo(wire)
426 repo = self._factory.repo(wire)
426 ctx = self._get_ctx(repo, commit_id)
427 ctx = self._get_ctx(repo, commit_id)
427 # public=0, draft=1, secret=3
428 # public=0, draft=1, secret=3
428 return ctx.phase()
429 return ctx.phase()
429 return _ctx_phase(context_uid, repo_id, commit_id)
430 return _ctx_phase(context_uid, repo_id, commit_id)
430
431
431 @reraise_safe_exceptions
432 @reraise_safe_exceptions
432 def ctx_obsolete(self, wire, commit_id):
433 def ctx_obsolete(self, wire, commit_id):
433 cache_on, context_uid, repo_id = self._cache_on(wire)
434 cache_on, context_uid, repo_id = self._cache_on(wire)
434 region = self._region(wire)
435 region = self._region(wire)
435
436
436 @region.conditional_cache_on_arguments(condition=cache_on)
437 @region.conditional_cache_on_arguments(condition=cache_on)
437 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
438 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
438 repo = self._factory.repo(wire)
439 repo = self._factory.repo(wire)
439 ctx = self._get_ctx(repo, commit_id)
440 ctx = self._get_ctx(repo, commit_id)
440 return ctx.obsolete()
441 return ctx.obsolete()
441 return _ctx_obsolete(context_uid, repo_id, commit_id)
442 return _ctx_obsolete(context_uid, repo_id, commit_id)
442
443
443 @reraise_safe_exceptions
444 @reraise_safe_exceptions
444 def ctx_hidden(self, wire, commit_id):
445 def ctx_hidden(self, wire, commit_id):
445 cache_on, context_uid, repo_id = self._cache_on(wire)
446 cache_on, context_uid, repo_id = self._cache_on(wire)
446 region = self._region(wire)
447 region = self._region(wire)
447
448
448 @region.conditional_cache_on_arguments(condition=cache_on)
449 @region.conditional_cache_on_arguments(condition=cache_on)
449 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
450 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
450 repo = self._factory.repo(wire)
451 repo = self._factory.repo(wire)
451 ctx = self._get_ctx(repo, commit_id)
452 ctx = self._get_ctx(repo, commit_id)
452 return ctx.hidden()
453 return ctx.hidden()
453 return _ctx_hidden(context_uid, repo_id, commit_id)
454 return _ctx_hidden(context_uid, repo_id, commit_id)
454
455
455 @reraise_safe_exceptions
456 @reraise_safe_exceptions
456 def ctx_substate(self, wire, revision):
457 def ctx_substate(self, wire, revision):
457 repo = self._factory.repo(wire)
458 repo = self._factory.repo(wire)
458 ctx = self._get_ctx(repo, revision)
459 ctx = self._get_ctx(repo, revision)
459 return ctx.substate
460 return ctx.substate
460
461
461 @reraise_safe_exceptions
462 @reraise_safe_exceptions
462 def ctx_status(self, wire, revision):
463 def ctx_status(self, wire, revision):
463 repo = self._factory.repo(wire)
464 repo = self._factory.repo(wire)
464 ctx = self._get_ctx(repo, revision)
465 ctx = self._get_ctx(repo, revision)
465 status = repo[ctx.p1().node()].status(other=ctx.node())
466 status = repo[ctx.p1().node()].status(other=ctx.node())
466 # object of status (odd, custom named tuple in mercurial) is not
467 # object of status (odd, custom named tuple in mercurial) is not
467 # correctly serializable, we make it a list, as the underling
468 # correctly serializable, we make it a list, as the underling
468 # API expects this to be a list
469 # API expects this to be a list
469 return list(status)
470 return list(status)
470
471
471 @reraise_safe_exceptions
472 @reraise_safe_exceptions
472 def ctx_user(self, wire, revision):
473 def ctx_user(self, wire, revision):
473 repo = self._factory.repo(wire)
474 repo = self._factory.repo(wire)
474 ctx = self._get_ctx(repo, revision)
475 ctx = self._get_ctx(repo, revision)
475 return ctx.user()
476 return ctx.user()
476
477
477 @reraise_safe_exceptions
478 @reraise_safe_exceptions
478 def check_url(self, url, config):
479 def check_url(self, url, config):
479 url, _proto = normalize_url_for_hg(url)
480 url, _proto = normalize_url_for_hg(url)
480 url_obj = url_parser(safe_bytes(url))
481 url_obj = url_parser(safe_bytes(url))
481
482
482 test_uri = safe_str(url_obj.authinfo()[0])
483 test_uri = safe_str(url_obj.authinfo()[0])
483 authinfo = url_obj.authinfo()[1]
484 authinfo = url_obj.authinfo()[1]
484 obfuscated_uri = get_obfuscated_url(url_obj)
485 obfuscated_uri = get_obfuscated_url(url_obj)
485 log.info("Checking URL for remote cloning/import: %s", obfuscated_uri)
486 log.info("Checking URL for remote cloning/import: %s", obfuscated_uri)
486
487
487 handlers = []
488 handlers = []
488 if authinfo:
489 if authinfo:
489 # create a password manager
490 # create a password manager
490 passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
491 passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
491 passmgr.add_password(*convert_to_str(authinfo))
492 passmgr.add_password(*convert_to_str(authinfo))
492
493
493 handlers.extend((httpbasicauthhandler(passmgr),
494 handlers.extend((httpbasicauthhandler(passmgr),
494 httpdigestauthhandler(passmgr)))
495 httpdigestauthhandler(passmgr)))
495
496
496 o = urllib.request.build_opener(*handlers)
497 o = urllib.request.build_opener(*handlers)
497 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
498 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
498 ('Accept', 'application/mercurial-0.1')]
499 ('Accept', 'application/mercurial-0.1')]
499
500
500 q = {"cmd": 'between'}
501 q = {"cmd": 'between'}
501 q.update({'pairs': "{}-{}".format('0' * 40, '0' * 40)})
502 q.update({'pairs': "{}-{}".format('0' * 40, '0' * 40)})
502 qs = f'?{urllib.parse.urlencode(q)}'
503 qs = f'?{urllib.parse.urlencode(q)}'
503 cu = f"{test_uri}{qs}"
504 cu = f"{test_uri}{qs}"
504
505
505 try:
506 try:
506 req = urllib.request.Request(cu, None, {})
507 req = urllib.request.Request(cu, None, {})
507 log.debug("Trying to open URL %s", obfuscated_uri)
508 log.debug("Trying to open URL %s", obfuscated_uri)
508 resp = o.open(req)
509 resp = o.open(req)
509 if resp.code != 200:
510 if resp.code != 200:
510 raise exceptions.URLError()('Return Code is not 200')
511 raise exceptions.URLError()('Return Code is not 200')
511 except Exception as e:
512 except Exception as e:
512 log.warning("URL cannot be opened: %s", obfuscated_uri, exc_info=True)
513 log.warning("URL cannot be opened: %s", obfuscated_uri, exc_info=True)
513 # means it cannot be cloned
514 # means it cannot be cloned
514 raise exceptions.URLError(e)(f"[{obfuscated_uri}] org_exc: {e}")
515 raise exceptions.URLError(e)(f"[{obfuscated_uri}] org_exc: {e}")
515
516
516 # now check if it's a proper hg repo, but don't do it for svn
517 # now check if it's a proper hg repo, but don't do it for svn
517 try:
518 try:
518 if _proto == 'svn':
519 if _proto == 'svn':
519 pass
520 pass
520 else:
521 else:
521 # check for pure hg repos
522 # check for pure hg repos
522 log.debug(
523 log.debug(
523 "Verifying if URL is a Mercurial repository: %s", obfuscated_uri)
524 "Verifying if URL is a Mercurial repository: %s", obfuscated_uri)
525 # Create repo path with custom mercurial path object
524 ui = make_ui_from_config(config)
526 ui = make_ui_from_config(config)
525 peer_checker = makepeer(ui, safe_bytes(url))
527 repo_path = hg_path(ui=ui, rawloc=safe_bytes(test_uri))
528 peer_checker = make_peer(ui, repo_path, False)
526 peer_checker.lookup(b'tip')
529 peer_checker.lookup(b'tip')
527 except Exception as e:
530 except Exception as e:
528 log.warning("URL is not a valid Mercurial repository: %s",
531 log.warning("URL is not a valid Mercurial repository: %s",
529 obfuscated_uri)
532 obfuscated_uri)
530 raise exceptions.URLError(e)(
533 raise exceptions.URLError(e)(
531 f"url [{obfuscated_uri}] does not look like an hg repo org_exc: {e}")
534 f"url [{obfuscated_uri}] does not look like an hg repo org_exc: {e}")
532
535
533 log.info("URL is a valid Mercurial repository: %s", obfuscated_uri)
536 log.info("URL is a valid Mercurial repository: %s", obfuscated_uri)
534 return True
537 return True
535
538
536 @reraise_safe_exceptions
539 @reraise_safe_exceptions
537 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
540 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
538 repo = self._factory.repo(wire)
541 repo = self._factory.repo(wire)
539
542
540 if file_filter:
543 if file_filter:
541 # unpack the file-filter
544 # unpack the file-filter
542 repo_path, node_path = file_filter
545 repo_path, node_path = file_filter
543 match_filter = match(safe_bytes(repo_path), b'', [safe_bytes(node_path)])
546 match_filter = match(safe_bytes(repo_path), b'', [safe_bytes(node_path)])
544 else:
547 else:
545 match_filter = file_filter
548 match_filter = file_filter
546 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context, showfunc=1)
549 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context, showfunc=1)
547
550
548 try:
551 try:
549 diff_iter = patch.diff(
552 diff_iter = patch.diff(
550 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts)
553 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts)
551 return BytesEnvelope(b"".join(diff_iter))
554 return BytesEnvelope(b"".join(diff_iter))
552 except RepoLookupError as e:
555 except RepoLookupError as e:
553 raise exceptions.LookupException(e)()
556 raise exceptions.LookupException(e)()
554
557
555 @reraise_safe_exceptions
558 @reraise_safe_exceptions
556 def node_history(self, wire, revision, path, limit):
559 def node_history(self, wire, revision, path, limit):
557 cache_on, context_uid, repo_id = self._cache_on(wire)
560 cache_on, context_uid, repo_id = self._cache_on(wire)
558 region = self._region(wire)
561 region = self._region(wire)
559
562
560 @region.conditional_cache_on_arguments(condition=cache_on)
563 @region.conditional_cache_on_arguments(condition=cache_on)
561 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
564 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
562 repo = self._factory.repo(wire)
565 repo = self._factory.repo(wire)
563
566
564 ctx = self._get_ctx(repo, revision)
567 ctx = self._get_ctx(repo, revision)
565 fctx = ctx.filectx(safe_bytes(path))
568 fctx = ctx.filectx(safe_bytes(path))
566
569
567 def history_iter():
570 def history_iter():
568 limit_rev = fctx.rev()
571 limit_rev = fctx.rev()
569
572
570 for fctx_candidate in reversed(list(fctx.filelog())):
573 for fctx_candidate in reversed(list(fctx.filelog())):
571 f_obj = fctx.filectx(fctx_candidate)
574 f_obj = fctx.filectx(fctx_candidate)
572
575
573 # NOTE: This can be problematic...we can hide ONLY history node resulting in empty history
576 # NOTE: This can be problematic...we can hide ONLY history node resulting in empty history
574 _ctx = f_obj.changectx()
577 _ctx = f_obj.changectx()
575 if _ctx.hidden() or _ctx.obsolete():
578 if _ctx.hidden() or _ctx.obsolete():
576 continue
579 continue
577
580
578 if limit_rev >= f_obj.rev():
581 if limit_rev >= f_obj.rev():
579 yield f_obj
582 yield f_obj
580
583
581 history = []
584 history = []
582 for cnt, obj in enumerate(history_iter()):
585 for cnt, obj in enumerate(history_iter()):
583 if limit and cnt >= limit:
586 if limit and cnt >= limit:
584 break
587 break
585 history.append(hex(obj.node()))
588 history.append(hex(obj.node()))
586
589
587 return [x for x in history]
590 return [x for x in history]
588 return _node_history(context_uid, repo_id, revision, path, limit)
591 return _node_history(context_uid, repo_id, revision, path, limit)
589
592
590 @reraise_safe_exceptions
593 @reraise_safe_exceptions
591 def node_history_until(self, wire, revision, path, limit):
594 def node_history_until(self, wire, revision, path, limit):
592 cache_on, context_uid, repo_id = self._cache_on(wire)
595 cache_on, context_uid, repo_id = self._cache_on(wire)
593 region = self._region(wire)
596 region = self._region(wire)
594
597
595 @region.conditional_cache_on_arguments(condition=cache_on)
598 @region.conditional_cache_on_arguments(condition=cache_on)
596 def _node_history_until(_context_uid, _repo_id):
599 def _node_history_until(_context_uid, _repo_id):
597 repo = self._factory.repo(wire)
600 repo = self._factory.repo(wire)
598 ctx = self._get_ctx(repo, revision)
601 ctx = self._get_ctx(repo, revision)
599 fctx = ctx.filectx(safe_bytes(path))
602 fctx = ctx.filectx(safe_bytes(path))
600
603
601 file_log = list(fctx.filelog())
604 file_log = list(fctx.filelog())
602 if limit:
605 if limit:
603 # Limit to the last n items
606 # Limit to the last n items
604 file_log = file_log[-limit:]
607 file_log = file_log[-limit:]
605
608
606 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
609 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
607 return _node_history_until(context_uid, repo_id, revision, path, limit)
610 return _node_history_until(context_uid, repo_id, revision, path, limit)
608
611
609 @reraise_safe_exceptions
612 @reraise_safe_exceptions
610 def bulk_file_request(self, wire, commit_id, path, pre_load):
613 def bulk_file_request(self, wire, commit_id, path, pre_load):
611 cache_on, context_uid, repo_id = self._cache_on(wire)
614 cache_on, context_uid, repo_id = self._cache_on(wire)
612 region = self._region(wire)
615 region = self._region(wire)
613
616
614 @region.conditional_cache_on_arguments(condition=cache_on)
617 @region.conditional_cache_on_arguments(condition=cache_on)
615 def _bulk_file_request(_repo_id, _commit_id, _path, _pre_load):
618 def _bulk_file_request(_repo_id, _commit_id, _path, _pre_load):
616 result = {}
619 result = {}
617 for attr in pre_load:
620 for attr in pre_load:
618 try:
621 try:
619 method = self._bulk_file_methods[attr]
622 method = self._bulk_file_methods[attr]
620 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
623 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
621 result[attr] = method(wire, _commit_id, _path)
624 result[attr] = method(wire, _commit_id, _path)
622 except KeyError as e:
625 except KeyError as e:
623 raise exceptions.VcsException(e)(f'Unknown bulk attribute: "{attr}"')
626 raise exceptions.VcsException(e)(f'Unknown bulk attribute: "{attr}"')
624 return result
627 return result
625
628
626 return BinaryEnvelope(_bulk_file_request(repo_id, commit_id, path, sorted(pre_load)))
629 return BinaryEnvelope(_bulk_file_request(repo_id, commit_id, path, sorted(pre_load)))
627
630
628 @reraise_safe_exceptions
631 @reraise_safe_exceptions
629 def fctx_annotate(self, wire, revision, path):
632 def fctx_annotate(self, wire, revision, path):
630 repo = self._factory.repo(wire)
633 repo = self._factory.repo(wire)
631 ctx = self._get_ctx(repo, revision)
634 ctx = self._get_ctx(repo, revision)
632 fctx = ctx.filectx(safe_bytes(path))
635 fctx = ctx.filectx(safe_bytes(path))
633
636
634 result = []
637 result = []
635 for i, annotate_obj in enumerate(fctx.annotate(), 1):
638 for i, annotate_obj in enumerate(fctx.annotate(), 1):
636 ln_no = i
639 ln_no = i
637 sha = hex(annotate_obj.fctx.node())
640 sha = hex(annotate_obj.fctx.node())
638 content = annotate_obj.text
641 content = annotate_obj.text
639 result.append((ln_no, ascii_str(sha), content))
642 result.append((ln_no, ascii_str(sha), content))
640 return BinaryEnvelope(result)
643 return BinaryEnvelope(result)
641
644
642 @reraise_safe_exceptions
645 @reraise_safe_exceptions
643 def fctx_node_data(self, wire, revision, path):
646 def fctx_node_data(self, wire, revision, path):
644 repo = self._factory.repo(wire)
647 repo = self._factory.repo(wire)
645 ctx = self._get_ctx(repo, revision)
648 ctx = self._get_ctx(repo, revision)
646 fctx = ctx.filectx(safe_bytes(path))
649 fctx = ctx.filectx(safe_bytes(path))
647 return BytesEnvelope(fctx.data())
650 return BytesEnvelope(fctx.data())
648
651
649 @reraise_safe_exceptions
652 @reraise_safe_exceptions
650 def fctx_flags(self, wire, commit_id, path):
653 def fctx_flags(self, wire, commit_id, path):
651 cache_on, context_uid, repo_id = self._cache_on(wire)
654 cache_on, context_uid, repo_id = self._cache_on(wire)
652 region = self._region(wire)
655 region = self._region(wire)
653
656
654 @region.conditional_cache_on_arguments(condition=cache_on)
657 @region.conditional_cache_on_arguments(condition=cache_on)
655 def _fctx_flags(_repo_id, _commit_id, _path):
658 def _fctx_flags(_repo_id, _commit_id, _path):
656 repo = self._factory.repo(wire)
659 repo = self._factory.repo(wire)
657 ctx = self._get_ctx(repo, commit_id)
660 ctx = self._get_ctx(repo, commit_id)
658 fctx = ctx.filectx(safe_bytes(path))
661 fctx = ctx.filectx(safe_bytes(path))
659 return fctx.flags()
662 return fctx.flags()
660
663
661 return _fctx_flags(repo_id, commit_id, path)
664 return _fctx_flags(repo_id, commit_id, path)
662
665
663 @reraise_safe_exceptions
666 @reraise_safe_exceptions
664 def fctx_size(self, wire, commit_id, path):
667 def fctx_size(self, wire, commit_id, path):
665 cache_on, context_uid, repo_id = self._cache_on(wire)
668 cache_on, context_uid, repo_id = self._cache_on(wire)
666 region = self._region(wire)
669 region = self._region(wire)
667
670
668 @region.conditional_cache_on_arguments(condition=cache_on)
671 @region.conditional_cache_on_arguments(condition=cache_on)
669 def _fctx_size(_repo_id, _revision, _path):
672 def _fctx_size(_repo_id, _revision, _path):
670 repo = self._factory.repo(wire)
673 repo = self._factory.repo(wire)
671 ctx = self._get_ctx(repo, commit_id)
674 ctx = self._get_ctx(repo, commit_id)
672 fctx = ctx.filectx(safe_bytes(path))
675 fctx = ctx.filectx(safe_bytes(path))
673 return fctx.size()
676 return fctx.size()
674 return _fctx_size(repo_id, commit_id, path)
677 return _fctx_size(repo_id, commit_id, path)
675
678
676 @reraise_safe_exceptions
679 @reraise_safe_exceptions
677 def get_all_commit_ids(self, wire, name):
680 def get_all_commit_ids(self, wire, name):
678 cache_on, context_uid, repo_id = self._cache_on(wire)
681 cache_on, context_uid, repo_id = self._cache_on(wire)
679 region = self._region(wire)
682 region = self._region(wire)
680
683
681 @region.conditional_cache_on_arguments(condition=cache_on)
684 @region.conditional_cache_on_arguments(condition=cache_on)
682 def _get_all_commit_ids(_context_uid, _repo_id, _name):
685 def _get_all_commit_ids(_context_uid, _repo_id, _name):
683 repo = self._factory.repo(wire)
686 repo = self._factory.repo(wire)
684 revs = [ascii_str(repo[x].hex()) for x in repo.filtered(b'visible').changelog.revs()]
687 revs = [ascii_str(repo[x].hex()) for x in repo.filtered(b'visible').changelog.revs()]
685 return revs
688 return revs
686 return _get_all_commit_ids(context_uid, repo_id, name)
689 return _get_all_commit_ids(context_uid, repo_id, name)
687
690
688 @reraise_safe_exceptions
691 @reraise_safe_exceptions
689 def get_config_value(self, wire, section, name, untrusted=False):
692 def get_config_value(self, wire, section, name, untrusted=False):
690 repo = self._factory.repo(wire)
693 repo = self._factory.repo(wire)
691 return repo.ui.config(ascii_bytes(section), ascii_bytes(name), untrusted=untrusted)
694 return repo.ui.config(ascii_bytes(section), ascii_bytes(name), untrusted=untrusted)
692
695
693 @reraise_safe_exceptions
696 @reraise_safe_exceptions
694 def is_large_file(self, wire, commit_id, path):
697 def is_large_file(self, wire, commit_id, path):
695 cache_on, context_uid, repo_id = self._cache_on(wire)
698 cache_on, context_uid, repo_id = self._cache_on(wire)
696 region = self._region(wire)
699 region = self._region(wire)
697
700
698 @region.conditional_cache_on_arguments(condition=cache_on)
701 @region.conditional_cache_on_arguments(condition=cache_on)
699 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
702 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
700 return largefiles.lfutil.isstandin(safe_bytes(path))
703 return largefiles.lfutil.isstandin(safe_bytes(path))
701
704
702 return _is_large_file(context_uid, repo_id, commit_id, path)
705 return _is_large_file(context_uid, repo_id, commit_id, path)
703
706
704 @reraise_safe_exceptions
707 @reraise_safe_exceptions
705 def is_binary(self, wire, revision, path):
708 def is_binary(self, wire, revision, path):
706 cache_on, context_uid, repo_id = self._cache_on(wire)
709 cache_on, context_uid, repo_id = self._cache_on(wire)
707 region = self._region(wire)
710 region = self._region(wire)
708
711
709 @region.conditional_cache_on_arguments(condition=cache_on)
712 @region.conditional_cache_on_arguments(condition=cache_on)
710 def _is_binary(_repo_id, _sha, _path):
713 def _is_binary(_repo_id, _sha, _path):
711 repo = self._factory.repo(wire)
714 repo = self._factory.repo(wire)
712 ctx = self._get_ctx(repo, revision)
715 ctx = self._get_ctx(repo, revision)
713 fctx = ctx.filectx(safe_bytes(path))
716 fctx = ctx.filectx(safe_bytes(path))
714 return fctx.isbinary()
717 return fctx.isbinary()
715
718
716 return _is_binary(repo_id, revision, path)
719 return _is_binary(repo_id, revision, path)
717
720
718 @reraise_safe_exceptions
721 @reraise_safe_exceptions
719 def md5_hash(self, wire, revision, path):
722 def md5_hash(self, wire, revision, path):
720 cache_on, context_uid, repo_id = self._cache_on(wire)
723 cache_on, context_uid, repo_id = self._cache_on(wire)
721 region = self._region(wire)
724 region = self._region(wire)
722
725
723 @region.conditional_cache_on_arguments(condition=cache_on)
726 @region.conditional_cache_on_arguments(condition=cache_on)
724 def _md5_hash(_repo_id, _sha, _path):
727 def _md5_hash(_repo_id, _sha, _path):
725 repo = self._factory.repo(wire)
728 repo = self._factory.repo(wire)
726 ctx = self._get_ctx(repo, revision)
729 ctx = self._get_ctx(repo, revision)
727 fctx = ctx.filectx(safe_bytes(path))
730 fctx = ctx.filectx(safe_bytes(path))
728 return hashlib.md5(fctx.data()).hexdigest()
731 return hashlib.md5(fctx.data()).hexdigest()
729
732
730 return _md5_hash(repo_id, revision, path)
733 return _md5_hash(repo_id, revision, path)
731
734
732 @reraise_safe_exceptions
735 @reraise_safe_exceptions
733 def in_largefiles_store(self, wire, sha):
736 def in_largefiles_store(self, wire, sha):
734 repo = self._factory.repo(wire)
737 repo = self._factory.repo(wire)
735 return largefiles.lfutil.instore(repo, sha)
738 return largefiles.lfutil.instore(repo, sha)
736
739
737 @reraise_safe_exceptions
740 @reraise_safe_exceptions
738 def in_user_cache(self, wire, sha):
741 def in_user_cache(self, wire, sha):
739 repo = self._factory.repo(wire)
742 repo = self._factory.repo(wire)
740 return largefiles.lfutil.inusercache(repo.ui, sha)
743 return largefiles.lfutil.inusercache(repo.ui, sha)
741
744
742 @reraise_safe_exceptions
745 @reraise_safe_exceptions
743 def store_path(self, wire, sha):
746 def store_path(self, wire, sha):
744 repo = self._factory.repo(wire)
747 repo = self._factory.repo(wire)
745 return largefiles.lfutil.storepath(repo, sha)
748 return largefiles.lfutil.storepath(repo, sha)
746
749
747 @reraise_safe_exceptions
750 @reraise_safe_exceptions
748 def link(self, wire, sha, path):
751 def link(self, wire, sha, path):
749 repo = self._factory.repo(wire)
752 repo = self._factory.repo(wire)
750 largefiles.lfutil.link(
753 largefiles.lfutil.link(
751 largefiles.lfutil.usercachepath(repo.ui, sha), path)
754 largefiles.lfutil.usercachepath(repo.ui, sha), path)
752
755
753 @reraise_safe_exceptions
756 @reraise_safe_exceptions
754 def localrepository(self, wire, create=False):
757 def localrepository(self, wire, create=False):
755 self._factory.repo(wire, create=create)
758 self._factory.repo(wire, create=create)
756
759
757 @reraise_safe_exceptions
760 @reraise_safe_exceptions
758 def lookup(self, wire, revision, both):
761 def lookup(self, wire, revision, both):
759 cache_on, context_uid, repo_id = self._cache_on(wire)
762 cache_on, context_uid, repo_id = self._cache_on(wire)
760 region = self._region(wire)
763 region = self._region(wire)
761
764
762 @region.conditional_cache_on_arguments(condition=cache_on)
765 @region.conditional_cache_on_arguments(condition=cache_on)
763 def _lookup(_context_uid, _repo_id, _revision, _both):
766 def _lookup(_context_uid, _repo_id, _revision, _both):
764 repo = self._factory.repo(wire)
767 repo = self._factory.repo(wire)
765 rev = _revision
768 rev = _revision
766 if isinstance(rev, int):
769 if isinstance(rev, int):
767 # NOTE(marcink):
770 # NOTE(marcink):
768 # since Mercurial doesn't support negative indexes properly
771 # since Mercurial doesn't support negative indexes properly
769 # we need to shift accordingly by one to get proper index, e.g
772 # we need to shift accordingly by one to get proper index, e.g
770 # repo[-1] => repo[-2]
773 # repo[-1] => repo[-2]
771 # repo[0] => repo[-1]
774 # repo[0] => repo[-1]
772 if rev <= 0:
775 if rev <= 0:
773 rev = rev + -1
776 rev = rev + -1
774 try:
777 try:
775 ctx = self._get_ctx(repo, rev)
778 ctx = self._get_ctx(repo, rev)
776 except AmbiguousPrefixLookupError:
779 except AmbiguousPrefixLookupError:
777 e = RepoLookupError(rev)
780 e = RepoLookupError(rev)
778 e._org_exc_tb = format_exc(sys.exc_info())
781 e._org_exc_tb = format_exc(sys.exc_info())
779 raise exceptions.LookupException(e)(rev)
782 raise exceptions.LookupException(e)(rev)
780 except (TypeError, RepoLookupError, binascii.Error) as e:
783 except (TypeError, RepoLookupError, binascii.Error) as e:
781 e._org_exc_tb = format_exc(sys.exc_info())
784 e._org_exc_tb = format_exc(sys.exc_info())
782 raise exceptions.LookupException(e)(rev)
785 raise exceptions.LookupException(e)(rev)
783 except LookupError as e:
786 except LookupError as e:
784 e._org_exc_tb = format_exc(sys.exc_info())
787 e._org_exc_tb = format_exc(sys.exc_info())
785 raise exceptions.LookupException(e)(e.name)
788 raise exceptions.LookupException(e)(e.name)
786
789
787 if not both:
790 if not both:
788 return ctx.hex()
791 return ctx.hex()
789
792
790 ctx = repo[ctx.hex()]
793 ctx = repo[ctx.hex()]
791 return ctx.hex(), ctx.rev()
794 return ctx.hex(), ctx.rev()
792
795
793 return _lookup(context_uid, repo_id, revision, both)
796 return _lookup(context_uid, repo_id, revision, both)
794
797
795 @reraise_safe_exceptions
798 @reraise_safe_exceptions
796 def sync_push(self, wire, url):
799 def sync_push(self, wire, url):
797 if not self.check_url(url, wire['config']):
800 if not self.check_url(url, wire['config']):
798 return
801 return
799
802
800 repo = self._factory.repo(wire)
803 repo = self._factory.repo(wire)
801
804
802 # Disable any prompts for this repo
805 # Disable any prompts for this repo
803 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
806 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
804
807
805 bookmarks = list(dict(repo._bookmarks).keys())
808 bookmarks = list(dict(repo._bookmarks).keys())
806 remote = peer(repo, {}, safe_bytes(url))
809 remote = peer(repo, {}, safe_bytes(url))
807 # Disable any prompts for this remote
810 # Disable any prompts for this remote
808 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
811 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
809
812
810 return exchange.push(
813 return exchange.push(
811 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
814 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
812
815
813 @reraise_safe_exceptions
816 @reraise_safe_exceptions
814 def revision(self, wire, rev):
817 def revision(self, wire, rev):
815 repo = self._factory.repo(wire)
818 repo = self._factory.repo(wire)
816 ctx = self._get_ctx(repo, rev)
819 ctx = self._get_ctx(repo, rev)
817 return ctx.rev()
820 return ctx.rev()
818
821
819 @reraise_safe_exceptions
822 @reraise_safe_exceptions
820 def rev_range(self, wire, commit_filter):
823 def rev_range(self, wire, commit_filter):
821 cache_on, context_uid, repo_id = self._cache_on(wire)
824 cache_on, context_uid, repo_id = self._cache_on(wire)
822 region = self._region(wire)
825 region = self._region(wire)
823
826
824 @region.conditional_cache_on_arguments(condition=cache_on)
827 @region.conditional_cache_on_arguments(condition=cache_on)
825 def _rev_range(_context_uid, _repo_id, _filter):
828 def _rev_range(_context_uid, _repo_id, _filter):
826 repo = self._factory.repo(wire)
829 repo = self._factory.repo(wire)
827 revisions = [
830 revisions = [
828 ascii_str(repo[rev].hex())
831 ascii_str(repo[rev].hex())
829 for rev in revrange(repo, list(map(ascii_bytes, commit_filter)))
832 for rev in revrange(repo, list(map(ascii_bytes, commit_filter)))
830 ]
833 ]
831 return revisions
834 return revisions
832
835
833 return _rev_range(context_uid, repo_id, sorted(commit_filter))
836 return _rev_range(context_uid, repo_id, sorted(commit_filter))
834
837
835 @reraise_safe_exceptions
838 @reraise_safe_exceptions
836 def rev_range_hash(self, wire, node):
839 def rev_range_hash(self, wire, node):
837 repo = self._factory.repo(wire)
840 repo = self._factory.repo(wire)
838
841
839 def get_revs(repo, rev_opt):
842 def get_revs(repo, rev_opt):
840 if rev_opt:
843 if rev_opt:
841 revs = revrange(repo, rev_opt)
844 revs = revrange(repo, rev_opt)
842 if len(revs) == 0:
845 if len(revs) == 0:
843 return (nullrev, nullrev)
846 return (nullrev, nullrev)
844 return max(revs), min(revs)
847 return max(revs), min(revs)
845 else:
848 else:
846 return len(repo) - 1, 0
849 return len(repo) - 1, 0
847
850
848 stop, start = get_revs(repo, [node + ':'])
851 stop, start = get_revs(repo, [node + ':'])
849 revs = [ascii_str(repo[r].hex()) for r in range(start, stop + 1)]
852 revs = [ascii_str(repo[r].hex()) for r in range(start, stop + 1)]
850 return revs
853 return revs
851
854
852 @reraise_safe_exceptions
855 @reraise_safe_exceptions
853 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
856 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
854 org_path = safe_bytes(wire["path"])
857 org_path = safe_bytes(wire["path"])
855 other_path = safe_bytes(kwargs.pop('other_path', ''))
858 other_path = safe_bytes(kwargs.pop('other_path', ''))
856
859
857 # case when we want to compare two independent repositories
860 # case when we want to compare two independent repositories
858 if other_path and other_path != wire["path"]:
861 if other_path and other_path != wire["path"]:
859 baseui = self._factory._create_config(wire["config"])
862 baseui = self._factory._create_config(wire["config"])
860 repo = unionrepo.makeunionrepository(baseui, other_path, org_path)
863 repo = unionrepo.makeunionrepository(baseui, other_path, org_path)
861 else:
864 else:
862 repo = self._factory.repo(wire)
865 repo = self._factory.repo(wire)
863 return list(repo.revs(rev_spec, *args))
866 return list(repo.revs(rev_spec, *args))
864
867
865 @reraise_safe_exceptions
868 @reraise_safe_exceptions
866 def verify(self, wire,):
869 def verify(self, wire,):
867 repo = self._factory.repo(wire)
870 repo = self._factory.repo(wire)
868 baseui = self._factory._create_config(wire['config'])
871 baseui = self._factory._create_config(wire['config'])
869
872
870 baseui, output = patch_ui_message_output(baseui)
873 baseui, output = patch_ui_message_output(baseui)
871
874
872 repo.ui = baseui
875 repo.ui = baseui
873 verify.verify(repo)
876 verify.verify(repo)
874 return output.getvalue()
877 return output.getvalue()
875
878
876 @reraise_safe_exceptions
879 @reraise_safe_exceptions
877 def hg_update_cache(self, wire,):
880 def hg_update_cache(self, wire,):
878 repo = self._factory.repo(wire)
881 repo = self._factory.repo(wire)
879 baseui = self._factory._create_config(wire['config'])
882 baseui = self._factory._create_config(wire['config'])
880 baseui, output = patch_ui_message_output(baseui)
883 baseui, output = patch_ui_message_output(baseui)
881
884
882 repo.ui = baseui
885 repo.ui = baseui
883 with repo.wlock(), repo.lock():
886 with repo.wlock(), repo.lock():
884 repo.updatecaches(full=True)
887 repo.updatecaches(full=True)
885
888
886 return output.getvalue()
889 return output.getvalue()
887
890
888 @reraise_safe_exceptions
891 @reraise_safe_exceptions
889 def hg_rebuild_fn_cache(self, wire,):
892 def hg_rebuild_fn_cache(self, wire,):
890 repo = self._factory.repo(wire)
893 repo = self._factory.repo(wire)
891 baseui = self._factory._create_config(wire['config'])
894 baseui = self._factory._create_config(wire['config'])
892 baseui, output = patch_ui_message_output(baseui)
895 baseui, output = patch_ui_message_output(baseui)
893
896
894 repo.ui = baseui
897 repo.ui = baseui
895
898
896 repair.rebuildfncache(baseui, repo)
899 repair.rebuildfncache(baseui, repo)
897
900
898 return output.getvalue()
901 return output.getvalue()
899
902
900 @reraise_safe_exceptions
903 @reraise_safe_exceptions
901 def tags(self, wire):
904 def tags(self, wire):
902 cache_on, context_uid, repo_id = self._cache_on(wire)
905 cache_on, context_uid, repo_id = self._cache_on(wire)
903 region = self._region(wire)
906 region = self._region(wire)
904
907
905 @region.conditional_cache_on_arguments(condition=cache_on)
908 @region.conditional_cache_on_arguments(condition=cache_on)
906 def _tags(_context_uid, _repo_id):
909 def _tags(_context_uid, _repo_id):
907 repo = self._factory.repo(wire)
910 repo = self._factory.repo(wire)
908 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo.tags().items()}
911 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo.tags().items()}
909
912
910 return _tags(context_uid, repo_id)
913 return _tags(context_uid, repo_id)
911
914
912 @reraise_safe_exceptions
915 @reraise_safe_exceptions
913 def update(self, wire, node='', clean=False):
916 def update(self, wire, node='', clean=False):
914 repo = self._factory.repo(wire)
917 repo = self._factory.repo(wire)
915 baseui = self._factory._create_config(wire['config'])
918 baseui = self._factory._create_config(wire['config'])
916 node = safe_bytes(node)
919 node = safe_bytes(node)
917
920
918 commands.update(baseui, repo, node=node, clean=clean)
921 commands.update(baseui, repo, node=node, clean=clean)
919
922
920 @reraise_safe_exceptions
923 @reraise_safe_exceptions
921 def identify(self, wire):
924 def identify(self, wire):
922 repo = self._factory.repo(wire)
925 repo = self._factory.repo(wire)
923 baseui = self._factory._create_config(wire['config'])
926 baseui = self._factory._create_config(wire['config'])
924 output = io.BytesIO()
927 output = io.BytesIO()
925 baseui.write = output.write
928 baseui.write = output.write
926 # This is required to get a full node id
929 # This is required to get a full node id
927 baseui.debugflag = True
930 baseui.debugflag = True
928 commands.identify(baseui, repo, id=True)
931 commands.identify(baseui, repo, id=True)
929
932
930 return output.getvalue()
933 return output.getvalue()
931
934
932 @reraise_safe_exceptions
935 @reraise_safe_exceptions
933 def heads(self, wire, branch=None):
936 def heads(self, wire, branch=None):
934 repo = self._factory.repo(wire)
937 repo = self._factory.repo(wire)
935 baseui = self._factory._create_config(wire['config'])
938 baseui = self._factory._create_config(wire['config'])
936 output = io.BytesIO()
939 output = io.BytesIO()
937
940
938 def write(data, **unused_kwargs):
941 def write(data, **unused_kwargs):
939 output.write(data)
942 output.write(data)
940
943
941 baseui.write = write
944 baseui.write = write
942 if branch:
945 if branch:
943 args = [safe_bytes(branch)]
946 args = [safe_bytes(branch)]
944 else:
947 else:
945 args = []
948 args = []
946 commands.heads(baseui, repo, template=b'{node} ', *args)
949 commands.heads(baseui, repo, template=b'{node} ', *args)
947
950
948 return output.getvalue()
951 return output.getvalue()
949
952
950 @reraise_safe_exceptions
953 @reraise_safe_exceptions
951 def ancestor(self, wire, revision1, revision2):
954 def ancestor(self, wire, revision1, revision2):
952 repo = self._factory.repo(wire)
955 repo = self._factory.repo(wire)
953 changelog = repo.changelog
956 changelog = repo.changelog
954 lookup = repo.lookup
957 lookup = repo.lookup
955 a = changelog.ancestor(lookup(safe_bytes(revision1)), lookup(safe_bytes(revision2)))
958 a = changelog.ancestor(lookup(safe_bytes(revision1)), lookup(safe_bytes(revision2)))
956 return hex(a)
959 return hex(a)
957
960
958 @reraise_safe_exceptions
961 @reraise_safe_exceptions
959 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
962 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
960 baseui = self._factory._create_config(wire["config"], hooks=hooks)
963 baseui = self._factory._create_config(wire["config"], hooks=hooks)
961 clone(baseui, safe_bytes(source), safe_bytes(dest), noupdate=not update_after_clone)
964 clone(baseui, safe_bytes(source), safe_bytes(dest), noupdate=not update_after_clone)
962
965
963 @reraise_safe_exceptions
966 @reraise_safe_exceptions
964 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
967 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
965
968
966 repo = self._factory.repo(wire)
969 repo = self._factory.repo(wire)
967 baseui = self._factory._create_config(wire['config'])
970 baseui = self._factory._create_config(wire['config'])
968 publishing = baseui.configbool(b'phases', b'publish')
971 publishing = baseui.configbool(b'phases', b'publish')
969
972
970 def _filectxfn(_repo, ctx, path: bytes):
973 def _filectxfn(_repo, ctx, path: bytes):
971 """
974 """
972 Marks given path as added/changed/removed in a given _repo. This is
975 Marks given path as added/changed/removed in a given _repo. This is
973 for internal mercurial commit function.
976 for internal mercurial commit function.
974 """
977 """
975
978
976 # check if this path is removed
979 # check if this path is removed
977 if safe_str(path) in removed:
980 if safe_str(path) in removed:
978 # returning None is a way to mark node for removal
981 # returning None is a way to mark node for removal
979 return None
982 return None
980
983
981 # check if this path is added
984 # check if this path is added
982 for node in updated:
985 for node in updated:
983 if safe_bytes(node['path']) == path:
986 if safe_bytes(node['path']) == path:
984 return memfilectx(
987 return memfilectx(
985 _repo,
988 _repo,
986 changectx=ctx,
989 changectx=ctx,
987 path=safe_bytes(node['path']),
990 path=safe_bytes(node['path']),
988 data=safe_bytes(node['content']),
991 data=safe_bytes(node['content']),
989 islink=False,
992 islink=False,
990 isexec=bool(node['mode'] & stat.S_IXUSR),
993 isexec=bool(node['mode'] & stat.S_IXUSR),
991 copysource=False)
994 copysource=False)
992 abort_exc = exceptions.AbortException()
995 abort_exc = exceptions.AbortException()
993 raise abort_exc(f"Given path haven't been marked as added, changed or removed ({path})")
996 raise abort_exc(f"Given path haven't been marked as added, changed or removed ({path})")
994
997
995 if publishing:
998 if publishing:
996 new_commit_phase = b'public'
999 new_commit_phase = b'public'
997 else:
1000 else:
998 new_commit_phase = b'draft'
1001 new_commit_phase = b'draft'
999 with repo.ui.configoverride({(b'phases', b'new-commit'): new_commit_phase}):
1002 with repo.ui.configoverride({(b'phases', b'new-commit'): new_commit_phase}):
1000 kwargs = {safe_bytes(k): safe_bytes(v) for k, v in extra.items()}
1003 kwargs = {safe_bytes(k): safe_bytes(v) for k, v in extra.items()}
1001 commit_ctx = memctx(
1004 commit_ctx = memctx(
1002 repo=repo,
1005 repo=repo,
1003 parents=parents,
1006 parents=parents,
1004 text=safe_bytes(message),
1007 text=safe_bytes(message),
1005 files=[safe_bytes(x) for x in files],
1008 files=[safe_bytes(x) for x in files],
1006 filectxfn=_filectxfn,
1009 filectxfn=_filectxfn,
1007 user=safe_bytes(user),
1010 user=safe_bytes(user),
1008 date=(commit_time, commit_timezone),
1011 date=(commit_time, commit_timezone),
1009 extra=kwargs)
1012 extra=kwargs)
1010
1013
1011 n = repo.commitctx(commit_ctx)
1014 n = repo.commitctx(commit_ctx)
1012 new_id = hex(n)
1015 new_id = hex(n)
1013
1016
1014 return new_id
1017 return new_id
1015
1018
1016 @reraise_safe_exceptions
1019 @reraise_safe_exceptions
1017 def pull(self, wire, url, commit_ids=None):
1020 def pull(self, wire, url, commit_ids=None):
1018 repo = self._factory.repo(wire)
1021 repo = self._factory.repo(wire)
1019 # Disable any prompts for this repo
1022 # Disable any prompts for this repo
1020 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
1023 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
1021
1024
1022 remote = peer(repo, {}, safe_bytes(url))
1025 remote = peer(repo, {}, safe_bytes(url))
1023 # Disable any prompts for this remote
1026 # Disable any prompts for this remote
1024 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
1027 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
1025
1028
1026 if commit_ids:
1029 if commit_ids:
1027 commit_ids = [bin(commit_id) for commit_id in commit_ids]
1030 commit_ids = [bin(commit_id) for commit_id in commit_ids]
1028
1031
1029 return exchange.pull(
1032 return exchange.pull(
1030 repo, remote, heads=commit_ids, force=None).cgresult
1033 repo, remote, heads=commit_ids, force=None).cgresult
1031
1034
1032 @reraise_safe_exceptions
1035 @reraise_safe_exceptions
1033 def pull_cmd(self, wire, source, bookmark='', branch='', revision='', hooks=True):
1036 def pull_cmd(self, wire, source, bookmark='', branch='', revision='', hooks=True):
1034 repo = self._factory.repo(wire)
1037 repo = self._factory.repo(wire)
1035 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1038 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1036
1039
1037 source = safe_bytes(source)
1040 source = safe_bytes(source)
1038
1041
1039 # Mercurial internally has a lot of logic that checks ONLY if
1042 # Mercurial internally has a lot of logic that checks ONLY if
1040 # option is defined, we just pass those if they are defined then
1043 # option is defined, we just pass those if they are defined then
1041 opts = {}
1044 opts = {"remote_hidden": False}
1042
1045
1043 if bookmark:
1046 if bookmark:
1044 opts['bookmark'] = [safe_bytes(x) for x in bookmark] \
1047 opts['bookmark'] = [safe_bytes(x) for x in bookmark] \
1045 if isinstance(bookmark, list) else safe_bytes(bookmark)
1048 if isinstance(bookmark, list) else safe_bytes(bookmark)
1046
1049
1047 if branch:
1050 if branch:
1048 opts['branch'] = [safe_bytes(x) for x in branch] \
1051 opts['branch'] = [safe_bytes(x) for x in branch] \
1049 if isinstance(branch, list) else safe_bytes(branch)
1052 if isinstance(branch, list) else safe_bytes(branch)
1050
1053
1051 if revision:
1054 if revision:
1052 opts['rev'] = [safe_bytes(x) for x in revision] \
1055 opts['rev'] = [safe_bytes(x) for x in revision] \
1053 if isinstance(revision, list) else safe_bytes(revision)
1056 if isinstance(revision, list) else safe_bytes(revision)
1054
1057
1055 commands.pull(baseui, repo, source, **opts)
1058 commands.pull(baseui, repo, source, **opts)
1056
1059
1057 @reraise_safe_exceptions
1060 @reraise_safe_exceptions
1058 def push(self, wire, revisions, dest_path, hooks: bool = True, push_branches: bool = False):
1061 def push(self, wire, revisions, dest_path, hooks: bool = True, push_branches: bool = False):
1059 repo = self._factory.repo(wire)
1062 repo = self._factory.repo(wire)
1060 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1063 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1061
1064
1062 revisions = [safe_bytes(x) for x in revisions] \
1065 revisions = [safe_bytes(x) for x in revisions] \
1063 if isinstance(revisions, list) else safe_bytes(revisions)
1066 if isinstance(revisions, list) else safe_bytes(revisions)
1064
1067
1065 commands.push(baseui, repo, safe_bytes(dest_path),
1068 commands.push(baseui, repo, safe_bytes(dest_path),
1066 rev=revisions,
1069 rev=revisions,
1067 new_branch=push_branches)
1070 new_branch=push_branches)
1068
1071
1069 @reraise_safe_exceptions
1072 @reraise_safe_exceptions
1070 def strip(self, wire, revision, update, backup):
1073 def strip(self, wire, revision, update, backup):
1071 repo = self._factory.repo(wire)
1074 repo = self._factory.repo(wire)
1072 ctx = self._get_ctx(repo, revision)
1075 ctx = self._get_ctx(repo, revision)
1073 hgext_strip.strip(
1076 hgext_strip.strip(
1074 repo.baseui, repo, ctx.node(), update=update, backup=backup)
1077 repo.baseui, repo, ctx.node(), update=update, backup=backup)
1075
1078
1076 @reraise_safe_exceptions
1079 @reraise_safe_exceptions
1077 def get_unresolved_files(self, wire):
1080 def get_unresolved_files(self, wire):
1078 repo = self._factory.repo(wire)
1081 repo = self._factory.repo(wire)
1079
1082
1080 log.debug('Calculating unresolved files for repo: %s', repo)
1083 log.debug('Calculating unresolved files for repo: %s', repo)
1081 output = io.BytesIO()
1084 output = io.BytesIO()
1082
1085
1083 def write(data, **unused_kwargs):
1086 def write(data, **unused_kwargs):
1084 output.write(data)
1087 output.write(data)
1085
1088
1086 baseui = self._factory._create_config(wire['config'])
1089 baseui = self._factory._create_config(wire['config'])
1087 baseui.write = write
1090 baseui.write = write
1088
1091
1089 commands.resolve(baseui, repo, list=True)
1092 commands.resolve(baseui, repo, list=True)
1090 unresolved = output.getvalue().splitlines(0)
1093 unresolved = output.getvalue().splitlines(0)
1091 return unresolved
1094 return unresolved
1092
1095
1093 @reraise_safe_exceptions
1096 @reraise_safe_exceptions
1094 def merge(self, wire, revision):
1097 def merge(self, wire, revision):
1095 repo = self._factory.repo(wire)
1098 repo = self._factory.repo(wire)
1096 baseui = self._factory._create_config(wire['config'])
1099 baseui = self._factory._create_config(wire['config'])
1097 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1100 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1098
1101
1099 # In case of sub repositories are used mercurial prompts the user in
1102 # In case of sub repositories are used mercurial prompts the user in
1100 # case of merge conflicts or different sub repository sources. By
1103 # case of merge conflicts or different sub repository sources. By
1101 # setting the interactive flag to `False` mercurial doesn't prompt the
1104 # setting the interactive flag to `False` mercurial doesn't prompt the
1102 # used but instead uses a default value.
1105 # used but instead uses a default value.
1103 repo.ui.setconfig(b'ui', b'interactive', False)
1106 repo.ui.setconfig(b'ui', b'interactive', False)
1104 commands.merge(baseui, repo, rev=safe_bytes(revision))
1107 commands.merge(baseui, repo, rev=safe_bytes(revision))
1105
1108
1106 @reraise_safe_exceptions
1109 @reraise_safe_exceptions
1107 def merge_state(self, wire):
1110 def merge_state(self, wire):
1108 repo = self._factory.repo(wire)
1111 repo = self._factory.repo(wire)
1109 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1112 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1110
1113
1111 # In case of sub repositories are used mercurial prompts the user in
1114 # In case of sub repositories are used mercurial prompts the user in
1112 # case of merge conflicts or different sub repository sources. By
1115 # case of merge conflicts or different sub repository sources. By
1113 # setting the interactive flag to `False` mercurial doesn't prompt the
1116 # setting the interactive flag to `False` mercurial doesn't prompt the
1114 # used but instead uses a default value.
1117 # used but instead uses a default value.
1115 repo.ui.setconfig(b'ui', b'interactive', False)
1118 repo.ui.setconfig(b'ui', b'interactive', False)
1116 ms = hg_merge.mergestate(repo)
1119 ms = hg_merge.mergestate(repo)
1117 return [x for x in ms.unresolved()]
1120 return [x for x in ms.unresolved()]
1118
1121
1119 @reraise_safe_exceptions
1122 @reraise_safe_exceptions
1120 def commit(self, wire, message, username, close_branch=False):
1123 def commit(self, wire, message, username, close_branch=False):
1121 repo = self._factory.repo(wire)
1124 repo = self._factory.repo(wire)
1122 baseui = self._factory._create_config(wire['config'])
1125 baseui = self._factory._create_config(wire['config'])
1123 repo.ui.setconfig(b'ui', b'username', safe_bytes(username))
1126 repo.ui.setconfig(b'ui', b'username', safe_bytes(username))
1124 commands.commit(baseui, repo, message=safe_bytes(message), close_branch=close_branch)
1127 commands.commit(baseui, repo, message=safe_bytes(message), close_branch=close_branch)
1125
1128
1126 @reraise_safe_exceptions
1129 @reraise_safe_exceptions
1127 def rebase(self, wire, source='', dest='', abort=False):
1130 def rebase(self, wire, source='', dest='', abort=False):
1128
1131
1129 repo = self._factory.repo(wire)
1132 repo = self._factory.repo(wire)
1130 baseui = self._factory._create_config(wire['config'])
1133 baseui = self._factory._create_config(wire['config'])
1131 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1134 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1132 # In case of sub repositories are used mercurial prompts the user in
1135 # In case of sub repositories are used mercurial prompts the user in
1133 # case of merge conflicts or different sub repository sources. By
1136 # case of merge conflicts or different sub repository sources. By
1134 # setting the interactive flag to `False` mercurial doesn't prompt the
1137 # setting the interactive flag to `False` mercurial doesn't prompt the
1135 # used but instead uses a default value.
1138 # used but instead uses a default value.
1136 repo.ui.setconfig(b'ui', b'interactive', False)
1139 repo.ui.setconfig(b'ui', b'interactive', False)
1137
1140
1138 rebase_kws = dict(
1141 rebase_kws = dict(
1139 keep=not abort,
1142 keep=not abort,
1140 abort=abort
1143 abort=abort
1141 )
1144 )
1142
1145
1143 if source:
1146 if source:
1144 source = repo[source]
1147 source = repo[source]
1145 rebase_kws['base'] = [source.hex()]
1148 rebase_kws['base'] = [source.hex()]
1146 if dest:
1149 if dest:
1147 dest = repo[dest]
1150 dest = repo[dest]
1148 rebase_kws['dest'] = dest.hex()
1151 rebase_kws['dest'] = dest.hex()
1149
1152
1150 rebase.rebase(baseui, repo, **rebase_kws)
1153 rebase.rebase(baseui, repo, **rebase_kws)
1151
1154
1152 @reraise_safe_exceptions
1155 @reraise_safe_exceptions
1153 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
1156 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
1154 repo = self._factory.repo(wire)
1157 repo = self._factory.repo(wire)
1155 ctx = self._get_ctx(repo, revision)
1158 ctx = self._get_ctx(repo, revision)
1156 node = ctx.node()
1159 node = ctx.node()
1157
1160
1158 date = (tag_time, tag_timezone)
1161 date = (tag_time, tag_timezone)
1159 try:
1162 try:
1160 hg_tag.tag(repo, safe_bytes(name), node, safe_bytes(message), local, safe_bytes(user), date)
1163 hg_tag.tag(repo, safe_bytes(name), node, safe_bytes(message), local, safe_bytes(user), date)
1161 except Abort as e:
1164 except Abort as e:
1162 log.exception("Tag operation aborted")
1165 log.exception("Tag operation aborted")
1163 # Exception can contain unicode which we convert
1166 # Exception can contain unicode which we convert
1164 raise exceptions.AbortException(e)(repr(e))
1167 raise exceptions.AbortException(e)(repr(e))
1165
1168
1166 @reraise_safe_exceptions
1169 @reraise_safe_exceptions
1167 def bookmark(self, wire, bookmark, revision=''):
1170 def bookmark(self, wire, bookmark, revision=''):
1168 repo = self._factory.repo(wire)
1171 repo = self._factory.repo(wire)
1169 baseui = self._factory._create_config(wire['config'])
1172 baseui = self._factory._create_config(wire['config'])
1170 revision = revision or ''
1173 revision = revision or ''
1171 commands.bookmark(baseui, repo, safe_bytes(bookmark), rev=safe_bytes(revision), force=True)
1174 commands.bookmark(baseui, repo, safe_bytes(bookmark), rev=safe_bytes(revision), force=True)
1172
1175
1173 @reraise_safe_exceptions
1176 @reraise_safe_exceptions
1174 def install_hooks(self, wire, force=False):
1177 def install_hooks(self, wire, force=False):
1175 # we don't need any special hooks for Mercurial
1178 # we don't need any special hooks for Mercurial
1176 pass
1179 pass
1177
1180
1178 @reraise_safe_exceptions
1181 @reraise_safe_exceptions
1179 def get_hooks_info(self, wire):
1182 def get_hooks_info(self, wire):
1180 return {
1183 return {
1181 'pre_version': vcsserver.get_version(),
1184 'pre_version': vcsserver.get_version(),
1182 'post_version': vcsserver.get_version(),
1185 'post_version': vcsserver.get_version(),
1183 }
1186 }
1184
1187
1185 @reraise_safe_exceptions
1188 @reraise_safe_exceptions
1186 def set_head_ref(self, wire, head_name):
1189 def set_head_ref(self, wire, head_name):
1187 pass
1190 pass
1188
1191
1189 @reraise_safe_exceptions
1192 @reraise_safe_exceptions
1190 def archive_repo(self, wire, archive_name_key, kind, mtime, archive_at_path,
1193 def archive_repo(self, wire, archive_name_key, kind, mtime, archive_at_path,
1191 archive_dir_name, commit_id, cache_config):
1194 archive_dir_name, commit_id, cache_config):
1192
1195
1193 def file_walker(_commit_id, path):
1196 def file_walker(_commit_id, path):
1194 repo = self._factory.repo(wire)
1197 repo = self._factory.repo(wire)
1195 ctx = repo[_commit_id]
1198 ctx = repo[_commit_id]
1196 is_root = path in ['', '/']
1199 is_root = path in ['', '/']
1197 if is_root:
1200 if is_root:
1198 matcher = alwaysmatcher(badfn=None)
1201 matcher = alwaysmatcher(badfn=None)
1199 else:
1202 else:
1200 matcher = patternmatcher('', [(b'glob', safe_bytes(path)+b'/**', b'')], badfn=None)
1203 matcher = patternmatcher('', [(b'glob', safe_bytes(path)+b'/**', b'')], badfn=None)
1201 file_iter = ctx.manifest().walk(matcher)
1204 file_iter = ctx.manifest().walk(matcher)
1202
1205
1203 for fn in file_iter:
1206 for fn in file_iter:
1204 file_path = fn
1207 file_path = fn
1205 flags = ctx.flags(fn)
1208 flags = ctx.flags(fn)
1206 mode = b'x' in flags and 0o755 or 0o644
1209 mode = b'x' in flags and 0o755 or 0o644
1207 is_link = b'l' in flags
1210 is_link = b'l' in flags
1208
1211
1209 yield ArchiveNode(file_path, mode, is_link, ctx[fn].data)
1212 yield ArchiveNode(file_path, mode, is_link, ctx[fn].data)
1210
1213
1211 return store_archive_in_cache(
1214 return store_archive_in_cache(
1212 file_walker, archive_name_key, kind, mtime, archive_at_path, archive_dir_name, commit_id, cache_config=cache_config)
1215 file_walker, archive_name_key, kind, mtime, archive_at_path, archive_dir_name, commit_id, cache_config=cache_config)
1213
1216
General Comments 0
You need to be logged in to leave comments. Login now