##// END OF EJS Templates
sshpeer: initial definition and implementation of new SSH protocol...
Gregory Szorc -
r35994:48a3a928 default
parent child Browse files
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 2 wire protocol commands:
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()
293
294 # For version 1, we should see a ``capabilities`` line in response to the
295 # ``hello`` command.
296 if protoname == wireprotoserver.SSHV1:
238 for l in reversed(lines):
297 for l in reversed(lines):
239 # Look for response to ``hello`` command. Scan from the back so
298 # Look for response to ``hello`` command. Scan from the back so
240 # we don't misinterpret banner output as the command reply.
299 # we don't misinterpret banner output as the command reply.
241 if l.startswith('capabilities:'):
300 if l.startswith('capabilities:'):
242 caps.update(l[:-1].split(':')[1].split())
301 caps.update(l[:-1].split(':')[1].split())
243 break
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()
244
311
245 # Error if we couldn't find a response to ``hello``. This could
312 capsline = stdout.read(valuelen)
246 # mean:
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