Show More
@@ -1,1305 +1,1308 b'' | |||||
1 | # configitems.py - centralized declaration of configuration option |
|
1 | # configitems.py - centralized declaration of configuration option | |
2 | # |
|
2 | # | |
3 | # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net> |
|
3 | # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
10 | import functools |
|
10 | import functools | |
11 | import re |
|
11 | import re | |
12 |
|
12 | |||
13 | from . import ( |
|
13 | from . import ( | |
14 | encoding, |
|
14 | encoding, | |
15 | error, |
|
15 | error, | |
16 | ) |
|
16 | ) | |
17 |
|
17 | |||
18 | def loadconfigtable(ui, extname, configtable): |
|
18 | def loadconfigtable(ui, extname, configtable): | |
19 | """update config item known to the ui with the extension ones""" |
|
19 | """update config item known to the ui with the extension ones""" | |
20 | for section, items in sorted(configtable.items()): |
|
20 | for section, items in sorted(configtable.items()): | |
21 | knownitems = ui._knownconfig.setdefault(section, itemregister()) |
|
21 | knownitems = ui._knownconfig.setdefault(section, itemregister()) | |
22 | knownkeys = set(knownitems) |
|
22 | knownkeys = set(knownitems) | |
23 | newkeys = set(items) |
|
23 | newkeys = set(items) | |
24 | for key in sorted(knownkeys & newkeys): |
|
24 | for key in sorted(knownkeys & newkeys): | |
25 | msg = "extension '%s' overwrite config item '%s.%s'" |
|
25 | msg = "extension '%s' overwrite config item '%s.%s'" | |
26 | msg %= (extname, section, key) |
|
26 | msg %= (extname, section, key) | |
27 | ui.develwarn(msg, config='warn-config') |
|
27 | ui.develwarn(msg, config='warn-config') | |
28 |
|
28 | |||
29 | knownitems.update(items) |
|
29 | knownitems.update(items) | |
30 |
|
30 | |||
31 | class configitem(object): |
|
31 | class configitem(object): | |
32 | """represent a known config item |
|
32 | """represent a known config item | |
33 |
|
33 | |||
34 | :section: the official config section where to find this item, |
|
34 | :section: the official config section where to find this item, | |
35 | :name: the official name within the section, |
|
35 | :name: the official name within the section, | |
36 | :default: default value for this item, |
|
36 | :default: default value for this item, | |
37 | :alias: optional list of tuples as alternatives, |
|
37 | :alias: optional list of tuples as alternatives, | |
38 | :generic: this is a generic definition, match name using regular expression. |
|
38 | :generic: this is a generic definition, match name using regular expression. | |
39 | """ |
|
39 | """ | |
40 |
|
40 | |||
41 | def __init__(self, section, name, default=None, alias=(), |
|
41 | def __init__(self, section, name, default=None, alias=(), | |
42 | generic=False, priority=0): |
|
42 | generic=False, priority=0): | |
43 | self.section = section |
|
43 | self.section = section | |
44 | self.name = name |
|
44 | self.name = name | |
45 | self.default = default |
|
45 | self.default = default | |
46 | self.alias = list(alias) |
|
46 | self.alias = list(alias) | |
47 | self.generic = generic |
|
47 | self.generic = generic | |
48 | self.priority = priority |
|
48 | self.priority = priority | |
49 | self._re = None |
|
49 | self._re = None | |
50 | if generic: |
|
50 | if generic: | |
51 | self._re = re.compile(self.name) |
|
51 | self._re = re.compile(self.name) | |
52 |
|
52 | |||
53 | class itemregister(dict): |
|
53 | class itemregister(dict): | |
54 | """A specialized dictionary that can handle wild-card selection""" |
|
54 | """A specialized dictionary that can handle wild-card selection""" | |
55 |
|
55 | |||
56 | def __init__(self): |
|
56 | def __init__(self): | |
57 | super(itemregister, self).__init__() |
|
57 | super(itemregister, self).__init__() | |
58 | self._generics = set() |
|
58 | self._generics = set() | |
59 |
|
59 | |||
60 | def update(self, other): |
|
60 | def update(self, other): | |
61 | super(itemregister, self).update(other) |
|
61 | super(itemregister, self).update(other) | |
62 | self._generics.update(other._generics) |
|
62 | self._generics.update(other._generics) | |
63 |
|
63 | |||
64 | def __setitem__(self, key, item): |
|
64 | def __setitem__(self, key, item): | |
65 | super(itemregister, self).__setitem__(key, item) |
|
65 | super(itemregister, self).__setitem__(key, item) | |
66 | if item.generic: |
|
66 | if item.generic: | |
67 | self._generics.add(item) |
|
67 | self._generics.add(item) | |
68 |
|
68 | |||
69 | def get(self, key): |
|
69 | def get(self, key): | |
70 | baseitem = super(itemregister, self).get(key) |
|
70 | baseitem = super(itemregister, self).get(key) | |
71 | if baseitem is not None and not baseitem.generic: |
|
71 | if baseitem is not None and not baseitem.generic: | |
72 | return baseitem |
|
72 | return baseitem | |
73 |
|
73 | |||
74 | # search for a matching generic item |
|
74 | # search for a matching generic item | |
75 | generics = sorted(self._generics, key=(lambda x: (x.priority, x.name))) |
|
75 | generics = sorted(self._generics, key=(lambda x: (x.priority, x.name))) | |
76 | for item in generics: |
|
76 | for item in generics: | |
77 | # we use 'match' instead of 'search' to make the matching simpler |
|
77 | # we use 'match' instead of 'search' to make the matching simpler | |
78 | # for people unfamiliar with regular expression. Having the match |
|
78 | # for people unfamiliar with regular expression. Having the match | |
79 | # rooted to the start of the string will produce less surprising |
|
79 | # rooted to the start of the string will produce less surprising | |
80 | # result for user writing simple regex for sub-attribute. |
|
80 | # result for user writing simple regex for sub-attribute. | |
81 | # |
|
81 | # | |
82 | # For example using "color\..*" match produces an unsurprising |
|
82 | # For example using "color\..*" match produces an unsurprising | |
83 | # result, while using search could suddenly match apparently |
|
83 | # result, while using search could suddenly match apparently | |
84 | # unrelated configuration that happens to contains "color." |
|
84 | # unrelated configuration that happens to contains "color." | |
85 | # anywhere. This is a tradeoff where we favor requiring ".*" on |
|
85 | # anywhere. This is a tradeoff where we favor requiring ".*" on | |
86 | # some match to avoid the need to prefix most pattern with "^". |
|
86 | # some match to avoid the need to prefix most pattern with "^". | |
87 | # The "^" seems more error prone. |
|
87 | # The "^" seems more error prone. | |
88 | if item._re.match(key): |
|
88 | if item._re.match(key): | |
89 | return item |
|
89 | return item | |
90 |
|
90 | |||
91 | return None |
|
91 | return None | |
92 |
|
92 | |||
93 | coreitems = {} |
|
93 | coreitems = {} | |
94 |
|
94 | |||
95 | def _register(configtable, *args, **kwargs): |
|
95 | def _register(configtable, *args, **kwargs): | |
96 | item = configitem(*args, **kwargs) |
|
96 | item = configitem(*args, **kwargs) | |
97 | section = configtable.setdefault(item.section, itemregister()) |
|
97 | section = configtable.setdefault(item.section, itemregister()) | |
98 | if item.name in section: |
|
98 | if item.name in section: | |
99 | msg = "duplicated config item registration for '%s.%s'" |
|
99 | msg = "duplicated config item registration for '%s.%s'" | |
100 | raise error.ProgrammingError(msg % (item.section, item.name)) |
|
100 | raise error.ProgrammingError(msg % (item.section, item.name)) | |
101 | section[item.name] = item |
|
101 | section[item.name] = item | |
102 |
|
102 | |||
103 | # special value for case where the default is derived from other values |
|
103 | # special value for case where the default is derived from other values | |
104 | dynamicdefault = object() |
|
104 | dynamicdefault = object() | |
105 |
|
105 | |||
106 | # Registering actual config items |
|
106 | # Registering actual config items | |
107 |
|
107 | |||
108 | def getitemregister(configtable): |
|
108 | def getitemregister(configtable): | |
109 | f = functools.partial(_register, configtable) |
|
109 | f = functools.partial(_register, configtable) | |
110 | # export pseudo enum as configitem.* |
|
110 | # export pseudo enum as configitem.* | |
111 | f.dynamicdefault = dynamicdefault |
|
111 | f.dynamicdefault = dynamicdefault | |
112 | return f |
|
112 | return f | |
113 |
|
113 | |||
114 | coreconfigitem = getitemregister(coreitems) |
|
114 | coreconfigitem = getitemregister(coreitems) | |
115 |
|
115 | |||
116 | coreconfigitem('alias', '.*', |
|
116 | coreconfigitem('alias', '.*', | |
117 | default=None, |
|
117 | default=None, | |
118 | generic=True, |
|
118 | generic=True, | |
119 | ) |
|
119 | ) | |
120 | coreconfigitem('annotate', 'nodates', |
|
120 | coreconfigitem('annotate', 'nodates', | |
121 | default=False, |
|
121 | default=False, | |
122 | ) |
|
122 | ) | |
123 | coreconfigitem('annotate', 'showfunc', |
|
123 | coreconfigitem('annotate', 'showfunc', | |
124 | default=False, |
|
124 | default=False, | |
125 | ) |
|
125 | ) | |
126 | coreconfigitem('annotate', 'unified', |
|
126 | coreconfigitem('annotate', 'unified', | |
127 | default=None, |
|
127 | default=None, | |
128 | ) |
|
128 | ) | |
129 | coreconfigitem('annotate', 'git', |
|
129 | coreconfigitem('annotate', 'git', | |
130 | default=False, |
|
130 | default=False, | |
131 | ) |
|
131 | ) | |
132 | coreconfigitem('annotate', 'ignorews', |
|
132 | coreconfigitem('annotate', 'ignorews', | |
133 | default=False, |
|
133 | default=False, | |
134 | ) |
|
134 | ) | |
135 | coreconfigitem('annotate', 'ignorewsamount', |
|
135 | coreconfigitem('annotate', 'ignorewsamount', | |
136 | default=False, |
|
136 | default=False, | |
137 | ) |
|
137 | ) | |
138 | coreconfigitem('annotate', 'ignoreblanklines', |
|
138 | coreconfigitem('annotate', 'ignoreblanklines', | |
139 | default=False, |
|
139 | default=False, | |
140 | ) |
|
140 | ) | |
141 | coreconfigitem('annotate', 'ignorewseol', |
|
141 | coreconfigitem('annotate', 'ignorewseol', | |
142 | default=False, |
|
142 | default=False, | |
143 | ) |
|
143 | ) | |
144 | coreconfigitem('annotate', 'nobinary', |
|
144 | coreconfigitem('annotate', 'nobinary', | |
145 | default=False, |
|
145 | default=False, | |
146 | ) |
|
146 | ) | |
147 | coreconfigitem('annotate', 'noprefix', |
|
147 | coreconfigitem('annotate', 'noprefix', | |
148 | default=False, |
|
148 | default=False, | |
149 | ) |
|
149 | ) | |
150 | coreconfigitem('auth', 'cookiefile', |
|
150 | coreconfigitem('auth', 'cookiefile', | |
151 | default=None, |
|
151 | default=None, | |
152 | ) |
|
152 | ) | |
153 | # bookmarks.pushing: internal hack for discovery |
|
153 | # bookmarks.pushing: internal hack for discovery | |
154 | coreconfigitem('bookmarks', 'pushing', |
|
154 | coreconfigitem('bookmarks', 'pushing', | |
155 | default=list, |
|
155 | default=list, | |
156 | ) |
|
156 | ) | |
157 | # bundle.mainreporoot: internal hack for bundlerepo |
|
157 | # bundle.mainreporoot: internal hack for bundlerepo | |
158 | coreconfigitem('bundle', 'mainreporoot', |
|
158 | coreconfigitem('bundle', 'mainreporoot', | |
159 | default='', |
|
159 | default='', | |
160 | ) |
|
160 | ) | |
161 | # bundle.reorder: experimental config |
|
161 | # bundle.reorder: experimental config | |
162 | coreconfigitem('bundle', 'reorder', |
|
162 | coreconfigitem('bundle', 'reorder', | |
163 | default='auto', |
|
163 | default='auto', | |
164 | ) |
|
164 | ) | |
165 | coreconfigitem('censor', 'policy', |
|
165 | coreconfigitem('censor', 'policy', | |
166 | default='abort', |
|
166 | default='abort', | |
167 | ) |
|
167 | ) | |
168 | coreconfigitem('chgserver', 'idletimeout', |
|
168 | coreconfigitem('chgserver', 'idletimeout', | |
169 | default=3600, |
|
169 | default=3600, | |
170 | ) |
|
170 | ) | |
171 | coreconfigitem('chgserver', 'skiphash', |
|
171 | coreconfigitem('chgserver', 'skiphash', | |
172 | default=False, |
|
172 | default=False, | |
173 | ) |
|
173 | ) | |
174 | coreconfigitem('cmdserver', 'log', |
|
174 | coreconfigitem('cmdserver', 'log', | |
175 | default=None, |
|
175 | default=None, | |
176 | ) |
|
176 | ) | |
177 | coreconfigitem('color', '.*', |
|
177 | coreconfigitem('color', '.*', | |
178 | default=None, |
|
178 | default=None, | |
179 | generic=True, |
|
179 | generic=True, | |
180 | ) |
|
180 | ) | |
181 | coreconfigitem('color', 'mode', |
|
181 | coreconfigitem('color', 'mode', | |
182 | default='auto', |
|
182 | default='auto', | |
183 | ) |
|
183 | ) | |
184 | coreconfigitem('color', 'pagermode', |
|
184 | coreconfigitem('color', 'pagermode', | |
185 | default=dynamicdefault, |
|
185 | default=dynamicdefault, | |
186 | ) |
|
186 | ) | |
187 | coreconfigitem('commands', 'show.aliasprefix', |
|
187 | coreconfigitem('commands', 'show.aliasprefix', | |
188 | default=list, |
|
188 | default=list, | |
189 | ) |
|
189 | ) | |
190 | coreconfigitem('commands', 'status.relative', |
|
190 | coreconfigitem('commands', 'status.relative', | |
191 | default=False, |
|
191 | default=False, | |
192 | ) |
|
192 | ) | |
193 | coreconfigitem('commands', 'status.skipstates', |
|
193 | coreconfigitem('commands', 'status.skipstates', | |
194 | default=[], |
|
194 | default=[], | |
195 | ) |
|
195 | ) | |
196 | coreconfigitem('commands', 'status.verbose', |
|
196 | coreconfigitem('commands', 'status.verbose', | |
197 | default=False, |
|
197 | default=False, | |
198 | ) |
|
198 | ) | |
199 | coreconfigitem('commands', 'update.check', |
|
199 | coreconfigitem('commands', 'update.check', | |
200 | default=None, |
|
200 | default=None, | |
201 | # Deprecated, remove after 4.4 release |
|
201 | # Deprecated, remove after 4.4 release | |
202 | alias=[('experimental', 'updatecheck')] |
|
202 | alias=[('experimental', 'updatecheck')] | |
203 | ) |
|
203 | ) | |
204 | coreconfigitem('commands', 'update.requiredest', |
|
204 | coreconfigitem('commands', 'update.requiredest', | |
205 | default=False, |
|
205 | default=False, | |
206 | ) |
|
206 | ) | |
207 | coreconfigitem('committemplate', '.*', |
|
207 | coreconfigitem('committemplate', '.*', | |
208 | default=None, |
|
208 | default=None, | |
209 | generic=True, |
|
209 | generic=True, | |
210 | ) |
|
210 | ) | |
211 | coreconfigitem('convert', 'cvsps.cache', |
|
211 | coreconfigitem('convert', 'cvsps.cache', | |
212 | default=True, |
|
212 | default=True, | |
213 | ) |
|
213 | ) | |
214 | coreconfigitem('convert', 'cvsps.fuzz', |
|
214 | coreconfigitem('convert', 'cvsps.fuzz', | |
215 | default=60, |
|
215 | default=60, | |
216 | ) |
|
216 | ) | |
217 | coreconfigitem('convert', 'cvsps.logencoding', |
|
217 | coreconfigitem('convert', 'cvsps.logencoding', | |
218 | default=None, |
|
218 | default=None, | |
219 | ) |
|
219 | ) | |
220 | coreconfigitem('convert', 'cvsps.mergefrom', |
|
220 | coreconfigitem('convert', 'cvsps.mergefrom', | |
221 | default=None, |
|
221 | default=None, | |
222 | ) |
|
222 | ) | |
223 | coreconfigitem('convert', 'cvsps.mergeto', |
|
223 | coreconfigitem('convert', 'cvsps.mergeto', | |
224 | default=None, |
|
224 | default=None, | |
225 | ) |
|
225 | ) | |
226 | coreconfigitem('convert', 'git.committeractions', |
|
226 | coreconfigitem('convert', 'git.committeractions', | |
227 | default=lambda: ['messagedifferent'], |
|
227 | default=lambda: ['messagedifferent'], | |
228 | ) |
|
228 | ) | |
229 | coreconfigitem('convert', 'git.extrakeys', |
|
229 | coreconfigitem('convert', 'git.extrakeys', | |
230 | default=list, |
|
230 | default=list, | |
231 | ) |
|
231 | ) | |
232 | coreconfigitem('convert', 'git.findcopiesharder', |
|
232 | coreconfigitem('convert', 'git.findcopiesharder', | |
233 | default=False, |
|
233 | default=False, | |
234 | ) |
|
234 | ) | |
235 | coreconfigitem('convert', 'git.remoteprefix', |
|
235 | coreconfigitem('convert', 'git.remoteprefix', | |
236 | default='remote', |
|
236 | default='remote', | |
237 | ) |
|
237 | ) | |
238 | coreconfigitem('convert', 'git.renamelimit', |
|
238 | coreconfigitem('convert', 'git.renamelimit', | |
239 | default=400, |
|
239 | default=400, | |
240 | ) |
|
240 | ) | |
241 | coreconfigitem('convert', 'git.saverev', |
|
241 | coreconfigitem('convert', 'git.saverev', | |
242 | default=True, |
|
242 | default=True, | |
243 | ) |
|
243 | ) | |
244 | coreconfigitem('convert', 'git.similarity', |
|
244 | coreconfigitem('convert', 'git.similarity', | |
245 | default=50, |
|
245 | default=50, | |
246 | ) |
|
246 | ) | |
247 | coreconfigitem('convert', 'git.skipsubmodules', |
|
247 | coreconfigitem('convert', 'git.skipsubmodules', | |
248 | default=False, |
|
248 | default=False, | |
249 | ) |
|
249 | ) | |
250 | coreconfigitem('convert', 'hg.clonebranches', |
|
250 | coreconfigitem('convert', 'hg.clonebranches', | |
251 | default=False, |
|
251 | default=False, | |
252 | ) |
|
252 | ) | |
253 | coreconfigitem('convert', 'hg.ignoreerrors', |
|
253 | coreconfigitem('convert', 'hg.ignoreerrors', | |
254 | default=False, |
|
254 | default=False, | |
255 | ) |
|
255 | ) | |
256 | coreconfigitem('convert', 'hg.revs', |
|
256 | coreconfigitem('convert', 'hg.revs', | |
257 | default=None, |
|
257 | default=None, | |
258 | ) |
|
258 | ) | |
259 | coreconfigitem('convert', 'hg.saverev', |
|
259 | coreconfigitem('convert', 'hg.saverev', | |
260 | default=False, |
|
260 | default=False, | |
261 | ) |
|
261 | ) | |
262 | coreconfigitem('convert', 'hg.sourcename', |
|
262 | coreconfigitem('convert', 'hg.sourcename', | |
263 | default=None, |
|
263 | default=None, | |
264 | ) |
|
264 | ) | |
265 | coreconfigitem('convert', 'hg.startrev', |
|
265 | coreconfigitem('convert', 'hg.startrev', | |
266 | default=None, |
|
266 | default=None, | |
267 | ) |
|
267 | ) | |
268 | coreconfigitem('convert', 'hg.tagsbranch', |
|
268 | coreconfigitem('convert', 'hg.tagsbranch', | |
269 | default='default', |
|
269 | default='default', | |
270 | ) |
|
270 | ) | |
271 | coreconfigitem('convert', 'hg.usebranchnames', |
|
271 | coreconfigitem('convert', 'hg.usebranchnames', | |
272 | default=True, |
|
272 | default=True, | |
273 | ) |
|
273 | ) | |
274 | coreconfigitem('convert', 'ignoreancestorcheck', |
|
274 | coreconfigitem('convert', 'ignoreancestorcheck', | |
275 | default=False, |
|
275 | default=False, | |
276 | ) |
|
276 | ) | |
277 | coreconfigitem('convert', 'localtimezone', |
|
277 | coreconfigitem('convert', 'localtimezone', | |
278 | default=False, |
|
278 | default=False, | |
279 | ) |
|
279 | ) | |
280 | coreconfigitem('convert', 'p4.encoding', |
|
280 | coreconfigitem('convert', 'p4.encoding', | |
281 | default=dynamicdefault, |
|
281 | default=dynamicdefault, | |
282 | ) |
|
282 | ) | |
283 | coreconfigitem('convert', 'p4.startrev', |
|
283 | coreconfigitem('convert', 'p4.startrev', | |
284 | default=0, |
|
284 | default=0, | |
285 | ) |
|
285 | ) | |
286 | coreconfigitem('convert', 'skiptags', |
|
286 | coreconfigitem('convert', 'skiptags', | |
287 | default=False, |
|
287 | default=False, | |
288 | ) |
|
288 | ) | |
289 | coreconfigitem('convert', 'svn.debugsvnlog', |
|
289 | coreconfigitem('convert', 'svn.debugsvnlog', | |
290 | default=True, |
|
290 | default=True, | |
291 | ) |
|
291 | ) | |
292 | coreconfigitem('convert', 'svn.trunk', |
|
292 | coreconfigitem('convert', 'svn.trunk', | |
293 | default=None, |
|
293 | default=None, | |
294 | ) |
|
294 | ) | |
295 | coreconfigitem('convert', 'svn.tags', |
|
295 | coreconfigitem('convert', 'svn.tags', | |
296 | default=None, |
|
296 | default=None, | |
297 | ) |
|
297 | ) | |
298 | coreconfigitem('convert', 'svn.branches', |
|
298 | coreconfigitem('convert', 'svn.branches', | |
299 | default=None, |
|
299 | default=None, | |
300 | ) |
|
300 | ) | |
301 | coreconfigitem('convert', 'svn.startrev', |
|
301 | coreconfigitem('convert', 'svn.startrev', | |
302 | default=0, |
|
302 | default=0, | |
303 | ) |
|
303 | ) | |
304 | coreconfigitem('debug', 'dirstate.delaywrite', |
|
304 | coreconfigitem('debug', 'dirstate.delaywrite', | |
305 | default=0, |
|
305 | default=0, | |
306 | ) |
|
306 | ) | |
307 | coreconfigitem('defaults', '.*', |
|
307 | coreconfigitem('defaults', '.*', | |
308 | default=None, |
|
308 | default=None, | |
309 | generic=True, |
|
309 | generic=True, | |
310 | ) |
|
310 | ) | |
311 | coreconfigitem('devel', 'all-warnings', |
|
311 | coreconfigitem('devel', 'all-warnings', | |
312 | default=False, |
|
312 | default=False, | |
313 | ) |
|
313 | ) | |
314 | coreconfigitem('devel', 'bundle2.debug', |
|
314 | coreconfigitem('devel', 'bundle2.debug', | |
315 | default=False, |
|
315 | default=False, | |
316 | ) |
|
316 | ) | |
317 | coreconfigitem('devel', 'cache-vfs', |
|
317 | coreconfigitem('devel', 'cache-vfs', | |
318 | default=None, |
|
318 | default=None, | |
319 | ) |
|
319 | ) | |
320 | coreconfigitem('devel', 'check-locks', |
|
320 | coreconfigitem('devel', 'check-locks', | |
321 | default=False, |
|
321 | default=False, | |
322 | ) |
|
322 | ) | |
323 | coreconfigitem('devel', 'check-relroot', |
|
323 | coreconfigitem('devel', 'check-relroot', | |
324 | default=False, |
|
324 | default=False, | |
325 | ) |
|
325 | ) | |
326 | coreconfigitem('devel', 'default-date', |
|
326 | coreconfigitem('devel', 'default-date', | |
327 | default=None, |
|
327 | default=None, | |
328 | ) |
|
328 | ) | |
329 | coreconfigitem('devel', 'deprec-warn', |
|
329 | coreconfigitem('devel', 'deprec-warn', | |
330 | default=False, |
|
330 | default=False, | |
331 | ) |
|
331 | ) | |
332 | coreconfigitem('devel', 'disableloaddefaultcerts', |
|
332 | coreconfigitem('devel', 'disableloaddefaultcerts', | |
333 | default=False, |
|
333 | default=False, | |
334 | ) |
|
334 | ) | |
335 | coreconfigitem('devel', 'warn-empty-changegroup', |
|
335 | coreconfigitem('devel', 'warn-empty-changegroup', | |
336 | default=False, |
|
336 | default=False, | |
337 | ) |
|
337 | ) | |
338 | coreconfigitem('devel', 'legacy.exchange', |
|
338 | coreconfigitem('devel', 'legacy.exchange', | |
339 | default=list, |
|
339 | default=list, | |
340 | ) |
|
340 | ) | |
341 | coreconfigitem('devel', 'servercafile', |
|
341 | coreconfigitem('devel', 'servercafile', | |
342 | default='', |
|
342 | default='', | |
343 | ) |
|
343 | ) | |
344 | coreconfigitem('devel', 'serverexactprotocol', |
|
344 | coreconfigitem('devel', 'serverexactprotocol', | |
345 | default='', |
|
345 | default='', | |
346 | ) |
|
346 | ) | |
347 | coreconfigitem('devel', 'serverrequirecert', |
|
347 | coreconfigitem('devel', 'serverrequirecert', | |
348 | default=False, |
|
348 | default=False, | |
349 | ) |
|
349 | ) | |
350 | coreconfigitem('devel', 'strip-obsmarkers', |
|
350 | coreconfigitem('devel', 'strip-obsmarkers', | |
351 | default=True, |
|
351 | default=True, | |
352 | ) |
|
352 | ) | |
353 | coreconfigitem('devel', 'warn-config', |
|
353 | coreconfigitem('devel', 'warn-config', | |
354 | default=None, |
|
354 | default=None, | |
355 | ) |
|
355 | ) | |
356 | coreconfigitem('devel', 'warn-config-default', |
|
356 | coreconfigitem('devel', 'warn-config-default', | |
357 | default=None, |
|
357 | default=None, | |
358 | ) |
|
358 | ) | |
359 | coreconfigitem('devel', 'user.obsmarker', |
|
359 | coreconfigitem('devel', 'user.obsmarker', | |
360 | default=None, |
|
360 | default=None, | |
361 | ) |
|
361 | ) | |
362 | coreconfigitem('devel', 'warn-config-unknown', |
|
362 | coreconfigitem('devel', 'warn-config-unknown', | |
363 | default=None, |
|
363 | default=None, | |
364 | ) |
|
364 | ) | |
365 | coreconfigitem('devel', 'debug.peer-request', |
|
365 | coreconfigitem('devel', 'debug.peer-request', | |
366 | default=False, |
|
366 | default=False, | |
367 | ) |
|
367 | ) | |
368 | coreconfigitem('diff', 'nodates', |
|
368 | coreconfigitem('diff', 'nodates', | |
369 | default=False, |
|
369 | default=False, | |
370 | ) |
|
370 | ) | |
371 | coreconfigitem('diff', 'showfunc', |
|
371 | coreconfigitem('diff', 'showfunc', | |
372 | default=False, |
|
372 | default=False, | |
373 | ) |
|
373 | ) | |
374 | coreconfigitem('diff', 'unified', |
|
374 | coreconfigitem('diff', 'unified', | |
375 | default=None, |
|
375 | default=None, | |
376 | ) |
|
376 | ) | |
377 | coreconfigitem('diff', 'git', |
|
377 | coreconfigitem('diff', 'git', | |
378 | default=False, |
|
378 | default=False, | |
379 | ) |
|
379 | ) | |
380 | coreconfigitem('diff', 'ignorews', |
|
380 | coreconfigitem('diff', 'ignorews', | |
381 | default=False, |
|
381 | default=False, | |
382 | ) |
|
382 | ) | |
383 | coreconfigitem('diff', 'ignorewsamount', |
|
383 | coreconfigitem('diff', 'ignorewsamount', | |
384 | default=False, |
|
384 | default=False, | |
385 | ) |
|
385 | ) | |
386 | coreconfigitem('diff', 'ignoreblanklines', |
|
386 | coreconfigitem('diff', 'ignoreblanklines', | |
387 | default=False, |
|
387 | default=False, | |
388 | ) |
|
388 | ) | |
389 | coreconfigitem('diff', 'ignorewseol', |
|
389 | coreconfigitem('diff', 'ignorewseol', | |
390 | default=False, |
|
390 | default=False, | |
391 | ) |
|
391 | ) | |
392 | coreconfigitem('diff', 'nobinary', |
|
392 | coreconfigitem('diff', 'nobinary', | |
393 | default=False, |
|
393 | default=False, | |
394 | ) |
|
394 | ) | |
395 | coreconfigitem('diff', 'noprefix', |
|
395 | coreconfigitem('diff', 'noprefix', | |
396 | default=False, |
|
396 | default=False, | |
397 | ) |
|
397 | ) | |
398 | coreconfigitem('email', 'bcc', |
|
398 | coreconfigitem('email', 'bcc', | |
399 | default=None, |
|
399 | default=None, | |
400 | ) |
|
400 | ) | |
401 | coreconfigitem('email', 'cc', |
|
401 | coreconfigitem('email', 'cc', | |
402 | default=None, |
|
402 | default=None, | |
403 | ) |
|
403 | ) | |
404 | coreconfigitem('email', 'charsets', |
|
404 | coreconfigitem('email', 'charsets', | |
405 | default=list, |
|
405 | default=list, | |
406 | ) |
|
406 | ) | |
407 | coreconfigitem('email', 'from', |
|
407 | coreconfigitem('email', 'from', | |
408 | default=None, |
|
408 | default=None, | |
409 | ) |
|
409 | ) | |
410 | coreconfigitem('email', 'method', |
|
410 | coreconfigitem('email', 'method', | |
411 | default='smtp', |
|
411 | default='smtp', | |
412 | ) |
|
412 | ) | |
413 | coreconfigitem('email', 'reply-to', |
|
413 | coreconfigitem('email', 'reply-to', | |
414 | default=None, |
|
414 | default=None, | |
415 | ) |
|
415 | ) | |
416 | coreconfigitem('email', 'to', |
|
416 | coreconfigitem('email', 'to', | |
417 | default=None, |
|
417 | default=None, | |
418 | ) |
|
418 | ) | |
419 | coreconfigitem('experimental', 'archivemetatemplate', |
|
419 | coreconfigitem('experimental', 'archivemetatemplate', | |
420 | default=dynamicdefault, |
|
420 | default=dynamicdefault, | |
421 | ) |
|
421 | ) | |
422 | coreconfigitem('experimental', 'bundle-phases', |
|
422 | coreconfigitem('experimental', 'bundle-phases', | |
423 | default=False, |
|
423 | default=False, | |
424 | ) |
|
424 | ) | |
425 | coreconfigitem('experimental', 'bundle2-advertise', |
|
425 | coreconfigitem('experimental', 'bundle2-advertise', | |
426 | default=True, |
|
426 | default=True, | |
427 | ) |
|
427 | ) | |
428 | coreconfigitem('experimental', 'bundle2-output-capture', |
|
428 | coreconfigitem('experimental', 'bundle2-output-capture', | |
429 | default=False, |
|
429 | default=False, | |
430 | ) |
|
430 | ) | |
431 | coreconfigitem('experimental', 'bundle2.pushback', |
|
431 | coreconfigitem('experimental', 'bundle2.pushback', | |
432 | default=False, |
|
432 | default=False, | |
433 | ) |
|
433 | ) | |
434 | coreconfigitem('experimental', 'bundle2.stream', |
|
434 | coreconfigitem('experimental', 'bundle2.stream', | |
435 | default=False, |
|
435 | default=False, | |
436 | ) |
|
436 | ) | |
437 | coreconfigitem('experimental', 'bundle2lazylocking', |
|
437 | coreconfigitem('experimental', 'bundle2lazylocking', | |
438 | default=False, |
|
438 | default=False, | |
439 | ) |
|
439 | ) | |
440 | coreconfigitem('experimental', 'bundlecomplevel', |
|
440 | coreconfigitem('experimental', 'bundlecomplevel', | |
441 | default=None, |
|
441 | default=None, | |
442 | ) |
|
442 | ) | |
443 | coreconfigitem('experimental', 'changegroup3', |
|
443 | coreconfigitem('experimental', 'changegroup3', | |
444 | default=False, |
|
444 | default=False, | |
445 | ) |
|
445 | ) | |
446 | coreconfigitem('experimental', 'clientcompressionengines', |
|
446 | coreconfigitem('experimental', 'clientcompressionengines', | |
447 | default=list, |
|
447 | default=list, | |
448 | ) |
|
448 | ) | |
449 | coreconfigitem('experimental', 'copytrace', |
|
449 | coreconfigitem('experimental', 'copytrace', | |
450 | default='on', |
|
450 | default='on', | |
451 | ) |
|
451 | ) | |
452 | coreconfigitem('experimental', 'copytrace.movecandidateslimit', |
|
452 | coreconfigitem('experimental', 'copytrace.movecandidateslimit', | |
453 | default=100, |
|
453 | default=100, | |
454 | ) |
|
454 | ) | |
455 | coreconfigitem('experimental', 'copytrace.sourcecommitlimit', |
|
455 | coreconfigitem('experimental', 'copytrace.sourcecommitlimit', | |
456 | default=100, |
|
456 | default=100, | |
457 | ) |
|
457 | ) | |
458 | coreconfigitem('experimental', 'crecordtest', |
|
458 | coreconfigitem('experimental', 'crecordtest', | |
459 | default=None, |
|
459 | default=None, | |
460 | ) |
|
460 | ) | |
461 | coreconfigitem('experimental', 'directaccess', |
|
461 | coreconfigitem('experimental', 'directaccess', | |
462 | default=False, |
|
462 | default=False, | |
463 | ) |
|
463 | ) | |
464 | coreconfigitem('experimental', 'directaccess.revnums', |
|
464 | coreconfigitem('experimental', 'directaccess.revnums', | |
465 | default=False, |
|
465 | default=False, | |
466 | ) |
|
466 | ) | |
467 | coreconfigitem('experimental', 'editortmpinhg', |
|
467 | coreconfigitem('experimental', 'editortmpinhg', | |
468 | default=False, |
|
468 | default=False, | |
469 | ) |
|
469 | ) | |
470 | coreconfigitem('experimental', 'evolution', |
|
470 | coreconfigitem('experimental', 'evolution', | |
471 | default=list, |
|
471 | default=list, | |
472 | ) |
|
472 | ) | |
473 | coreconfigitem('experimental', 'evolution.allowdivergence', |
|
473 | coreconfigitem('experimental', 'evolution.allowdivergence', | |
474 | default=False, |
|
474 | default=False, | |
475 | alias=[('experimental', 'allowdivergence')] |
|
475 | alias=[('experimental', 'allowdivergence')] | |
476 | ) |
|
476 | ) | |
477 | coreconfigitem('experimental', 'evolution.allowunstable', |
|
477 | coreconfigitem('experimental', 'evolution.allowunstable', | |
478 | default=None, |
|
478 | default=None, | |
479 | ) |
|
479 | ) | |
480 | coreconfigitem('experimental', 'evolution.createmarkers', |
|
480 | coreconfigitem('experimental', 'evolution.createmarkers', | |
481 | default=None, |
|
481 | default=None, | |
482 | ) |
|
482 | ) | |
483 | coreconfigitem('experimental', 'evolution.effect-flags', |
|
483 | coreconfigitem('experimental', 'evolution.effect-flags', | |
484 | default=True, |
|
484 | default=True, | |
485 | alias=[('experimental', 'effect-flags')] |
|
485 | alias=[('experimental', 'effect-flags')] | |
486 | ) |
|
486 | ) | |
487 | coreconfigitem('experimental', 'evolution.exchange', |
|
487 | coreconfigitem('experimental', 'evolution.exchange', | |
488 | default=None, |
|
488 | default=None, | |
489 | ) |
|
489 | ) | |
490 | coreconfigitem('experimental', 'evolution.bundle-obsmarker', |
|
490 | coreconfigitem('experimental', 'evolution.bundle-obsmarker', | |
491 | default=False, |
|
491 | default=False, | |
492 | ) |
|
492 | ) | |
493 | coreconfigitem('experimental', 'evolution.report-instabilities', |
|
493 | coreconfigitem('experimental', 'evolution.report-instabilities', | |
494 | default=True, |
|
494 | default=True, | |
495 | ) |
|
495 | ) | |
496 | coreconfigitem('experimental', 'evolution.track-operation', |
|
496 | coreconfigitem('experimental', 'evolution.track-operation', | |
497 | default=True, |
|
497 | default=True, | |
498 | ) |
|
498 | ) | |
499 | coreconfigitem('experimental', 'worddiff', |
|
499 | coreconfigitem('experimental', 'worddiff', | |
500 | default=False, |
|
500 | default=False, | |
501 | ) |
|
501 | ) | |
502 | coreconfigitem('experimental', 'maxdeltachainspan', |
|
502 | coreconfigitem('experimental', 'maxdeltachainspan', | |
503 | default=-1, |
|
503 | default=-1, | |
504 | ) |
|
504 | ) | |
505 | coreconfigitem('experimental', 'mmapindexthreshold', |
|
505 | coreconfigitem('experimental', 'mmapindexthreshold', | |
506 | default=None, |
|
506 | default=None, | |
507 | ) |
|
507 | ) | |
508 | coreconfigitem('experimental', 'nonnormalparanoidcheck', |
|
508 | coreconfigitem('experimental', 'nonnormalparanoidcheck', | |
509 | default=False, |
|
509 | default=False, | |
510 | ) |
|
510 | ) | |
511 | coreconfigitem('experimental', 'exportableenviron', |
|
511 | coreconfigitem('experimental', 'exportableenviron', | |
512 | default=list, |
|
512 | default=list, | |
513 | ) |
|
513 | ) | |
514 | coreconfigitem('experimental', 'extendedheader.index', |
|
514 | coreconfigitem('experimental', 'extendedheader.index', | |
515 | default=None, |
|
515 | default=None, | |
516 | ) |
|
516 | ) | |
517 | coreconfigitem('experimental', 'extendedheader.similarity', |
|
517 | coreconfigitem('experimental', 'extendedheader.similarity', | |
518 | default=False, |
|
518 | default=False, | |
519 | ) |
|
519 | ) | |
520 | coreconfigitem('experimental', 'format.compression', |
|
520 | coreconfigitem('experimental', 'format.compression', | |
521 | default='zlib', |
|
521 | default='zlib', | |
522 | ) |
|
522 | ) | |
523 | coreconfigitem('experimental', 'graphshorten', |
|
523 | coreconfigitem('experimental', 'graphshorten', | |
524 | default=False, |
|
524 | default=False, | |
525 | ) |
|
525 | ) | |
526 | coreconfigitem('experimental', 'graphstyle.parent', |
|
526 | coreconfigitem('experimental', 'graphstyle.parent', | |
527 | default=dynamicdefault, |
|
527 | default=dynamicdefault, | |
528 | ) |
|
528 | ) | |
529 | coreconfigitem('experimental', 'graphstyle.missing', |
|
529 | coreconfigitem('experimental', 'graphstyle.missing', | |
530 | default=dynamicdefault, |
|
530 | default=dynamicdefault, | |
531 | ) |
|
531 | ) | |
532 | coreconfigitem('experimental', 'graphstyle.grandparent', |
|
532 | coreconfigitem('experimental', 'graphstyle.grandparent', | |
533 | default=dynamicdefault, |
|
533 | default=dynamicdefault, | |
534 | ) |
|
534 | ) | |
535 | coreconfigitem('experimental', 'hook-track-tags', |
|
535 | coreconfigitem('experimental', 'hook-track-tags', | |
536 | default=False, |
|
536 | default=False, | |
537 | ) |
|
537 | ) | |
538 | coreconfigitem('experimental', 'httppostargs', |
|
538 | coreconfigitem('experimental', 'httppostargs', | |
539 | default=False, |
|
539 | default=False, | |
540 | ) |
|
540 | ) | |
541 | coreconfigitem('experimental', 'manifestv2', |
|
541 | coreconfigitem('experimental', 'manifestv2', | |
542 | default=False, |
|
542 | default=False, | |
543 | ) |
|
543 | ) | |
544 | coreconfigitem('experimental', 'mergedriver', |
|
544 | coreconfigitem('experimental', 'mergedriver', | |
545 | default=None, |
|
545 | default=None, | |
546 | ) |
|
546 | ) | |
547 | coreconfigitem('experimental', 'obsmarkers-exchange-debug', |
|
547 | coreconfigitem('experimental', 'obsmarkers-exchange-debug', | |
548 | default=False, |
|
548 | default=False, | |
549 | ) |
|
549 | ) | |
550 | coreconfigitem('experimental', 'remotenames', |
|
550 | coreconfigitem('experimental', 'remotenames', | |
551 | default=False, |
|
551 | default=False, | |
552 | ) |
|
552 | ) | |
553 | coreconfigitem('experimental', 'revlogv2', |
|
553 | coreconfigitem('experimental', 'revlogv2', | |
554 | default=None, |
|
554 | default=None, | |
555 | ) |
|
555 | ) | |
556 | coreconfigitem('experimental', 'single-head-per-branch', |
|
556 | coreconfigitem('experimental', 'single-head-per-branch', | |
557 | default=False, |
|
557 | default=False, | |
558 | ) |
|
558 | ) | |
559 | coreconfigitem('experimental', 'spacemovesdown', |
|
559 | coreconfigitem('experimental', 'spacemovesdown', | |
560 | default=False, |
|
560 | default=False, | |
561 | ) |
|
561 | ) | |
562 | coreconfigitem('experimental', 'sparse-read', |
|
562 | coreconfigitem('experimental', 'sparse-read', | |
563 | default=False, |
|
563 | default=False, | |
564 | ) |
|
564 | ) | |
565 | coreconfigitem('experimental', 'sparse-read.density-threshold', |
|
565 | coreconfigitem('experimental', 'sparse-read.density-threshold', | |
566 | default=0.25, |
|
566 | default=0.25, | |
567 | ) |
|
567 | ) | |
568 | coreconfigitem('experimental', 'sparse-read.min-gap-size', |
|
568 | coreconfigitem('experimental', 'sparse-read.min-gap-size', | |
569 | default='256K', |
|
569 | default='256K', | |
570 | ) |
|
570 | ) | |
571 | coreconfigitem('experimental', 'treemanifest', |
|
571 | coreconfigitem('experimental', 'treemanifest', | |
572 | default=False, |
|
572 | default=False, | |
573 | ) |
|
573 | ) | |
574 | coreconfigitem('experimental', 'update.atomic-file', |
|
574 | coreconfigitem('experimental', 'update.atomic-file', | |
575 | default=False, |
|
575 | default=False, | |
576 | ) |
|
576 | ) | |
|
577 | coreconfigitem('experimental', 'sshpeer.advertise-v2', | |||
|
578 | default=False, | |||
|
579 | ) | |||
577 | coreconfigitem('extensions', '.*', |
|
580 | coreconfigitem('extensions', '.*', | |
578 | default=None, |
|
581 | default=None, | |
579 | generic=True, |
|
582 | generic=True, | |
580 | ) |
|
583 | ) | |
581 | coreconfigitem('extdata', '.*', |
|
584 | coreconfigitem('extdata', '.*', | |
582 | default=None, |
|
585 | default=None, | |
583 | generic=True, |
|
586 | generic=True, | |
584 | ) |
|
587 | ) | |
585 | coreconfigitem('format', 'aggressivemergedeltas', |
|
588 | coreconfigitem('format', 'aggressivemergedeltas', | |
586 | default=False, |
|
589 | default=False, | |
587 | ) |
|
590 | ) | |
588 | coreconfigitem('format', 'chunkcachesize', |
|
591 | coreconfigitem('format', 'chunkcachesize', | |
589 | default=None, |
|
592 | default=None, | |
590 | ) |
|
593 | ) | |
591 | coreconfigitem('format', 'dotencode', |
|
594 | coreconfigitem('format', 'dotencode', | |
592 | default=True, |
|
595 | default=True, | |
593 | ) |
|
596 | ) | |
594 | coreconfigitem('format', 'generaldelta', |
|
597 | coreconfigitem('format', 'generaldelta', | |
595 | default=False, |
|
598 | default=False, | |
596 | ) |
|
599 | ) | |
597 | coreconfigitem('format', 'manifestcachesize', |
|
600 | coreconfigitem('format', 'manifestcachesize', | |
598 | default=None, |
|
601 | default=None, | |
599 | ) |
|
602 | ) | |
600 | coreconfigitem('format', 'maxchainlen', |
|
603 | coreconfigitem('format', 'maxchainlen', | |
601 | default=None, |
|
604 | default=None, | |
602 | ) |
|
605 | ) | |
603 | coreconfigitem('format', 'obsstore-version', |
|
606 | coreconfigitem('format', 'obsstore-version', | |
604 | default=None, |
|
607 | default=None, | |
605 | ) |
|
608 | ) | |
606 | coreconfigitem('format', 'usefncache', |
|
609 | coreconfigitem('format', 'usefncache', | |
607 | default=True, |
|
610 | default=True, | |
608 | ) |
|
611 | ) | |
609 | coreconfigitem('format', 'usegeneraldelta', |
|
612 | coreconfigitem('format', 'usegeneraldelta', | |
610 | default=True, |
|
613 | default=True, | |
611 | ) |
|
614 | ) | |
612 | coreconfigitem('format', 'usestore', |
|
615 | coreconfigitem('format', 'usestore', | |
613 | default=True, |
|
616 | default=True, | |
614 | ) |
|
617 | ) | |
615 | coreconfigitem('fsmonitor', 'warn_when_unused', |
|
618 | coreconfigitem('fsmonitor', 'warn_when_unused', | |
616 | default=True, |
|
619 | default=True, | |
617 | ) |
|
620 | ) | |
618 | coreconfigitem('fsmonitor', 'warn_update_file_count', |
|
621 | coreconfigitem('fsmonitor', 'warn_update_file_count', | |
619 | default=50000, |
|
622 | default=50000, | |
620 | ) |
|
623 | ) | |
621 | coreconfigitem('hooks', '.*', |
|
624 | coreconfigitem('hooks', '.*', | |
622 | default=dynamicdefault, |
|
625 | default=dynamicdefault, | |
623 | generic=True, |
|
626 | generic=True, | |
624 | ) |
|
627 | ) | |
625 | coreconfigitem('hgweb-paths', '.*', |
|
628 | coreconfigitem('hgweb-paths', '.*', | |
626 | default=list, |
|
629 | default=list, | |
627 | generic=True, |
|
630 | generic=True, | |
628 | ) |
|
631 | ) | |
629 | coreconfigitem('hostfingerprints', '.*', |
|
632 | coreconfigitem('hostfingerprints', '.*', | |
630 | default=list, |
|
633 | default=list, | |
631 | generic=True, |
|
634 | generic=True, | |
632 | ) |
|
635 | ) | |
633 | coreconfigitem('hostsecurity', 'ciphers', |
|
636 | coreconfigitem('hostsecurity', 'ciphers', | |
634 | default=None, |
|
637 | default=None, | |
635 | ) |
|
638 | ) | |
636 | coreconfigitem('hostsecurity', 'disabletls10warning', |
|
639 | coreconfigitem('hostsecurity', 'disabletls10warning', | |
637 | default=False, |
|
640 | default=False, | |
638 | ) |
|
641 | ) | |
639 | coreconfigitem('hostsecurity', 'minimumprotocol', |
|
642 | coreconfigitem('hostsecurity', 'minimumprotocol', | |
640 | default=dynamicdefault, |
|
643 | default=dynamicdefault, | |
641 | ) |
|
644 | ) | |
642 | coreconfigitem('hostsecurity', '.*:minimumprotocol$', |
|
645 | coreconfigitem('hostsecurity', '.*:minimumprotocol$', | |
643 | default=dynamicdefault, |
|
646 | default=dynamicdefault, | |
644 | generic=True, |
|
647 | generic=True, | |
645 | ) |
|
648 | ) | |
646 | coreconfigitem('hostsecurity', '.*:ciphers$', |
|
649 | coreconfigitem('hostsecurity', '.*:ciphers$', | |
647 | default=dynamicdefault, |
|
650 | default=dynamicdefault, | |
648 | generic=True, |
|
651 | generic=True, | |
649 | ) |
|
652 | ) | |
650 | coreconfigitem('hostsecurity', '.*:fingerprints$', |
|
653 | coreconfigitem('hostsecurity', '.*:fingerprints$', | |
651 | default=list, |
|
654 | default=list, | |
652 | generic=True, |
|
655 | generic=True, | |
653 | ) |
|
656 | ) | |
654 | coreconfigitem('hostsecurity', '.*:verifycertsfile$', |
|
657 | coreconfigitem('hostsecurity', '.*:verifycertsfile$', | |
655 | default=None, |
|
658 | default=None, | |
656 | generic=True, |
|
659 | generic=True, | |
657 | ) |
|
660 | ) | |
658 |
|
661 | |||
659 | coreconfigitem('http_proxy', 'always', |
|
662 | coreconfigitem('http_proxy', 'always', | |
660 | default=False, |
|
663 | default=False, | |
661 | ) |
|
664 | ) | |
662 | coreconfigitem('http_proxy', 'host', |
|
665 | coreconfigitem('http_proxy', 'host', | |
663 | default=None, |
|
666 | default=None, | |
664 | ) |
|
667 | ) | |
665 | coreconfigitem('http_proxy', 'no', |
|
668 | coreconfigitem('http_proxy', 'no', | |
666 | default=list, |
|
669 | default=list, | |
667 | ) |
|
670 | ) | |
668 | coreconfigitem('http_proxy', 'passwd', |
|
671 | coreconfigitem('http_proxy', 'passwd', | |
669 | default=None, |
|
672 | default=None, | |
670 | ) |
|
673 | ) | |
671 | coreconfigitem('http_proxy', 'user', |
|
674 | coreconfigitem('http_proxy', 'user', | |
672 | default=None, |
|
675 | default=None, | |
673 | ) |
|
676 | ) | |
674 | coreconfigitem('logtoprocess', 'commandexception', |
|
677 | coreconfigitem('logtoprocess', 'commandexception', | |
675 | default=None, |
|
678 | default=None, | |
676 | ) |
|
679 | ) | |
677 | coreconfigitem('logtoprocess', 'commandfinish', |
|
680 | coreconfigitem('logtoprocess', 'commandfinish', | |
678 | default=None, |
|
681 | default=None, | |
679 | ) |
|
682 | ) | |
680 | coreconfigitem('logtoprocess', 'command', |
|
683 | coreconfigitem('logtoprocess', 'command', | |
681 | default=None, |
|
684 | default=None, | |
682 | ) |
|
685 | ) | |
683 | coreconfigitem('logtoprocess', 'develwarn', |
|
686 | coreconfigitem('logtoprocess', 'develwarn', | |
684 | default=None, |
|
687 | default=None, | |
685 | ) |
|
688 | ) | |
686 | coreconfigitem('logtoprocess', 'uiblocked', |
|
689 | coreconfigitem('logtoprocess', 'uiblocked', | |
687 | default=None, |
|
690 | default=None, | |
688 | ) |
|
691 | ) | |
689 | coreconfigitem('merge', 'checkunknown', |
|
692 | coreconfigitem('merge', 'checkunknown', | |
690 | default='abort', |
|
693 | default='abort', | |
691 | ) |
|
694 | ) | |
692 | coreconfigitem('merge', 'checkignored', |
|
695 | coreconfigitem('merge', 'checkignored', | |
693 | default='abort', |
|
696 | default='abort', | |
694 | ) |
|
697 | ) | |
695 | coreconfigitem('experimental', 'merge.checkpathconflicts', |
|
698 | coreconfigitem('experimental', 'merge.checkpathconflicts', | |
696 | default=False, |
|
699 | default=False, | |
697 | ) |
|
700 | ) | |
698 | coreconfigitem('merge', 'followcopies', |
|
701 | coreconfigitem('merge', 'followcopies', | |
699 | default=True, |
|
702 | default=True, | |
700 | ) |
|
703 | ) | |
701 | coreconfigitem('merge', 'on-failure', |
|
704 | coreconfigitem('merge', 'on-failure', | |
702 | default='continue', |
|
705 | default='continue', | |
703 | ) |
|
706 | ) | |
704 | coreconfigitem('merge', 'preferancestor', |
|
707 | coreconfigitem('merge', 'preferancestor', | |
705 | default=lambda: ['*'], |
|
708 | default=lambda: ['*'], | |
706 | ) |
|
709 | ) | |
707 | coreconfigitem('merge-tools', '.*', |
|
710 | coreconfigitem('merge-tools', '.*', | |
708 | default=None, |
|
711 | default=None, | |
709 | generic=True, |
|
712 | generic=True, | |
710 | ) |
|
713 | ) | |
711 | coreconfigitem('merge-tools', br'.*\.args$', |
|
714 | coreconfigitem('merge-tools', br'.*\.args$', | |
712 | default="$local $base $other", |
|
715 | default="$local $base $other", | |
713 | generic=True, |
|
716 | generic=True, | |
714 | priority=-1, |
|
717 | priority=-1, | |
715 | ) |
|
718 | ) | |
716 | coreconfigitem('merge-tools', br'.*\.binary$', |
|
719 | coreconfigitem('merge-tools', br'.*\.binary$', | |
717 | default=False, |
|
720 | default=False, | |
718 | generic=True, |
|
721 | generic=True, | |
719 | priority=-1, |
|
722 | priority=-1, | |
720 | ) |
|
723 | ) | |
721 | coreconfigitem('merge-tools', br'.*\.check$', |
|
724 | coreconfigitem('merge-tools', br'.*\.check$', | |
722 | default=list, |
|
725 | default=list, | |
723 | generic=True, |
|
726 | generic=True, | |
724 | priority=-1, |
|
727 | priority=-1, | |
725 | ) |
|
728 | ) | |
726 | coreconfigitem('merge-tools', br'.*\.checkchanged$', |
|
729 | coreconfigitem('merge-tools', br'.*\.checkchanged$', | |
727 | default=False, |
|
730 | default=False, | |
728 | generic=True, |
|
731 | generic=True, | |
729 | priority=-1, |
|
732 | priority=-1, | |
730 | ) |
|
733 | ) | |
731 | coreconfigitem('merge-tools', br'.*\.executable$', |
|
734 | coreconfigitem('merge-tools', br'.*\.executable$', | |
732 | default=dynamicdefault, |
|
735 | default=dynamicdefault, | |
733 | generic=True, |
|
736 | generic=True, | |
734 | priority=-1, |
|
737 | priority=-1, | |
735 | ) |
|
738 | ) | |
736 | coreconfigitem('merge-tools', br'.*\.fixeol$', |
|
739 | coreconfigitem('merge-tools', br'.*\.fixeol$', | |
737 | default=False, |
|
740 | default=False, | |
738 | generic=True, |
|
741 | generic=True, | |
739 | priority=-1, |
|
742 | priority=-1, | |
740 | ) |
|
743 | ) | |
741 | coreconfigitem('merge-tools', br'.*\.gui$', |
|
744 | coreconfigitem('merge-tools', br'.*\.gui$', | |
742 | default=False, |
|
745 | default=False, | |
743 | generic=True, |
|
746 | generic=True, | |
744 | priority=-1, |
|
747 | priority=-1, | |
745 | ) |
|
748 | ) | |
746 | coreconfigitem('merge-tools', br'.*\.mergemarkers$', |
|
749 | coreconfigitem('merge-tools', br'.*\.mergemarkers$', | |
747 | default='basic', |
|
750 | default='basic', | |
748 | generic=True, |
|
751 | generic=True, | |
749 | priority=-1, |
|
752 | priority=-1, | |
750 | ) |
|
753 | ) | |
751 | coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$', |
|
754 | coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$', | |
752 | default=dynamicdefault, # take from ui.mergemarkertemplate |
|
755 | default=dynamicdefault, # take from ui.mergemarkertemplate | |
753 | generic=True, |
|
756 | generic=True, | |
754 | priority=-1, |
|
757 | priority=-1, | |
755 | ) |
|
758 | ) | |
756 | coreconfigitem('merge-tools', br'.*\.priority$', |
|
759 | coreconfigitem('merge-tools', br'.*\.priority$', | |
757 | default=0, |
|
760 | default=0, | |
758 | generic=True, |
|
761 | generic=True, | |
759 | priority=-1, |
|
762 | priority=-1, | |
760 | ) |
|
763 | ) | |
761 | coreconfigitem('merge-tools', br'.*\.premerge$', |
|
764 | coreconfigitem('merge-tools', br'.*\.premerge$', | |
762 | default=dynamicdefault, |
|
765 | default=dynamicdefault, | |
763 | generic=True, |
|
766 | generic=True, | |
764 | priority=-1, |
|
767 | priority=-1, | |
765 | ) |
|
768 | ) | |
766 | coreconfigitem('merge-tools', br'.*\.symlink$', |
|
769 | coreconfigitem('merge-tools', br'.*\.symlink$', | |
767 | default=False, |
|
770 | default=False, | |
768 | generic=True, |
|
771 | generic=True, | |
769 | priority=-1, |
|
772 | priority=-1, | |
770 | ) |
|
773 | ) | |
771 | coreconfigitem('pager', 'attend-.*', |
|
774 | coreconfigitem('pager', 'attend-.*', | |
772 | default=dynamicdefault, |
|
775 | default=dynamicdefault, | |
773 | generic=True, |
|
776 | generic=True, | |
774 | ) |
|
777 | ) | |
775 | coreconfigitem('pager', 'ignore', |
|
778 | coreconfigitem('pager', 'ignore', | |
776 | default=list, |
|
779 | default=list, | |
777 | ) |
|
780 | ) | |
778 | coreconfigitem('pager', 'pager', |
|
781 | coreconfigitem('pager', 'pager', | |
779 | default=dynamicdefault, |
|
782 | default=dynamicdefault, | |
780 | ) |
|
783 | ) | |
781 | coreconfigitem('patch', 'eol', |
|
784 | coreconfigitem('patch', 'eol', | |
782 | default='strict', |
|
785 | default='strict', | |
783 | ) |
|
786 | ) | |
784 | coreconfigitem('patch', 'fuzz', |
|
787 | coreconfigitem('patch', 'fuzz', | |
785 | default=2, |
|
788 | default=2, | |
786 | ) |
|
789 | ) | |
787 | coreconfigitem('paths', 'default', |
|
790 | coreconfigitem('paths', 'default', | |
788 | default=None, |
|
791 | default=None, | |
789 | ) |
|
792 | ) | |
790 | coreconfigitem('paths', 'default-push', |
|
793 | coreconfigitem('paths', 'default-push', | |
791 | default=None, |
|
794 | default=None, | |
792 | ) |
|
795 | ) | |
793 | coreconfigitem('paths', '.*', |
|
796 | coreconfigitem('paths', '.*', | |
794 | default=None, |
|
797 | default=None, | |
795 | generic=True, |
|
798 | generic=True, | |
796 | ) |
|
799 | ) | |
797 | coreconfigitem('phases', 'checksubrepos', |
|
800 | coreconfigitem('phases', 'checksubrepos', | |
798 | default='follow', |
|
801 | default='follow', | |
799 | ) |
|
802 | ) | |
800 | coreconfigitem('phases', 'new-commit', |
|
803 | coreconfigitem('phases', 'new-commit', | |
801 | default='draft', |
|
804 | default='draft', | |
802 | ) |
|
805 | ) | |
803 | coreconfigitem('phases', 'publish', |
|
806 | coreconfigitem('phases', 'publish', | |
804 | default=True, |
|
807 | default=True, | |
805 | ) |
|
808 | ) | |
806 | coreconfigitem('profiling', 'enabled', |
|
809 | coreconfigitem('profiling', 'enabled', | |
807 | default=False, |
|
810 | default=False, | |
808 | ) |
|
811 | ) | |
809 | coreconfigitem('profiling', 'format', |
|
812 | coreconfigitem('profiling', 'format', | |
810 | default='text', |
|
813 | default='text', | |
811 | ) |
|
814 | ) | |
812 | coreconfigitem('profiling', 'freq', |
|
815 | coreconfigitem('profiling', 'freq', | |
813 | default=1000, |
|
816 | default=1000, | |
814 | ) |
|
817 | ) | |
815 | coreconfigitem('profiling', 'limit', |
|
818 | coreconfigitem('profiling', 'limit', | |
816 | default=30, |
|
819 | default=30, | |
817 | ) |
|
820 | ) | |
818 | coreconfigitem('profiling', 'nested', |
|
821 | coreconfigitem('profiling', 'nested', | |
819 | default=0, |
|
822 | default=0, | |
820 | ) |
|
823 | ) | |
821 | coreconfigitem('profiling', 'output', |
|
824 | coreconfigitem('profiling', 'output', | |
822 | default=None, |
|
825 | default=None, | |
823 | ) |
|
826 | ) | |
824 | coreconfigitem('profiling', 'showmax', |
|
827 | coreconfigitem('profiling', 'showmax', | |
825 | default=0.999, |
|
828 | default=0.999, | |
826 | ) |
|
829 | ) | |
827 | coreconfigitem('profiling', 'showmin', |
|
830 | coreconfigitem('profiling', 'showmin', | |
828 | default=dynamicdefault, |
|
831 | default=dynamicdefault, | |
829 | ) |
|
832 | ) | |
830 | coreconfigitem('profiling', 'sort', |
|
833 | coreconfigitem('profiling', 'sort', | |
831 | default='inlinetime', |
|
834 | default='inlinetime', | |
832 | ) |
|
835 | ) | |
833 | coreconfigitem('profiling', 'statformat', |
|
836 | coreconfigitem('profiling', 'statformat', | |
834 | default='hotpath', |
|
837 | default='hotpath', | |
835 | ) |
|
838 | ) | |
836 | coreconfigitem('profiling', 'type', |
|
839 | coreconfigitem('profiling', 'type', | |
837 | default='stat', |
|
840 | default='stat', | |
838 | ) |
|
841 | ) | |
839 | coreconfigitem('progress', 'assume-tty', |
|
842 | coreconfigitem('progress', 'assume-tty', | |
840 | default=False, |
|
843 | default=False, | |
841 | ) |
|
844 | ) | |
842 | coreconfigitem('progress', 'changedelay', |
|
845 | coreconfigitem('progress', 'changedelay', | |
843 | default=1, |
|
846 | default=1, | |
844 | ) |
|
847 | ) | |
845 | coreconfigitem('progress', 'clear-complete', |
|
848 | coreconfigitem('progress', 'clear-complete', | |
846 | default=True, |
|
849 | default=True, | |
847 | ) |
|
850 | ) | |
848 | coreconfigitem('progress', 'debug', |
|
851 | coreconfigitem('progress', 'debug', | |
849 | default=False, |
|
852 | default=False, | |
850 | ) |
|
853 | ) | |
851 | coreconfigitem('progress', 'delay', |
|
854 | coreconfigitem('progress', 'delay', | |
852 | default=3, |
|
855 | default=3, | |
853 | ) |
|
856 | ) | |
854 | coreconfigitem('progress', 'disable', |
|
857 | coreconfigitem('progress', 'disable', | |
855 | default=False, |
|
858 | default=False, | |
856 | ) |
|
859 | ) | |
857 | coreconfigitem('progress', 'estimateinterval', |
|
860 | coreconfigitem('progress', 'estimateinterval', | |
858 | default=60.0, |
|
861 | default=60.0, | |
859 | ) |
|
862 | ) | |
860 | coreconfigitem('progress', 'format', |
|
863 | coreconfigitem('progress', 'format', | |
861 | default=lambda: ['topic', 'bar', 'number', 'estimate'], |
|
864 | default=lambda: ['topic', 'bar', 'number', 'estimate'], | |
862 | ) |
|
865 | ) | |
863 | coreconfigitem('progress', 'refresh', |
|
866 | coreconfigitem('progress', 'refresh', | |
864 | default=0.1, |
|
867 | default=0.1, | |
865 | ) |
|
868 | ) | |
866 | coreconfigitem('progress', 'width', |
|
869 | coreconfigitem('progress', 'width', | |
867 | default=dynamicdefault, |
|
870 | default=dynamicdefault, | |
868 | ) |
|
871 | ) | |
869 | coreconfigitem('push', 'pushvars.server', |
|
872 | coreconfigitem('push', 'pushvars.server', | |
870 | default=False, |
|
873 | default=False, | |
871 | ) |
|
874 | ) | |
872 | coreconfigitem('server', 'bookmarks-pushkey-compat', |
|
875 | coreconfigitem('server', 'bookmarks-pushkey-compat', | |
873 | default=True, |
|
876 | default=True, | |
874 | ) |
|
877 | ) | |
875 | coreconfigitem('server', 'bundle1', |
|
878 | coreconfigitem('server', 'bundle1', | |
876 | default=True, |
|
879 | default=True, | |
877 | ) |
|
880 | ) | |
878 | coreconfigitem('server', 'bundle1gd', |
|
881 | coreconfigitem('server', 'bundle1gd', | |
879 | default=None, |
|
882 | default=None, | |
880 | ) |
|
883 | ) | |
881 | coreconfigitem('server', 'bundle1.pull', |
|
884 | coreconfigitem('server', 'bundle1.pull', | |
882 | default=None, |
|
885 | default=None, | |
883 | ) |
|
886 | ) | |
884 | coreconfigitem('server', 'bundle1gd.pull', |
|
887 | coreconfigitem('server', 'bundle1gd.pull', | |
885 | default=None, |
|
888 | default=None, | |
886 | ) |
|
889 | ) | |
887 | coreconfigitem('server', 'bundle1.push', |
|
890 | coreconfigitem('server', 'bundle1.push', | |
888 | default=None, |
|
891 | default=None, | |
889 | ) |
|
892 | ) | |
890 | coreconfigitem('server', 'bundle1gd.push', |
|
893 | coreconfigitem('server', 'bundle1gd.push', | |
891 | default=None, |
|
894 | default=None, | |
892 | ) |
|
895 | ) | |
893 | coreconfigitem('server', 'compressionengines', |
|
896 | coreconfigitem('server', 'compressionengines', | |
894 | default=list, |
|
897 | default=list, | |
895 | ) |
|
898 | ) | |
896 | coreconfigitem('server', 'concurrent-push-mode', |
|
899 | coreconfigitem('server', 'concurrent-push-mode', | |
897 | default='strict', |
|
900 | default='strict', | |
898 | ) |
|
901 | ) | |
899 | coreconfigitem('server', 'disablefullbundle', |
|
902 | coreconfigitem('server', 'disablefullbundle', | |
900 | default=False, |
|
903 | default=False, | |
901 | ) |
|
904 | ) | |
902 | coreconfigitem('server', 'maxhttpheaderlen', |
|
905 | coreconfigitem('server', 'maxhttpheaderlen', | |
903 | default=1024, |
|
906 | default=1024, | |
904 | ) |
|
907 | ) | |
905 | coreconfigitem('server', 'preferuncompressed', |
|
908 | coreconfigitem('server', 'preferuncompressed', | |
906 | default=False, |
|
909 | default=False, | |
907 | ) |
|
910 | ) | |
908 | coreconfigitem('server', 'uncompressed', |
|
911 | coreconfigitem('server', 'uncompressed', | |
909 | default=True, |
|
912 | default=True, | |
910 | ) |
|
913 | ) | |
911 | coreconfigitem('server', 'uncompressedallowsecret', |
|
914 | coreconfigitem('server', 'uncompressedallowsecret', | |
912 | default=False, |
|
915 | default=False, | |
913 | ) |
|
916 | ) | |
914 | coreconfigitem('server', 'validate', |
|
917 | coreconfigitem('server', 'validate', | |
915 | default=False, |
|
918 | default=False, | |
916 | ) |
|
919 | ) | |
917 | coreconfigitem('server', 'zliblevel', |
|
920 | coreconfigitem('server', 'zliblevel', | |
918 | default=-1, |
|
921 | default=-1, | |
919 | ) |
|
922 | ) | |
920 | coreconfigitem('share', 'pool', |
|
923 | coreconfigitem('share', 'pool', | |
921 | default=None, |
|
924 | default=None, | |
922 | ) |
|
925 | ) | |
923 | coreconfigitem('share', 'poolnaming', |
|
926 | coreconfigitem('share', 'poolnaming', | |
924 | default='identity', |
|
927 | default='identity', | |
925 | ) |
|
928 | ) | |
926 | coreconfigitem('smtp', 'host', |
|
929 | coreconfigitem('smtp', 'host', | |
927 | default=None, |
|
930 | default=None, | |
928 | ) |
|
931 | ) | |
929 | coreconfigitem('smtp', 'local_hostname', |
|
932 | coreconfigitem('smtp', 'local_hostname', | |
930 | default=None, |
|
933 | default=None, | |
931 | ) |
|
934 | ) | |
932 | coreconfigitem('smtp', 'password', |
|
935 | coreconfigitem('smtp', 'password', | |
933 | default=None, |
|
936 | default=None, | |
934 | ) |
|
937 | ) | |
935 | coreconfigitem('smtp', 'port', |
|
938 | coreconfigitem('smtp', 'port', | |
936 | default=dynamicdefault, |
|
939 | default=dynamicdefault, | |
937 | ) |
|
940 | ) | |
938 | coreconfigitem('smtp', 'tls', |
|
941 | coreconfigitem('smtp', 'tls', | |
939 | default='none', |
|
942 | default='none', | |
940 | ) |
|
943 | ) | |
941 | coreconfigitem('smtp', 'username', |
|
944 | coreconfigitem('smtp', 'username', | |
942 | default=None, |
|
945 | default=None, | |
943 | ) |
|
946 | ) | |
944 | coreconfigitem('sparse', 'missingwarning', |
|
947 | coreconfigitem('sparse', 'missingwarning', | |
945 | default=True, |
|
948 | default=True, | |
946 | ) |
|
949 | ) | |
947 | coreconfigitem('subrepos', 'allowed', |
|
950 | coreconfigitem('subrepos', 'allowed', | |
948 | default=dynamicdefault, # to make backporting simpler |
|
951 | default=dynamicdefault, # to make backporting simpler | |
949 | ) |
|
952 | ) | |
950 | coreconfigitem('subrepos', 'hg:allowed', |
|
953 | coreconfigitem('subrepos', 'hg:allowed', | |
951 | default=dynamicdefault, |
|
954 | default=dynamicdefault, | |
952 | ) |
|
955 | ) | |
953 | coreconfigitem('subrepos', 'git:allowed', |
|
956 | coreconfigitem('subrepos', 'git:allowed', | |
954 | default=dynamicdefault, |
|
957 | default=dynamicdefault, | |
955 | ) |
|
958 | ) | |
956 | coreconfigitem('subrepos', 'svn:allowed', |
|
959 | coreconfigitem('subrepos', 'svn:allowed', | |
957 | default=dynamicdefault, |
|
960 | default=dynamicdefault, | |
958 | ) |
|
961 | ) | |
959 | coreconfigitem('templates', '.*', |
|
962 | coreconfigitem('templates', '.*', | |
960 | default=None, |
|
963 | default=None, | |
961 | generic=True, |
|
964 | generic=True, | |
962 | ) |
|
965 | ) | |
963 | coreconfigitem('trusted', 'groups', |
|
966 | coreconfigitem('trusted', 'groups', | |
964 | default=list, |
|
967 | default=list, | |
965 | ) |
|
968 | ) | |
966 | coreconfigitem('trusted', 'users', |
|
969 | coreconfigitem('trusted', 'users', | |
967 | default=list, |
|
970 | default=list, | |
968 | ) |
|
971 | ) | |
969 | coreconfigitem('ui', '_usedassubrepo', |
|
972 | coreconfigitem('ui', '_usedassubrepo', | |
970 | default=False, |
|
973 | default=False, | |
971 | ) |
|
974 | ) | |
972 | coreconfigitem('ui', 'allowemptycommit', |
|
975 | coreconfigitem('ui', 'allowemptycommit', | |
973 | default=False, |
|
976 | default=False, | |
974 | ) |
|
977 | ) | |
975 | coreconfigitem('ui', 'archivemeta', |
|
978 | coreconfigitem('ui', 'archivemeta', | |
976 | default=True, |
|
979 | default=True, | |
977 | ) |
|
980 | ) | |
978 | coreconfigitem('ui', 'askusername', |
|
981 | coreconfigitem('ui', 'askusername', | |
979 | default=False, |
|
982 | default=False, | |
980 | ) |
|
983 | ) | |
981 | coreconfigitem('ui', 'clonebundlefallback', |
|
984 | coreconfigitem('ui', 'clonebundlefallback', | |
982 | default=False, |
|
985 | default=False, | |
983 | ) |
|
986 | ) | |
984 | coreconfigitem('ui', 'clonebundleprefers', |
|
987 | coreconfigitem('ui', 'clonebundleprefers', | |
985 | default=list, |
|
988 | default=list, | |
986 | ) |
|
989 | ) | |
987 | coreconfigitem('ui', 'clonebundles', |
|
990 | coreconfigitem('ui', 'clonebundles', | |
988 | default=True, |
|
991 | default=True, | |
989 | ) |
|
992 | ) | |
990 | coreconfigitem('ui', 'color', |
|
993 | coreconfigitem('ui', 'color', | |
991 | default='auto', |
|
994 | default='auto', | |
992 | ) |
|
995 | ) | |
993 | coreconfigitem('ui', 'commitsubrepos', |
|
996 | coreconfigitem('ui', 'commitsubrepos', | |
994 | default=False, |
|
997 | default=False, | |
995 | ) |
|
998 | ) | |
996 | coreconfigitem('ui', 'debug', |
|
999 | coreconfigitem('ui', 'debug', | |
997 | default=False, |
|
1000 | default=False, | |
998 | ) |
|
1001 | ) | |
999 | coreconfigitem('ui', 'debugger', |
|
1002 | coreconfigitem('ui', 'debugger', | |
1000 | default=None, |
|
1003 | default=None, | |
1001 | ) |
|
1004 | ) | |
1002 | coreconfigitem('ui', 'editor', |
|
1005 | coreconfigitem('ui', 'editor', | |
1003 | default=dynamicdefault, |
|
1006 | default=dynamicdefault, | |
1004 | ) |
|
1007 | ) | |
1005 | coreconfigitem('ui', 'fallbackencoding', |
|
1008 | coreconfigitem('ui', 'fallbackencoding', | |
1006 | default=None, |
|
1009 | default=None, | |
1007 | ) |
|
1010 | ) | |
1008 | coreconfigitem('ui', 'forcecwd', |
|
1011 | coreconfigitem('ui', 'forcecwd', | |
1009 | default=None, |
|
1012 | default=None, | |
1010 | ) |
|
1013 | ) | |
1011 | coreconfigitem('ui', 'forcemerge', |
|
1014 | coreconfigitem('ui', 'forcemerge', | |
1012 | default=None, |
|
1015 | default=None, | |
1013 | ) |
|
1016 | ) | |
1014 | coreconfigitem('ui', 'formatdebug', |
|
1017 | coreconfigitem('ui', 'formatdebug', | |
1015 | default=False, |
|
1018 | default=False, | |
1016 | ) |
|
1019 | ) | |
1017 | coreconfigitem('ui', 'formatjson', |
|
1020 | coreconfigitem('ui', 'formatjson', | |
1018 | default=False, |
|
1021 | default=False, | |
1019 | ) |
|
1022 | ) | |
1020 | coreconfigitem('ui', 'formatted', |
|
1023 | coreconfigitem('ui', 'formatted', | |
1021 | default=None, |
|
1024 | default=None, | |
1022 | ) |
|
1025 | ) | |
1023 | coreconfigitem('ui', 'graphnodetemplate', |
|
1026 | coreconfigitem('ui', 'graphnodetemplate', | |
1024 | default=None, |
|
1027 | default=None, | |
1025 | ) |
|
1028 | ) | |
1026 | coreconfigitem('ui', 'http2debuglevel', |
|
1029 | coreconfigitem('ui', 'http2debuglevel', | |
1027 | default=None, |
|
1030 | default=None, | |
1028 | ) |
|
1031 | ) | |
1029 | coreconfigitem('ui', 'interactive', |
|
1032 | coreconfigitem('ui', 'interactive', | |
1030 | default=None, |
|
1033 | default=None, | |
1031 | ) |
|
1034 | ) | |
1032 | coreconfigitem('ui', 'interface', |
|
1035 | coreconfigitem('ui', 'interface', | |
1033 | default=None, |
|
1036 | default=None, | |
1034 | ) |
|
1037 | ) | |
1035 | coreconfigitem('ui', 'interface.chunkselector', |
|
1038 | coreconfigitem('ui', 'interface.chunkselector', | |
1036 | default=None, |
|
1039 | default=None, | |
1037 | ) |
|
1040 | ) | |
1038 | coreconfigitem('ui', 'logblockedtimes', |
|
1041 | coreconfigitem('ui', 'logblockedtimes', | |
1039 | default=False, |
|
1042 | default=False, | |
1040 | ) |
|
1043 | ) | |
1041 | coreconfigitem('ui', 'logtemplate', |
|
1044 | coreconfigitem('ui', 'logtemplate', | |
1042 | default=None, |
|
1045 | default=None, | |
1043 | ) |
|
1046 | ) | |
1044 | coreconfigitem('ui', 'merge', |
|
1047 | coreconfigitem('ui', 'merge', | |
1045 | default=None, |
|
1048 | default=None, | |
1046 | ) |
|
1049 | ) | |
1047 | coreconfigitem('ui', 'mergemarkers', |
|
1050 | coreconfigitem('ui', 'mergemarkers', | |
1048 | default='basic', |
|
1051 | default='basic', | |
1049 | ) |
|
1052 | ) | |
1050 | coreconfigitem('ui', 'mergemarkertemplate', |
|
1053 | coreconfigitem('ui', 'mergemarkertemplate', | |
1051 | default=('{node|short} ' |
|
1054 | default=('{node|short} ' | |
1052 | '{ifeq(tags, "tip", "", ' |
|
1055 | '{ifeq(tags, "tip", "", ' | |
1053 | 'ifeq(tags, "", "", "{tags} "))}' |
|
1056 | 'ifeq(tags, "", "", "{tags} "))}' | |
1054 | '{if(bookmarks, "{bookmarks} ")}' |
|
1057 | '{if(bookmarks, "{bookmarks} ")}' | |
1055 | '{ifeq(branch, "default", "", "{branch} ")}' |
|
1058 | '{ifeq(branch, "default", "", "{branch} ")}' | |
1056 | '- {author|user}: {desc|firstline}') |
|
1059 | '- {author|user}: {desc|firstline}') | |
1057 | ) |
|
1060 | ) | |
1058 | coreconfigitem('ui', 'nontty', |
|
1061 | coreconfigitem('ui', 'nontty', | |
1059 | default=False, |
|
1062 | default=False, | |
1060 | ) |
|
1063 | ) | |
1061 | coreconfigitem('ui', 'origbackuppath', |
|
1064 | coreconfigitem('ui', 'origbackuppath', | |
1062 | default=None, |
|
1065 | default=None, | |
1063 | ) |
|
1066 | ) | |
1064 | coreconfigitem('ui', 'paginate', |
|
1067 | coreconfigitem('ui', 'paginate', | |
1065 | default=True, |
|
1068 | default=True, | |
1066 | ) |
|
1069 | ) | |
1067 | coreconfigitem('ui', 'patch', |
|
1070 | coreconfigitem('ui', 'patch', | |
1068 | default=None, |
|
1071 | default=None, | |
1069 | ) |
|
1072 | ) | |
1070 | coreconfigitem('ui', 'portablefilenames', |
|
1073 | coreconfigitem('ui', 'portablefilenames', | |
1071 | default='warn', |
|
1074 | default='warn', | |
1072 | ) |
|
1075 | ) | |
1073 | coreconfigitem('ui', 'promptecho', |
|
1076 | coreconfigitem('ui', 'promptecho', | |
1074 | default=False, |
|
1077 | default=False, | |
1075 | ) |
|
1078 | ) | |
1076 | coreconfigitem('ui', 'quiet', |
|
1079 | coreconfigitem('ui', 'quiet', | |
1077 | default=False, |
|
1080 | default=False, | |
1078 | ) |
|
1081 | ) | |
1079 | coreconfigitem('ui', 'quietbookmarkmove', |
|
1082 | coreconfigitem('ui', 'quietbookmarkmove', | |
1080 | default=False, |
|
1083 | default=False, | |
1081 | ) |
|
1084 | ) | |
1082 | coreconfigitem('ui', 'remotecmd', |
|
1085 | coreconfigitem('ui', 'remotecmd', | |
1083 | default='hg', |
|
1086 | default='hg', | |
1084 | ) |
|
1087 | ) | |
1085 | coreconfigitem('ui', 'report_untrusted', |
|
1088 | coreconfigitem('ui', 'report_untrusted', | |
1086 | default=True, |
|
1089 | default=True, | |
1087 | ) |
|
1090 | ) | |
1088 | coreconfigitem('ui', 'rollback', |
|
1091 | coreconfigitem('ui', 'rollback', | |
1089 | default=True, |
|
1092 | default=True, | |
1090 | ) |
|
1093 | ) | |
1091 | coreconfigitem('ui', 'slash', |
|
1094 | coreconfigitem('ui', 'slash', | |
1092 | default=False, |
|
1095 | default=False, | |
1093 | ) |
|
1096 | ) | |
1094 | coreconfigitem('ui', 'ssh', |
|
1097 | coreconfigitem('ui', 'ssh', | |
1095 | default='ssh', |
|
1098 | default='ssh', | |
1096 | ) |
|
1099 | ) | |
1097 | coreconfigitem('ui', 'ssherrorhint', |
|
1100 | coreconfigitem('ui', 'ssherrorhint', | |
1098 | default=None, |
|
1101 | default=None, | |
1099 | ) |
|
1102 | ) | |
1100 | coreconfigitem('ui', 'statuscopies', |
|
1103 | coreconfigitem('ui', 'statuscopies', | |
1101 | default=False, |
|
1104 | default=False, | |
1102 | ) |
|
1105 | ) | |
1103 | coreconfigitem('ui', 'strict', |
|
1106 | coreconfigitem('ui', 'strict', | |
1104 | default=False, |
|
1107 | default=False, | |
1105 | ) |
|
1108 | ) | |
1106 | coreconfigitem('ui', 'style', |
|
1109 | coreconfigitem('ui', 'style', | |
1107 | default='', |
|
1110 | default='', | |
1108 | ) |
|
1111 | ) | |
1109 | coreconfigitem('ui', 'supportcontact', |
|
1112 | coreconfigitem('ui', 'supportcontact', | |
1110 | default=None, |
|
1113 | default=None, | |
1111 | ) |
|
1114 | ) | |
1112 | coreconfigitem('ui', 'textwidth', |
|
1115 | coreconfigitem('ui', 'textwidth', | |
1113 | default=78, |
|
1116 | default=78, | |
1114 | ) |
|
1117 | ) | |
1115 | coreconfigitem('ui', 'timeout', |
|
1118 | coreconfigitem('ui', 'timeout', | |
1116 | default='600', |
|
1119 | default='600', | |
1117 | ) |
|
1120 | ) | |
1118 | coreconfigitem('ui', 'timeout.warn', |
|
1121 | coreconfigitem('ui', 'timeout.warn', | |
1119 | default=0, |
|
1122 | default=0, | |
1120 | ) |
|
1123 | ) | |
1121 | coreconfigitem('ui', 'traceback', |
|
1124 | coreconfigitem('ui', 'traceback', | |
1122 | default=False, |
|
1125 | default=False, | |
1123 | ) |
|
1126 | ) | |
1124 | coreconfigitem('ui', 'tweakdefaults', |
|
1127 | coreconfigitem('ui', 'tweakdefaults', | |
1125 | default=False, |
|
1128 | default=False, | |
1126 | ) |
|
1129 | ) | |
1127 | coreconfigitem('ui', 'usehttp2', |
|
1130 | coreconfigitem('ui', 'usehttp2', | |
1128 | default=False, |
|
1131 | default=False, | |
1129 | ) |
|
1132 | ) | |
1130 | coreconfigitem('ui', 'username', |
|
1133 | coreconfigitem('ui', 'username', | |
1131 | alias=[('ui', 'user')] |
|
1134 | alias=[('ui', 'user')] | |
1132 | ) |
|
1135 | ) | |
1133 | coreconfigitem('ui', 'verbose', |
|
1136 | coreconfigitem('ui', 'verbose', | |
1134 | default=False, |
|
1137 | default=False, | |
1135 | ) |
|
1138 | ) | |
1136 | coreconfigitem('verify', 'skipflags', |
|
1139 | coreconfigitem('verify', 'skipflags', | |
1137 | default=None, |
|
1140 | default=None, | |
1138 | ) |
|
1141 | ) | |
1139 | coreconfigitem('web', 'allowbz2', |
|
1142 | coreconfigitem('web', 'allowbz2', | |
1140 | default=False, |
|
1143 | default=False, | |
1141 | ) |
|
1144 | ) | |
1142 | coreconfigitem('web', 'allowgz', |
|
1145 | coreconfigitem('web', 'allowgz', | |
1143 | default=False, |
|
1146 | default=False, | |
1144 | ) |
|
1147 | ) | |
1145 | coreconfigitem('web', 'allow-pull', |
|
1148 | coreconfigitem('web', 'allow-pull', | |
1146 | alias=[('web', 'allowpull')], |
|
1149 | alias=[('web', 'allowpull')], | |
1147 | default=True, |
|
1150 | default=True, | |
1148 | ) |
|
1151 | ) | |
1149 | coreconfigitem('web', 'allow-push', |
|
1152 | coreconfigitem('web', 'allow-push', | |
1150 | alias=[('web', 'allow_push')], |
|
1153 | alias=[('web', 'allow_push')], | |
1151 | default=list, |
|
1154 | default=list, | |
1152 | ) |
|
1155 | ) | |
1153 | coreconfigitem('web', 'allowzip', |
|
1156 | coreconfigitem('web', 'allowzip', | |
1154 | default=False, |
|
1157 | default=False, | |
1155 | ) |
|
1158 | ) | |
1156 | coreconfigitem('web', 'archivesubrepos', |
|
1159 | coreconfigitem('web', 'archivesubrepos', | |
1157 | default=False, |
|
1160 | default=False, | |
1158 | ) |
|
1161 | ) | |
1159 | coreconfigitem('web', 'cache', |
|
1162 | coreconfigitem('web', 'cache', | |
1160 | default=True, |
|
1163 | default=True, | |
1161 | ) |
|
1164 | ) | |
1162 | coreconfigitem('web', 'contact', |
|
1165 | coreconfigitem('web', 'contact', | |
1163 | default=None, |
|
1166 | default=None, | |
1164 | ) |
|
1167 | ) | |
1165 | coreconfigitem('web', 'deny_push', |
|
1168 | coreconfigitem('web', 'deny_push', | |
1166 | default=list, |
|
1169 | default=list, | |
1167 | ) |
|
1170 | ) | |
1168 | coreconfigitem('web', 'guessmime', |
|
1171 | coreconfigitem('web', 'guessmime', | |
1169 | default=False, |
|
1172 | default=False, | |
1170 | ) |
|
1173 | ) | |
1171 | coreconfigitem('web', 'hidden', |
|
1174 | coreconfigitem('web', 'hidden', | |
1172 | default=False, |
|
1175 | default=False, | |
1173 | ) |
|
1176 | ) | |
1174 | coreconfigitem('web', 'labels', |
|
1177 | coreconfigitem('web', 'labels', | |
1175 | default=list, |
|
1178 | default=list, | |
1176 | ) |
|
1179 | ) | |
1177 | coreconfigitem('web', 'logoimg', |
|
1180 | coreconfigitem('web', 'logoimg', | |
1178 | default='hglogo.png', |
|
1181 | default='hglogo.png', | |
1179 | ) |
|
1182 | ) | |
1180 | coreconfigitem('web', 'logourl', |
|
1183 | coreconfigitem('web', 'logourl', | |
1181 | default='https://mercurial-scm.org/', |
|
1184 | default='https://mercurial-scm.org/', | |
1182 | ) |
|
1185 | ) | |
1183 | coreconfigitem('web', 'accesslog', |
|
1186 | coreconfigitem('web', 'accesslog', | |
1184 | default='-', |
|
1187 | default='-', | |
1185 | ) |
|
1188 | ) | |
1186 | coreconfigitem('web', 'address', |
|
1189 | coreconfigitem('web', 'address', | |
1187 | default='', |
|
1190 | default='', | |
1188 | ) |
|
1191 | ) | |
1189 | coreconfigitem('web', 'allow_archive', |
|
1192 | coreconfigitem('web', 'allow_archive', | |
1190 | default=list, |
|
1193 | default=list, | |
1191 | ) |
|
1194 | ) | |
1192 | coreconfigitem('web', 'allow_read', |
|
1195 | coreconfigitem('web', 'allow_read', | |
1193 | default=list, |
|
1196 | default=list, | |
1194 | ) |
|
1197 | ) | |
1195 | coreconfigitem('web', 'baseurl', |
|
1198 | coreconfigitem('web', 'baseurl', | |
1196 | default=None, |
|
1199 | default=None, | |
1197 | ) |
|
1200 | ) | |
1198 | coreconfigitem('web', 'cacerts', |
|
1201 | coreconfigitem('web', 'cacerts', | |
1199 | default=None, |
|
1202 | default=None, | |
1200 | ) |
|
1203 | ) | |
1201 | coreconfigitem('web', 'certificate', |
|
1204 | coreconfigitem('web', 'certificate', | |
1202 | default=None, |
|
1205 | default=None, | |
1203 | ) |
|
1206 | ) | |
1204 | coreconfigitem('web', 'collapse', |
|
1207 | coreconfigitem('web', 'collapse', | |
1205 | default=False, |
|
1208 | default=False, | |
1206 | ) |
|
1209 | ) | |
1207 | coreconfigitem('web', 'csp', |
|
1210 | coreconfigitem('web', 'csp', | |
1208 | default=None, |
|
1211 | default=None, | |
1209 | ) |
|
1212 | ) | |
1210 | coreconfigitem('web', 'deny_read', |
|
1213 | coreconfigitem('web', 'deny_read', | |
1211 | default=list, |
|
1214 | default=list, | |
1212 | ) |
|
1215 | ) | |
1213 | coreconfigitem('web', 'descend', |
|
1216 | coreconfigitem('web', 'descend', | |
1214 | default=True, |
|
1217 | default=True, | |
1215 | ) |
|
1218 | ) | |
1216 | coreconfigitem('web', 'description', |
|
1219 | coreconfigitem('web', 'description', | |
1217 | default="", |
|
1220 | default="", | |
1218 | ) |
|
1221 | ) | |
1219 | coreconfigitem('web', 'encoding', |
|
1222 | coreconfigitem('web', 'encoding', | |
1220 | default=lambda: encoding.encoding, |
|
1223 | default=lambda: encoding.encoding, | |
1221 | ) |
|
1224 | ) | |
1222 | coreconfigitem('web', 'errorlog', |
|
1225 | coreconfigitem('web', 'errorlog', | |
1223 | default='-', |
|
1226 | default='-', | |
1224 | ) |
|
1227 | ) | |
1225 | coreconfigitem('web', 'ipv6', |
|
1228 | coreconfigitem('web', 'ipv6', | |
1226 | default=False, |
|
1229 | default=False, | |
1227 | ) |
|
1230 | ) | |
1228 | coreconfigitem('web', 'maxchanges', |
|
1231 | coreconfigitem('web', 'maxchanges', | |
1229 | default=10, |
|
1232 | default=10, | |
1230 | ) |
|
1233 | ) | |
1231 | coreconfigitem('web', 'maxfiles', |
|
1234 | coreconfigitem('web', 'maxfiles', | |
1232 | default=10, |
|
1235 | default=10, | |
1233 | ) |
|
1236 | ) | |
1234 | coreconfigitem('web', 'maxshortchanges', |
|
1237 | coreconfigitem('web', 'maxshortchanges', | |
1235 | default=60, |
|
1238 | default=60, | |
1236 | ) |
|
1239 | ) | |
1237 | coreconfigitem('web', 'motd', |
|
1240 | coreconfigitem('web', 'motd', | |
1238 | default='', |
|
1241 | default='', | |
1239 | ) |
|
1242 | ) | |
1240 | coreconfigitem('web', 'name', |
|
1243 | coreconfigitem('web', 'name', | |
1241 | default=dynamicdefault, |
|
1244 | default=dynamicdefault, | |
1242 | ) |
|
1245 | ) | |
1243 | coreconfigitem('web', 'port', |
|
1246 | coreconfigitem('web', 'port', | |
1244 | default=8000, |
|
1247 | default=8000, | |
1245 | ) |
|
1248 | ) | |
1246 | coreconfigitem('web', 'prefix', |
|
1249 | coreconfigitem('web', 'prefix', | |
1247 | default='', |
|
1250 | default='', | |
1248 | ) |
|
1251 | ) | |
1249 | coreconfigitem('web', 'push_ssl', |
|
1252 | coreconfigitem('web', 'push_ssl', | |
1250 | default=True, |
|
1253 | default=True, | |
1251 | ) |
|
1254 | ) | |
1252 | coreconfigitem('web', 'refreshinterval', |
|
1255 | coreconfigitem('web', 'refreshinterval', | |
1253 | default=20, |
|
1256 | default=20, | |
1254 | ) |
|
1257 | ) | |
1255 | coreconfigitem('web', 'staticurl', |
|
1258 | coreconfigitem('web', 'staticurl', | |
1256 | default=None, |
|
1259 | default=None, | |
1257 | ) |
|
1260 | ) | |
1258 | coreconfigitem('web', 'stripes', |
|
1261 | coreconfigitem('web', 'stripes', | |
1259 | default=1, |
|
1262 | default=1, | |
1260 | ) |
|
1263 | ) | |
1261 | coreconfigitem('web', 'style', |
|
1264 | coreconfigitem('web', 'style', | |
1262 | default='paper', |
|
1265 | default='paper', | |
1263 | ) |
|
1266 | ) | |
1264 | coreconfigitem('web', 'templates', |
|
1267 | coreconfigitem('web', 'templates', | |
1265 | default=None, |
|
1268 | default=None, | |
1266 | ) |
|
1269 | ) | |
1267 | coreconfigitem('web', 'view', |
|
1270 | coreconfigitem('web', 'view', | |
1268 | default='served', |
|
1271 | default='served', | |
1269 | ) |
|
1272 | ) | |
1270 | coreconfigitem('worker', 'backgroundclose', |
|
1273 | coreconfigitem('worker', 'backgroundclose', | |
1271 | default=dynamicdefault, |
|
1274 | default=dynamicdefault, | |
1272 | ) |
|
1275 | ) | |
1273 | # Windows defaults to a limit of 512 open files. A buffer of 128 |
|
1276 | # Windows defaults to a limit of 512 open files. A buffer of 128 | |
1274 | # should give us enough headway. |
|
1277 | # should give us enough headway. | |
1275 | coreconfigitem('worker', 'backgroundclosemaxqueue', |
|
1278 | coreconfigitem('worker', 'backgroundclosemaxqueue', | |
1276 | default=384, |
|
1279 | default=384, | |
1277 | ) |
|
1280 | ) | |
1278 | coreconfigitem('worker', 'backgroundcloseminfilecount', |
|
1281 | coreconfigitem('worker', 'backgroundcloseminfilecount', | |
1279 | default=2048, |
|
1282 | default=2048, | |
1280 | ) |
|
1283 | ) | |
1281 | coreconfigitem('worker', 'backgroundclosethreadcount', |
|
1284 | coreconfigitem('worker', 'backgroundclosethreadcount', | |
1282 | default=4, |
|
1285 | default=4, | |
1283 | ) |
|
1286 | ) | |
1284 | coreconfigitem('worker', 'enabled', |
|
1287 | coreconfigitem('worker', 'enabled', | |
1285 | default=True, |
|
1288 | default=True, | |
1286 | ) |
|
1289 | ) | |
1287 | coreconfigitem('worker', 'numcpus', |
|
1290 | coreconfigitem('worker', 'numcpus', | |
1288 | default=None, |
|
1291 | default=None, | |
1289 | ) |
|
1292 | ) | |
1290 |
|
1293 | |||
1291 | # Rebase related configuration moved to core because other extension are doing |
|
1294 | # Rebase related configuration moved to core because other extension are doing | |
1292 | # strange things. For example, shelve import the extensions to reuse some bit |
|
1295 | # strange things. For example, shelve import the extensions to reuse some bit | |
1293 | # without formally loading it. |
|
1296 | # without formally loading it. | |
1294 | coreconfigitem('commands', 'rebase.requiredest', |
|
1297 | coreconfigitem('commands', 'rebase.requiredest', | |
1295 | default=False, |
|
1298 | default=False, | |
1296 | ) |
|
1299 | ) | |
1297 | coreconfigitem('experimental', 'rebaseskipobsolete', |
|
1300 | coreconfigitem('experimental', 'rebaseskipobsolete', | |
1298 | default=True, |
|
1301 | default=True, | |
1299 | ) |
|
1302 | ) | |
1300 | coreconfigitem('rebase', 'singletransaction', |
|
1303 | coreconfigitem('rebase', 'singletransaction', | |
1301 | default=False, |
|
1304 | default=False, | |
1302 | ) |
|
1305 | ) | |
1303 | coreconfigitem('rebase', 'experimental.inmemory', |
|
1306 | coreconfigitem('rebase', 'experimental.inmemory', | |
1304 | default=False, |
|
1307 | default=False, | |
1305 | ) |
|
1308 | ) |
@@ -1,990 +1,1104 b'' | |||||
1 | The Mercurial wire protocol is a request-response based protocol |
|
1 | The Mercurial wire protocol is a request-response based protocol | |
2 | with multiple wire representations. |
|
2 | with multiple wire representations. | |
3 |
|
3 | |||
4 | Each request is modeled as a command name, a dictionary of arguments, and |
|
4 | Each request is modeled as a command name, a dictionary of arguments, and | |
5 | optional raw input. Command arguments and their types are intrinsic |
|
5 | optional raw input. Command arguments and their types are intrinsic | |
6 | properties of commands. So is the response type of the command. This means |
|
6 | properties of commands. So is the response type of the command. This means | |
7 | clients can't always send arbitrary arguments to servers and servers can't |
|
7 | clients can't always send arbitrary arguments to servers and servers can't | |
8 | return multiple response types. |
|
8 | return multiple response types. | |
9 |
|
9 | |||
10 | The protocol is synchronous and does not support multiplexing (concurrent |
|
10 | The protocol is synchronous and does not support multiplexing (concurrent | |
11 | commands). |
|
11 | commands). | |
12 |
|
12 | |||
13 | Handshake |
|
13 | Handshake | |
14 | ========= |
|
14 | ========= | |
15 |
|
15 | |||
16 | It is required or common for clients to perform a *handshake* when connecting |
|
16 | It is required or common for clients to perform a *handshake* when connecting | |
17 | to a server. The handshake serves the following purposes: |
|
17 | to a server. The handshake serves the following purposes: | |
18 |
|
18 | |||
19 | * Negotiating protocol/transport level options |
|
19 | * Negotiating protocol/transport level options | |
20 | * Allows the client to learn about server capabilities to influence |
|
20 | * Allows the client to learn about server capabilities to influence | |
21 | future requests |
|
21 | future requests | |
22 | * Ensures the underlying transport channel is in a *clean* state |
|
22 | * Ensures the underlying transport channel is in a *clean* state | |
23 |
|
23 | |||
24 | An important goal of the handshake is to allow clients to use more modern |
|
24 | An important goal of the handshake is to allow clients to use more modern | |
25 | wire protocol features. By default, clients must assume they are talking |
|
25 | wire protocol features. By default, clients must assume they are talking | |
26 | to an old version of Mercurial server (possibly even the very first |
|
26 | to an old version of Mercurial server (possibly even the very first | |
27 | implementation). So, clients should not attempt to call or utilize modern |
|
27 | implementation). So, clients should not attempt to call or utilize modern | |
28 | wire protocol features until they have confirmation that the server |
|
28 | wire protocol features until they have confirmation that the server | |
29 | supports them. The handshake implementation is designed to allow both |
|
29 | supports them. The handshake implementation is designed to allow both | |
30 | ends to utilize the latest set of features and capabilities with as |
|
30 | ends to utilize the latest set of features and capabilities with as | |
31 | few round trips as possible. |
|
31 | few round trips as possible. | |
32 |
|
32 | |||
33 | The handshake mechanism varies by transport and protocol and is documented |
|
33 | The handshake mechanism varies by transport and protocol and is documented | |
34 | in the sections below. |
|
34 | in the sections below. | |
35 |
|
35 | |||
36 | HTTP Protocol |
|
36 | HTTP Protocol | |
37 | ============= |
|
37 | ============= | |
38 |
|
38 | |||
39 | Handshake |
|
39 | Handshake | |
40 | --------- |
|
40 | --------- | |
41 |
|
41 | |||
42 | The client sends a ``capabilities`` command request (``?cmd=capabilities``) |
|
42 | The client sends a ``capabilities`` command request (``?cmd=capabilities``) | |
43 | as soon as HTTP requests may be issued. |
|
43 | as soon as HTTP requests may be issued. | |
44 |
|
44 | |||
45 | The server responds with a capabilities string, which the client parses to |
|
45 | The server responds with a capabilities string, which the client parses to | |
46 | learn about the server's abilities. |
|
46 | learn about the server's abilities. | |
47 |
|
47 | |||
48 | HTTP Version 1 Transport |
|
48 | HTTP Version 1 Transport | |
49 | ------------------------ |
|
49 | ------------------------ | |
50 |
|
50 | |||
51 | Commands are issued as HTTP/1.0 or HTTP/1.1 requests. Commands are |
|
51 | Commands are issued as HTTP/1.0 or HTTP/1.1 requests. Commands are | |
52 | sent to the base URL of the repository with the command name sent in |
|
52 | sent to the base URL of the repository with the command name sent in | |
53 | the ``cmd`` query string parameter. e.g. |
|
53 | the ``cmd`` query string parameter. e.g. | |
54 | ``https://example.com/repo?cmd=capabilities``. The HTTP method is ``GET`` |
|
54 | ``https://example.com/repo?cmd=capabilities``. The HTTP method is ``GET`` | |
55 | or ``POST`` depending on the command and whether there is a request |
|
55 | or ``POST`` depending on the command and whether there is a request | |
56 | body. |
|
56 | body. | |
57 |
|
57 | |||
58 | Command arguments can be sent multiple ways. |
|
58 | Command arguments can be sent multiple ways. | |
59 |
|
59 | |||
60 | The simplest is part of the URL query string using ``x-www-form-urlencoded`` |
|
60 | The simplest is part of the URL query string using ``x-www-form-urlencoded`` | |
61 | encoding (see Python's ``urllib.urlencode()``. However, many servers impose |
|
61 | encoding (see Python's ``urllib.urlencode()``. However, many servers impose | |
62 | length limitations on the URL. So this mechanism is typically only used if |
|
62 | length limitations on the URL. So this mechanism is typically only used if | |
63 | the server doesn't support other mechanisms. |
|
63 | the server doesn't support other mechanisms. | |
64 |
|
64 | |||
65 | If the server supports the ``httpheader`` capability, command arguments can |
|
65 | If the server supports the ``httpheader`` capability, command arguments can | |
66 | be sent in HTTP request headers named ``X-HgArg-<N>`` where ``<N>`` is an |
|
66 | be sent in HTTP request headers named ``X-HgArg-<N>`` where ``<N>`` is an | |
67 | integer starting at 1. A ``x-www-form-urlencoded`` representation of the |
|
67 | integer starting at 1. A ``x-www-form-urlencoded`` representation of the | |
68 | arguments is obtained. This full string is then split into chunks and sent |
|
68 | arguments is obtained. This full string is then split into chunks and sent | |
69 | in numbered ``X-HgArg-<N>`` headers. The maximum length of each HTTP header |
|
69 | in numbered ``X-HgArg-<N>`` headers. The maximum length of each HTTP header | |
70 | is defined by the server in the ``httpheader`` capability value, which defaults |
|
70 | is defined by the server in the ``httpheader`` capability value, which defaults | |
71 | to ``1024``. The server reassembles the encoded arguments string by |
|
71 | to ``1024``. The server reassembles the encoded arguments string by | |
72 | concatenating the ``X-HgArg-<N>`` headers then URL decodes them into a |
|
72 | concatenating the ``X-HgArg-<N>`` headers then URL decodes them into a | |
73 | dictionary. |
|
73 | dictionary. | |
74 |
|
74 | |||
75 | The list of ``X-HgArg-<N>`` headers should be added to the ``Vary`` request |
|
75 | The list of ``X-HgArg-<N>`` headers should be added to the ``Vary`` request | |
76 | header to instruct caches to take these headers into consideration when caching |
|
76 | header to instruct caches to take these headers into consideration when caching | |
77 | requests. |
|
77 | requests. | |
78 |
|
78 | |||
79 | If the server supports the ``httppostargs`` capability, the client |
|
79 | If the server supports the ``httppostargs`` capability, the client | |
80 | may send command arguments in the HTTP request body as part of an |
|
80 | may send command arguments in the HTTP request body as part of an | |
81 | HTTP POST request. The command arguments will be URL encoded just like |
|
81 | HTTP POST request. The command arguments will be URL encoded just like | |
82 | they would for sending them via HTTP headers. However, no splitting is |
|
82 | they would for sending them via HTTP headers. However, no splitting is | |
83 | performed: the raw arguments are included in the HTTP request body. |
|
83 | performed: the raw arguments are included in the HTTP request body. | |
84 |
|
84 | |||
85 | The client sends a ``X-HgArgs-Post`` header with the string length of the |
|
85 | The client sends a ``X-HgArgs-Post`` header with the string length of the | |
86 | encoded arguments data. Additional data may be included in the HTTP |
|
86 | encoded arguments data. Additional data may be included in the HTTP | |
87 | request body immediately following the argument data. The offset of the |
|
87 | request body immediately following the argument data. The offset of the | |
88 | non-argument data is defined by the ``X-HgArgs-Post`` header. The |
|
88 | non-argument data is defined by the ``X-HgArgs-Post`` header. The | |
89 | ``X-HgArgs-Post`` header is not required if there is no argument data. |
|
89 | ``X-HgArgs-Post`` header is not required if there is no argument data. | |
90 |
|
90 | |||
91 | Additional command data can be sent as part of the HTTP request body. The |
|
91 | Additional command data can be sent as part of the HTTP request body. The | |
92 | default ``Content-Type`` when sending data is ``application/mercurial-0.1``. |
|
92 | default ``Content-Type`` when sending data is ``application/mercurial-0.1``. | |
93 | A ``Content-Length`` header is currently always sent. |
|
93 | A ``Content-Length`` header is currently always sent. | |
94 |
|
94 | |||
95 | Example HTTP requests:: |
|
95 | Example HTTP requests:: | |
96 |
|
96 | |||
97 | GET /repo?cmd=capabilities |
|
97 | GET /repo?cmd=capabilities | |
98 | X-HgArg-1: foo=bar&baz=hello%20world |
|
98 | X-HgArg-1: foo=bar&baz=hello%20world | |
99 |
|
99 | |||
100 | The request media type should be chosen based on server support. If the |
|
100 | The request media type should be chosen based on server support. If the | |
101 | ``httpmediatype`` server capability is present, the client should send |
|
101 | ``httpmediatype`` server capability is present, the client should send | |
102 | the newest mutually supported media type. If this capability is absent, |
|
102 | the newest mutually supported media type. If this capability is absent, | |
103 | the client must assume the server only supports the |
|
103 | the client must assume the server only supports the | |
104 | ``application/mercurial-0.1`` media type. |
|
104 | ``application/mercurial-0.1`` media type. | |
105 |
|
105 | |||
106 | The ``Content-Type`` HTTP response header identifies the response as coming |
|
106 | The ``Content-Type`` HTTP response header identifies the response as coming | |
107 | from Mercurial and can also be used to signal an error has occurred. |
|
107 | from Mercurial and can also be used to signal an error has occurred. | |
108 |
|
108 | |||
109 | The ``application/mercurial-*`` media types indicate a generic Mercurial |
|
109 | The ``application/mercurial-*`` media types indicate a generic Mercurial | |
110 | data type. |
|
110 | data type. | |
111 |
|
111 | |||
112 | The ``application/mercurial-0.1`` media type is raw Mercurial data. It is the |
|
112 | The ``application/mercurial-0.1`` media type is raw Mercurial data. It is the | |
113 | predecessor of the format below. |
|
113 | predecessor of the format below. | |
114 |
|
114 | |||
115 | The ``application/mercurial-0.2`` media type is compression framed Mercurial |
|
115 | The ``application/mercurial-0.2`` media type is compression framed Mercurial | |
116 | data. The first byte of the payload indicates the length of the compression |
|
116 | data. The first byte of the payload indicates the length of the compression | |
117 | format identifier that follows. Next are N bytes indicating the compression |
|
117 | format identifier that follows. Next are N bytes indicating the compression | |
118 | format. e.g. ``zlib``. The remaining bytes are compressed according to that |
|
118 | format. e.g. ``zlib``. The remaining bytes are compressed according to that | |
119 | compression format. The decompressed data behaves the same as with |
|
119 | compression format. The decompressed data behaves the same as with | |
120 | ``application/mercurial-0.1``. |
|
120 | ``application/mercurial-0.1``. | |
121 |
|
121 | |||
122 | The ``application/hg-error`` media type indicates a generic error occurred. |
|
122 | The ``application/hg-error`` media type indicates a generic error occurred. | |
123 | The content of the HTTP response body typically holds text describing the |
|
123 | The content of the HTTP response body typically holds text describing the | |
124 | error. |
|
124 | error. | |
125 |
|
125 | |||
126 | The ``application/hg-changegroup`` media type indicates a changegroup response |
|
126 | The ``application/hg-changegroup`` media type indicates a changegroup response | |
127 | type. |
|
127 | type. | |
128 |
|
128 | |||
129 | Clients also accept the ``text/plain`` media type. All other media |
|
129 | Clients also accept the ``text/plain`` media type. All other media | |
130 | types should cause the client to error. |
|
130 | types should cause the client to error. | |
131 |
|
131 | |||
132 | Behavior of media types is further described in the ``Content Negotiation`` |
|
132 | Behavior of media types is further described in the ``Content Negotiation`` | |
133 | section below. |
|
133 | section below. | |
134 |
|
134 | |||
135 | Clients should issue a ``User-Agent`` request header that identifies the client. |
|
135 | Clients should issue a ``User-Agent`` request header that identifies the client. | |
136 | The server should not use the ``User-Agent`` for feature detection. |
|
136 | The server should not use the ``User-Agent`` for feature detection. | |
137 |
|
137 | |||
138 | A command returning a ``string`` response issues a |
|
138 | A command returning a ``string`` response issues a | |
139 | ``application/mercurial-0.*`` media type and the HTTP response body contains |
|
139 | ``application/mercurial-0.*`` media type and the HTTP response body contains | |
140 | the raw string value (after compression decoding, if used). A |
|
140 | the raw string value (after compression decoding, if used). A | |
141 | ``Content-Length`` header is typically issued, but not required. |
|
141 | ``Content-Length`` header is typically issued, but not required. | |
142 |
|
142 | |||
143 | A command returning a ``stream`` response issues a |
|
143 | A command returning a ``stream`` response issues a | |
144 | ``application/mercurial-0.*`` media type and the HTTP response is typically |
|
144 | ``application/mercurial-0.*`` media type and the HTTP response is typically | |
145 | using *chunked transfer* (``Transfer-Encoding: chunked``). |
|
145 | using *chunked transfer* (``Transfer-Encoding: chunked``). | |
146 |
|
146 | |||
147 | SSH Protocol |
|
147 | SSH Protocol | |
148 | ============ |
|
148 | ============ | |
149 |
|
149 | |||
150 | Handshake |
|
150 | Handshake | |
151 | --------- |
|
151 | --------- | |
152 |
|
152 | |||
153 | For all clients, the handshake consists of the client sending 1 or more |
|
153 | For all clients, the handshake consists of the client sending 1 or more | |
154 | commands to the server using version 1 of the transport. Servers respond |
|
154 | commands to the server using version 1 of the transport. Servers respond | |
155 | to commands they know how to respond to and send an empty response (``0\n``) |
|
155 | to commands they know how to respond to and send an empty response (``0\n``) | |
156 | for unknown commands (per standard behavior of version 1 of the transport). |
|
156 | for unknown commands (per standard behavior of version 1 of the transport). | |
157 | Clients then typically look for a response to the newest sent command to |
|
157 | Clients then typically look for a response to the newest sent command to | |
158 | determine which transport version to use and what the available features for |
|
158 | determine which transport version to use and what the available features for | |
159 | the connection and server are. |
|
159 | the connection and server are. | |
160 |
|
160 | |||
161 | Preceding any response from client-issued commands, the server may print |
|
161 | Preceding any response from client-issued commands, the server may print | |
162 | non-protocol output. It is common for SSH servers to print banners, message |
|
162 | non-protocol output. It is common for SSH servers to print banners, message | |
163 | of the day announcements, etc when clients connect. It is assumed that any |
|
163 | of the day announcements, etc when clients connect. It is assumed that any | |
164 | such *banner* output will precede any Mercurial server output. So clients |
|
164 | such *banner* output will precede any Mercurial server output. So clients | |
165 | must be prepared to handle server output on initial connect that isn't |
|
165 | must be prepared to handle server output on initial connect that isn't | |
166 | in response to any client-issued command and doesn't conform to Mercurial's |
|
166 | in response to any client-issued command and doesn't conform to Mercurial's | |
167 | wire protocol. This *banner* output should only be on stdout. However, |
|
167 | wire protocol. This *banner* output should only be on stdout. However, | |
168 | some servers may send output on stderr. |
|
168 | some servers may send output on stderr. | |
169 |
|
169 | |||
170 | Pre 0.9.1 clients issue a ``between`` command with the ``pairs`` argument |
|
170 | Pre 0.9.1 clients issue a ``between`` command with the ``pairs`` argument | |
171 | having the value |
|
171 | having the value | |
172 | ``0000000000000000000000000000000000000000-0000000000000000000000000000000000000000``. |
|
172 | ``0000000000000000000000000000000000000000-0000000000000000000000000000000000000000``. | |
173 |
|
173 | |||
174 | The ``between`` command has been supported since the original Mercurial |
|
174 | The ``between`` command has been supported since the original Mercurial | |
175 | SSH server. Requesting the empty range will return a ``\n`` string response, |
|
175 | SSH server. Requesting the empty range will return a ``\n`` string response, | |
176 | which will be encoded as ``1\n\n`` (value length of ``1`` followed by a newline |
|
176 | which will be encoded as ``1\n\n`` (value length of ``1`` followed by a newline | |
177 | followed by the value, which happens to be a newline). |
|
177 | followed by the value, which happens to be a newline). | |
178 |
|
178 | |||
179 | For pre 0.9.1 clients and all servers, the exchange looks like:: |
|
179 | For pre 0.9.1 clients and all servers, the exchange looks like:: | |
180 |
|
180 | |||
181 | c: between\n |
|
181 | c: between\n | |
182 | c: pairs 81\n |
|
182 | c: pairs 81\n | |
183 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
183 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
184 | s: 1\n |
|
184 | s: 1\n | |
185 | s: \n |
|
185 | s: \n | |
186 |
|
186 | |||
187 | 0.9.1+ clients send a ``hello`` command (with no arguments) before the |
|
187 | 0.9.1+ clients send a ``hello`` command (with no arguments) before the | |
188 | ``between`` command. The response to this command allows clients to |
|
188 | ``between`` command. The response to this command allows clients to | |
189 | discover server capabilities and settings. |
|
189 | discover server capabilities and settings. | |
190 |
|
190 | |||
191 | An example exchange between 0.9.1+ clients and a ``hello`` aware server looks |
|
191 | An example exchange between 0.9.1+ clients and a ``hello`` aware server looks | |
192 | like:: |
|
192 | like:: | |
193 |
|
193 | |||
194 | c: hello\n |
|
194 | c: hello\n | |
195 | c: between\n |
|
195 | c: between\n | |
196 | c: pairs 81\n |
|
196 | c: pairs 81\n | |
197 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
197 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
198 | s: 324\n |
|
198 | s: 324\n | |
199 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n |
|
199 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n | |
200 | s: 1\n |
|
200 | s: 1\n | |
201 | s: \n |
|
201 | s: \n | |
202 |
|
202 | |||
203 | And a similar scenario but with servers sending a banner on connect:: |
|
203 | And a similar scenario but with servers sending a banner on connect:: | |
204 |
|
204 | |||
205 | c: hello\n |
|
205 | c: hello\n | |
206 | c: between\n |
|
206 | c: between\n | |
207 | c: pairs 81\n |
|
207 | c: pairs 81\n | |
208 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
208 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
209 | s: welcome to the server\n |
|
209 | s: welcome to the server\n | |
210 | s: if you find any issues, email someone@somewhere.com\n |
|
210 | s: if you find any issues, email someone@somewhere.com\n | |
211 | s: 324\n |
|
211 | s: 324\n | |
212 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n |
|
212 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n | |
213 | s: 1\n |
|
213 | s: 1\n | |
214 | s: \n |
|
214 | s: \n | |
215 |
|
215 | |||
216 | Note that output from the ``hello`` command is terminated by a ``\n``. This is |
|
216 | Note that output from the ``hello`` command is terminated by a ``\n``. This is | |
217 | part of the response payload and not part of the wire protocol adding a newline |
|
217 | part of the response payload and not part of the wire protocol adding a newline | |
218 | after responses. In other words, the length of the response contains the |
|
218 | after responses. In other words, the length of the response contains the | |
219 | trailing ``\n``. |
|
219 | trailing ``\n``. | |
220 |
|
220 | |||
|
221 | Clients supporting version 2 of the SSH transport send a line beginning | |||
|
222 | with ``upgrade`` before the ``hello`` and ``between`` commands. The line | |||
|
223 | (which isn't a well-formed command line because it doesn't consist of a | |||
|
224 | single command name) serves to both communicate the client's intent to | |||
|
225 | switch to transport version 2 (transports are version 1 by default) as | |||
|
226 | well as to advertise the client's transport-level capabilities so the | |||
|
227 | server may satisfy that request immediately. | |||
|
228 | ||||
|
229 | The upgrade line has the form: | |||
|
230 | ||||
|
231 | upgrade <token> <transport capabilities> | |||
|
232 | ||||
|
233 | That is the literal string ``upgrade`` followed by a space, followed by | |||
|
234 | a randomly generated string, followed by a space, followed by a string | |||
|
235 | denoting the client's transport capabilities. | |||
|
236 | ||||
|
237 | The token can be anything. However, a random UUID is recommended. (Use | |||
|
238 | of version 4 UUIDs is recommended because version 1 UUIDs can leak the | |||
|
239 | client's MAC address.) | |||
|
240 | ||||
|
241 | The transport capabilities string is a URL/percent encoded string | |||
|
242 | containing key-value pairs defining the client's transport-level | |||
|
243 | capabilities. The following capabilities are defined: | |||
|
244 | ||||
|
245 | proto | |||
|
246 | A comma-delimited list of transport protocol versions the client | |||
|
247 | supports. e.g. ``ssh-v2``. | |||
|
248 | ||||
|
249 | If the server does not recognize the ``upgrade`` line, it should issue | |||
|
250 | an empty response and continue processing the ``hello`` and ``between`` | |||
|
251 | commands. Here is an example handshake between a version 2 aware client | |||
|
252 | and a non version 2 aware server: | |||
|
253 | ||||
|
254 | c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 | |||
|
255 | c: hello\n | |||
|
256 | c: between\n | |||
|
257 | c: pairs 81\n | |||
|
258 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
259 | s: 0\n | |||
|
260 | s: 324\n | |||
|
261 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n | |||
|
262 | s: 1\n | |||
|
263 | s: \n | |||
|
264 | ||||
|
265 | (The initial ``0\n`` line from the server indicates an empty response to | |||
|
266 | the unknown ``upgrade ..`` command/line.) | |||
|
267 | ||||
|
268 | If the server recognizes the ``upgrade`` line and is willing to satisfy that | |||
|
269 | upgrade request, it replies to with a payload of the following form: | |||
|
270 | ||||
|
271 | upgraded <token> <transport name>\n | |||
|
272 | ||||
|
273 | This line is the literal string ``upgraded``, a space, the token that was | |||
|
274 | specified by the client in its ``upgrade ...`` request line, a space, and the | |||
|
275 | name of the transport protocol that was chosen by the server. The transport | |||
|
276 | name MUST match one of the names the client specified in the ``proto`` field | |||
|
277 | of its ``upgrade ...`` request line. | |||
|
278 | ||||
|
279 | If a server issues an ``upgraded`` response, it MUST also read and ignore | |||
|
280 | the lines associated with the ``hello`` and ``between`` command requests | |||
|
281 | that were issued by the server. It is assumed that the negotiated transport | |||
|
282 | will respond with equivalent requested information following the transport | |||
|
283 | handshake. | |||
|
284 | ||||
|
285 | All data following the ``\n`` terminating the ``upgraded`` line is the | |||
|
286 | domain of the negotiated transport. It is common for the data immediately | |||
|
287 | following to contain additional metadata about the state of the transport and | |||
|
288 | the server. However, this isn't strictly speaking part of the transport | |||
|
289 | handshake and isn't covered by this section. | |||
|
290 | ||||
|
291 | Here is an example handshake between a version 2 aware client and a version | |||
|
292 | 2 aware server: | |||
|
293 | ||||
|
294 | c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 | |||
|
295 | c: hello\n | |||
|
296 | c: between\n | |||
|
297 | c: pairs 81\n | |||
|
298 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
299 | s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n | |||
|
300 | s: <additional transport specific data> | |||
|
301 | ||||
|
302 | The client-issued token that is echoed in the response provides a more | |||
|
303 | resilient mechanism for differentiating *banner* output from Mercurial | |||
|
304 | output. In version 1, properly formatted banner output could get confused | |||
|
305 | for Mercurial server output. By submitting a randomly generated token | |||
|
306 | that is then present in the response, the client can look for that token | |||
|
307 | in response lines and have reasonable certainty that the line did not | |||
|
308 | originate from a *banner* message. | |||
|
309 | ||||
221 | SSH Version 1 Transport |
|
310 | SSH Version 1 Transport | |
222 | ----------------------- |
|
311 | ----------------------- | |
223 |
|
312 | |||
224 | The SSH transport (version 1) is a custom text-based protocol suitable for |
|
313 | The SSH transport (version 1) is a custom text-based protocol suitable for | |
225 | use over any bi-directional stream transport. It is most commonly used with |
|
314 | use over any bi-directional stream transport. It is most commonly used with | |
226 | SSH. |
|
315 | SSH. | |
227 |
|
316 | |||
228 | A SSH transport server can be started with ``hg serve --stdio``. The stdin, |
|
317 | A SSH transport server can be started with ``hg serve --stdio``. The stdin, | |
229 | stderr, and stdout file descriptors of the started process are used to exchange |
|
318 | stderr, and stdout file descriptors of the started process are used to exchange | |
230 | data. When Mercurial connects to a remote server over SSH, it actually starts |
|
319 | data. When Mercurial connects to a remote server over SSH, it actually starts | |
231 | a ``hg serve --stdio`` process on the remote server. |
|
320 | a ``hg serve --stdio`` process on the remote server. | |
232 |
|
321 | |||
233 | Commands are issued by sending the command name followed by a trailing newline |
|
322 | Commands are issued by sending the command name followed by a trailing newline | |
234 | ``\n`` to the server. e.g. ``capabilities\n``. |
|
323 | ``\n`` to the server. e.g. ``capabilities\n``. | |
235 |
|
324 | |||
236 | Command arguments are sent in the following format:: |
|
325 | Command arguments are sent in the following format:: | |
237 |
|
326 | |||
238 | <argument> <length>\n<value> |
|
327 | <argument> <length>\n<value> | |
239 |
|
328 | |||
240 | That is, the argument string name followed by a space followed by the |
|
329 | That is, the argument string name followed by a space followed by the | |
241 | integer length of the value (expressed as a string) followed by a newline |
|
330 | integer length of the value (expressed as a string) followed by a newline | |
242 | (``\n``) followed by the raw argument value. |
|
331 | (``\n``) followed by the raw argument value. | |
243 |
|
332 | |||
244 | Dictionary arguments are encoded differently:: |
|
333 | Dictionary arguments are encoded differently:: | |
245 |
|
334 | |||
246 | <argument> <# elements>\n |
|
335 | <argument> <# elements>\n | |
247 | <key1> <length1>\n<value1> |
|
336 | <key1> <length1>\n<value1> | |
248 | <key2> <length2>\n<value2> |
|
337 | <key2> <length2>\n<value2> | |
249 | ... |
|
338 | ... | |
250 |
|
339 | |||
251 | Non-argument data is sent immediately after the final argument value. It is |
|
340 | Non-argument data is sent immediately after the final argument value. It is | |
252 | encoded in chunks:: |
|
341 | encoded in chunks:: | |
253 |
|
342 | |||
254 | <length>\n<data> |
|
343 | <length>\n<data> | |
255 |
|
344 | |||
256 | Each command declares a list of supported arguments and their types. If a |
|
345 | Each command declares a list of supported arguments and their types. If a | |
257 | client sends an unknown argument to the server, the server should abort |
|
346 | client sends an unknown argument to the server, the server should abort | |
258 | immediately. The special argument ``*`` in a command's definition indicates |
|
347 | immediately. The special argument ``*`` in a command's definition indicates | |
259 | that all argument names are allowed. |
|
348 | that all argument names are allowed. | |
260 |
|
349 | |||
261 | The definition of supported arguments and types is initially made when a |
|
350 | The definition of supported arguments and types is initially made when a | |
262 | new command is implemented. The client and server must initially independently |
|
351 | new command is implemented. The client and server must initially independently | |
263 | agree on the arguments and their types. This initial set of arguments can be |
|
352 | agree on the arguments and their types. This initial set of arguments can be | |
264 | supplemented through the presence of *capabilities* advertised by the server. |
|
353 | supplemented through the presence of *capabilities* advertised by the server. | |
265 |
|
354 | |||
266 | Each command has a defined expected response type. |
|
355 | Each command has a defined expected response type. | |
267 |
|
356 | |||
268 | A ``string`` response type is a length framed value. The response consists of |
|
357 | A ``string`` response type is a length framed value. The response consists of | |
269 | the string encoded integer length of a value followed by a newline (``\n``) |
|
358 | the string encoded integer length of a value followed by a newline (``\n``) | |
270 | followed by the value. Empty values are allowed (and are represented as |
|
359 | followed by the value. Empty values are allowed (and are represented as | |
271 | ``0\n``). |
|
360 | ``0\n``). | |
272 |
|
361 | |||
273 | A ``stream`` response type consists of raw bytes of data. There is no framing. |
|
362 | A ``stream`` response type consists of raw bytes of data. There is no framing. | |
274 |
|
363 | |||
275 | A generic error response type is also supported. It consists of a an error |
|
364 | A generic error response type is also supported. It consists of a an error | |
276 | message written to ``stderr`` followed by ``\n-\n``. In addition, ``\n`` is |
|
365 | message written to ``stderr`` followed by ``\n-\n``. In addition, ``\n`` is | |
277 | written to ``stdout``. |
|
366 | written to ``stdout``. | |
278 |
|
367 | |||
279 | If the server receives an unknown command, it will send an empty ``string`` |
|
368 | If the server receives an unknown command, it will send an empty ``string`` | |
280 | response. |
|
369 | response. | |
281 |
|
370 | |||
282 | The server terminates if it receives an empty command (a ``\n`` character). |
|
371 | The server terminates if it receives an empty command (a ``\n`` character). | |
283 |
|
372 | |||
|
373 | SSH Version 2 Transport | |||
|
374 | ----------------------- | |||
|
375 | ||||
|
376 | **Experimental** | |||
|
377 | ||||
|
378 | Version 2 of the SSH transport behaves identically to version 1 of the SSH | |||
|
379 | transport with the exception of handshake semantics. See above for how | |||
|
380 | version 2 of the SSH transport is negotiated. | |||
|
381 | ||||
|
382 | Immediately following the ``upgraded`` line signaling a switch to version | |||
|
383 | 2 of the SSH protocol, the server automatically sends additional details | |||
|
384 | about the capabilities of the remote server. This has the form: | |||
|
385 | ||||
|
386 | <integer length of value>\n | |||
|
387 | capabilities: ...\n | |||
|
388 | ||||
|
389 | e.g. | |||
|
390 | ||||
|
391 | s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n | |||
|
392 | s: 240\n | |||
|
393 | s: capabilities: known getbundle batch ...\n | |||
|
394 | ||||
|
395 | Following capabilities advertisement, the peers communicate using version | |||
|
396 | 1 of the SSH transport. | |||
|
397 | ||||
284 | Capabilities |
|
398 | Capabilities | |
285 | ============ |
|
399 | ============ | |
286 |
|
400 | |||
287 | Servers advertise supported wire protocol features. This allows clients to |
|
401 | Servers advertise supported wire protocol features. This allows clients to | |
288 | probe for server features before blindly calling a command or passing a |
|
402 | probe for server features before blindly calling a command or passing a | |
289 | specific argument. |
|
403 | specific argument. | |
290 |
|
404 | |||
291 | The server's features are exposed via a *capabilities* string. This is a |
|
405 | The server's features are exposed via a *capabilities* string. This is a | |
292 | space-delimited string of tokens/features. Some features are single words |
|
406 | space-delimited string of tokens/features. Some features are single words | |
293 | like ``lookup`` or ``batch``. Others are complicated key-value pairs |
|
407 | like ``lookup`` or ``batch``. Others are complicated key-value pairs | |
294 | advertising sub-features. e.g. ``httpheader=2048``. When complex, non-word |
|
408 | advertising sub-features. e.g. ``httpheader=2048``. When complex, non-word | |
295 | values are used, each feature name can define its own encoding of sub-values. |
|
409 | values are used, each feature name can define its own encoding of sub-values. | |
296 | Comma-delimited and ``x-www-form-urlencoded`` values are common. |
|
410 | Comma-delimited and ``x-www-form-urlencoded`` values are common. | |
297 |
|
411 | |||
298 | The following document capabilities defined by the canonical Mercurial server |
|
412 | The following document capabilities defined by the canonical Mercurial server | |
299 | implementation. |
|
413 | implementation. | |
300 |
|
414 | |||
301 | batch |
|
415 | batch | |
302 | ----- |
|
416 | ----- | |
303 |
|
417 | |||
304 | Whether the server supports the ``batch`` command. |
|
418 | Whether the server supports the ``batch`` command. | |
305 |
|
419 | |||
306 | This capability/command was introduced in Mercurial 1.9 (released July 2011). |
|
420 | This capability/command was introduced in Mercurial 1.9 (released July 2011). | |
307 |
|
421 | |||
308 | branchmap |
|
422 | branchmap | |
309 | --------- |
|
423 | --------- | |
310 |
|
424 | |||
311 | Whether the server supports the ``branchmap`` command. |
|
425 | Whether the server supports the ``branchmap`` command. | |
312 |
|
426 | |||
313 | This capability/command was introduced in Mercurial 1.3 (released July 2009). |
|
427 | This capability/command was introduced in Mercurial 1.3 (released July 2009). | |
314 |
|
428 | |||
315 | bundle2-exp |
|
429 | bundle2-exp | |
316 | ----------- |
|
430 | ----------- | |
317 |
|
431 | |||
318 | Precursor to ``bundle2`` capability that was used before bundle2 was a |
|
432 | Precursor to ``bundle2`` capability that was used before bundle2 was a | |
319 | stable feature. |
|
433 | stable feature. | |
320 |
|
434 | |||
321 | This capability was introduced in Mercurial 3.0 behind an experimental |
|
435 | This capability was introduced in Mercurial 3.0 behind an experimental | |
322 | flag. This capability should not be observed in the wild. |
|
436 | flag. This capability should not be observed in the wild. | |
323 |
|
437 | |||
324 | bundle2 |
|
438 | bundle2 | |
325 | ------- |
|
439 | ------- | |
326 |
|
440 | |||
327 | Indicates whether the server supports the ``bundle2`` data exchange format. |
|
441 | Indicates whether the server supports the ``bundle2`` data exchange format. | |
328 |
|
442 | |||
329 | The value of the capability is a URL quoted, newline (``\n``) delimited |
|
443 | The value of the capability is a URL quoted, newline (``\n``) delimited | |
330 | list of keys or key-value pairs. |
|
444 | list of keys or key-value pairs. | |
331 |
|
445 | |||
332 | A key is simply a URL encoded string. |
|
446 | A key is simply a URL encoded string. | |
333 |
|
447 | |||
334 | A key-value pair is a URL encoded key separated from a URL encoded value by |
|
448 | A key-value pair is a URL encoded key separated from a URL encoded value by | |
335 | an ``=``. If the value is a list, elements are delimited by a ``,`` after |
|
449 | an ``=``. If the value is a list, elements are delimited by a ``,`` after | |
336 | URL encoding. |
|
450 | URL encoding. | |
337 |
|
451 | |||
338 | For example, say we have the values:: |
|
452 | For example, say we have the values:: | |
339 |
|
453 | |||
340 | {'HG20': [], 'changegroup': ['01', '02'], 'digests': ['sha1', 'sha512']} |
|
454 | {'HG20': [], 'changegroup': ['01', '02'], 'digests': ['sha1', 'sha512']} | |
341 |
|
455 | |||
342 | We would first construct a string:: |
|
456 | We would first construct a string:: | |
343 |
|
457 | |||
344 | HG20\nchangegroup=01,02\ndigests=sha1,sha512 |
|
458 | HG20\nchangegroup=01,02\ndigests=sha1,sha512 | |
345 |
|
459 | |||
346 | We would then URL quote this string:: |
|
460 | We would then URL quote this string:: | |
347 |
|
461 | |||
348 | HG20%0Achangegroup%3D01%2C02%0Adigests%3Dsha1%2Csha512 |
|
462 | HG20%0Achangegroup%3D01%2C02%0Adigests%3Dsha1%2Csha512 | |
349 |
|
463 | |||
350 | This capability was introduced in Mercurial 3.4 (released May 2015). |
|
464 | This capability was introduced in Mercurial 3.4 (released May 2015). | |
351 |
|
465 | |||
352 | changegroupsubset |
|
466 | changegroupsubset | |
353 | ----------------- |
|
467 | ----------------- | |
354 |
|
468 | |||
355 | Whether the server supports the ``changegroupsubset`` command. |
|
469 | Whether the server supports the ``changegroupsubset`` command. | |
356 |
|
470 | |||
357 | This capability was introduced in Mercurial 0.9.2 (released December |
|
471 | This capability was introduced in Mercurial 0.9.2 (released December | |
358 | 2006). |
|
472 | 2006). | |
359 |
|
473 | |||
360 | This capability was introduced at the same time as the ``lookup`` |
|
474 | This capability was introduced at the same time as the ``lookup`` | |
361 | capability/command. |
|
475 | capability/command. | |
362 |
|
476 | |||
363 | compression |
|
477 | compression | |
364 | ----------- |
|
478 | ----------- | |
365 |
|
479 | |||
366 | Declares support for negotiating compression formats. |
|
480 | Declares support for negotiating compression formats. | |
367 |
|
481 | |||
368 | Presence of this capability indicates the server supports dynamic selection |
|
482 | Presence of this capability indicates the server supports dynamic selection | |
369 | of compression formats based on the client request. |
|
483 | of compression formats based on the client request. | |
370 |
|
484 | |||
371 | Servers advertising this capability are required to support the |
|
485 | Servers advertising this capability are required to support the | |
372 | ``application/mercurial-0.2`` media type in response to commands returning |
|
486 | ``application/mercurial-0.2`` media type in response to commands returning | |
373 | streams. Servers may support this media type on any command. |
|
487 | streams. Servers may support this media type on any command. | |
374 |
|
488 | |||
375 | The value of the capability is a comma-delimited list of strings declaring |
|
489 | The value of the capability is a comma-delimited list of strings declaring | |
376 | supported compression formats. The order of the compression formats is in |
|
490 | supported compression formats. The order of the compression formats is in | |
377 | server-preferred order, most preferred first. |
|
491 | server-preferred order, most preferred first. | |
378 |
|
492 | |||
379 | The identifiers used by the official Mercurial distribution are: |
|
493 | The identifiers used by the official Mercurial distribution are: | |
380 |
|
494 | |||
381 | bzip2 |
|
495 | bzip2 | |
382 | bzip2 |
|
496 | bzip2 | |
383 | none |
|
497 | none | |
384 | uncompressed / raw data |
|
498 | uncompressed / raw data | |
385 | zlib |
|
499 | zlib | |
386 | zlib (no gzip header) |
|
500 | zlib (no gzip header) | |
387 | zstd |
|
501 | zstd | |
388 | zstd |
|
502 | zstd | |
389 |
|
503 | |||
390 | This capability was introduced in Mercurial 4.1 (released February 2017). |
|
504 | This capability was introduced in Mercurial 4.1 (released February 2017). | |
391 |
|
505 | |||
392 | getbundle |
|
506 | getbundle | |
393 | --------- |
|
507 | --------- | |
394 |
|
508 | |||
395 | Whether the server supports the ``getbundle`` command. |
|
509 | Whether the server supports the ``getbundle`` command. | |
396 |
|
510 | |||
397 | This capability was introduced in Mercurial 1.9 (released July 2011). |
|
511 | This capability was introduced in Mercurial 1.9 (released July 2011). | |
398 |
|
512 | |||
399 | httpheader |
|
513 | httpheader | |
400 | ---------- |
|
514 | ---------- | |
401 |
|
515 | |||
402 | Whether the server supports receiving command arguments via HTTP request |
|
516 | Whether the server supports receiving command arguments via HTTP request | |
403 | headers. |
|
517 | headers. | |
404 |
|
518 | |||
405 | The value of the capability is an integer describing the max header |
|
519 | The value of the capability is an integer describing the max header | |
406 | length that clients should send. Clients should ignore any content after a |
|
520 | length that clients should send. Clients should ignore any content after a | |
407 | comma in the value, as this is reserved for future use. |
|
521 | comma in the value, as this is reserved for future use. | |
408 |
|
522 | |||
409 | This capability was introduced in Mercurial 1.9 (released July 2011). |
|
523 | This capability was introduced in Mercurial 1.9 (released July 2011). | |
410 |
|
524 | |||
411 | httpmediatype |
|
525 | httpmediatype | |
412 | ------------- |
|
526 | ------------- | |
413 |
|
527 | |||
414 | Indicates which HTTP media types (``Content-Type`` header) the server is |
|
528 | Indicates which HTTP media types (``Content-Type`` header) the server is | |
415 | capable of receiving and sending. |
|
529 | capable of receiving and sending. | |
416 |
|
530 | |||
417 | The value of the capability is a comma-delimited list of strings identifying |
|
531 | The value of the capability is a comma-delimited list of strings identifying | |
418 | support for media type and transmission direction. The following strings may |
|
532 | support for media type and transmission direction. The following strings may | |
419 | be present: |
|
533 | be present: | |
420 |
|
534 | |||
421 | 0.1rx |
|
535 | 0.1rx | |
422 | Indicates server support for receiving ``application/mercurial-0.1`` media |
|
536 | Indicates server support for receiving ``application/mercurial-0.1`` media | |
423 | types. |
|
537 | types. | |
424 |
|
538 | |||
425 | 0.1tx |
|
539 | 0.1tx | |
426 | Indicates server support for sending ``application/mercurial-0.1`` media |
|
540 | Indicates server support for sending ``application/mercurial-0.1`` media | |
427 | types. |
|
541 | types. | |
428 |
|
542 | |||
429 | 0.2rx |
|
543 | 0.2rx | |
430 | Indicates server support for receiving ``application/mercurial-0.2`` media |
|
544 | Indicates server support for receiving ``application/mercurial-0.2`` media | |
431 | types. |
|
545 | types. | |
432 |
|
546 | |||
433 | 0.2tx |
|
547 | 0.2tx | |
434 | Indicates server support for sending ``application/mercurial-0.2`` media |
|
548 | Indicates server support for sending ``application/mercurial-0.2`` media | |
435 | types. |
|
549 | types. | |
436 |
|
550 | |||
437 | minrx=X |
|
551 | minrx=X | |
438 | Minimum media type version the server is capable of receiving. Value is a |
|
552 | Minimum media type version the server is capable of receiving. Value is a | |
439 | string like ``0.2``. |
|
553 | string like ``0.2``. | |
440 |
|
554 | |||
441 | This capability can be used by servers to limit connections from legacy |
|
555 | This capability can be used by servers to limit connections from legacy | |
442 | clients not using the latest supported media type. However, only clients |
|
556 | clients not using the latest supported media type. However, only clients | |
443 | with knowledge of this capability will know to consult this value. This |
|
557 | with knowledge of this capability will know to consult this value. This | |
444 | capability is present so the client may issue a more user-friendly error |
|
558 | capability is present so the client may issue a more user-friendly error | |
445 | when the server has locked out a legacy client. |
|
559 | when the server has locked out a legacy client. | |
446 |
|
560 | |||
447 | mintx=X |
|
561 | mintx=X | |
448 | Minimum media type version the server is capable of sending. Value is a |
|
562 | Minimum media type version the server is capable of sending. Value is a | |
449 | string like ``0.1``. |
|
563 | string like ``0.1``. | |
450 |
|
564 | |||
451 | Servers advertising support for the ``application/mercurial-0.2`` media type |
|
565 | Servers advertising support for the ``application/mercurial-0.2`` media type | |
452 | should also advertise the ``compression`` capability. |
|
566 | should also advertise the ``compression`` capability. | |
453 |
|
567 | |||
454 | This capability was introduced in Mercurial 4.1 (released February 2017). |
|
568 | This capability was introduced in Mercurial 4.1 (released February 2017). | |
455 |
|
569 | |||
456 | httppostargs |
|
570 | httppostargs | |
457 | ------------ |
|
571 | ------------ | |
458 |
|
572 | |||
459 | **Experimental** |
|
573 | **Experimental** | |
460 |
|
574 | |||
461 | Indicates that the server supports and prefers clients send command arguments |
|
575 | Indicates that the server supports and prefers clients send command arguments | |
462 | via a HTTP POST request as part of the request body. |
|
576 | via a HTTP POST request as part of the request body. | |
463 |
|
577 | |||
464 | This capability was introduced in Mercurial 3.8 (released May 2016). |
|
578 | This capability was introduced in Mercurial 3.8 (released May 2016). | |
465 |
|
579 | |||
466 | known |
|
580 | known | |
467 | ----- |
|
581 | ----- | |
468 |
|
582 | |||
469 | Whether the server supports the ``known`` command. |
|
583 | Whether the server supports the ``known`` command. | |
470 |
|
584 | |||
471 | This capability/command was introduced in Mercurial 1.9 (released July 2011). |
|
585 | This capability/command was introduced in Mercurial 1.9 (released July 2011). | |
472 |
|
586 | |||
473 | lookup |
|
587 | lookup | |
474 | ------ |
|
588 | ------ | |
475 |
|
589 | |||
476 | Whether the server supports the ``lookup`` command. |
|
590 | Whether the server supports the ``lookup`` command. | |
477 |
|
591 | |||
478 | This capability was introduced in Mercurial 0.9.2 (released December |
|
592 | This capability was introduced in Mercurial 0.9.2 (released December | |
479 | 2006). |
|
593 | 2006). | |
480 |
|
594 | |||
481 | This capability was introduced at the same time as the ``changegroupsubset`` |
|
595 | This capability was introduced at the same time as the ``changegroupsubset`` | |
482 | capability/command. |
|
596 | capability/command. | |
483 |
|
597 | |||
484 | pushkey |
|
598 | pushkey | |
485 | ------- |
|
599 | ------- | |
486 |
|
600 | |||
487 | Whether the server supports the ``pushkey`` and ``listkeys`` commands. |
|
601 | Whether the server supports the ``pushkey`` and ``listkeys`` commands. | |
488 |
|
602 | |||
489 | This capability was introduced in Mercurial 1.6 (released July 2010). |
|
603 | This capability was introduced in Mercurial 1.6 (released July 2010). | |
490 |
|
604 | |||
491 | standardbundle |
|
605 | standardbundle | |
492 | -------------- |
|
606 | -------------- | |
493 |
|
607 | |||
494 | **Unsupported** |
|
608 | **Unsupported** | |
495 |
|
609 | |||
496 | This capability was introduced during the Mercurial 0.9.2 development cycle in |
|
610 | This capability was introduced during the Mercurial 0.9.2 development cycle in | |
497 | 2006. It was never present in a release, as it was replaced by the ``unbundle`` |
|
611 | 2006. It was never present in a release, as it was replaced by the ``unbundle`` | |
498 | capability. This capability should not be encountered in the wild. |
|
612 | capability. This capability should not be encountered in the wild. | |
499 |
|
613 | |||
500 | stream-preferred |
|
614 | stream-preferred | |
501 | ---------------- |
|
615 | ---------------- | |
502 |
|
616 | |||
503 | If present the server prefers that clients clone using the streaming clone |
|
617 | If present the server prefers that clients clone using the streaming clone | |
504 | protocol (``hg clone --stream``) rather than the standard |
|
618 | protocol (``hg clone --stream``) rather than the standard | |
505 | changegroup/bundle based protocol. |
|
619 | changegroup/bundle based protocol. | |
506 |
|
620 | |||
507 | This capability was introduced in Mercurial 2.2 (released May 2012). |
|
621 | This capability was introduced in Mercurial 2.2 (released May 2012). | |
508 |
|
622 | |||
509 | streamreqs |
|
623 | streamreqs | |
510 | ---------- |
|
624 | ---------- | |
511 |
|
625 | |||
512 | Indicates whether the server supports *streaming clones* and the *requirements* |
|
626 | Indicates whether the server supports *streaming clones* and the *requirements* | |
513 | that clients must support to receive it. |
|
627 | that clients must support to receive it. | |
514 |
|
628 | |||
515 | If present, the server supports the ``stream_out`` command, which transmits |
|
629 | If present, the server supports the ``stream_out`` command, which transmits | |
516 | raw revlogs from the repository instead of changegroups. This provides a faster |
|
630 | raw revlogs from the repository instead of changegroups. This provides a faster | |
517 | cloning mechanism at the expense of more bandwidth used. |
|
631 | cloning mechanism at the expense of more bandwidth used. | |
518 |
|
632 | |||
519 | The value of this capability is a comma-delimited list of repo format |
|
633 | The value of this capability is a comma-delimited list of repo format | |
520 | *requirements*. These are requirements that impact the reading of data in |
|
634 | *requirements*. These are requirements that impact the reading of data in | |
521 | the ``.hg/store`` directory. An example value is |
|
635 | the ``.hg/store`` directory. An example value is | |
522 | ``streamreqs=generaldelta,revlogv1`` indicating the server repo requires |
|
636 | ``streamreqs=generaldelta,revlogv1`` indicating the server repo requires | |
523 | the ``revlogv1`` and ``generaldelta`` requirements. |
|
637 | the ``revlogv1`` and ``generaldelta`` requirements. | |
524 |
|
638 | |||
525 | If the only format requirement is ``revlogv1``, the server may expose the |
|
639 | If the only format requirement is ``revlogv1``, the server may expose the | |
526 | ``stream`` capability instead of the ``streamreqs`` capability. |
|
640 | ``stream`` capability instead of the ``streamreqs`` capability. | |
527 |
|
641 | |||
528 | This capability was introduced in Mercurial 1.7 (released November 2010). |
|
642 | This capability was introduced in Mercurial 1.7 (released November 2010). | |
529 |
|
643 | |||
530 | stream |
|
644 | stream | |
531 | ------ |
|
645 | ------ | |
532 |
|
646 | |||
533 | Whether the server supports *streaming clones* from ``revlogv1`` repos. |
|
647 | Whether the server supports *streaming clones* from ``revlogv1`` repos. | |
534 |
|
648 | |||
535 | If present, the server supports the ``stream_out`` command, which transmits |
|
649 | If present, the server supports the ``stream_out`` command, which transmits | |
536 | raw revlogs from the repository instead of changegroups. This provides a faster |
|
650 | raw revlogs from the repository instead of changegroups. This provides a faster | |
537 | cloning mechanism at the expense of more bandwidth used. |
|
651 | cloning mechanism at the expense of more bandwidth used. | |
538 |
|
652 | |||
539 | This capability was introduced in Mercurial 0.9.1 (released July 2006). |
|
653 | This capability was introduced in Mercurial 0.9.1 (released July 2006). | |
540 |
|
654 | |||
541 | When initially introduced, the value of the capability was the numeric |
|
655 | When initially introduced, the value of the capability was the numeric | |
542 | revlog revision. e.g. ``stream=1``. This indicates the changegroup is using |
|
656 | revlog revision. e.g. ``stream=1``. This indicates the changegroup is using | |
543 | ``revlogv1``. This simple integer value wasn't powerful enough, so the |
|
657 | ``revlogv1``. This simple integer value wasn't powerful enough, so the | |
544 | ``streamreqs`` capability was invented to handle cases where the repo |
|
658 | ``streamreqs`` capability was invented to handle cases where the repo | |
545 | requirements have more than just ``revlogv1``. Newer servers omit the |
|
659 | requirements have more than just ``revlogv1``. Newer servers omit the | |
546 | ``=1`` since it was the only value supported and the value of ``1`` can |
|
660 | ``=1`` since it was the only value supported and the value of ``1`` can | |
547 | be implied by clients. |
|
661 | be implied by clients. | |
548 |
|
662 | |||
549 | unbundlehash |
|
663 | unbundlehash | |
550 | ------------ |
|
664 | ------------ | |
551 |
|
665 | |||
552 | Whether the ``unbundle`` commands supports receiving a hash of all the |
|
666 | Whether the ``unbundle`` commands supports receiving a hash of all the | |
553 | heads instead of a list. |
|
667 | heads instead of a list. | |
554 |
|
668 | |||
555 | For more, see the documentation for the ``unbundle`` command. |
|
669 | For more, see the documentation for the ``unbundle`` command. | |
556 |
|
670 | |||
557 | This capability was introduced in Mercurial 1.9 (released July 2011). |
|
671 | This capability was introduced in Mercurial 1.9 (released July 2011). | |
558 |
|
672 | |||
559 | unbundle |
|
673 | unbundle | |
560 | -------- |
|
674 | -------- | |
561 |
|
675 | |||
562 | Whether the server supports pushing via the ``unbundle`` command. |
|
676 | Whether the server supports pushing via the ``unbundle`` command. | |
563 |
|
677 | |||
564 | This capability/command has been present since Mercurial 0.9.1 (released |
|
678 | This capability/command has been present since Mercurial 0.9.1 (released | |
565 | July 2006). |
|
679 | July 2006). | |
566 |
|
680 | |||
567 | Mercurial 0.9.2 (released December 2006) added values to the capability |
|
681 | Mercurial 0.9.2 (released December 2006) added values to the capability | |
568 | indicating which bundle types the server supports receiving. This value is a |
|
682 | indicating which bundle types the server supports receiving. This value is a | |
569 | comma-delimited list. e.g. ``HG10GZ,HG10BZ,HG10UN``. The order of values |
|
683 | comma-delimited list. e.g. ``HG10GZ,HG10BZ,HG10UN``. The order of values | |
570 | reflects the priority/preference of that type, where the first value is the |
|
684 | reflects the priority/preference of that type, where the first value is the | |
571 | most preferred type. |
|
685 | most preferred type. | |
572 |
|
686 | |||
573 | Content Negotiation |
|
687 | Content Negotiation | |
574 | =================== |
|
688 | =================== | |
575 |
|
689 | |||
576 | The wire protocol has some mechanisms to help peers determine what content |
|
690 | The wire protocol has some mechanisms to help peers determine what content | |
577 | types and encoding the other side will accept. Historically, these mechanisms |
|
691 | types and encoding the other side will accept. Historically, these mechanisms | |
578 | have been built into commands themselves because most commands only send a |
|
692 | have been built into commands themselves because most commands only send a | |
579 | well-defined response type and only certain commands needed to support |
|
693 | well-defined response type and only certain commands needed to support | |
580 | functionality like compression. |
|
694 | functionality like compression. | |
581 |
|
695 | |||
582 | Currently, only the HTTP version 1 transport supports content negotiation |
|
696 | Currently, only the HTTP version 1 transport supports content negotiation | |
583 | at the protocol layer. |
|
697 | at the protocol layer. | |
584 |
|
698 | |||
585 | HTTP requests advertise supported response formats via the ``X-HgProto-<N>`` |
|
699 | HTTP requests advertise supported response formats via the ``X-HgProto-<N>`` | |
586 | request header, where ``<N>`` is an integer starting at 1 allowing the logical |
|
700 | request header, where ``<N>`` is an integer starting at 1 allowing the logical | |
587 | value to span multiple headers. This value consists of a list of |
|
701 | value to span multiple headers. This value consists of a list of | |
588 | space-delimited parameters. Each parameter denotes a feature or capability. |
|
702 | space-delimited parameters. Each parameter denotes a feature or capability. | |
589 |
|
703 | |||
590 | The following parameters are defined: |
|
704 | The following parameters are defined: | |
591 |
|
705 | |||
592 | 0.1 |
|
706 | 0.1 | |
593 | Indicates the client supports receiving ``application/mercurial-0.1`` |
|
707 | Indicates the client supports receiving ``application/mercurial-0.1`` | |
594 | responses. |
|
708 | responses. | |
595 |
|
709 | |||
596 | 0.2 |
|
710 | 0.2 | |
597 | Indicates the client supports receiving ``application/mercurial-0.2`` |
|
711 | Indicates the client supports receiving ``application/mercurial-0.2`` | |
598 | responses. |
|
712 | responses. | |
599 |
|
713 | |||
600 | comp |
|
714 | comp | |
601 | Indicates compression formats the client can decode. Value is a list of |
|
715 | Indicates compression formats the client can decode. Value is a list of | |
602 | comma delimited strings identifying compression formats ordered from |
|
716 | comma delimited strings identifying compression formats ordered from | |
603 | most preferential to least preferential. e.g. ``comp=zstd,zlib,none``. |
|
717 | most preferential to least preferential. e.g. ``comp=zstd,zlib,none``. | |
604 |
|
718 | |||
605 | This parameter does not have an effect if only the ``0.1`` parameter |
|
719 | This parameter does not have an effect if only the ``0.1`` parameter | |
606 | is defined, as support for ``application/mercurial-0.2`` or greater is |
|
720 | is defined, as support for ``application/mercurial-0.2`` or greater is | |
607 | required to use arbitrary compression formats. |
|
721 | required to use arbitrary compression formats. | |
608 |
|
722 | |||
609 | If this parameter is not advertised, the server interprets this as |
|
723 | If this parameter is not advertised, the server interprets this as | |
610 | equivalent to ``zlib,none``. |
|
724 | equivalent to ``zlib,none``. | |
611 |
|
725 | |||
612 | Clients may choose to only send this header if the ``httpmediatype`` |
|
726 | Clients may choose to only send this header if the ``httpmediatype`` | |
613 | server capability is present, as currently all server-side features |
|
727 | server capability is present, as currently all server-side features | |
614 | consulting this header require the client to opt in to new protocol features |
|
728 | consulting this header require the client to opt in to new protocol features | |
615 | advertised via the ``httpmediatype`` capability. |
|
729 | advertised via the ``httpmediatype`` capability. | |
616 |
|
730 | |||
617 | A server that doesn't receive an ``X-HgProto-<N>`` header should infer a |
|
731 | A server that doesn't receive an ``X-HgProto-<N>`` header should infer a | |
618 | value of ``0.1``. This is compatible with legacy clients. |
|
732 | value of ``0.1``. This is compatible with legacy clients. | |
619 |
|
733 | |||
620 | A server receiving a request indicating support for multiple media type |
|
734 | A server receiving a request indicating support for multiple media type | |
621 | versions may respond with any of the supported media types. Not all servers |
|
735 | versions may respond with any of the supported media types. Not all servers | |
622 | may support all media types on all commands. |
|
736 | may support all media types on all commands. | |
623 |
|
737 | |||
624 | Commands |
|
738 | Commands | |
625 | ======== |
|
739 | ======== | |
626 |
|
740 | |||
627 | This section contains a list of all wire protocol commands implemented by |
|
741 | This section contains a list of all wire protocol commands implemented by | |
628 | the canonical Mercurial server. |
|
742 | the canonical Mercurial server. | |
629 |
|
743 | |||
630 | batch |
|
744 | batch | |
631 | ----- |
|
745 | ----- | |
632 |
|
746 | |||
633 | Issue multiple commands while sending a single command request. The purpose |
|
747 | Issue multiple commands while sending a single command request. The purpose | |
634 | of this command is to allow a client to issue multiple commands while avoiding |
|
748 | of this command is to allow a client to issue multiple commands while avoiding | |
635 | multiple round trips to the server therefore enabling commands to complete |
|
749 | multiple round trips to the server therefore enabling commands to complete | |
636 | quicker. |
|
750 | quicker. | |
637 |
|
751 | |||
638 | The command accepts a ``cmds`` argument that contains a list of commands to |
|
752 | The command accepts a ``cmds`` argument that contains a list of commands to | |
639 | execute. |
|
753 | execute. | |
640 |
|
754 | |||
641 | The value of ``cmds`` is a ``;`` delimited list of strings. Each string has the |
|
755 | The value of ``cmds`` is a ``;`` delimited list of strings. Each string has the | |
642 | form ``<command> <arguments>``. That is, the command name followed by a space |
|
756 | form ``<command> <arguments>``. That is, the command name followed by a space | |
643 | followed by an argument string. |
|
757 | followed by an argument string. | |
644 |
|
758 | |||
645 | The argument string is a ``,`` delimited list of ``<key>=<value>`` values |
|
759 | The argument string is a ``,`` delimited list of ``<key>=<value>`` values | |
646 | corresponding to command arguments. Both the argument name and value are |
|
760 | corresponding to command arguments. Both the argument name and value are | |
647 | escaped using a special substitution map:: |
|
761 | escaped using a special substitution map:: | |
648 |
|
762 | |||
649 | : -> :c |
|
763 | : -> :c | |
650 | , -> :o |
|
764 | , -> :o | |
651 | ; -> :s |
|
765 | ; -> :s | |
652 | = -> :e |
|
766 | = -> :e | |
653 |
|
767 | |||
654 | The response type for this command is ``string``. The value contains a |
|
768 | The response type for this command is ``string``. The value contains a | |
655 | ``;`` delimited list of responses for each requested command. Each value |
|
769 | ``;`` delimited list of responses for each requested command. Each value | |
656 | in this list is escaped using the same substitution map used for arguments. |
|
770 | in this list is escaped using the same substitution map used for arguments. | |
657 |
|
771 | |||
658 | If an error occurs, the generic error response may be sent. |
|
772 | If an error occurs, the generic error response may be sent. | |
659 |
|
773 | |||
660 | between |
|
774 | between | |
661 | ------- |
|
775 | ------- | |
662 |
|
776 | |||
663 | (Legacy command used for discovery in old clients) |
|
777 | (Legacy command used for discovery in old clients) | |
664 |
|
778 | |||
665 | Obtain nodes between pairs of nodes. |
|
779 | Obtain nodes between pairs of nodes. | |
666 |
|
780 | |||
667 | The ``pairs`` arguments contains a space-delimited list of ``-`` delimited |
|
781 | The ``pairs`` arguments contains a space-delimited list of ``-`` delimited | |
668 | hex node pairs. e.g.:: |
|
782 | hex node pairs. e.g.:: | |
669 |
|
783 | |||
670 | a072279d3f7fd3a4aa7ffa1a5af8efc573e1c896-6dc58916e7c070f678682bfe404d2e2d68291a18 |
|
784 | a072279d3f7fd3a4aa7ffa1a5af8efc573e1c896-6dc58916e7c070f678682bfe404d2e2d68291a18 | |
671 |
|
785 | |||
672 | Return type is a ``string``. Value consists of lines corresponding to each |
|
786 | Return type is a ``string``. Value consists of lines corresponding to each | |
673 | requested range. Each line contains a space-delimited list of hex nodes. |
|
787 | requested range. Each line contains a space-delimited list of hex nodes. | |
674 | A newline ``\n`` terminates each line, including the last one. |
|
788 | A newline ``\n`` terminates each line, including the last one. | |
675 |
|
789 | |||
676 | branchmap |
|
790 | branchmap | |
677 | --------- |
|
791 | --------- | |
678 |
|
792 | |||
679 | Obtain heads in named branches. |
|
793 | Obtain heads in named branches. | |
680 |
|
794 | |||
681 | Accepts no arguments. Return type is a ``string``. |
|
795 | Accepts no arguments. Return type is a ``string``. | |
682 |
|
796 | |||
683 | Return value contains lines with URL encoded branch names followed by a space |
|
797 | Return value contains lines with URL encoded branch names followed by a space | |
684 | followed by a space-delimited list of hex nodes of heads on that branch. |
|
798 | followed by a space-delimited list of hex nodes of heads on that branch. | |
685 | e.g.:: |
|
799 | e.g.:: | |
686 |
|
800 | |||
687 | default a072279d3f7fd3a4aa7ffa1a5af8efc573e1c896 6dc58916e7c070f678682bfe404d2e2d68291a18 |
|
801 | default a072279d3f7fd3a4aa7ffa1a5af8efc573e1c896 6dc58916e7c070f678682bfe404d2e2d68291a18 | |
688 | stable baae3bf31522f41dd5e6d7377d0edd8d1cf3fccc |
|
802 | stable baae3bf31522f41dd5e6d7377d0edd8d1cf3fccc | |
689 |
|
803 | |||
690 | There is no trailing newline. |
|
804 | There is no trailing newline. | |
691 |
|
805 | |||
692 | branches |
|
806 | branches | |
693 | -------- |
|
807 | -------- | |
694 |
|
808 | |||
695 | (Legacy command used for discovery in old clients. Clients with ``getbundle`` |
|
809 | (Legacy command used for discovery in old clients. Clients with ``getbundle`` | |
696 | use the ``known`` and ``heads`` commands instead.) |
|
810 | use the ``known`` and ``heads`` commands instead.) | |
697 |
|
811 | |||
698 | Obtain ancestor changesets of specific nodes back to a branch point. |
|
812 | Obtain ancestor changesets of specific nodes back to a branch point. | |
699 |
|
813 | |||
700 | Despite the name, this command has nothing to do with Mercurial named branches. |
|
814 | Despite the name, this command has nothing to do with Mercurial named branches. | |
701 | Instead, it is related to DAG branches. |
|
815 | Instead, it is related to DAG branches. | |
702 |
|
816 | |||
703 | The command accepts a ``nodes`` argument, which is a string of space-delimited |
|
817 | The command accepts a ``nodes`` argument, which is a string of space-delimited | |
704 | hex nodes. |
|
818 | hex nodes. | |
705 |
|
819 | |||
706 | For each node requested, the server will find the first ancestor node that is |
|
820 | For each node requested, the server will find the first ancestor node that is | |
707 | a DAG root or is a merge. |
|
821 | a DAG root or is a merge. | |
708 |
|
822 | |||
709 | Return type is a ``string``. Return value contains lines with result data for |
|
823 | Return type is a ``string``. Return value contains lines with result data for | |
710 | each requested node. Each line contains space-delimited nodes followed by a |
|
824 | each requested node. Each line contains space-delimited nodes followed by a | |
711 | newline (``\n``). The 4 nodes reported on each line correspond to the requested |
|
825 | newline (``\n``). The 4 nodes reported on each line correspond to the requested | |
712 | node, the ancestor node found, and its 2 parent nodes (which may be the null |
|
826 | node, the ancestor node found, and its 2 parent nodes (which may be the null | |
713 | node). |
|
827 | node). | |
714 |
|
828 | |||
715 | capabilities |
|
829 | capabilities | |
716 | ------------ |
|
830 | ------------ | |
717 |
|
831 | |||
718 | Obtain the capabilities string for the repo. |
|
832 | Obtain the capabilities string for the repo. | |
719 |
|
833 | |||
720 | Unlike the ``hello`` command, the capabilities string is not prefixed. |
|
834 | Unlike the ``hello`` command, the capabilities string is not prefixed. | |
721 | There is no trailing newline. |
|
835 | There is no trailing newline. | |
722 |
|
836 | |||
723 | This command does not accept any arguments. Return type is a ``string``. |
|
837 | This command does not accept any arguments. Return type is a ``string``. | |
724 |
|
838 | |||
725 | This command was introduced in Mercurial 0.9.1 (released July 2006). |
|
839 | This command was introduced in Mercurial 0.9.1 (released July 2006). | |
726 |
|
840 | |||
727 | changegroup |
|
841 | changegroup | |
728 | ----------- |
|
842 | ----------- | |
729 |
|
843 | |||
730 | (Legacy command: use ``getbundle`` instead) |
|
844 | (Legacy command: use ``getbundle`` instead) | |
731 |
|
845 | |||
732 | Obtain a changegroup version 1 with data for changesets that are |
|
846 | Obtain a changegroup version 1 with data for changesets that are | |
733 | descendants of client-specified changesets. |
|
847 | descendants of client-specified changesets. | |
734 |
|
848 | |||
735 | The ``roots`` arguments contains a list of space-delimited hex nodes. |
|
849 | The ``roots`` arguments contains a list of space-delimited hex nodes. | |
736 |
|
850 | |||
737 | The server responds with a changegroup version 1 containing all |
|
851 | The server responds with a changegroup version 1 containing all | |
738 | changesets between the requested root/base nodes and the repo's head nodes |
|
852 | changesets between the requested root/base nodes and the repo's head nodes | |
739 | at the time of the request. |
|
853 | at the time of the request. | |
740 |
|
854 | |||
741 | The return type is a ``stream``. |
|
855 | The return type is a ``stream``. | |
742 |
|
856 | |||
743 | changegroupsubset |
|
857 | changegroupsubset | |
744 | ----------------- |
|
858 | ----------------- | |
745 |
|
859 | |||
746 | (Legacy command: use ``getbundle`` instead) |
|
860 | (Legacy command: use ``getbundle`` instead) | |
747 |
|
861 | |||
748 | Obtain a changegroup version 1 with data for changesetsets between |
|
862 | Obtain a changegroup version 1 with data for changesetsets between | |
749 | client specified base and head nodes. |
|
863 | client specified base and head nodes. | |
750 |
|
864 | |||
751 | The ``bases`` argument contains a list of space-delimited hex nodes. |
|
865 | The ``bases`` argument contains a list of space-delimited hex nodes. | |
752 | The ``heads`` argument contains a list of space-delimited hex nodes. |
|
866 | The ``heads`` argument contains a list of space-delimited hex nodes. | |
753 |
|
867 | |||
754 | The server responds with a changegroup version 1 containing all |
|
868 | The server responds with a changegroup version 1 containing all | |
755 | changesets between the requested base and head nodes at the time of the |
|
869 | changesets between the requested base and head nodes at the time of the | |
756 | request. |
|
870 | request. | |
757 |
|
871 | |||
758 | The return type is a ``stream``. |
|
872 | The return type is a ``stream``. | |
759 |
|
873 | |||
760 | clonebundles |
|
874 | clonebundles | |
761 | ------------ |
|
875 | ------------ | |
762 |
|
876 | |||
763 | Obtains a manifest of bundle URLs available to seed clones. |
|
877 | Obtains a manifest of bundle URLs available to seed clones. | |
764 |
|
878 | |||
765 | Each returned line contains a URL followed by metadata. See the |
|
879 | Each returned line contains a URL followed by metadata. See the | |
766 | documentation in the ``clonebundles`` extension for more. |
|
880 | documentation in the ``clonebundles`` extension for more. | |
767 |
|
881 | |||
768 | The return type is a ``string``. |
|
882 | The return type is a ``string``. | |
769 |
|
883 | |||
770 | getbundle |
|
884 | getbundle | |
771 | --------- |
|
885 | --------- | |
772 |
|
886 | |||
773 | Obtain a bundle containing repository data. |
|
887 | Obtain a bundle containing repository data. | |
774 |
|
888 | |||
775 | This command accepts the following arguments: |
|
889 | This command accepts the following arguments: | |
776 |
|
890 | |||
777 | heads |
|
891 | heads | |
778 | List of space-delimited hex nodes of heads to retrieve. |
|
892 | List of space-delimited hex nodes of heads to retrieve. | |
779 | common |
|
893 | common | |
780 | List of space-delimited hex nodes that the client has in common with the |
|
894 | List of space-delimited hex nodes that the client has in common with the | |
781 | server. |
|
895 | server. | |
782 | obsmarkers |
|
896 | obsmarkers | |
783 | Boolean indicating whether to include obsolescence markers as part |
|
897 | Boolean indicating whether to include obsolescence markers as part | |
784 | of the response. Only works with bundle2. |
|
898 | of the response. Only works with bundle2. | |
785 | bundlecaps |
|
899 | bundlecaps | |
786 | Comma-delimited set of strings defining client bundle capabilities. |
|
900 | Comma-delimited set of strings defining client bundle capabilities. | |
787 | listkeys |
|
901 | listkeys | |
788 | Comma-delimited list of strings of ``pushkey`` namespaces. For each |
|
902 | Comma-delimited list of strings of ``pushkey`` namespaces. For each | |
789 | namespace listed, a bundle2 part will be included with the content of |
|
903 | namespace listed, a bundle2 part will be included with the content of | |
790 | that namespace. |
|
904 | that namespace. | |
791 | cg |
|
905 | cg | |
792 | Boolean indicating whether changegroup data is requested. |
|
906 | Boolean indicating whether changegroup data is requested. | |
793 | cbattempted |
|
907 | cbattempted | |
794 | Boolean indicating whether the client attempted to use the *clone bundles* |
|
908 | Boolean indicating whether the client attempted to use the *clone bundles* | |
795 | feature before performing this request. |
|
909 | feature before performing this request. | |
796 | bookmarks |
|
910 | bookmarks | |
797 | Boolean indicating whether bookmark data is requested. |
|
911 | Boolean indicating whether bookmark data is requested. | |
798 | phases |
|
912 | phases | |
799 | Boolean indicating whether phases data is requested. |
|
913 | Boolean indicating whether phases data is requested. | |
800 |
|
914 | |||
801 | The return type on success is a ``stream`` where the value is bundle. |
|
915 | The return type on success is a ``stream`` where the value is bundle. | |
802 | On the HTTP version 1 transport, the response is zlib compressed. |
|
916 | On the HTTP version 1 transport, the response is zlib compressed. | |
803 |
|
917 | |||
804 | If an error occurs, a generic error response can be sent. |
|
918 | If an error occurs, a generic error response can be sent. | |
805 |
|
919 | |||
806 | Unless the client sends a false value for the ``cg`` argument, the returned |
|
920 | Unless the client sends a false value for the ``cg`` argument, the returned | |
807 | bundle contains a changegroup with the nodes between the specified ``common`` |
|
921 | bundle contains a changegroup with the nodes between the specified ``common`` | |
808 | and ``heads`` nodes. Depending on the command arguments, the type and content |
|
922 | and ``heads`` nodes. Depending on the command arguments, the type and content | |
809 | of the returned bundle can vary significantly. |
|
923 | of the returned bundle can vary significantly. | |
810 |
|
924 | |||
811 | The default behavior is for the server to send a raw changegroup version |
|
925 | The default behavior is for the server to send a raw changegroup version | |
812 | ``01`` response. |
|
926 | ``01`` response. | |
813 |
|
927 | |||
814 | If the ``bundlecaps`` provided by the client contain a value beginning |
|
928 | If the ``bundlecaps`` provided by the client contain a value beginning | |
815 | with ``HG2``, a bundle2 will be returned. The bundle2 data may contain |
|
929 | with ``HG2``, a bundle2 will be returned. The bundle2 data may contain | |
816 | additional repository data, such as ``pushkey`` namespace values. |
|
930 | additional repository data, such as ``pushkey`` namespace values. | |
817 |
|
931 | |||
818 | heads |
|
932 | heads | |
819 | ----- |
|
933 | ----- | |
820 |
|
934 | |||
821 | Returns a list of space-delimited hex nodes of repository heads followed |
|
935 | Returns a list of space-delimited hex nodes of repository heads followed | |
822 | by a newline. e.g. |
|
936 | by a newline. e.g. | |
823 | ``a9eeb3adc7ddb5006c088e9eda61791c777cbf7c 31f91a3da534dc849f0d6bfc00a395a97cf218a1\n`` |
|
937 | ``a9eeb3adc7ddb5006c088e9eda61791c777cbf7c 31f91a3da534dc849f0d6bfc00a395a97cf218a1\n`` | |
824 |
|
938 | |||
825 | This command does not accept any arguments. The return type is a ``string``. |
|
939 | This command does not accept any arguments. The return type is a ``string``. | |
826 |
|
940 | |||
827 | hello |
|
941 | hello | |
828 | ----- |
|
942 | ----- | |
829 |
|
943 | |||
830 | Returns lines describing interesting things about the server in an RFC-822 |
|
944 | Returns lines describing interesting things about the server in an RFC-822 | |
831 | like format. |
|
945 | like format. | |
832 |
|
946 | |||
833 | Currently, the only line defines the server capabilities. It has the form:: |
|
947 | Currently, the only line defines the server capabilities. It has the form:: | |
834 |
|
948 | |||
835 | capabilities: <value> |
|
949 | capabilities: <value> | |
836 |
|
950 | |||
837 | See above for more about the capabilities string. |
|
951 | See above for more about the capabilities string. | |
838 |
|
952 | |||
839 | SSH clients typically issue this command as soon as a connection is |
|
953 | SSH clients typically issue this command as soon as a connection is | |
840 | established. |
|
954 | established. | |
841 |
|
955 | |||
842 | This command does not accept any arguments. The return type is a ``string``. |
|
956 | This command does not accept any arguments. The return type is a ``string``. | |
843 |
|
957 | |||
844 | This command was introduced in Mercurial 0.9.1 (released July 2006). |
|
958 | This command was introduced in Mercurial 0.9.1 (released July 2006). | |
845 |
|
959 | |||
846 | listkeys |
|
960 | listkeys | |
847 | -------- |
|
961 | -------- | |
848 |
|
962 | |||
849 | List values in a specified ``pushkey`` namespace. |
|
963 | List values in a specified ``pushkey`` namespace. | |
850 |
|
964 | |||
851 | The ``namespace`` argument defines the pushkey namespace to operate on. |
|
965 | The ``namespace`` argument defines the pushkey namespace to operate on. | |
852 |
|
966 | |||
853 | The return type is a ``string``. The value is an encoded dictionary of keys. |
|
967 | The return type is a ``string``. The value is an encoded dictionary of keys. | |
854 |
|
968 | |||
855 | Key-value pairs are delimited by newlines (``\n``). Within each line, keys and |
|
969 | Key-value pairs are delimited by newlines (``\n``). Within each line, keys and | |
856 | values are separated by a tab (``\t``). Keys and values are both strings. |
|
970 | values are separated by a tab (``\t``). Keys and values are both strings. | |
857 |
|
971 | |||
858 | lookup |
|
972 | lookup | |
859 | ------ |
|
973 | ------ | |
860 |
|
974 | |||
861 | Try to resolve a value to a known repository revision. |
|
975 | Try to resolve a value to a known repository revision. | |
862 |
|
976 | |||
863 | The ``key`` argument is converted from bytes to an |
|
977 | The ``key`` argument is converted from bytes to an | |
864 | ``encoding.localstr`` instance then passed into |
|
978 | ``encoding.localstr`` instance then passed into | |
865 | ``localrepository.__getitem__`` in an attempt to resolve it. |
|
979 | ``localrepository.__getitem__`` in an attempt to resolve it. | |
866 |
|
980 | |||
867 | The return type is a ``string``. |
|
981 | The return type is a ``string``. | |
868 |
|
982 | |||
869 | Upon successful resolution, returns ``1 <hex node>\n``. On failure, |
|
983 | Upon successful resolution, returns ``1 <hex node>\n``. On failure, | |
870 | returns ``0 <error string>\n``. e.g.:: |
|
984 | returns ``0 <error string>\n``. e.g.:: | |
871 |
|
985 | |||
872 | 1 273ce12ad8f155317b2c078ec75a4eba507f1fba\n |
|
986 | 1 273ce12ad8f155317b2c078ec75a4eba507f1fba\n | |
873 |
|
987 | |||
874 | 0 unknown revision 'foo'\n |
|
988 | 0 unknown revision 'foo'\n | |
875 |
|
989 | |||
876 | known |
|
990 | known | |
877 | ----- |
|
991 | ----- | |
878 |
|
992 | |||
879 | Determine whether multiple nodes are known. |
|
993 | Determine whether multiple nodes are known. | |
880 |
|
994 | |||
881 | The ``nodes`` argument is a list of space-delimited hex nodes to check |
|
995 | The ``nodes`` argument is a list of space-delimited hex nodes to check | |
882 | for existence. |
|
996 | for existence. | |
883 |
|
997 | |||
884 | The return type is ``string``. |
|
998 | The return type is ``string``. | |
885 |
|
999 | |||
886 | Returns a string consisting of ``0``s and ``1``s indicating whether nodes |
|
1000 | Returns a string consisting of ``0``s and ``1``s indicating whether nodes | |
887 | are known. If the Nth node specified in the ``nodes`` argument is known, |
|
1001 | are known. If the Nth node specified in the ``nodes`` argument is known, | |
888 | a ``1`` will be returned at byte offset N. If the node isn't known, ``0`` |
|
1002 | a ``1`` will be returned at byte offset N. If the node isn't known, ``0`` | |
889 | will be present at byte offset N. |
|
1003 | will be present at byte offset N. | |
890 |
|
1004 | |||
891 | There is no trailing newline. |
|
1005 | There is no trailing newline. | |
892 |
|
1006 | |||
893 | pushkey |
|
1007 | pushkey | |
894 | ------- |
|
1008 | ------- | |
895 |
|
1009 | |||
896 | Set a value using the ``pushkey`` protocol. |
|
1010 | Set a value using the ``pushkey`` protocol. | |
897 |
|
1011 | |||
898 | Accepts arguments ``namespace``, ``key``, ``old``, and ``new``, which |
|
1012 | Accepts arguments ``namespace``, ``key``, ``old``, and ``new``, which | |
899 | correspond to the pushkey namespace to operate on, the key within that |
|
1013 | correspond to the pushkey namespace to operate on, the key within that | |
900 | namespace to change, the old value (which may be empty), and the new value. |
|
1014 | namespace to change, the old value (which may be empty), and the new value. | |
901 | All arguments are string types. |
|
1015 | All arguments are string types. | |
902 |
|
1016 | |||
903 | The return type is a ``string``. The value depends on the transport protocol. |
|
1017 | The return type is a ``string``. The value depends on the transport protocol. | |
904 |
|
1018 | |||
905 | The SSH version 1 transport sends a string encoded integer followed by a |
|
1019 | The SSH version 1 transport sends a string encoded integer followed by a | |
906 | newline (``\n``) which indicates operation result. The server may send |
|
1020 | newline (``\n``) which indicates operation result. The server may send | |
907 | additional output on the ``stderr`` stream that should be displayed to the |
|
1021 | additional output on the ``stderr`` stream that should be displayed to the | |
908 | user. |
|
1022 | user. | |
909 |
|
1023 | |||
910 | The HTTP version 1 transport sends a string encoded integer followed by a |
|
1024 | The HTTP version 1 transport sends a string encoded integer followed by a | |
911 | newline followed by additional server output that should be displayed to |
|
1025 | newline followed by additional server output that should be displayed to | |
912 | the user. This may include output from hooks, etc. |
|
1026 | the user. This may include output from hooks, etc. | |
913 |
|
1027 | |||
914 | The integer result varies by namespace. ``0`` means an error has occurred |
|
1028 | The integer result varies by namespace. ``0`` means an error has occurred | |
915 | and there should be additional output to display to the user. |
|
1029 | and there should be additional output to display to the user. | |
916 |
|
1030 | |||
917 | stream_out |
|
1031 | stream_out | |
918 | ---------- |
|
1032 | ---------- | |
919 |
|
1033 | |||
920 | Obtain *streaming clone* data. |
|
1034 | Obtain *streaming clone* data. | |
921 |
|
1035 | |||
922 | The return type is either a ``string`` or a ``stream``, depending on |
|
1036 | The return type is either a ``string`` or a ``stream``, depending on | |
923 | whether the request was fulfilled properly. |
|
1037 | whether the request was fulfilled properly. | |
924 |
|
1038 | |||
925 | A return value of ``1\n`` indicates the server is not configured to serve |
|
1039 | A return value of ``1\n`` indicates the server is not configured to serve | |
926 | this data. If this is seen by the client, they may not have verified the |
|
1040 | this data. If this is seen by the client, they may not have verified the | |
927 | ``stream`` capability is set before making the request. |
|
1041 | ``stream`` capability is set before making the request. | |
928 |
|
1042 | |||
929 | A return value of ``2\n`` indicates the server was unable to lock the |
|
1043 | A return value of ``2\n`` indicates the server was unable to lock the | |
930 | repository to generate data. |
|
1044 | repository to generate data. | |
931 |
|
1045 | |||
932 | All other responses are a ``stream`` of bytes. The first line of this data |
|
1046 | All other responses are a ``stream`` of bytes. The first line of this data | |
933 | contains 2 space-delimited integers corresponding to the path count and |
|
1047 | contains 2 space-delimited integers corresponding to the path count and | |
934 | payload size, respectively:: |
|
1048 | payload size, respectively:: | |
935 |
|
1049 | |||
936 | <path count> <payload size>\n |
|
1050 | <path count> <payload size>\n | |
937 |
|
1051 | |||
938 | The ``<payload size>`` is the total size of path data: it does not include |
|
1052 | The ``<payload size>`` is the total size of path data: it does not include | |
939 | the size of the per-path header lines. |
|
1053 | the size of the per-path header lines. | |
940 |
|
1054 | |||
941 | Following that header are ``<path count>`` entries. Each entry consists of a |
|
1055 | Following that header are ``<path count>`` entries. Each entry consists of a | |
942 | line with metadata followed by raw revlog data. The line consists of:: |
|
1056 | line with metadata followed by raw revlog data. The line consists of:: | |
943 |
|
1057 | |||
944 | <store path>\0<size>\n |
|
1058 | <store path>\0<size>\n | |
945 |
|
1059 | |||
946 | The ``<store path>`` is the encoded store path of the data that follows. |
|
1060 | The ``<store path>`` is the encoded store path of the data that follows. | |
947 | ``<size>`` is the amount of data for this store path/revlog that follows the |
|
1061 | ``<size>`` is the amount of data for this store path/revlog that follows the | |
948 | newline. |
|
1062 | newline. | |
949 |
|
1063 | |||
950 | There is no trailer to indicate end of data. Instead, the client should stop |
|
1064 | There is no trailer to indicate end of data. Instead, the client should stop | |
951 | reading after ``<path count>`` entries are consumed. |
|
1065 | reading after ``<path count>`` entries are consumed. | |
952 |
|
1066 | |||
953 | unbundle |
|
1067 | unbundle | |
954 | -------- |
|
1068 | -------- | |
955 |
|
1069 | |||
956 | Send a bundle containing data (usually changegroup data) to the server. |
|
1070 | Send a bundle containing data (usually changegroup data) to the server. | |
957 |
|
1071 | |||
958 | Accepts the argument ``heads``, which is a space-delimited list of hex nodes |
|
1072 | Accepts the argument ``heads``, which is a space-delimited list of hex nodes | |
959 | corresponding to server repository heads observed by the client. This is used |
|
1073 | corresponding to server repository heads observed by the client. This is used | |
960 | to detect race conditions and abort push operations before a server performs |
|
1074 | to detect race conditions and abort push operations before a server performs | |
961 | too much work or a client transfers too much data. |
|
1075 | too much work or a client transfers too much data. | |
962 |
|
1076 | |||
963 | The request payload consists of a bundle to be applied to the repository, |
|
1077 | The request payload consists of a bundle to be applied to the repository, | |
964 | similarly to as if :hg:`unbundle` were called. |
|
1078 | similarly to as if :hg:`unbundle` were called. | |
965 |
|
1079 | |||
966 | In most scenarios, a special ``push response`` type is returned. This type |
|
1080 | In most scenarios, a special ``push response`` type is returned. This type | |
967 | contains an integer describing the change in heads as a result of the |
|
1081 | contains an integer describing the change in heads as a result of the | |
968 | operation. A value of ``0`` indicates nothing changed. ``1`` means the number |
|
1082 | operation. A value of ``0`` indicates nothing changed. ``1`` means the number | |
969 | of heads remained the same. Values ``2`` and larger indicate the number of |
|
1083 | of heads remained the same. Values ``2`` and larger indicate the number of | |
970 | added heads minus 1. e.g. ``3`` means 2 heads were added. Negative values |
|
1084 | added heads minus 1. e.g. ``3`` means 2 heads were added. Negative values | |
971 | indicate the number of fewer heads, also off by 1. e.g. ``-2`` means there |
|
1085 | indicate the number of fewer heads, also off by 1. e.g. ``-2`` means there | |
972 | is 1 fewer head. |
|
1086 | is 1 fewer head. | |
973 |
|
1087 | |||
974 | The encoding of the ``push response`` type varies by transport. |
|
1088 | The encoding of the ``push response`` type varies by transport. | |
975 |
|
1089 | |||
976 | For the SSH version 1 transport, this type is composed of 2 ``string`` |
|
1090 | For the SSH version 1 transport, this type is composed of 2 ``string`` | |
977 | responses: an empty response (``0\n``) followed by the integer result value. |
|
1091 | responses: an empty response (``0\n``) followed by the integer result value. | |
978 | e.g. ``1\n2``. So the full response might be ``0\n1\n2``. |
|
1092 | e.g. ``1\n2``. So the full response might be ``0\n1\n2``. | |
979 |
|
1093 | |||
980 | For the HTTP version 1 transport, the response is a ``string`` type composed |
|
1094 | For the HTTP version 1 transport, the response is a ``string`` type composed | |
981 | of an integer result value followed by a newline (``\n``) followed by string |
|
1095 | of an integer result value followed by a newline (``\n``) followed by string | |
982 | content holding server output that should be displayed on the client (output |
|
1096 | content holding server output that should be displayed on the client (output | |
983 | hooks, etc). |
|
1097 | hooks, etc). | |
984 |
|
1098 | |||
985 | In some cases, the server may respond with a ``bundle2`` bundle. In this |
|
1099 | In some cases, the server may respond with a ``bundle2`` bundle. In this | |
986 | case, the response type is ``stream``. For the HTTP version 1 transport, the |
|
1100 | case, the response type is ``stream``. For the HTTP version 1 transport, the | |
987 | response is zlib compressed. |
|
1101 | response is zlib compressed. | |
988 |
|
1102 | |||
989 | The server may also respond with a generic error type, which contains a string |
|
1103 | The server may also respond with a generic error type, which contains a string | |
990 | indicating the failure. |
|
1104 | indicating the failure. |
@@ -1,466 +1,540 b'' | |||||
1 | # sshpeer.py - ssh repository proxy class for mercurial |
|
1 | # sshpeer.py - ssh repository proxy class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
10 | import re |
|
10 | import re | |
|
11 | import uuid | |||
11 |
|
12 | |||
12 | from .i18n import _ |
|
13 | from .i18n import _ | |
13 | from . import ( |
|
14 | from . import ( | |
14 | error, |
|
15 | error, | |
15 | pycompat, |
|
16 | pycompat, | |
16 | util, |
|
17 | util, | |
17 | wireproto, |
|
18 | wireproto, | |
|
19 | wireprotoserver, | |||
18 | ) |
|
20 | ) | |
19 |
|
21 | |||
20 | def _serverquote(s): |
|
22 | def _serverquote(s): | |
21 | """quote a string for the remote shell ... which we assume is sh""" |
|
23 | """quote a string for the remote shell ... which we assume is sh""" | |
22 | if not s: |
|
24 | if not s: | |
23 | return s |
|
25 | return s | |
24 | if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s): |
|
26 | if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s): | |
25 | return s |
|
27 | return s | |
26 | return "'%s'" % s.replace("'", "'\\''") |
|
28 | return "'%s'" % s.replace("'", "'\\''") | |
27 |
|
29 | |||
28 | def _forwardoutput(ui, pipe): |
|
30 | def _forwardoutput(ui, pipe): | |
29 | """display all data currently available on pipe as remote output. |
|
31 | """display all data currently available on pipe as remote output. | |
30 |
|
32 | |||
31 | This is non blocking.""" |
|
33 | This is non blocking.""" | |
32 | s = util.readpipe(pipe) |
|
34 | s = util.readpipe(pipe) | |
33 | if s: |
|
35 | if s: | |
34 | for l in s.splitlines(): |
|
36 | for l in s.splitlines(): | |
35 | ui.status(_("remote: "), l, '\n') |
|
37 | ui.status(_("remote: "), l, '\n') | |
36 |
|
38 | |||
37 | class doublepipe(object): |
|
39 | class doublepipe(object): | |
38 | """Operate a side-channel pipe in addition of a main one |
|
40 | """Operate a side-channel pipe in addition of a main one | |
39 |
|
41 | |||
40 | The side-channel pipe contains server output to be forwarded to the user |
|
42 | The side-channel pipe contains server output to be forwarded to the user | |
41 | input. The double pipe will behave as the "main" pipe, but will ensure the |
|
43 | input. The double pipe will behave as the "main" pipe, but will ensure the | |
42 | content of the "side" pipe is properly processed while we wait for blocking |
|
44 | content of the "side" pipe is properly processed while we wait for blocking | |
43 | call on the "main" pipe. |
|
45 | call on the "main" pipe. | |
44 |
|
46 | |||
45 | If large amounts of data are read from "main", the forward will cease after |
|
47 | If large amounts of data are read from "main", the forward will cease after | |
46 | the first bytes start to appear. This simplifies the implementation |
|
48 | the first bytes start to appear. This simplifies the implementation | |
47 | without affecting actual output of sshpeer too much as we rarely issue |
|
49 | without affecting actual output of sshpeer too much as we rarely issue | |
48 | large read for data not yet emitted by the server. |
|
50 | large read for data not yet emitted by the server. | |
49 |
|
51 | |||
50 | The main pipe is expected to be a 'bufferedinputpipe' from the util module |
|
52 | The main pipe is expected to be a 'bufferedinputpipe' from the util module | |
51 | that handle all the os specific bits. This class lives in this module |
|
53 | that handle all the os specific bits. This class lives in this module | |
52 | because it focus on behavior specific to the ssh protocol.""" |
|
54 | because it focus on behavior specific to the ssh protocol.""" | |
53 |
|
55 | |||
54 | def __init__(self, ui, main, side): |
|
56 | def __init__(self, ui, main, side): | |
55 | self._ui = ui |
|
57 | self._ui = ui | |
56 | self._main = main |
|
58 | self._main = main | |
57 | self._side = side |
|
59 | self._side = side | |
58 |
|
60 | |||
59 | def _wait(self): |
|
61 | def _wait(self): | |
60 | """wait until some data are available on main or side |
|
62 | """wait until some data are available on main or side | |
61 |
|
63 | |||
62 | return a pair of boolean (ismainready, issideready) |
|
64 | return a pair of boolean (ismainready, issideready) | |
63 |
|
65 | |||
64 | (This will only wait for data if the setup is supported by `util.poll`) |
|
66 | (This will only wait for data if the setup is supported by `util.poll`) | |
65 | """ |
|
67 | """ | |
66 | if getattr(self._main, 'hasbuffer', False): # getattr for classic pipe |
|
68 | if getattr(self._main, 'hasbuffer', False): # getattr for classic pipe | |
67 | return (True, True) # main has data, assume side is worth poking at. |
|
69 | return (True, True) # main has data, assume side is worth poking at. | |
68 | fds = [self._main.fileno(), self._side.fileno()] |
|
70 | fds = [self._main.fileno(), self._side.fileno()] | |
69 | try: |
|
71 | try: | |
70 | act = util.poll(fds) |
|
72 | act = util.poll(fds) | |
71 | except NotImplementedError: |
|
73 | except NotImplementedError: | |
72 | # non supported yet case, assume all have data. |
|
74 | # non supported yet case, assume all have data. | |
73 | act = fds |
|
75 | act = fds | |
74 | return (self._main.fileno() in act, self._side.fileno() in act) |
|
76 | return (self._main.fileno() in act, self._side.fileno() in act) | |
75 |
|
77 | |||
76 | def write(self, data): |
|
78 | def write(self, data): | |
77 | return self._call('write', data) |
|
79 | return self._call('write', data) | |
78 |
|
80 | |||
79 | def read(self, size): |
|
81 | def read(self, size): | |
80 | r = self._call('read', size) |
|
82 | r = self._call('read', size) | |
81 | if size != 0 and not r: |
|
83 | if size != 0 and not r: | |
82 | # We've observed a condition that indicates the |
|
84 | # We've observed a condition that indicates the | |
83 | # stdout closed unexpectedly. Check stderr one |
|
85 | # stdout closed unexpectedly. Check stderr one | |
84 | # more time and snag anything that's there before |
|
86 | # more time and snag anything that's there before | |
85 | # letting anyone know the main part of the pipe |
|
87 | # letting anyone know the main part of the pipe | |
86 | # closed prematurely. |
|
88 | # closed prematurely. | |
87 | _forwardoutput(self._ui, self._side) |
|
89 | _forwardoutput(self._ui, self._side) | |
88 | return r |
|
90 | return r | |
89 |
|
91 | |||
90 | def readline(self): |
|
92 | def readline(self): | |
91 | return self._call('readline') |
|
93 | return self._call('readline') | |
92 |
|
94 | |||
93 | def _call(self, methname, data=None): |
|
95 | def _call(self, methname, data=None): | |
94 | """call <methname> on "main", forward output of "side" while blocking |
|
96 | """call <methname> on "main", forward output of "side" while blocking | |
95 | """ |
|
97 | """ | |
96 | # data can be '' or 0 |
|
98 | # data can be '' or 0 | |
97 | if (data is not None and not data) or self._main.closed: |
|
99 | if (data is not None and not data) or self._main.closed: | |
98 | _forwardoutput(self._ui, self._side) |
|
100 | _forwardoutput(self._ui, self._side) | |
99 | return '' |
|
101 | return '' | |
100 | while True: |
|
102 | while True: | |
101 | mainready, sideready = self._wait() |
|
103 | mainready, sideready = self._wait() | |
102 | if sideready: |
|
104 | if sideready: | |
103 | _forwardoutput(self._ui, self._side) |
|
105 | _forwardoutput(self._ui, self._side) | |
104 | if mainready: |
|
106 | if mainready: | |
105 | meth = getattr(self._main, methname) |
|
107 | meth = getattr(self._main, methname) | |
106 | if data is None: |
|
108 | if data is None: | |
107 | return meth() |
|
109 | return meth() | |
108 | else: |
|
110 | else: | |
109 | return meth(data) |
|
111 | return meth(data) | |
110 |
|
112 | |||
111 | def close(self): |
|
113 | def close(self): | |
112 | return self._main.close() |
|
114 | return self._main.close() | |
113 |
|
115 | |||
114 | def flush(self): |
|
116 | def flush(self): | |
115 | return self._main.flush() |
|
117 | return self._main.flush() | |
116 |
|
118 | |||
117 | def _cleanuppipes(ui, pipei, pipeo, pipee): |
|
119 | def _cleanuppipes(ui, pipei, pipeo, pipee): | |
118 | """Clean up pipes used by an SSH connection.""" |
|
120 | """Clean up pipes used by an SSH connection.""" | |
119 | if pipeo: |
|
121 | if pipeo: | |
120 | pipeo.close() |
|
122 | pipeo.close() | |
121 | if pipei: |
|
123 | if pipei: | |
122 | pipei.close() |
|
124 | pipei.close() | |
123 |
|
125 | |||
124 | if pipee: |
|
126 | if pipee: | |
125 | # Try to read from the err descriptor until EOF. |
|
127 | # Try to read from the err descriptor until EOF. | |
126 | try: |
|
128 | try: | |
127 | for l in pipee: |
|
129 | for l in pipee: | |
128 | ui.status(_('remote: '), l) |
|
130 | ui.status(_('remote: '), l) | |
129 | except (IOError, ValueError): |
|
131 | except (IOError, ValueError): | |
130 | pass |
|
132 | pass | |
131 |
|
133 | |||
132 | pipee.close() |
|
134 | pipee.close() | |
133 |
|
135 | |||
134 | def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): |
|
136 | def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): | |
135 | """Create an SSH connection to a server. |
|
137 | """Create an SSH connection to a server. | |
136 |
|
138 | |||
137 | Returns a tuple of (process, stdin, stdout, stderr) for the |
|
139 | Returns a tuple of (process, stdin, stdout, stderr) for the | |
138 | spawned process. |
|
140 | spawned process. | |
139 | """ |
|
141 | """ | |
140 | cmd = '%s %s %s' % ( |
|
142 | cmd = '%s %s %s' % ( | |
141 | sshcmd, |
|
143 | sshcmd, | |
142 | args, |
|
144 | args, | |
143 | util.shellquote('%s -R %s serve --stdio' % ( |
|
145 | util.shellquote('%s -R %s serve --stdio' % ( | |
144 | _serverquote(remotecmd), _serverquote(path)))) |
|
146 | _serverquote(remotecmd), _serverquote(path)))) | |
145 |
|
147 | |||
146 | ui.debug('running %s\n' % cmd) |
|
148 | ui.debug('running %s\n' % cmd) | |
147 | cmd = util.quotecommand(cmd) |
|
149 | cmd = util.quotecommand(cmd) | |
148 |
|
150 | |||
149 | # no buffer allow the use of 'select' |
|
151 | # no buffer allow the use of 'select' | |
150 | # feel free to remove buffering and select usage when we ultimately |
|
152 | # feel free to remove buffering and select usage when we ultimately | |
151 | # move to threading. |
|
153 | # move to threading. | |
152 | stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv) |
|
154 | stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv) | |
153 |
|
155 | |||
154 | stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) |
|
156 | stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) | |
155 | stdin = doublepipe(ui, stdin, stderr) |
|
157 | stdin = doublepipe(ui, stdin, stderr) | |
156 |
|
158 | |||
157 | return proc, stdin, stdout, stderr |
|
159 | return proc, stdin, stdout, stderr | |
158 |
|
160 | |||
159 | def _performhandshake(ui, stdin, stdout, stderr): |
|
161 | def _performhandshake(ui, stdin, stdout, stderr): | |
160 | def badresponse(): |
|
162 | def badresponse(): | |
161 | msg = _('no suitable response from remote hg') |
|
163 | msg = _('no suitable response from remote hg') | |
162 | hint = ui.config('ui', 'ssherrorhint') |
|
164 | hint = ui.config('ui', 'ssherrorhint') | |
163 | raise error.RepoError(msg, hint=hint) |
|
165 | raise error.RepoError(msg, hint=hint) | |
164 |
|
166 | |||
165 |
# The handshake consists of sending |
|
167 | # The handshake consists of sending wire protocol commands in reverse | |
166 | # ``hello`` and ``between``. |
|
168 | # order of protocol implementation and then sniffing for a response | |
|
169 | # to one of them. | |||
|
170 | # | |||
|
171 | # Those commands (from oldest to newest) are: | |||
167 | # |
|
172 | # | |
168 | # The ``hello`` command (which was introduced in Mercurial 0.9.1) |
|
173 | # ``between`` | |
169 | # instructs the server to advertise its capabilities. |
|
174 | # Asks for the set of revisions between a pair of revisions. Command | |
|
175 | # present in all Mercurial server implementations. | |||
170 | # |
|
176 | # | |
171 | # The ``between`` command (which has existed in all Mercurial servers |
|
177 | # ``hello`` | |
172 | # for as long as SSH support has existed), asks for the set of revisions |
|
178 | # Instructs the server to advertise its capabilities. Introduced in | |
173 | # between a pair of revisions. |
|
179 | # Mercurial 0.9.1. | |
|
180 | # | |||
|
181 | # ``upgrade`` | |||
|
182 | # Requests upgrade from default transport protocol version 1 to | |||
|
183 | # a newer version. Introduced in Mercurial 4.6 as an experimental | |||
|
184 | # feature. | |||
174 | # |
|
185 | # | |
175 | # The ``between`` command is issued with a request for the null |
|
186 | # The ``between`` command is issued with a request for the null | |
176 | # range. If the remote is a Mercurial server, this request will |
|
187 | # range. If the remote is a Mercurial server, this request will | |
177 | # generate a specific response: ``1\n\n``. This represents the |
|
188 | # generate a specific response: ``1\n\n``. This represents the | |
178 | # wire protocol encoded value for ``\n``. We look for ``1\n\n`` |
|
189 | # wire protocol encoded value for ``\n``. We look for ``1\n\n`` | |
179 | # in the output stream and know this is the response to ``between`` |
|
190 | # in the output stream and know this is the response to ``between`` | |
180 | # and we're at the end of our handshake reply. |
|
191 | # and we're at the end of our handshake reply. | |
181 | # |
|
192 | # | |
182 | # The response to the ``hello`` command will be a line with the |
|
193 | # The response to the ``hello`` command will be a line with the | |
183 | # length of the value returned by that command followed by that |
|
194 | # length of the value returned by that command followed by that | |
184 | # value. If the server doesn't support ``hello`` (which should be |
|
195 | # value. If the server doesn't support ``hello`` (which should be | |
185 | # rare), that line will be ``0\n``. Otherwise, the value will contain |
|
196 | # rare), that line will be ``0\n``. Otherwise, the value will contain | |
186 | # RFC 822 like lines. Of these, the ``capabilities:`` line contains |
|
197 | # RFC 822 like lines. Of these, the ``capabilities:`` line contains | |
187 | # the capabilities of the server. |
|
198 | # the capabilities of the server. | |
188 | # |
|
199 | # | |
|
200 | # The ``upgrade`` command isn't really a command in the traditional | |||
|
201 | # sense of version 1 of the transport because it isn't using the | |||
|
202 | # proper mechanism for formatting insteads: instead, it just encodes | |||
|
203 | # arguments on the line, delimited by spaces. | |||
|
204 | # | |||
|
205 | # The ``upgrade`` line looks like ``upgrade <token> <capabilities>``. | |||
|
206 | # If the server doesn't support protocol upgrades, it will reply to | |||
|
207 | # this line with ``0\n``. Otherwise, it emits an | |||
|
208 | # ``upgraded <token> <protocol>`` line to both stdout and stderr. | |||
|
209 | # Content immediately following this line describes additional | |||
|
210 | # protocol and server state. | |||
|
211 | # | |||
189 | # In addition to the responses to our command requests, the server |
|
212 | # In addition to the responses to our command requests, the server | |
190 | # may emit "banner" output on stdout. SSH servers are allowed to |
|
213 | # may emit "banner" output on stdout. SSH servers are allowed to | |
191 | # print messages to stdout on login. Issuing commands on connection |
|
214 | # print messages to stdout on login. Issuing commands on connection | |
192 | # allows us to flush this banner output from the server by scanning |
|
215 | # allows us to flush this banner output from the server by scanning | |
193 | # for output to our well-known ``between`` command. Of course, if |
|
216 | # for output to our well-known ``between`` command. Of course, if | |
194 | # the banner contains ``1\n\n``, this will throw off our detection. |
|
217 | # the banner contains ``1\n\n``, this will throw off our detection. | |
195 |
|
218 | |||
196 | requestlog = ui.configbool('devel', 'debug.peer-request') |
|
219 | requestlog = ui.configbool('devel', 'debug.peer-request') | |
197 |
|
220 | |||
|
221 | # Generate a random token to help identify responses to version 2 | |||
|
222 | # upgrade request. | |||
|
223 | token = bytes(uuid.uuid4()) | |||
|
224 | upgradecaps = [ | |||
|
225 | ('proto', wireprotoserver.SSHV2), | |||
|
226 | ] | |||
|
227 | upgradecaps = util.urlreq.urlencode(upgradecaps) | |||
|
228 | ||||
198 | try: |
|
229 | try: | |
199 | pairsarg = '%s-%s' % ('0' * 40, '0' * 40) |
|
230 | pairsarg = '%s-%s' % ('0' * 40, '0' * 40) | |
200 | handshake = [ |
|
231 | handshake = [ | |
201 | 'hello\n', |
|
232 | 'hello\n', | |
202 | 'between\n', |
|
233 | 'between\n', | |
203 | 'pairs %d\n' % len(pairsarg), |
|
234 | 'pairs %d\n' % len(pairsarg), | |
204 | pairsarg, |
|
235 | pairsarg, | |
205 | ] |
|
236 | ] | |
206 |
|
237 | |||
|
238 | # Request upgrade to version 2 if configured. | |||
|
239 | if ui.configbool('experimental', 'sshpeer.advertise-v2'): | |||
|
240 | ui.debug('sending upgrade request: %s %s\n' % (token, upgradecaps)) | |||
|
241 | handshake.insert(0, 'upgrade %s %s\n' % (token, upgradecaps)) | |||
|
242 | ||||
207 | if requestlog: |
|
243 | if requestlog: | |
208 | ui.debug('devel-peer-request: hello\n') |
|
244 | ui.debug('devel-peer-request: hello\n') | |
209 | ui.debug('sending hello command\n') |
|
245 | ui.debug('sending hello command\n') | |
210 | if requestlog: |
|
246 | if requestlog: | |
211 | ui.debug('devel-peer-request: between\n') |
|
247 | ui.debug('devel-peer-request: between\n') | |
212 | ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) |
|
248 | ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) | |
213 | ui.debug('sending between command\n') |
|
249 | ui.debug('sending between command\n') | |
214 |
|
250 | |||
215 | stdin.write(''.join(handshake)) |
|
251 | stdin.write(''.join(handshake)) | |
216 | stdin.flush() |
|
252 | stdin.flush() | |
217 | except IOError: |
|
253 | except IOError: | |
218 | badresponse() |
|
254 | badresponse() | |
219 |
|
255 | |||
|
256 | # Assume version 1 of wire protocol by default. | |||
|
257 | protoname = wireprotoserver.SSHV1 | |||
|
258 | reupgraded = re.compile(b'^upgraded %s (.*)$' % re.escape(token)) | |||
|
259 | ||||
220 | lines = ['', 'dummy'] |
|
260 | lines = ['', 'dummy'] | |
221 | max_noise = 500 |
|
261 | max_noise = 500 | |
222 | while lines[-1] and max_noise: |
|
262 | while lines[-1] and max_noise: | |
223 | try: |
|
263 | try: | |
224 | l = stdout.readline() |
|
264 | l = stdout.readline() | |
225 | _forwardoutput(ui, stderr) |
|
265 | _forwardoutput(ui, stderr) | |
|
266 | ||||
|
267 | # Look for reply to protocol upgrade request. It has a token | |||
|
268 | # in it, so there should be no false positives. | |||
|
269 | m = reupgraded.match(l) | |||
|
270 | if m: | |||
|
271 | protoname = m.group(1) | |||
|
272 | ui.debug('protocol upgraded to %s\n' % protoname) | |||
|
273 | # If an upgrade was handled, the ``hello`` and ``between`` | |||
|
274 | # requests are ignored. The next output belongs to the | |||
|
275 | # protocol, so stop scanning lines. | |||
|
276 | break | |||
|
277 | ||||
|
278 | # Otherwise it could be a banner, ``0\n`` response if server | |||
|
279 | # doesn't support upgrade. | |||
|
280 | ||||
226 | if lines[-1] == '1\n' and l == '\n': |
|
281 | if lines[-1] == '1\n' and l == '\n': | |
227 | break |
|
282 | break | |
228 | if l: |
|
283 | if l: | |
229 | ui.debug('remote: ', l) |
|
284 | ui.debug('remote: ', l) | |
230 | lines.append(l) |
|
285 | lines.append(l) | |
231 | max_noise -= 1 |
|
286 | max_noise -= 1 | |
232 | except IOError: |
|
287 | except IOError: | |
233 | badresponse() |
|
288 | badresponse() | |
234 | else: |
|
289 | else: | |
235 | badresponse() |
|
290 | badresponse() | |
236 |
|
291 | |||
237 | caps = set() |
|
292 | caps = set() | |
238 | for l in reversed(lines): |
|
|||
239 | # Look for response to ``hello`` command. Scan from the back so |
|
|||
240 | # we don't misinterpret banner output as the command reply. |
|
|||
241 | if l.startswith('capabilities:'): |
|
|||
242 | caps.update(l[:-1].split(':')[1].split()) |
|
|||
243 | break |
|
|||
244 |
|
293 | |||
245 | # Error if we couldn't find a response to ``hello``. This could |
|
294 | # For version 1, we should see a ``capabilities`` line in response to the | |
246 | # mean: |
|
295 | # ``hello`` command. | |
|
296 | if protoname == wireprotoserver.SSHV1: | |||
|
297 | for l in reversed(lines): | |||
|
298 | # Look for response to ``hello`` command. Scan from the back so | |||
|
299 | # we don't misinterpret banner output as the command reply. | |||
|
300 | if l.startswith('capabilities:'): | |||
|
301 | caps.update(l[:-1].split(':')[1].split()) | |||
|
302 | break | |||
|
303 | elif protoname == wireprotoserver.SSHV2: | |||
|
304 | # We see a line with number of bytes to follow and then a value | |||
|
305 | # looking like ``capabilities: *``. | |||
|
306 | line = stdout.readline() | |||
|
307 | try: | |||
|
308 | valuelen = int(line) | |||
|
309 | except ValueError: | |||
|
310 | badresponse() | |||
|
311 | ||||
|
312 | capsline = stdout.read(valuelen) | |||
|
313 | if not capsline.startswith('capabilities: '): | |||
|
314 | badresponse() | |||
|
315 | ||||
|
316 | caps.update(capsline.split(':')[1].split()) | |||
|
317 | # Trailing newline. | |||
|
318 | stdout.read(1) | |||
|
319 | ||||
|
320 | # Error if we couldn't find capabilities, this means: | |||
247 | # |
|
321 | # | |
248 | # 1. Remote isn't a Mercurial server |
|
322 | # 1. Remote isn't a Mercurial server | |
249 | # 2. Remote is a <0.9.1 Mercurial server |
|
323 | # 2. Remote is a <0.9.1 Mercurial server | |
250 | # 3. Remote is a future Mercurial server that dropped ``hello`` |
|
324 | # 3. Remote is a future Mercurial server that dropped ``hello`` | |
251 | # support. |
|
325 | # and other attempted handshake mechanisms. | |
252 | if not caps: |
|
326 | if not caps: | |
253 | badresponse() |
|
327 | badresponse() | |
254 |
|
328 | |||
255 | return caps |
|
329 | return caps | |
256 |
|
330 | |||
257 | class sshpeer(wireproto.wirepeer): |
|
331 | class sshpeer(wireproto.wirepeer): | |
258 | def __init__(self, ui, url, proc, stdin, stdout, stderr, caps): |
|
332 | def __init__(self, ui, url, proc, stdin, stdout, stderr, caps): | |
259 | """Create a peer from an existing SSH connection. |
|
333 | """Create a peer from an existing SSH connection. | |
260 |
|
334 | |||
261 | ``proc`` is a handle on the underlying SSH process. |
|
335 | ``proc`` is a handle on the underlying SSH process. | |
262 | ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio |
|
336 | ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio | |
263 | pipes for that process. |
|
337 | pipes for that process. | |
264 | ``caps`` is a set of capabilities supported by the remote. |
|
338 | ``caps`` is a set of capabilities supported by the remote. | |
265 | """ |
|
339 | """ | |
266 | self._url = url |
|
340 | self._url = url | |
267 | self._ui = ui |
|
341 | self._ui = ui | |
268 | # self._subprocess is unused. Keeping a handle on the process |
|
342 | # self._subprocess is unused. Keeping a handle on the process | |
269 | # holds a reference and prevents it from being garbage collected. |
|
343 | # holds a reference and prevents it from being garbage collected. | |
270 | self._subprocess = proc |
|
344 | self._subprocess = proc | |
271 | self._pipeo = stdin |
|
345 | self._pipeo = stdin | |
272 | self._pipei = stdout |
|
346 | self._pipei = stdout | |
273 | self._pipee = stderr |
|
347 | self._pipee = stderr | |
274 | self._caps = caps |
|
348 | self._caps = caps | |
275 |
|
349 | |||
276 | # Begin of _basepeer interface. |
|
350 | # Begin of _basepeer interface. | |
277 |
|
351 | |||
278 | @util.propertycache |
|
352 | @util.propertycache | |
279 | def ui(self): |
|
353 | def ui(self): | |
280 | return self._ui |
|
354 | return self._ui | |
281 |
|
355 | |||
282 | def url(self): |
|
356 | def url(self): | |
283 | return self._url |
|
357 | return self._url | |
284 |
|
358 | |||
285 | def local(self): |
|
359 | def local(self): | |
286 | return None |
|
360 | return None | |
287 |
|
361 | |||
288 | def peer(self): |
|
362 | def peer(self): | |
289 | return self |
|
363 | return self | |
290 |
|
364 | |||
291 | def canpush(self): |
|
365 | def canpush(self): | |
292 | return True |
|
366 | return True | |
293 |
|
367 | |||
294 | def close(self): |
|
368 | def close(self): | |
295 | pass |
|
369 | pass | |
296 |
|
370 | |||
297 | # End of _basepeer interface. |
|
371 | # End of _basepeer interface. | |
298 |
|
372 | |||
299 | # Begin of _basewirecommands interface. |
|
373 | # Begin of _basewirecommands interface. | |
300 |
|
374 | |||
301 | def capabilities(self): |
|
375 | def capabilities(self): | |
302 | return self._caps |
|
376 | return self._caps | |
303 |
|
377 | |||
304 | # End of _basewirecommands interface. |
|
378 | # End of _basewirecommands interface. | |
305 |
|
379 | |||
306 | def _readerr(self): |
|
380 | def _readerr(self): | |
307 | _forwardoutput(self.ui, self._pipee) |
|
381 | _forwardoutput(self.ui, self._pipee) | |
308 |
|
382 | |||
309 | def _abort(self, exception): |
|
383 | def _abort(self, exception): | |
310 | self._cleanup() |
|
384 | self._cleanup() | |
311 | raise exception |
|
385 | raise exception | |
312 |
|
386 | |||
313 | def _cleanup(self): |
|
387 | def _cleanup(self): | |
314 | _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) |
|
388 | _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) | |
315 |
|
389 | |||
316 | __del__ = _cleanup |
|
390 | __del__ = _cleanup | |
317 |
|
391 | |||
318 | def _submitbatch(self, req): |
|
392 | def _submitbatch(self, req): | |
319 | rsp = self._callstream("batch", cmds=wireproto.encodebatchcmds(req)) |
|
393 | rsp = self._callstream("batch", cmds=wireproto.encodebatchcmds(req)) | |
320 | available = self._getamount() |
|
394 | available = self._getamount() | |
321 | # TODO this response parsing is probably suboptimal for large |
|
395 | # TODO this response parsing is probably suboptimal for large | |
322 | # batches with large responses. |
|
396 | # batches with large responses. | |
323 | toread = min(available, 1024) |
|
397 | toread = min(available, 1024) | |
324 | work = rsp.read(toread) |
|
398 | work = rsp.read(toread) | |
325 | available -= toread |
|
399 | available -= toread | |
326 | chunk = work |
|
400 | chunk = work | |
327 | while chunk: |
|
401 | while chunk: | |
328 | while ';' in work: |
|
402 | while ';' in work: | |
329 | one, work = work.split(';', 1) |
|
403 | one, work = work.split(';', 1) | |
330 | yield wireproto.unescapearg(one) |
|
404 | yield wireproto.unescapearg(one) | |
331 | toread = min(available, 1024) |
|
405 | toread = min(available, 1024) | |
332 | chunk = rsp.read(toread) |
|
406 | chunk = rsp.read(toread) | |
333 | available -= toread |
|
407 | available -= toread | |
334 | work += chunk |
|
408 | work += chunk | |
335 | yield wireproto.unescapearg(work) |
|
409 | yield wireproto.unescapearg(work) | |
336 |
|
410 | |||
337 | def _callstream(self, cmd, **args): |
|
411 | def _callstream(self, cmd, **args): | |
338 | args = pycompat.byteskwargs(args) |
|
412 | args = pycompat.byteskwargs(args) | |
339 | if (self.ui.debugflag |
|
413 | if (self.ui.debugflag | |
340 | and self.ui.configbool('devel', 'debug.peer-request')): |
|
414 | and self.ui.configbool('devel', 'debug.peer-request')): | |
341 | dbg = self.ui.debug |
|
415 | dbg = self.ui.debug | |
342 | line = 'devel-peer-request: %s\n' |
|
416 | line = 'devel-peer-request: %s\n' | |
343 | dbg(line % cmd) |
|
417 | dbg(line % cmd) | |
344 | for key, value in sorted(args.items()): |
|
418 | for key, value in sorted(args.items()): | |
345 | if not isinstance(value, dict): |
|
419 | if not isinstance(value, dict): | |
346 | dbg(line % ' %s: %d bytes' % (key, len(value))) |
|
420 | dbg(line % ' %s: %d bytes' % (key, len(value))) | |
347 | else: |
|
421 | else: | |
348 | for dk, dv in sorted(value.items()): |
|
422 | for dk, dv in sorted(value.items()): | |
349 | dbg(line % ' %s-%s: %d' % (key, dk, len(dv))) |
|
423 | dbg(line % ' %s-%s: %d' % (key, dk, len(dv))) | |
350 | self.ui.debug("sending %s command\n" % cmd) |
|
424 | self.ui.debug("sending %s command\n" % cmd) | |
351 | self._pipeo.write("%s\n" % cmd) |
|
425 | self._pipeo.write("%s\n" % cmd) | |
352 | _func, names = wireproto.commands[cmd] |
|
426 | _func, names = wireproto.commands[cmd] | |
353 | keys = names.split() |
|
427 | keys = names.split() | |
354 | wireargs = {} |
|
428 | wireargs = {} | |
355 | for k in keys: |
|
429 | for k in keys: | |
356 | if k == '*': |
|
430 | if k == '*': | |
357 | wireargs['*'] = args |
|
431 | wireargs['*'] = args | |
358 | break |
|
432 | break | |
359 | else: |
|
433 | else: | |
360 | wireargs[k] = args[k] |
|
434 | wireargs[k] = args[k] | |
361 | del args[k] |
|
435 | del args[k] | |
362 | for k, v in sorted(wireargs.iteritems()): |
|
436 | for k, v in sorted(wireargs.iteritems()): | |
363 | self._pipeo.write("%s %d\n" % (k, len(v))) |
|
437 | self._pipeo.write("%s %d\n" % (k, len(v))) | |
364 | if isinstance(v, dict): |
|
438 | if isinstance(v, dict): | |
365 | for dk, dv in v.iteritems(): |
|
439 | for dk, dv in v.iteritems(): | |
366 | self._pipeo.write("%s %d\n" % (dk, len(dv))) |
|
440 | self._pipeo.write("%s %d\n" % (dk, len(dv))) | |
367 | self._pipeo.write(dv) |
|
441 | self._pipeo.write(dv) | |
368 | else: |
|
442 | else: | |
369 | self._pipeo.write(v) |
|
443 | self._pipeo.write(v) | |
370 | self._pipeo.flush() |
|
444 | self._pipeo.flush() | |
371 |
|
445 | |||
372 | return self._pipei |
|
446 | return self._pipei | |
373 |
|
447 | |||
374 | def _callcompressable(self, cmd, **args): |
|
448 | def _callcompressable(self, cmd, **args): | |
375 | return self._callstream(cmd, **args) |
|
449 | return self._callstream(cmd, **args) | |
376 |
|
450 | |||
377 | def _call(self, cmd, **args): |
|
451 | def _call(self, cmd, **args): | |
378 | self._callstream(cmd, **args) |
|
452 | self._callstream(cmd, **args) | |
379 | return self._recv() |
|
453 | return self._recv() | |
380 |
|
454 | |||
381 | def _callpush(self, cmd, fp, **args): |
|
455 | def _callpush(self, cmd, fp, **args): | |
382 | r = self._call(cmd, **args) |
|
456 | r = self._call(cmd, **args) | |
383 | if r: |
|
457 | if r: | |
384 | return '', r |
|
458 | return '', r | |
385 | for d in iter(lambda: fp.read(4096), ''): |
|
459 | for d in iter(lambda: fp.read(4096), ''): | |
386 | self._send(d) |
|
460 | self._send(d) | |
387 | self._send("", flush=True) |
|
461 | self._send("", flush=True) | |
388 | r = self._recv() |
|
462 | r = self._recv() | |
389 | if r: |
|
463 | if r: | |
390 | return '', r |
|
464 | return '', r | |
391 | return self._recv(), '' |
|
465 | return self._recv(), '' | |
392 |
|
466 | |||
393 | def _calltwowaystream(self, cmd, fp, **args): |
|
467 | def _calltwowaystream(self, cmd, fp, **args): | |
394 | r = self._call(cmd, **args) |
|
468 | r = self._call(cmd, **args) | |
395 | if r: |
|
469 | if r: | |
396 | # XXX needs to be made better |
|
470 | # XXX needs to be made better | |
397 | raise error.Abort(_('unexpected remote reply: %s') % r) |
|
471 | raise error.Abort(_('unexpected remote reply: %s') % r) | |
398 | for d in iter(lambda: fp.read(4096), ''): |
|
472 | for d in iter(lambda: fp.read(4096), ''): | |
399 | self._send(d) |
|
473 | self._send(d) | |
400 | self._send("", flush=True) |
|
474 | self._send("", flush=True) | |
401 | return self._pipei |
|
475 | return self._pipei | |
402 |
|
476 | |||
403 | def _getamount(self): |
|
477 | def _getamount(self): | |
404 | l = self._pipei.readline() |
|
478 | l = self._pipei.readline() | |
405 | if l == '\n': |
|
479 | if l == '\n': | |
406 | self._readerr() |
|
480 | self._readerr() | |
407 | msg = _('check previous remote output') |
|
481 | msg = _('check previous remote output') | |
408 | self._abort(error.OutOfBandError(hint=msg)) |
|
482 | self._abort(error.OutOfBandError(hint=msg)) | |
409 | self._readerr() |
|
483 | self._readerr() | |
410 | try: |
|
484 | try: | |
411 | return int(l) |
|
485 | return int(l) | |
412 | except ValueError: |
|
486 | except ValueError: | |
413 | self._abort(error.ResponseError(_("unexpected response:"), l)) |
|
487 | self._abort(error.ResponseError(_("unexpected response:"), l)) | |
414 |
|
488 | |||
415 | def _recv(self): |
|
489 | def _recv(self): | |
416 | return self._pipei.read(self._getamount()) |
|
490 | return self._pipei.read(self._getamount()) | |
417 |
|
491 | |||
418 | def _send(self, data, flush=False): |
|
492 | def _send(self, data, flush=False): | |
419 | self._pipeo.write("%d\n" % len(data)) |
|
493 | self._pipeo.write("%d\n" % len(data)) | |
420 | if data: |
|
494 | if data: | |
421 | self._pipeo.write(data) |
|
495 | self._pipeo.write(data) | |
422 | if flush: |
|
496 | if flush: | |
423 | self._pipeo.flush() |
|
497 | self._pipeo.flush() | |
424 | self._readerr() |
|
498 | self._readerr() | |
425 |
|
499 | |||
426 | def instance(ui, path, create): |
|
500 | def instance(ui, path, create): | |
427 | """Create an SSH peer. |
|
501 | """Create an SSH peer. | |
428 |
|
502 | |||
429 | The returned object conforms to the ``wireproto.wirepeer`` interface. |
|
503 | The returned object conforms to the ``wireproto.wirepeer`` interface. | |
430 | """ |
|
504 | """ | |
431 | u = util.url(path, parsequery=False, parsefragment=False) |
|
505 | u = util.url(path, parsequery=False, parsefragment=False) | |
432 | if u.scheme != 'ssh' or not u.host or u.path is None: |
|
506 | if u.scheme != 'ssh' or not u.host or u.path is None: | |
433 | raise error.RepoError(_("couldn't parse location %s") % path) |
|
507 | raise error.RepoError(_("couldn't parse location %s") % path) | |
434 |
|
508 | |||
435 | util.checksafessh(path) |
|
509 | util.checksafessh(path) | |
436 |
|
510 | |||
437 | if u.passwd is not None: |
|
511 | if u.passwd is not None: | |
438 | raise error.RepoError(_('password in URL not supported')) |
|
512 | raise error.RepoError(_('password in URL not supported')) | |
439 |
|
513 | |||
440 | sshcmd = ui.config('ui', 'ssh') |
|
514 | sshcmd = ui.config('ui', 'ssh') | |
441 | remotecmd = ui.config('ui', 'remotecmd') |
|
515 | remotecmd = ui.config('ui', 'remotecmd') | |
442 | sshaddenv = dict(ui.configitems('sshenv')) |
|
516 | sshaddenv = dict(ui.configitems('sshenv')) | |
443 | sshenv = util.shellenviron(sshaddenv) |
|
517 | sshenv = util.shellenviron(sshaddenv) | |
444 | remotepath = u.path or '.' |
|
518 | remotepath = u.path or '.' | |
445 |
|
519 | |||
446 | args = util.sshargs(sshcmd, u.host, u.user, u.port) |
|
520 | args = util.sshargs(sshcmd, u.host, u.user, u.port) | |
447 |
|
521 | |||
448 | if create: |
|
522 | if create: | |
449 | cmd = '%s %s %s' % (sshcmd, args, |
|
523 | cmd = '%s %s %s' % (sshcmd, args, | |
450 | util.shellquote('%s init %s' % |
|
524 | util.shellquote('%s init %s' % | |
451 | (_serverquote(remotecmd), _serverquote(remotepath)))) |
|
525 | (_serverquote(remotecmd), _serverquote(remotepath)))) | |
452 | ui.debug('running %s\n' % cmd) |
|
526 | ui.debug('running %s\n' % cmd) | |
453 | res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) |
|
527 | res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) | |
454 | if res != 0: |
|
528 | if res != 0: | |
455 | raise error.RepoError(_('could not create remote repo')) |
|
529 | raise error.RepoError(_('could not create remote repo')) | |
456 |
|
530 | |||
457 | proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, |
|
531 | proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, | |
458 | remotepath, sshenv) |
|
532 | remotepath, sshenv) | |
459 |
|
533 | |||
460 | try: |
|
534 | try: | |
461 | caps = _performhandshake(ui, stdin, stdout, stderr) |
|
535 | caps = _performhandshake(ui, stdin, stdout, stderr) | |
462 | except Exception: |
|
536 | except Exception: | |
463 | _cleanuppipes(ui, stdout, stdin, stderr) |
|
537 | _cleanuppipes(ui, stdout, stdin, stderr) | |
464 | raise |
|
538 | raise | |
465 |
|
539 | |||
466 | return sshpeer(ui, path, proc, stdin, stdout, stderr, caps) |
|
540 | return sshpeer(ui, path, proc, stdin, stdout, stderr, caps) |
@@ -1,357 +1,363 b'' | |||||
1 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
1 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
2 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
|
2 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | |
3 | # |
|
3 | # | |
4 | # This software may be used and distributed according to the terms of the |
|
4 | # This software may be used and distributed according to the terms of the | |
5 | # GNU General Public License version 2 or any later version. |
|
5 | # GNU General Public License version 2 or any later version. | |
6 |
|
6 | |||
7 | from __future__ import absolute_import |
|
7 | from __future__ import absolute_import | |
8 |
|
8 | |||
9 | import abc |
|
9 | import abc | |
10 | import cgi |
|
10 | import cgi | |
11 | import struct |
|
11 | import struct | |
12 | import sys |
|
12 | import sys | |
13 |
|
13 | |||
14 | from .i18n import _ |
|
14 | from .i18n import _ | |
15 | from . import ( |
|
15 | from . import ( | |
16 | encoding, |
|
16 | encoding, | |
17 | error, |
|
17 | error, | |
18 | hook, |
|
18 | hook, | |
19 | pycompat, |
|
19 | pycompat, | |
20 | util, |
|
20 | util, | |
21 | wireproto, |
|
21 | wireproto, | |
22 | ) |
|
22 | ) | |
23 |
|
23 | |||
24 | stringio = util.stringio |
|
24 | stringio = util.stringio | |
25 |
|
25 | |||
26 | urlerr = util.urlerr |
|
26 | urlerr = util.urlerr | |
27 | urlreq = util.urlreq |
|
27 | urlreq = util.urlreq | |
28 |
|
28 | |||
29 | HTTP_OK = 200 |
|
29 | HTTP_OK = 200 | |
30 |
|
30 | |||
31 | HGTYPE = 'application/mercurial-0.1' |
|
31 | HGTYPE = 'application/mercurial-0.1' | |
32 | HGTYPE2 = 'application/mercurial-0.2' |
|
32 | HGTYPE2 = 'application/mercurial-0.2' | |
33 | HGERRTYPE = 'application/hg-error' |
|
33 | HGERRTYPE = 'application/hg-error' | |
34 |
|
34 | |||
|
35 | # Names of the SSH protocol implementations. | |||
|
36 | SSHV1 = 'ssh-v1' | |||
|
37 | # This is advertised over the wire. Incremental the counter at the end | |||
|
38 | # to reflect BC breakages. | |||
|
39 | SSHV2 = 'exp-ssh-v2-0001' | |||
|
40 | ||||
35 | class abstractserverproto(object): |
|
41 | class abstractserverproto(object): | |
36 | """abstract class that summarizes the protocol API |
|
42 | """abstract class that summarizes the protocol API | |
37 |
|
43 | |||
38 | Used as reference and documentation. |
|
44 | Used as reference and documentation. | |
39 | """ |
|
45 | """ | |
40 |
|
46 | |||
41 | __metaclass__ = abc.ABCMeta |
|
47 | __metaclass__ = abc.ABCMeta | |
42 |
|
48 | |||
43 | @abc.abstractproperty |
|
49 | @abc.abstractproperty | |
44 | def name(self): |
|
50 | def name(self): | |
45 | """The name of the protocol implementation. |
|
51 | """The name of the protocol implementation. | |
46 |
|
52 | |||
47 | Used for uniquely identifying the transport type. |
|
53 | Used for uniquely identifying the transport type. | |
48 | """ |
|
54 | """ | |
49 |
|
55 | |||
50 | @abc.abstractmethod |
|
56 | @abc.abstractmethod | |
51 | def getargs(self, args): |
|
57 | def getargs(self, args): | |
52 | """return the value for arguments in <args> |
|
58 | """return the value for arguments in <args> | |
53 |
|
59 | |||
54 | returns a list of values (same order as <args>)""" |
|
60 | returns a list of values (same order as <args>)""" | |
55 |
|
61 | |||
56 | @abc.abstractmethod |
|
62 | @abc.abstractmethod | |
57 | def getfile(self, fp): |
|
63 | def getfile(self, fp): | |
58 | """write the whole content of a file into a file like object |
|
64 | """write the whole content of a file into a file like object | |
59 |
|
65 | |||
60 | The file is in the form:: |
|
66 | The file is in the form:: | |
61 |
|
67 | |||
62 | (<chunk-size>\n<chunk>)+0\n |
|
68 | (<chunk-size>\n<chunk>)+0\n | |
63 |
|
69 | |||
64 | chunk size is the ascii version of the int. |
|
70 | chunk size is the ascii version of the int. | |
65 | """ |
|
71 | """ | |
66 |
|
72 | |||
67 | @abc.abstractmethod |
|
73 | @abc.abstractmethod | |
68 | def redirect(self): |
|
74 | def redirect(self): | |
69 | """may setup interception for stdout and stderr |
|
75 | """may setup interception for stdout and stderr | |
70 |
|
76 | |||
71 | See also the `restore` method.""" |
|
77 | See also the `restore` method.""" | |
72 |
|
78 | |||
73 | # If the `redirect` function does install interception, the `restore` |
|
79 | # If the `redirect` function does install interception, the `restore` | |
74 | # function MUST be defined. If interception is not used, this function |
|
80 | # function MUST be defined. If interception is not used, this function | |
75 | # MUST NOT be defined. |
|
81 | # MUST NOT be defined. | |
76 | # |
|
82 | # | |
77 | # left commented here on purpose |
|
83 | # left commented here on purpose | |
78 | # |
|
84 | # | |
79 | #def restore(self): |
|
85 | #def restore(self): | |
80 | # """reinstall previous stdout and stderr and return intercepted stdout |
|
86 | # """reinstall previous stdout and stderr and return intercepted stdout | |
81 | # """ |
|
87 | # """ | |
82 | # raise NotImplementedError() |
|
88 | # raise NotImplementedError() | |
83 |
|
89 | |||
84 | def decodevaluefromheaders(req, headerprefix): |
|
90 | def decodevaluefromheaders(req, headerprefix): | |
85 | """Decode a long value from multiple HTTP request headers. |
|
91 | """Decode a long value from multiple HTTP request headers. | |
86 |
|
92 | |||
87 | Returns the value as a bytes, not a str. |
|
93 | Returns the value as a bytes, not a str. | |
88 | """ |
|
94 | """ | |
89 | chunks = [] |
|
95 | chunks = [] | |
90 | i = 1 |
|
96 | i = 1 | |
91 | prefix = headerprefix.upper().replace(r'-', r'_') |
|
97 | prefix = headerprefix.upper().replace(r'-', r'_') | |
92 | while True: |
|
98 | while True: | |
93 | v = req.env.get(r'HTTP_%s_%d' % (prefix, i)) |
|
99 | v = req.env.get(r'HTTP_%s_%d' % (prefix, i)) | |
94 | if v is None: |
|
100 | if v is None: | |
95 | break |
|
101 | break | |
96 | chunks.append(pycompat.bytesurl(v)) |
|
102 | chunks.append(pycompat.bytesurl(v)) | |
97 | i += 1 |
|
103 | i += 1 | |
98 |
|
104 | |||
99 | return ''.join(chunks) |
|
105 | return ''.join(chunks) | |
100 |
|
106 | |||
101 | class webproto(abstractserverproto): |
|
107 | class webproto(abstractserverproto): | |
102 | def __init__(self, req, ui): |
|
108 | def __init__(self, req, ui): | |
103 | self._req = req |
|
109 | self._req = req | |
104 | self._ui = ui |
|
110 | self._ui = ui | |
105 |
|
111 | |||
106 | @property |
|
112 | @property | |
107 | def name(self): |
|
113 | def name(self): | |
108 | return 'http' |
|
114 | return 'http' | |
109 |
|
115 | |||
110 | def getargs(self, args): |
|
116 | def getargs(self, args): | |
111 | knownargs = self._args() |
|
117 | knownargs = self._args() | |
112 | data = {} |
|
118 | data = {} | |
113 | keys = args.split() |
|
119 | keys = args.split() | |
114 | for k in keys: |
|
120 | for k in keys: | |
115 | if k == '*': |
|
121 | if k == '*': | |
116 | star = {} |
|
122 | star = {} | |
117 | for key in knownargs.keys(): |
|
123 | for key in knownargs.keys(): | |
118 | if key != 'cmd' and key not in keys: |
|
124 | if key != 'cmd' and key not in keys: | |
119 | star[key] = knownargs[key][0] |
|
125 | star[key] = knownargs[key][0] | |
120 | data['*'] = star |
|
126 | data['*'] = star | |
121 | else: |
|
127 | else: | |
122 | data[k] = knownargs[k][0] |
|
128 | data[k] = knownargs[k][0] | |
123 | return [data[k] for k in keys] |
|
129 | return [data[k] for k in keys] | |
124 |
|
130 | |||
125 | def _args(self): |
|
131 | def _args(self): | |
126 | args = util.rapply(pycompat.bytesurl, self._req.form.copy()) |
|
132 | args = util.rapply(pycompat.bytesurl, self._req.form.copy()) | |
127 | postlen = int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0)) |
|
133 | postlen = int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0)) | |
128 | if postlen: |
|
134 | if postlen: | |
129 | args.update(cgi.parse_qs( |
|
135 | args.update(cgi.parse_qs( | |
130 | self._req.read(postlen), keep_blank_values=True)) |
|
136 | self._req.read(postlen), keep_blank_values=True)) | |
131 | return args |
|
137 | return args | |
132 |
|
138 | |||
133 | argvalue = decodevaluefromheaders(self._req, r'X-HgArg') |
|
139 | argvalue = decodevaluefromheaders(self._req, r'X-HgArg') | |
134 | args.update(cgi.parse_qs(argvalue, keep_blank_values=True)) |
|
140 | args.update(cgi.parse_qs(argvalue, keep_blank_values=True)) | |
135 | return args |
|
141 | return args | |
136 |
|
142 | |||
137 | def getfile(self, fp): |
|
143 | def getfile(self, fp): | |
138 | length = int(self._req.env[r'CONTENT_LENGTH']) |
|
144 | length = int(self._req.env[r'CONTENT_LENGTH']) | |
139 | # If httppostargs is used, we need to read Content-Length |
|
145 | # If httppostargs is used, we need to read Content-Length | |
140 | # minus the amount that was consumed by args. |
|
146 | # minus the amount that was consumed by args. | |
141 | length -= int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0)) |
|
147 | length -= int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0)) | |
142 | for s in util.filechunkiter(self._req, limit=length): |
|
148 | for s in util.filechunkiter(self._req, limit=length): | |
143 | fp.write(s) |
|
149 | fp.write(s) | |
144 |
|
150 | |||
145 | def redirect(self): |
|
151 | def redirect(self): | |
146 | self._oldio = self._ui.fout, self._ui.ferr |
|
152 | self._oldio = self._ui.fout, self._ui.ferr | |
147 | self._ui.ferr = self._ui.fout = stringio() |
|
153 | self._ui.ferr = self._ui.fout = stringio() | |
148 |
|
154 | |||
149 | def restore(self): |
|
155 | def restore(self): | |
150 | val = self._ui.fout.getvalue() |
|
156 | val = self._ui.fout.getvalue() | |
151 | self._ui.ferr, self._ui.fout = self._oldio |
|
157 | self._ui.ferr, self._ui.fout = self._oldio | |
152 | return val |
|
158 | return val | |
153 |
|
159 | |||
154 | def _client(self): |
|
160 | def _client(self): | |
155 | return 'remote:%s:%s:%s' % ( |
|
161 | return 'remote:%s:%s:%s' % ( | |
156 | self._req.env.get('wsgi.url_scheme') or 'http', |
|
162 | self._req.env.get('wsgi.url_scheme') or 'http', | |
157 | urlreq.quote(self._req.env.get('REMOTE_HOST', '')), |
|
163 | urlreq.quote(self._req.env.get('REMOTE_HOST', '')), | |
158 | urlreq.quote(self._req.env.get('REMOTE_USER', ''))) |
|
164 | urlreq.quote(self._req.env.get('REMOTE_USER', ''))) | |
159 |
|
165 | |||
160 | def responsetype(self, prefer_uncompressed): |
|
166 | def responsetype(self, prefer_uncompressed): | |
161 | """Determine the appropriate response type and compression settings. |
|
167 | """Determine the appropriate response type and compression settings. | |
162 |
|
168 | |||
163 | Returns a tuple of (mediatype, compengine, engineopts). |
|
169 | Returns a tuple of (mediatype, compengine, engineopts). | |
164 | """ |
|
170 | """ | |
165 | # Determine the response media type and compression engine based |
|
171 | # Determine the response media type and compression engine based | |
166 | # on the request parameters. |
|
172 | # on the request parameters. | |
167 | protocaps = decodevaluefromheaders(self._req, r'X-HgProto').split(' ') |
|
173 | protocaps = decodevaluefromheaders(self._req, r'X-HgProto').split(' ') | |
168 |
|
174 | |||
169 | if '0.2' in protocaps: |
|
175 | if '0.2' in protocaps: | |
170 | # All clients are expected to support uncompressed data. |
|
176 | # All clients are expected to support uncompressed data. | |
171 | if prefer_uncompressed: |
|
177 | if prefer_uncompressed: | |
172 | return HGTYPE2, util._noopengine(), {} |
|
178 | return HGTYPE2, util._noopengine(), {} | |
173 |
|
179 | |||
174 | # Default as defined by wire protocol spec. |
|
180 | # Default as defined by wire protocol spec. | |
175 | compformats = ['zlib', 'none'] |
|
181 | compformats = ['zlib', 'none'] | |
176 | for cap in protocaps: |
|
182 | for cap in protocaps: | |
177 | if cap.startswith('comp='): |
|
183 | if cap.startswith('comp='): | |
178 | compformats = cap[5:].split(',') |
|
184 | compformats = cap[5:].split(',') | |
179 | break |
|
185 | break | |
180 |
|
186 | |||
181 | # Now find an agreed upon compression format. |
|
187 | # Now find an agreed upon compression format. | |
182 | for engine in wireproto.supportedcompengines(self._ui, self, |
|
188 | for engine in wireproto.supportedcompengines(self._ui, self, | |
183 | util.SERVERROLE): |
|
189 | util.SERVERROLE): | |
184 | if engine.wireprotosupport().name in compformats: |
|
190 | if engine.wireprotosupport().name in compformats: | |
185 | opts = {} |
|
191 | opts = {} | |
186 | level = self._ui.configint('server', |
|
192 | level = self._ui.configint('server', | |
187 | '%slevel' % engine.name()) |
|
193 | '%slevel' % engine.name()) | |
188 | if level is not None: |
|
194 | if level is not None: | |
189 | opts['level'] = level |
|
195 | opts['level'] = level | |
190 |
|
196 | |||
191 | return HGTYPE2, engine, opts |
|
197 | return HGTYPE2, engine, opts | |
192 |
|
198 | |||
193 | # No mutually supported compression format. Fall back to the |
|
199 | # No mutually supported compression format. Fall back to the | |
194 | # legacy protocol. |
|
200 | # legacy protocol. | |
195 |
|
201 | |||
196 | # Don't allow untrusted settings because disabling compression or |
|
202 | # Don't allow untrusted settings because disabling compression or | |
197 | # setting a very high compression level could lead to flooding |
|
203 | # setting a very high compression level could lead to flooding | |
198 | # the server's network or CPU. |
|
204 | # the server's network or CPU. | |
199 | opts = {'level': self._ui.configint('server', 'zliblevel')} |
|
205 | opts = {'level': self._ui.configint('server', 'zliblevel')} | |
200 | return HGTYPE, util.compengines['zlib'], opts |
|
206 | return HGTYPE, util.compengines['zlib'], opts | |
201 |
|
207 | |||
202 | def iscmd(cmd): |
|
208 | def iscmd(cmd): | |
203 | return cmd in wireproto.commands |
|
209 | return cmd in wireproto.commands | |
204 |
|
210 | |||
205 | def callhttp(repo, req, cmd): |
|
211 | def callhttp(repo, req, cmd): | |
206 | proto = webproto(req, repo.ui) |
|
212 | proto = webproto(req, repo.ui) | |
207 |
|
213 | |||
208 | def genversion2(gen, engine, engineopts): |
|
214 | def genversion2(gen, engine, engineopts): | |
209 | # application/mercurial-0.2 always sends a payload header |
|
215 | # application/mercurial-0.2 always sends a payload header | |
210 | # identifying the compression engine. |
|
216 | # identifying the compression engine. | |
211 | name = engine.wireprotosupport().name |
|
217 | name = engine.wireprotosupport().name | |
212 | assert 0 < len(name) < 256 |
|
218 | assert 0 < len(name) < 256 | |
213 | yield struct.pack('B', len(name)) |
|
219 | yield struct.pack('B', len(name)) | |
214 | yield name |
|
220 | yield name | |
215 |
|
221 | |||
216 | for chunk in gen: |
|
222 | for chunk in gen: | |
217 | yield chunk |
|
223 | yield chunk | |
218 |
|
224 | |||
219 | rsp = wireproto.dispatch(repo, proto, cmd) |
|
225 | rsp = wireproto.dispatch(repo, proto, cmd) | |
220 | if isinstance(rsp, bytes): |
|
226 | if isinstance(rsp, bytes): | |
221 | req.respond(HTTP_OK, HGTYPE, body=rsp) |
|
227 | req.respond(HTTP_OK, HGTYPE, body=rsp) | |
222 | return [] |
|
228 | return [] | |
223 | elif isinstance(rsp, wireproto.streamres_legacy): |
|
229 | elif isinstance(rsp, wireproto.streamres_legacy): | |
224 | gen = rsp.gen |
|
230 | gen = rsp.gen | |
225 | req.respond(HTTP_OK, HGTYPE) |
|
231 | req.respond(HTTP_OK, HGTYPE) | |
226 | return gen |
|
232 | return gen | |
227 | elif isinstance(rsp, wireproto.streamres): |
|
233 | elif isinstance(rsp, wireproto.streamres): | |
228 | gen = rsp.gen |
|
234 | gen = rsp.gen | |
229 |
|
235 | |||
230 | # This code for compression should not be streamres specific. It |
|
236 | # This code for compression should not be streamres specific. It | |
231 | # is here because we only compress streamres at the moment. |
|
237 | # is here because we only compress streamres at the moment. | |
232 | mediatype, engine, engineopts = proto.responsetype( |
|
238 | mediatype, engine, engineopts = proto.responsetype( | |
233 | rsp.prefer_uncompressed) |
|
239 | rsp.prefer_uncompressed) | |
234 | gen = engine.compressstream(gen, engineopts) |
|
240 | gen = engine.compressstream(gen, engineopts) | |
235 |
|
241 | |||
236 | if mediatype == HGTYPE2: |
|
242 | if mediatype == HGTYPE2: | |
237 | gen = genversion2(gen, engine, engineopts) |
|
243 | gen = genversion2(gen, engine, engineopts) | |
238 |
|
244 | |||
239 | req.respond(HTTP_OK, mediatype) |
|
245 | req.respond(HTTP_OK, mediatype) | |
240 | return gen |
|
246 | return gen | |
241 | elif isinstance(rsp, wireproto.pushres): |
|
247 | elif isinstance(rsp, wireproto.pushres): | |
242 | val = proto.restore() |
|
248 | val = proto.restore() | |
243 | rsp = '%d\n%s' % (rsp.res, val) |
|
249 | rsp = '%d\n%s' % (rsp.res, val) | |
244 | req.respond(HTTP_OK, HGTYPE, body=rsp) |
|
250 | req.respond(HTTP_OK, HGTYPE, body=rsp) | |
245 | return [] |
|
251 | return [] | |
246 | elif isinstance(rsp, wireproto.pusherr): |
|
252 | elif isinstance(rsp, wireproto.pusherr): | |
247 | # drain the incoming bundle |
|
253 | # drain the incoming bundle | |
248 | req.drain() |
|
254 | req.drain() | |
249 | proto.restore() |
|
255 | proto.restore() | |
250 | rsp = '0\n%s\n' % rsp.res |
|
256 | rsp = '0\n%s\n' % rsp.res | |
251 | req.respond(HTTP_OK, HGTYPE, body=rsp) |
|
257 | req.respond(HTTP_OK, HGTYPE, body=rsp) | |
252 | return [] |
|
258 | return [] | |
253 | elif isinstance(rsp, wireproto.ooberror): |
|
259 | elif isinstance(rsp, wireproto.ooberror): | |
254 | rsp = rsp.message |
|
260 | rsp = rsp.message | |
255 | req.respond(HTTP_OK, HGERRTYPE, body=rsp) |
|
261 | req.respond(HTTP_OK, HGERRTYPE, body=rsp) | |
256 | return [] |
|
262 | return [] | |
257 | raise error.ProgrammingError('hgweb.protocol internal failure', rsp) |
|
263 | raise error.ProgrammingError('hgweb.protocol internal failure', rsp) | |
258 |
|
264 | |||
259 | class sshserver(abstractserverproto): |
|
265 | class sshserver(abstractserverproto): | |
260 | def __init__(self, ui, repo): |
|
266 | def __init__(self, ui, repo): | |
261 | self._ui = ui |
|
267 | self._ui = ui | |
262 | self._repo = repo |
|
268 | self._repo = repo | |
263 | self._fin = ui.fin |
|
269 | self._fin = ui.fin | |
264 | self._fout = ui.fout |
|
270 | self._fout = ui.fout | |
265 |
|
271 | |||
266 | hook.redirect(True) |
|
272 | hook.redirect(True) | |
267 | ui.fout = repo.ui.fout = ui.ferr |
|
273 | ui.fout = repo.ui.fout = ui.ferr | |
268 |
|
274 | |||
269 | # Prevent insertion/deletion of CRs |
|
275 | # Prevent insertion/deletion of CRs | |
270 | util.setbinary(self._fin) |
|
276 | util.setbinary(self._fin) | |
271 | util.setbinary(self._fout) |
|
277 | util.setbinary(self._fout) | |
272 |
|
278 | |||
273 | @property |
|
279 | @property | |
274 | def name(self): |
|
280 | def name(self): | |
275 | return 'ssh' |
|
281 | return 'ssh' | |
276 |
|
282 | |||
277 | def getargs(self, args): |
|
283 | def getargs(self, args): | |
278 | data = {} |
|
284 | data = {} | |
279 | keys = args.split() |
|
285 | keys = args.split() | |
280 | for n in xrange(len(keys)): |
|
286 | for n in xrange(len(keys)): | |
281 | argline = self._fin.readline()[:-1] |
|
287 | argline = self._fin.readline()[:-1] | |
282 | arg, l = argline.split() |
|
288 | arg, l = argline.split() | |
283 | if arg not in keys: |
|
289 | if arg not in keys: | |
284 | raise error.Abort(_("unexpected parameter %r") % arg) |
|
290 | raise error.Abort(_("unexpected parameter %r") % arg) | |
285 | if arg == '*': |
|
291 | if arg == '*': | |
286 | star = {} |
|
292 | star = {} | |
287 | for k in xrange(int(l)): |
|
293 | for k in xrange(int(l)): | |
288 | argline = self._fin.readline()[:-1] |
|
294 | argline = self._fin.readline()[:-1] | |
289 | arg, l = argline.split() |
|
295 | arg, l = argline.split() | |
290 | val = self._fin.read(int(l)) |
|
296 | val = self._fin.read(int(l)) | |
291 | star[arg] = val |
|
297 | star[arg] = val | |
292 | data['*'] = star |
|
298 | data['*'] = star | |
293 | else: |
|
299 | else: | |
294 | val = self._fin.read(int(l)) |
|
300 | val = self._fin.read(int(l)) | |
295 | data[arg] = val |
|
301 | data[arg] = val | |
296 | return [data[k] for k in keys] |
|
302 | return [data[k] for k in keys] | |
297 |
|
303 | |||
298 | def getfile(self, fpout): |
|
304 | def getfile(self, fpout): | |
299 | self._sendresponse('') |
|
305 | self._sendresponse('') | |
300 | count = int(self._fin.readline()) |
|
306 | count = int(self._fin.readline()) | |
301 | while count: |
|
307 | while count: | |
302 | fpout.write(self._fin.read(count)) |
|
308 | fpout.write(self._fin.read(count)) | |
303 | count = int(self._fin.readline()) |
|
309 | count = int(self._fin.readline()) | |
304 |
|
310 | |||
305 | def redirect(self): |
|
311 | def redirect(self): | |
306 | pass |
|
312 | pass | |
307 |
|
313 | |||
308 | def _sendresponse(self, v): |
|
314 | def _sendresponse(self, v): | |
309 | self._fout.write("%d\n" % len(v)) |
|
315 | self._fout.write("%d\n" % len(v)) | |
310 | self._fout.write(v) |
|
316 | self._fout.write(v) | |
311 | self._fout.flush() |
|
317 | self._fout.flush() | |
312 |
|
318 | |||
313 | def _sendstream(self, source): |
|
319 | def _sendstream(self, source): | |
314 | write = self._fout.write |
|
320 | write = self._fout.write | |
315 | for chunk in source.gen: |
|
321 | for chunk in source.gen: | |
316 | write(chunk) |
|
322 | write(chunk) | |
317 | self._fout.flush() |
|
323 | self._fout.flush() | |
318 |
|
324 | |||
319 | def _sendpushresponse(self, rsp): |
|
325 | def _sendpushresponse(self, rsp): | |
320 | self._sendresponse('') |
|
326 | self._sendresponse('') | |
321 | self._sendresponse(str(rsp.res)) |
|
327 | self._sendresponse(str(rsp.res)) | |
322 |
|
328 | |||
323 | def _sendpusherror(self, rsp): |
|
329 | def _sendpusherror(self, rsp): | |
324 | self._sendresponse(rsp.res) |
|
330 | self._sendresponse(rsp.res) | |
325 |
|
331 | |||
326 | def _sendooberror(self, rsp): |
|
332 | def _sendooberror(self, rsp): | |
327 | self._ui.ferr.write('%s\n-\n' % rsp.message) |
|
333 | self._ui.ferr.write('%s\n-\n' % rsp.message) | |
328 | self._ui.ferr.flush() |
|
334 | self._ui.ferr.flush() | |
329 | self._fout.write('\n') |
|
335 | self._fout.write('\n') | |
330 | self._fout.flush() |
|
336 | self._fout.flush() | |
331 |
|
337 | |||
332 | def serve_forever(self): |
|
338 | def serve_forever(self): | |
333 | while self.serve_one(): |
|
339 | while self.serve_one(): | |
334 | pass |
|
340 | pass | |
335 | sys.exit(0) |
|
341 | sys.exit(0) | |
336 |
|
342 | |||
337 | _handlers = { |
|
343 | _handlers = { | |
338 | str: _sendresponse, |
|
344 | str: _sendresponse, | |
339 | wireproto.streamres: _sendstream, |
|
345 | wireproto.streamres: _sendstream, | |
340 | wireproto.streamres_legacy: _sendstream, |
|
346 | wireproto.streamres_legacy: _sendstream, | |
341 | wireproto.pushres: _sendpushresponse, |
|
347 | wireproto.pushres: _sendpushresponse, | |
342 | wireproto.pusherr: _sendpusherror, |
|
348 | wireproto.pusherr: _sendpusherror, | |
343 | wireproto.ooberror: _sendooberror, |
|
349 | wireproto.ooberror: _sendooberror, | |
344 | } |
|
350 | } | |
345 |
|
351 | |||
346 | def serve_one(self): |
|
352 | def serve_one(self): | |
347 | cmd = self._fin.readline()[:-1] |
|
353 | cmd = self._fin.readline()[:-1] | |
348 | if cmd and cmd in wireproto.commands: |
|
354 | if cmd and cmd in wireproto.commands: | |
349 | rsp = wireproto.dispatch(self._repo, self, cmd) |
|
355 | rsp = wireproto.dispatch(self._repo, self, cmd) | |
350 | self._handlers[rsp.__class__](self, rsp) |
|
356 | self._handlers[rsp.__class__](self, rsp) | |
351 | elif cmd: |
|
357 | elif cmd: | |
352 | self._sendresponse("") |
|
358 | self._sendresponse("") | |
353 | return cmd != '' |
|
359 | return cmd != '' | |
354 |
|
360 | |||
355 | def _client(self): |
|
361 | def _client(self): | |
356 | client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0] |
|
362 | client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0] | |
357 | return 'remote:ssh:' + client |
|
363 | return 'remote:ssh:' + client |
@@ -1,96 +1,127 b'' | |||||
1 | # sshprotoext.py - Extension to test behavior of SSH protocol |
|
1 | # sshprotoext.py - Extension to test behavior of SSH protocol | |
2 | # |
|
2 | # | |
3 | # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com> |
|
3 | # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | # This extension replaces the SSH server started via `hg serve --stdio`. |
|
8 | # This extension replaces the SSH server started via `hg serve --stdio`. | |
9 | # The server behaves differently depending on environment variables. |
|
9 | # The server behaves differently depending on environment variables. | |
10 |
|
10 | |||
11 | from __future__ import absolute_import |
|
11 | from __future__ import absolute_import | |
12 |
|
12 | |||
13 | from mercurial import ( |
|
13 | from mercurial import ( | |
14 | error, |
|
14 | error, | |
15 | extensions, |
|
15 | extensions, | |
16 | registrar, |
|
16 | registrar, | |
17 | sshpeer, |
|
17 | sshpeer, | |
18 | wireproto, |
|
18 | wireproto, | |
19 | wireprotoserver, |
|
19 | wireprotoserver, | |
20 | ) |
|
20 | ) | |
21 |
|
21 | |||
22 | configtable = {} |
|
22 | configtable = {} | |
23 | configitem = registrar.configitem(configtable) |
|
23 | configitem = registrar.configitem(configtable) | |
24 |
|
24 | |||
25 | configitem('sshpeer', 'mode', default=None) |
|
25 | configitem('sshpeer', 'mode', default=None) | |
26 | configitem('sshpeer', 'handshake-mode', default=None) |
|
26 | configitem('sshpeer', 'handshake-mode', default=None) | |
27 |
|
27 | |||
28 | class bannerserver(wireprotoserver.sshserver): |
|
28 | class bannerserver(wireprotoserver.sshserver): | |
29 | """Server that sends a banner to stdout.""" |
|
29 | """Server that sends a banner to stdout.""" | |
30 | def serve_forever(self): |
|
30 | def serve_forever(self): | |
31 | for i in range(10): |
|
31 | for i in range(10): | |
32 | self._fout.write(b'banner: line %d\n' % i) |
|
32 | self._fout.write(b'banner: line %d\n' % i) | |
33 |
|
33 | |||
34 | super(bannerserver, self).serve_forever() |
|
34 | super(bannerserver, self).serve_forever() | |
35 |
|
35 | |||
36 | class prehelloserver(wireprotoserver.sshserver): |
|
36 | class prehelloserver(wireprotoserver.sshserver): | |
37 | """Tests behavior when connecting to <0.9.1 servers. |
|
37 | """Tests behavior when connecting to <0.9.1 servers. | |
38 |
|
38 | |||
39 | The ``hello`` wire protocol command was introduced in Mercurial |
|
39 | The ``hello`` wire protocol command was introduced in Mercurial | |
40 | 0.9.1. Modern clients send the ``hello`` command when connecting |
|
40 | 0.9.1. Modern clients send the ``hello`` command when connecting | |
41 | to SSH servers. This mock server tests behavior of the handshake |
|
41 | to SSH servers. This mock server tests behavior of the handshake | |
42 | when ``hello`` is not supported. |
|
42 | when ``hello`` is not supported. | |
43 | """ |
|
43 | """ | |
44 | def serve_forever(self): |
|
44 | def serve_forever(self): | |
45 | l = self._fin.readline() |
|
45 | l = self._fin.readline() | |
46 | assert l == b'hello\n' |
|
46 | assert l == b'hello\n' | |
47 | # Respond to unknown commands with an empty reply. |
|
47 | # Respond to unknown commands with an empty reply. | |
48 | self._sendresponse(b'') |
|
48 | self._sendresponse(b'') | |
49 | l = self._fin.readline() |
|
49 | l = self._fin.readline() | |
50 | assert l == b'between\n' |
|
50 | assert l == b'between\n' | |
51 | rsp = wireproto.dispatch(self._repo, self, b'between') |
|
51 | rsp = wireproto.dispatch(self._repo, self, b'between') | |
52 | self._handlers[rsp.__class__](self, rsp) |
|
52 | self._handlers[rsp.__class__](self, rsp) | |
53 |
|
53 | |||
54 | super(prehelloserver, self).serve_forever() |
|
54 | super(prehelloserver, self).serve_forever() | |
55 |
|
55 | |||
|
56 | class upgradev2server(wireprotoserver.sshserver): | |||
|
57 | """Tests behavior for clients that issue upgrade to version 2.""" | |||
|
58 | def serve_forever(self): | |||
|
59 | name = wireprotoserver.SSHV2 | |||
|
60 | l = self._fin.readline() | |||
|
61 | assert l.startswith(b'upgrade ') | |||
|
62 | token, caps = l[:-1].split(b' ')[1:] | |||
|
63 | assert caps == b'proto=%s' % name | |||
|
64 | ||||
|
65 | # Filter hello and between requests. | |||
|
66 | l = self._fin.readline() | |||
|
67 | assert l == b'hello\n' | |||
|
68 | l = self._fin.readline() | |||
|
69 | assert l == b'between\n' | |||
|
70 | l = self._fin.readline() | |||
|
71 | assert l == 'pairs 81\n' | |||
|
72 | self._fin.read(81) | |||
|
73 | ||||
|
74 | # Send the upgrade response. | |||
|
75 | self._fout.write(b'upgraded %s %s\n' % (token, name)) | |||
|
76 | servercaps = wireproto.capabilities(self._repo, self) | |||
|
77 | rsp = b'capabilities: %s' % servercaps | |||
|
78 | self._fout.write(b'%d\n' % len(rsp)) | |||
|
79 | self._fout.write(rsp) | |||
|
80 | self._fout.write(b'\n') | |||
|
81 | self._fout.flush() | |||
|
82 | ||||
|
83 | super(upgradev2server, self).serve_forever() | |||
|
84 | ||||
56 | def performhandshake(orig, ui, stdin, stdout, stderr): |
|
85 | def performhandshake(orig, ui, stdin, stdout, stderr): | |
57 | """Wrapped version of sshpeer._performhandshake to send extra commands.""" |
|
86 | """Wrapped version of sshpeer._performhandshake to send extra commands.""" | |
58 | mode = ui.config(b'sshpeer', b'handshake-mode') |
|
87 | mode = ui.config(b'sshpeer', b'handshake-mode') | |
59 | if mode == b'pre-no-args': |
|
88 | if mode == b'pre-no-args': | |
60 | ui.debug(b'sending no-args command\n') |
|
89 | ui.debug(b'sending no-args command\n') | |
61 | stdin.write(b'no-args\n') |
|
90 | stdin.write(b'no-args\n') | |
62 | stdin.flush() |
|
91 | stdin.flush() | |
63 | return orig(ui, stdin, stdout, stderr) |
|
92 | return orig(ui, stdin, stdout, stderr) | |
64 | elif mode == b'pre-multiple-no-args': |
|
93 | elif mode == b'pre-multiple-no-args': | |
65 | ui.debug(b'sending unknown1 command\n') |
|
94 | ui.debug(b'sending unknown1 command\n') | |
66 | stdin.write(b'unknown1\n') |
|
95 | stdin.write(b'unknown1\n') | |
67 | ui.debug(b'sending unknown2 command\n') |
|
96 | ui.debug(b'sending unknown2 command\n') | |
68 | stdin.write(b'unknown2\n') |
|
97 | stdin.write(b'unknown2\n') | |
69 | ui.debug(b'sending unknown3 command\n') |
|
98 | ui.debug(b'sending unknown3 command\n') | |
70 | stdin.write(b'unknown3\n') |
|
99 | stdin.write(b'unknown3\n') | |
71 | stdin.flush() |
|
100 | stdin.flush() | |
72 | return orig(ui, stdin, stdout, stderr) |
|
101 | return orig(ui, stdin, stdout, stderr) | |
73 | else: |
|
102 | else: | |
74 | raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' % |
|
103 | raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' % | |
75 | mode) |
|
104 | mode) | |
76 |
|
105 | |||
77 | def extsetup(ui): |
|
106 | def extsetup(ui): | |
78 | # It's easier for tests to define the server behavior via environment |
|
107 | # It's easier for tests to define the server behavior via environment | |
79 | # variables than config options. This is because `hg serve --stdio` |
|
108 | # variables than config options. This is because `hg serve --stdio` | |
80 | # has to be invoked with a certain form for security reasons and |
|
109 | # has to be invoked with a certain form for security reasons and | |
81 | # `dummyssh` can't just add `--config` flags to the command line. |
|
110 | # `dummyssh` can't just add `--config` flags to the command line. | |
82 | servermode = ui.environ.get(b'SSHSERVERMODE') |
|
111 | servermode = ui.environ.get(b'SSHSERVERMODE') | |
83 |
|
112 | |||
84 | if servermode == b'banner': |
|
113 | if servermode == b'banner': | |
85 | wireprotoserver.sshserver = bannerserver |
|
114 | wireprotoserver.sshserver = bannerserver | |
86 | elif servermode == b'no-hello': |
|
115 | elif servermode == b'no-hello': | |
87 | wireprotoserver.sshserver = prehelloserver |
|
116 | wireprotoserver.sshserver = prehelloserver | |
|
117 | elif servermode == b'upgradev2': | |||
|
118 | wireprotoserver.sshserver = upgradev2server | |||
88 | elif servermode: |
|
119 | elif servermode: | |
89 | raise error.ProgrammingError(b'unknown server mode: %s' % servermode) |
|
120 | raise error.ProgrammingError(b'unknown server mode: %s' % servermode) | |
90 |
|
121 | |||
91 | peermode = ui.config(b'sshpeer', b'mode') |
|
122 | peermode = ui.config(b'sshpeer', b'mode') | |
92 |
|
123 | |||
93 | if peermode == b'extra-handshake-commands': |
|
124 | if peermode == b'extra-handshake-commands': | |
94 | extensions.wrapfunction(sshpeer, '_performhandshake', performhandshake) |
|
125 | extensions.wrapfunction(sshpeer, '_performhandshake', performhandshake) | |
95 | elif peermode: |
|
126 | elif peermode: | |
96 | raise error.ProgrammingError(b'unknown peer mode: %s' % peermode) |
|
127 | raise error.ProgrammingError(b'unknown peer mode: %s' % peermode) |
@@ -1,390 +1,494 b'' | |||||
1 | $ cat >> $HGRCPATH << EOF |
|
1 | $ cat >> $HGRCPATH << EOF | |
2 | > [ui] |
|
2 | > [ui] | |
3 | > ssh = $PYTHON "$TESTDIR/dummyssh" |
|
3 | > ssh = $PYTHON "$TESTDIR/dummyssh" | |
4 | > [devel] |
|
4 | > [devel] | |
5 | > debug.peer-request = true |
|
5 | > debug.peer-request = true | |
6 | > [extensions] |
|
6 | > [extensions] | |
7 | > sshprotoext = $TESTDIR/sshprotoext.py |
|
7 | > sshprotoext = $TESTDIR/sshprotoext.py | |
8 | > EOF |
|
8 | > EOF | |
9 |
|
9 | |||
10 | $ hg init server |
|
10 | $ hg init server | |
11 | $ cd server |
|
11 | $ cd server | |
12 | $ echo 0 > foo |
|
12 | $ echo 0 > foo | |
13 | $ hg -q add foo |
|
13 | $ hg -q add foo | |
14 | $ hg commit -m initial |
|
14 | $ hg commit -m initial | |
15 | $ cd .. |
|
15 | $ cd .. | |
16 |
|
16 | |||
17 | Test a normal behaving server, for sanity |
|
17 | Test a normal behaving server, for sanity | |
18 |
|
18 | |||
19 | $ hg --debug debugpeer ssh://user@dummy/server |
|
19 | $ hg --debug debugpeer ssh://user@dummy/server | |
20 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) |
|
20 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |
21 | devel-peer-request: hello |
|
21 | devel-peer-request: hello | |
22 | sending hello command |
|
22 | sending hello command | |
23 | devel-peer-request: between |
|
23 | devel-peer-request: between | |
24 | devel-peer-request: pairs: 81 bytes |
|
24 | devel-peer-request: pairs: 81 bytes | |
25 | sending between command |
|
25 | sending between command | |
26 | remote: 384 |
|
26 | remote: 384 | |
27 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
27 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
28 | remote: 1 |
|
28 | remote: 1 | |
29 | url: ssh://user@dummy/server |
|
29 | url: ssh://user@dummy/server | |
30 | local: no |
|
30 | local: no | |
31 | pushable: yes |
|
31 | pushable: yes | |
32 |
|
32 | |||
33 | Server should answer the "hello" command in isolation |
|
33 | Server should answer the "hello" command in isolation | |
34 |
|
34 | |||
35 | $ hg -R server serve --stdio << EOF |
|
35 | $ hg -R server serve --stdio << EOF | |
36 | > hello |
|
36 | > hello | |
37 | > EOF |
|
37 | > EOF | |
38 | 384 |
|
38 | 384 | |
39 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
39 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
40 |
|
40 | |||
41 | >=0.9.1 clients send a "hello" + "between" for the null range as part of handshake. |
|
41 | >=0.9.1 clients send a "hello" + "between" for the null range as part of handshake. | |
42 | Server should reply with capabilities and should send "1\n\n" as a successful |
|
42 | Server should reply with capabilities and should send "1\n\n" as a successful | |
43 | reply with empty response to the "between". |
|
43 | reply with empty response to the "between". | |
44 |
|
44 | |||
45 | $ hg -R server serve --stdio << EOF |
|
45 | $ hg -R server serve --stdio << EOF | |
46 | > hello |
|
46 | > hello | |
47 | > between |
|
47 | > between | |
48 | > pairs 81 |
|
48 | > pairs 81 | |
49 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
49 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
50 | > EOF |
|
50 | > EOF | |
51 | 384 |
|
51 | 384 | |
52 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
52 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
53 | 1 |
|
53 | 1 | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | SSH banner is not printed by default, ignored by clients |
|
56 | SSH banner is not printed by default, ignored by clients | |
57 |
|
57 | |||
58 | $ SSHSERVERMODE=banner hg debugpeer ssh://user@dummy/server |
|
58 | $ SSHSERVERMODE=banner hg debugpeer ssh://user@dummy/server | |
59 | url: ssh://user@dummy/server |
|
59 | url: ssh://user@dummy/server | |
60 | local: no |
|
60 | local: no | |
61 | pushable: yes |
|
61 | pushable: yes | |
62 |
|
62 | |||
63 | --debug will print the banner |
|
63 | --debug will print the banner | |
64 |
|
64 | |||
65 | $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server |
|
65 | $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server | |
66 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) |
|
66 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |
67 | devel-peer-request: hello |
|
67 | devel-peer-request: hello | |
68 | sending hello command |
|
68 | sending hello command | |
69 | devel-peer-request: between |
|
69 | devel-peer-request: between | |
70 | devel-peer-request: pairs: 81 bytes |
|
70 | devel-peer-request: pairs: 81 bytes | |
71 | sending between command |
|
71 | sending between command | |
72 | remote: banner: line 0 |
|
72 | remote: banner: line 0 | |
73 | remote: banner: line 1 |
|
73 | remote: banner: line 1 | |
74 | remote: banner: line 2 |
|
74 | remote: banner: line 2 | |
75 | remote: banner: line 3 |
|
75 | remote: banner: line 3 | |
76 | remote: banner: line 4 |
|
76 | remote: banner: line 4 | |
77 | remote: banner: line 5 |
|
77 | remote: banner: line 5 | |
78 | remote: banner: line 6 |
|
78 | remote: banner: line 6 | |
79 | remote: banner: line 7 |
|
79 | remote: banner: line 7 | |
80 | remote: banner: line 8 |
|
80 | remote: banner: line 8 | |
81 | remote: banner: line 9 |
|
81 | remote: banner: line 9 | |
82 | remote: 384 |
|
82 | remote: 384 | |
83 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
83 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
84 | remote: 1 |
|
84 | remote: 1 | |
85 | url: ssh://user@dummy/server |
|
85 | url: ssh://user@dummy/server | |
86 | local: no |
|
86 | local: no | |
87 | pushable: yes |
|
87 | pushable: yes | |
88 |
|
88 | |||
89 | And test the banner with the raw protocol |
|
89 | And test the banner with the raw protocol | |
90 |
|
90 | |||
91 | $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF |
|
91 | $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF | |
92 | > hello |
|
92 | > hello | |
93 | > between |
|
93 | > between | |
94 | > pairs 81 |
|
94 | > pairs 81 | |
95 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
95 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
96 | > EOF |
|
96 | > EOF | |
97 | banner: line 0 |
|
97 | banner: line 0 | |
98 | banner: line 1 |
|
98 | banner: line 1 | |
99 | banner: line 2 |
|
99 | banner: line 2 | |
100 | banner: line 3 |
|
100 | banner: line 3 | |
101 | banner: line 4 |
|
101 | banner: line 4 | |
102 | banner: line 5 |
|
102 | banner: line 5 | |
103 | banner: line 6 |
|
103 | banner: line 6 | |
104 | banner: line 7 |
|
104 | banner: line 7 | |
105 | banner: line 8 |
|
105 | banner: line 8 | |
106 | banner: line 9 |
|
106 | banner: line 9 | |
107 | 384 |
|
107 | 384 | |
108 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
108 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
109 | 1 |
|
109 | 1 | |
110 |
|
110 | |||
111 |
|
111 | |||
112 | Connecting to a <0.9.1 server that doesn't support the hello command. |
|
112 | Connecting to a <0.9.1 server that doesn't support the hello command. | |
113 | The client should refuse, as we dropped support for connecting to such |
|
113 | The client should refuse, as we dropped support for connecting to such | |
114 | servers. |
|
114 | servers. | |
115 |
|
115 | |||
116 | $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server |
|
116 | $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server | |
117 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) |
|
117 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |
118 | devel-peer-request: hello |
|
118 | devel-peer-request: hello | |
119 | sending hello command |
|
119 | sending hello command | |
120 | devel-peer-request: between |
|
120 | devel-peer-request: between | |
121 | devel-peer-request: pairs: 81 bytes |
|
121 | devel-peer-request: pairs: 81 bytes | |
122 | sending between command |
|
122 | sending between command | |
123 | remote: 0 |
|
123 | remote: 0 | |
124 | remote: 1 |
|
124 | remote: 1 | |
125 | abort: no suitable response from remote hg! |
|
125 | abort: no suitable response from remote hg! | |
126 | [255] |
|
126 | [255] | |
127 |
|
127 | |||
128 | Sending an unknown command to the server results in an empty response to that command |
|
128 | Sending an unknown command to the server results in an empty response to that command | |
129 |
|
129 | |||
130 | $ hg -R server serve --stdio << EOF |
|
130 | $ hg -R server serve --stdio << EOF | |
131 | > pre-hello |
|
131 | > pre-hello | |
132 | > hello |
|
132 | > hello | |
133 | > between |
|
133 | > between | |
134 | > pairs 81 |
|
134 | > pairs 81 | |
135 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
135 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
136 | > EOF |
|
136 | > EOF | |
137 | 0 |
|
137 | 0 | |
138 | 384 |
|
138 | 384 | |
139 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
139 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
140 | 1 |
|
140 | 1 | |
141 |
|
141 | |||
142 |
|
142 | |||
143 | $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server |
|
143 | $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server | |
144 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) |
|
144 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |
145 | sending no-args command |
|
145 | sending no-args command | |
146 | devel-peer-request: hello |
|
146 | devel-peer-request: hello | |
147 | sending hello command |
|
147 | sending hello command | |
148 | devel-peer-request: between |
|
148 | devel-peer-request: between | |
149 | devel-peer-request: pairs: 81 bytes |
|
149 | devel-peer-request: pairs: 81 bytes | |
150 | sending between command |
|
150 | sending between command | |
151 | remote: 0 |
|
151 | remote: 0 | |
152 | remote: 384 |
|
152 | remote: 384 | |
153 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
153 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
154 | remote: 1 |
|
154 | remote: 1 | |
155 | url: ssh://user@dummy/server |
|
155 | url: ssh://user@dummy/server | |
156 | local: no |
|
156 | local: no | |
157 | pushable: yes |
|
157 | pushable: yes | |
158 |
|
158 | |||
159 | Send multiple unknown commands before hello |
|
159 | Send multiple unknown commands before hello | |
160 |
|
160 | |||
161 | $ hg -R server serve --stdio << EOF |
|
161 | $ hg -R server serve --stdio << EOF | |
162 | > unknown1 |
|
162 | > unknown1 | |
163 | > unknown2 |
|
163 | > unknown2 | |
164 | > unknown3 |
|
164 | > unknown3 | |
165 | > hello |
|
165 | > hello | |
166 | > between |
|
166 | > between | |
167 | > pairs 81 |
|
167 | > pairs 81 | |
168 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
168 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
169 | > EOF |
|
169 | > EOF | |
170 | 0 |
|
170 | 0 | |
171 | 0 |
|
171 | 0 | |
172 | 0 |
|
172 | 0 | |
173 | 384 |
|
173 | 384 | |
174 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
174 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
175 | 1 |
|
175 | 1 | |
176 |
|
176 | |||
177 |
|
177 | |||
178 | $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server |
|
178 | $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server | |
179 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) |
|
179 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |
180 | sending unknown1 command |
|
180 | sending unknown1 command | |
181 | sending unknown2 command |
|
181 | sending unknown2 command | |
182 | sending unknown3 command |
|
182 | sending unknown3 command | |
183 | devel-peer-request: hello |
|
183 | devel-peer-request: hello | |
184 | sending hello command |
|
184 | sending hello command | |
185 | devel-peer-request: between |
|
185 | devel-peer-request: between | |
186 | devel-peer-request: pairs: 81 bytes |
|
186 | devel-peer-request: pairs: 81 bytes | |
187 | sending between command |
|
187 | sending between command | |
188 | remote: 0 |
|
188 | remote: 0 | |
189 | remote: 0 |
|
189 | remote: 0 | |
190 | remote: 0 |
|
190 | remote: 0 | |
191 | remote: 384 |
|
191 | remote: 384 | |
192 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
192 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
193 | remote: 1 |
|
193 | remote: 1 | |
194 | url: ssh://user@dummy/server |
|
194 | url: ssh://user@dummy/server | |
195 | local: no |
|
195 | local: no | |
196 | pushable: yes |
|
196 | pushable: yes | |
197 |
|
197 | |||
198 | Send an unknown command before hello that has arguments |
|
198 | Send an unknown command before hello that has arguments | |
199 |
|
199 | |||
200 | $ hg -R server serve --stdio << EOF |
|
200 | $ hg -R server serve --stdio << EOF | |
201 | > with-args |
|
201 | > with-args | |
202 | > foo 13 |
|
202 | > foo 13 | |
203 | > value for foo |
|
203 | > value for foo | |
204 | > bar 13 |
|
204 | > bar 13 | |
205 | > value for bar |
|
205 | > value for bar | |
206 | > hello |
|
206 | > hello | |
207 | > between |
|
207 | > between | |
208 | > pairs 81 |
|
208 | > pairs 81 | |
209 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
209 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
210 | > EOF |
|
210 | > EOF | |
211 | 0 |
|
211 | 0 | |
212 | 0 |
|
212 | 0 | |
213 | 0 |
|
213 | 0 | |
214 | 0 |
|
214 | 0 | |
215 | 0 |
|
215 | 0 | |
216 | 384 |
|
216 | 384 | |
217 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
217 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
218 | 1 |
|
218 | 1 | |
219 |
|
219 | |||
220 |
|
220 | |||
221 | Send an unknown command having an argument that looks numeric |
|
221 | Send an unknown command having an argument that looks numeric | |
222 |
|
222 | |||
223 | $ hg -R server serve --stdio << EOF |
|
223 | $ hg -R server serve --stdio << EOF | |
224 | > unknown |
|
224 | > unknown | |
225 | > foo 1 |
|
225 | > foo 1 | |
226 | > 0 |
|
226 | > 0 | |
227 | > hello |
|
227 | > hello | |
228 | > between |
|
228 | > between | |
229 | > pairs 81 |
|
229 | > pairs 81 | |
230 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
230 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
231 | > EOF |
|
231 | > EOF | |
232 | 0 |
|
232 | 0 | |
233 | 0 |
|
233 | 0 | |
234 | 0 |
|
234 | 0 | |
235 | 384 |
|
235 | 384 | |
236 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
236 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
237 | 1 |
|
237 | 1 | |
238 |
|
238 | |||
239 |
|
239 | |||
240 | $ hg -R server serve --stdio << EOF |
|
240 | $ hg -R server serve --stdio << EOF | |
241 | > unknown |
|
241 | > unknown | |
242 | > foo 1 |
|
242 | > foo 1 | |
243 | > 1 |
|
243 | > 1 | |
244 | > hello |
|
244 | > hello | |
245 | > between |
|
245 | > between | |
246 | > pairs 81 |
|
246 | > pairs 81 | |
247 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
247 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
248 | > EOF |
|
248 | > EOF | |
249 | 0 |
|
249 | 0 | |
250 | 0 |
|
250 | 0 | |
251 | 0 |
|
251 | 0 | |
252 | 384 |
|
252 | 384 | |
253 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
253 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
254 | 1 |
|
254 | 1 | |
255 |
|
255 | |||
256 |
|
256 | |||
257 | When sending a dict argument value, it is serialized to |
|
257 | When sending a dict argument value, it is serialized to | |
258 | "<arg> <item count>" followed by "<key> <len>\n<value>" for each item |
|
258 | "<arg> <item count>" followed by "<key> <len>\n<value>" for each item | |
259 | in the dict. |
|
259 | in the dict. | |
260 |
|
260 | |||
261 | Dictionary value for unknown command |
|
261 | Dictionary value for unknown command | |
262 |
|
262 | |||
263 | $ hg -R server serve --stdio << EOF |
|
263 | $ hg -R server serve --stdio << EOF | |
264 | > unknown |
|
264 | > unknown | |
265 | > dict 3 |
|
265 | > dict 3 | |
266 | > key1 3 |
|
266 | > key1 3 | |
267 | > foo |
|
267 | > foo | |
268 | > key2 3 |
|
268 | > key2 3 | |
269 | > bar |
|
269 | > bar | |
270 | > key3 3 |
|
270 | > key3 3 | |
271 | > baz |
|
271 | > baz | |
272 | > hello |
|
272 | > hello | |
273 | > EOF |
|
273 | > EOF | |
274 | 0 |
|
274 | 0 | |
275 | 0 |
|
275 | 0 | |
276 | 0 |
|
276 | 0 | |
277 | 0 |
|
277 | 0 | |
278 | 0 |
|
278 | 0 | |
279 | 0 |
|
279 | 0 | |
280 | 0 |
|
280 | 0 | |
281 | 0 |
|
281 | 0 | |
282 | 384 |
|
282 | 384 | |
283 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
283 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
284 |
|
284 | |||
285 | Incomplete dictionary send |
|
285 | Incomplete dictionary send | |
286 |
|
286 | |||
287 | $ hg -R server serve --stdio << EOF |
|
287 | $ hg -R server serve --stdio << EOF | |
288 | > unknown |
|
288 | > unknown | |
289 | > dict 3 |
|
289 | > dict 3 | |
290 | > key1 3 |
|
290 | > key1 3 | |
291 | > foo |
|
291 | > foo | |
292 | > EOF |
|
292 | > EOF | |
293 | 0 |
|
293 | 0 | |
294 | 0 |
|
294 | 0 | |
295 | 0 |
|
295 | 0 | |
296 | 0 |
|
296 | 0 | |
297 |
|
297 | |||
298 | Incomplete value send |
|
298 | Incomplete value send | |
299 |
|
299 | |||
300 | $ hg -R server serve --stdio << EOF |
|
300 | $ hg -R server serve --stdio << EOF | |
301 | > unknown |
|
301 | > unknown | |
302 | > dict 3 |
|
302 | > dict 3 | |
303 | > key1 3 |
|
303 | > key1 3 | |
304 | > fo |
|
304 | > fo | |
305 | > EOF |
|
305 | > EOF | |
306 | 0 |
|
306 | 0 | |
307 | 0 |
|
307 | 0 | |
308 | 0 |
|
308 | 0 | |
309 | 0 |
|
309 | 0 | |
310 |
|
310 | |||
311 | Send a command line with spaces |
|
311 | Send a command line with spaces | |
312 |
|
312 | |||
313 | $ hg -R server serve --stdio << EOF |
|
313 | $ hg -R server serve --stdio << EOF | |
314 | > unknown withspace |
|
314 | > unknown withspace | |
315 | > hello |
|
315 | > hello | |
316 | > between |
|
316 | > between | |
317 | > pairs 81 |
|
317 | > pairs 81 | |
318 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
318 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
319 | > EOF |
|
319 | > EOF | |
320 | 0 |
|
320 | 0 | |
321 | 384 |
|
321 | 384 | |
322 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
322 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
323 | 1 |
|
323 | 1 | |
324 |
|
324 | |||
325 |
|
325 | |||
326 | $ hg -R server serve --stdio << EOF |
|
326 | $ hg -R server serve --stdio << EOF | |
327 | > unknown with multiple spaces |
|
327 | > unknown with multiple spaces | |
328 | > hello |
|
328 | > hello | |
329 | > between |
|
329 | > between | |
330 | > pairs 81 |
|
330 | > pairs 81 | |
331 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
331 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
332 | > EOF |
|
332 | > EOF | |
333 | 0 |
|
333 | 0 | |
334 | 384 |
|
334 | 384 | |
335 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
335 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
336 | 1 |
|
336 | 1 | |
337 |
|
337 | |||
338 |
|
338 | |||
339 | $ hg -R server serve --stdio << EOF |
|
339 | $ hg -R server serve --stdio << EOF | |
340 | > unknown with spaces |
|
340 | > unknown with spaces | |
341 | > key 10 |
|
341 | > key 10 | |
342 | > some value |
|
342 | > some value | |
343 | > hello |
|
343 | > hello | |
344 | > between |
|
344 | > between | |
345 | > pairs 81 |
|
345 | > pairs 81 | |
346 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 |
|
346 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |
347 | > EOF |
|
347 | > EOF | |
348 | 0 |
|
348 | 0 | |
349 | 0 |
|
349 | 0 | |
350 | 0 |
|
350 | 0 | |
351 | 384 |
|
351 | 384 | |
352 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
352 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
353 | 1 |
|
353 | 1 | |
354 |
|
354 | |||
355 |
|
355 | |||
356 | Send an unknown command after the "between" |
|
356 | Send an unknown command after the "between" | |
357 |
|
357 | |||
358 | $ hg -R server serve --stdio << EOF |
|
358 | $ hg -R server serve --stdio << EOF | |
359 | > hello |
|
359 | > hello | |
360 | > between |
|
360 | > between | |
361 | > pairs 81 |
|
361 | > pairs 81 | |
362 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown |
|
362 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown | |
363 | > EOF |
|
363 | > EOF | |
364 | 384 |
|
364 | 384 | |
365 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
365 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
366 | 1 |
|
366 | 1 | |
367 |
|
367 | |||
368 | 0 |
|
368 | 0 | |
369 |
|
369 | |||
370 | And one with arguments |
|
370 | And one with arguments | |
371 |
|
371 | |||
372 | $ hg -R server serve --stdio << EOF |
|
372 | $ hg -R server serve --stdio << EOF | |
373 | > hello |
|
373 | > hello | |
374 | > between |
|
374 | > between | |
375 | > pairs 81 |
|
375 | > pairs 81 | |
376 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown |
|
376 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown | |
377 | > foo 5 |
|
377 | > foo 5 | |
378 | > value |
|
378 | > value | |
379 | > bar 3 |
|
379 | > bar 3 | |
380 | > baz |
|
380 | > baz | |
381 | > EOF |
|
381 | > EOF | |
382 | 384 |
|
382 | 384 | |
383 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN |
|
383 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |
384 | 1 |
|
384 | 1 | |
385 |
|
385 | |||
386 | 0 |
|
386 | 0 | |
387 | 0 |
|
387 | 0 | |
388 | 0 |
|
388 | 0 | |
389 | 0 |
|
389 | 0 | |
390 | 0 |
|
390 | 0 | |
|
391 | ||||
|
392 | Send an upgrade request to a server that doesn't support that command | |||
|
393 | ||||
|
394 | $ hg -R server serve --stdio << EOF | |||
|
395 | > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2 | |||
|
396 | > hello | |||
|
397 | > between | |||
|
398 | > pairs 81 | |||
|
399 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
400 | > EOF | |||
|
401 | 0 | |||
|
402 | 384 | |||
|
403 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
404 | 1 | |||
|
405 | ||||
|
406 | ||||
|
407 | $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server | |||
|
408 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
409 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
410 | devel-peer-request: hello | |||
|
411 | sending hello command | |||
|
412 | devel-peer-request: between | |||
|
413 | devel-peer-request: pairs: 81 bytes | |||
|
414 | sending between command | |||
|
415 | remote: 0 | |||
|
416 | remote: 384 | |||
|
417 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
418 | remote: 1 | |||
|
419 | url: ssh://user@dummy/server | |||
|
420 | local: no | |||
|
421 | pushable: yes | |||
|
422 | ||||
|
423 | Send an upgrade request to a server that supports upgrade | |||
|
424 | ||||
|
425 | $ SSHSERVERMODE=upgradev2 hg -R server serve --stdio << EOF | |||
|
426 | > upgrade this-is-some-token proto=exp-ssh-v2-0001 | |||
|
427 | > hello | |||
|
428 | > between | |||
|
429 | > pairs 81 | |||
|
430 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
431 | > EOF | |||
|
432 | upgraded this-is-some-token exp-ssh-v2-0001 | |||
|
433 | 383 | |||
|
434 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
435 | ||||
|
436 | $ SSHSERVERMODE=upgradev2 hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server | |||
|
437 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
438 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
439 | devel-peer-request: hello | |||
|
440 | sending hello command | |||
|
441 | devel-peer-request: between | |||
|
442 | devel-peer-request: pairs: 81 bytes | |||
|
443 | sending between command | |||
|
444 | protocol upgraded to exp-ssh-v2-0001 | |||
|
445 | url: ssh://user@dummy/server | |||
|
446 | local: no | |||
|
447 | pushable: yes | |||
|
448 | ||||
|
449 | Verify the peer has capabilities | |||
|
450 | ||||
|
451 | $ SSHSERVERMODE=upgradev2 hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server | |||
|
452 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
453 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
454 | devel-peer-request: hello | |||
|
455 | sending hello command | |||
|
456 | devel-peer-request: between | |||
|
457 | devel-peer-request: pairs: 81 bytes | |||
|
458 | sending between command | |||
|
459 | protocol upgraded to exp-ssh-v2-0001 | |||
|
460 | Main capabilities: | |||
|
461 | batch | |||
|
462 | branchmap | |||
|
463 | $USUAL_BUNDLE2_CAPS_SERVER$ | |||
|
464 | changegroupsubset | |||
|
465 | getbundle | |||
|
466 | known | |||
|
467 | lookup | |||
|
468 | pushkey | |||
|
469 | streamreqs=generaldelta,revlogv1 | |||
|
470 | unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
471 | unbundlehash | |||
|
472 | Bundle2 capabilities: | |||
|
473 | HG20 | |||
|
474 | bookmarks | |||
|
475 | changegroup | |||
|
476 | 01 | |||
|
477 | 02 | |||
|
478 | digests | |||
|
479 | md5 | |||
|
480 | sha1 | |||
|
481 | sha512 | |||
|
482 | error | |||
|
483 | abort | |||
|
484 | unsupportedcontent | |||
|
485 | pushraced | |||
|
486 | pushkey | |||
|
487 | hgtagsfnodes | |||
|
488 | listkeys | |||
|
489 | phases | |||
|
490 | heads | |||
|
491 | pushkey | |||
|
492 | remote-changegroup | |||
|
493 | http | |||
|
494 | https |
General Comments 0
You need to be logged in to leave comments.
Login now