##// END OF EJS Templates
merge with stable
Augie Fackler -
r40972:e06719b7 merge default
parent child Browse files
Show More
@@ -1,1460 +1,1463 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=dynamicdefault,
117 default=dynamicdefault,
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('annotate', 'word-diff',
150 coreconfigitem('annotate', 'word-diff',
151 default=False,
151 default=False,
152 )
152 )
153 coreconfigitem('auth', 'cookiefile',
153 coreconfigitem('auth', 'cookiefile',
154 default=None,
154 default=None,
155 )
155 )
156 # bookmarks.pushing: internal hack for discovery
156 # bookmarks.pushing: internal hack for discovery
157 coreconfigitem('bookmarks', 'pushing',
157 coreconfigitem('bookmarks', 'pushing',
158 default=list,
158 default=list,
159 )
159 )
160 # bundle.mainreporoot: internal hack for bundlerepo
160 # bundle.mainreporoot: internal hack for bundlerepo
161 coreconfigitem('bundle', 'mainreporoot',
161 coreconfigitem('bundle', 'mainreporoot',
162 default='',
162 default='',
163 )
163 )
164 coreconfigitem('censor', 'policy',
164 coreconfigitem('censor', 'policy',
165 default='abort',
165 default='abort',
166 )
166 )
167 coreconfigitem('chgserver', 'idletimeout',
167 coreconfigitem('chgserver', 'idletimeout',
168 default=3600,
168 default=3600,
169 )
169 )
170 coreconfigitem('chgserver', 'skiphash',
170 coreconfigitem('chgserver', 'skiphash',
171 default=False,
171 default=False,
172 )
172 )
173 coreconfigitem('cmdserver', 'log',
173 coreconfigitem('cmdserver', 'log',
174 default=None,
174 default=None,
175 )
175 )
176 coreconfigitem('cmdserver', 'max-log-files',
176 coreconfigitem('cmdserver', 'max-log-files',
177 default=7,
177 default=7,
178 )
178 )
179 coreconfigitem('cmdserver', 'max-log-size',
179 coreconfigitem('cmdserver', 'max-log-size',
180 default='1 MB',
180 default='1 MB',
181 )
181 )
182 coreconfigitem('cmdserver', 'message-encodings',
182 coreconfigitem('cmdserver', 'message-encodings',
183 default=list,
183 default=list,
184 )
184 )
185 coreconfigitem('cmdserver', 'track-log',
185 coreconfigitem('cmdserver', 'track-log',
186 default=lambda: ['chgserver', 'cmdserver'],
186 default=lambda: ['chgserver', 'cmdserver'],
187 )
187 )
188 coreconfigitem('color', '.*',
188 coreconfigitem('color', '.*',
189 default=None,
189 default=None,
190 generic=True,
190 generic=True,
191 )
191 )
192 coreconfigitem('color', 'mode',
192 coreconfigitem('color', 'mode',
193 default='auto',
193 default='auto',
194 )
194 )
195 coreconfigitem('color', 'pagermode',
195 coreconfigitem('color', 'pagermode',
196 default=dynamicdefault,
196 default=dynamicdefault,
197 )
197 )
198 coreconfigitem('commands', 'grep.all-files',
198 coreconfigitem('commands', 'grep.all-files',
199 default=False,
199 default=False,
200 )
200 )
201 coreconfigitem('commands', 'resolve.confirm',
201 coreconfigitem('commands', 'resolve.confirm',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('commands', 'resolve.explicit-re-merge',
204 coreconfigitem('commands', 'resolve.explicit-re-merge',
205 default=False,
205 default=False,
206 )
206 )
207 coreconfigitem('commands', 'resolve.mark-check',
207 coreconfigitem('commands', 'resolve.mark-check',
208 default='none',
208 default='none',
209 )
209 )
210 coreconfigitem('commands', 'show.aliasprefix',
210 coreconfigitem('commands', 'show.aliasprefix',
211 default=list,
211 default=list,
212 )
212 )
213 coreconfigitem('commands', 'status.relative',
213 coreconfigitem('commands', 'status.relative',
214 default=False,
214 default=False,
215 )
215 )
216 coreconfigitem('commands', 'status.skipstates',
216 coreconfigitem('commands', 'status.skipstates',
217 default=[],
217 default=[],
218 )
218 )
219 coreconfigitem('commands', 'status.terse',
219 coreconfigitem('commands', 'status.terse',
220 default='',
220 default='',
221 )
221 )
222 coreconfigitem('commands', 'status.verbose',
222 coreconfigitem('commands', 'status.verbose',
223 default=False,
223 default=False,
224 )
224 )
225 coreconfigitem('commands', 'update.check',
225 coreconfigitem('commands', 'update.check',
226 default=None,
226 default=None,
227 )
227 )
228 coreconfigitem('commands', 'update.requiredest',
228 coreconfigitem('commands', 'update.requiredest',
229 default=False,
229 default=False,
230 )
230 )
231 coreconfigitem('committemplate', '.*',
231 coreconfigitem('committemplate', '.*',
232 default=None,
232 default=None,
233 generic=True,
233 generic=True,
234 )
234 )
235 coreconfigitem('convert', 'bzr.saverev',
235 coreconfigitem('convert', 'bzr.saverev',
236 default=True,
236 default=True,
237 )
237 )
238 coreconfigitem('convert', 'cvsps.cache',
238 coreconfigitem('convert', 'cvsps.cache',
239 default=True,
239 default=True,
240 )
240 )
241 coreconfigitem('convert', 'cvsps.fuzz',
241 coreconfigitem('convert', 'cvsps.fuzz',
242 default=60,
242 default=60,
243 )
243 )
244 coreconfigitem('convert', 'cvsps.logencoding',
244 coreconfigitem('convert', 'cvsps.logencoding',
245 default=None,
245 default=None,
246 )
246 )
247 coreconfigitem('convert', 'cvsps.mergefrom',
247 coreconfigitem('convert', 'cvsps.mergefrom',
248 default=None,
248 default=None,
249 )
249 )
250 coreconfigitem('convert', 'cvsps.mergeto',
250 coreconfigitem('convert', 'cvsps.mergeto',
251 default=None,
251 default=None,
252 )
252 )
253 coreconfigitem('convert', 'git.committeractions',
253 coreconfigitem('convert', 'git.committeractions',
254 default=lambda: ['messagedifferent'],
254 default=lambda: ['messagedifferent'],
255 )
255 )
256 coreconfigitem('convert', 'git.extrakeys',
256 coreconfigitem('convert', 'git.extrakeys',
257 default=list,
257 default=list,
258 )
258 )
259 coreconfigitem('convert', 'git.findcopiesharder',
259 coreconfigitem('convert', 'git.findcopiesharder',
260 default=False,
260 default=False,
261 )
261 )
262 coreconfigitem('convert', 'git.remoteprefix',
262 coreconfigitem('convert', 'git.remoteprefix',
263 default='remote',
263 default='remote',
264 )
264 )
265 coreconfigitem('convert', 'git.renamelimit',
265 coreconfigitem('convert', 'git.renamelimit',
266 default=400,
266 default=400,
267 )
267 )
268 coreconfigitem('convert', 'git.saverev',
268 coreconfigitem('convert', 'git.saverev',
269 default=True,
269 default=True,
270 )
270 )
271 coreconfigitem('convert', 'git.similarity',
271 coreconfigitem('convert', 'git.similarity',
272 default=50,
272 default=50,
273 )
273 )
274 coreconfigitem('convert', 'git.skipsubmodules',
274 coreconfigitem('convert', 'git.skipsubmodules',
275 default=False,
275 default=False,
276 )
276 )
277 coreconfigitem('convert', 'hg.clonebranches',
277 coreconfigitem('convert', 'hg.clonebranches',
278 default=False,
278 default=False,
279 )
279 )
280 coreconfigitem('convert', 'hg.ignoreerrors',
280 coreconfigitem('convert', 'hg.ignoreerrors',
281 default=False,
281 default=False,
282 )
282 )
283 coreconfigitem('convert', 'hg.revs',
283 coreconfigitem('convert', 'hg.revs',
284 default=None,
284 default=None,
285 )
285 )
286 coreconfigitem('convert', 'hg.saverev',
286 coreconfigitem('convert', 'hg.saverev',
287 default=False,
287 default=False,
288 )
288 )
289 coreconfigitem('convert', 'hg.sourcename',
289 coreconfigitem('convert', 'hg.sourcename',
290 default=None,
290 default=None,
291 )
291 )
292 coreconfigitem('convert', 'hg.startrev',
292 coreconfigitem('convert', 'hg.startrev',
293 default=None,
293 default=None,
294 )
294 )
295 coreconfigitem('convert', 'hg.tagsbranch',
295 coreconfigitem('convert', 'hg.tagsbranch',
296 default='default',
296 default='default',
297 )
297 )
298 coreconfigitem('convert', 'hg.usebranchnames',
298 coreconfigitem('convert', 'hg.usebranchnames',
299 default=True,
299 default=True,
300 )
300 )
301 coreconfigitem('convert', 'ignoreancestorcheck',
301 coreconfigitem('convert', 'ignoreancestorcheck',
302 default=False,
302 default=False,
303 )
303 )
304 coreconfigitem('convert', 'localtimezone',
304 coreconfigitem('convert', 'localtimezone',
305 default=False,
305 default=False,
306 )
306 )
307 coreconfigitem('convert', 'p4.encoding',
307 coreconfigitem('convert', 'p4.encoding',
308 default=dynamicdefault,
308 default=dynamicdefault,
309 )
309 )
310 coreconfigitem('convert', 'p4.startrev',
310 coreconfigitem('convert', 'p4.startrev',
311 default=0,
311 default=0,
312 )
312 )
313 coreconfigitem('convert', 'skiptags',
313 coreconfigitem('convert', 'skiptags',
314 default=False,
314 default=False,
315 )
315 )
316 coreconfigitem('convert', 'svn.debugsvnlog',
316 coreconfigitem('convert', 'svn.debugsvnlog',
317 default=True,
317 default=True,
318 )
318 )
319 coreconfigitem('convert', 'svn.trunk',
319 coreconfigitem('convert', 'svn.trunk',
320 default=None,
320 default=None,
321 )
321 )
322 coreconfigitem('convert', 'svn.tags',
322 coreconfigitem('convert', 'svn.tags',
323 default=None,
323 default=None,
324 )
324 )
325 coreconfigitem('convert', 'svn.branches',
325 coreconfigitem('convert', 'svn.branches',
326 default=None,
326 default=None,
327 )
327 )
328 coreconfigitem('convert', 'svn.startrev',
328 coreconfigitem('convert', 'svn.startrev',
329 default=0,
329 default=0,
330 )
330 )
331 coreconfigitem('debug', 'dirstate.delaywrite',
331 coreconfigitem('debug', 'dirstate.delaywrite',
332 default=0,
332 default=0,
333 )
333 )
334 coreconfigitem('defaults', '.*',
334 coreconfigitem('defaults', '.*',
335 default=None,
335 default=None,
336 generic=True,
336 generic=True,
337 )
337 )
338 coreconfigitem('devel', 'all-warnings',
338 coreconfigitem('devel', 'all-warnings',
339 default=False,
339 default=False,
340 )
340 )
341 coreconfigitem('devel', 'bundle2.debug',
341 coreconfigitem('devel', 'bundle2.debug',
342 default=False,
342 default=False,
343 )
343 )
344 coreconfigitem('devel', 'bundle.delta',
344 coreconfigitem('devel', 'bundle.delta',
345 default='',
345 default='',
346 )
346 )
347 coreconfigitem('devel', 'cache-vfs',
347 coreconfigitem('devel', 'cache-vfs',
348 default=None,
348 default=None,
349 )
349 )
350 coreconfigitem('devel', 'check-locks',
350 coreconfigitem('devel', 'check-locks',
351 default=False,
351 default=False,
352 )
352 )
353 coreconfigitem('devel', 'check-relroot',
353 coreconfigitem('devel', 'check-relroot',
354 default=False,
354 default=False,
355 )
355 )
356 coreconfigitem('devel', 'default-date',
356 coreconfigitem('devel', 'default-date',
357 default=None,
357 default=None,
358 )
358 )
359 coreconfigitem('devel', 'deprec-warn',
359 coreconfigitem('devel', 'deprec-warn',
360 default=False,
360 default=False,
361 )
361 )
362 coreconfigitem('devel', 'disableloaddefaultcerts',
362 coreconfigitem('devel', 'disableloaddefaultcerts',
363 default=False,
363 default=False,
364 )
364 )
365 coreconfigitem('devel', 'warn-empty-changegroup',
365 coreconfigitem('devel', 'warn-empty-changegroup',
366 default=False,
366 default=False,
367 )
367 )
368 coreconfigitem('devel', 'legacy.exchange',
368 coreconfigitem('devel', 'legacy.exchange',
369 default=list,
369 default=list,
370 )
370 )
371 coreconfigitem('devel', 'servercafile',
371 coreconfigitem('devel', 'servercafile',
372 default='',
372 default='',
373 )
373 )
374 coreconfigitem('devel', 'serverexactprotocol',
374 coreconfigitem('devel', 'serverexactprotocol',
375 default='',
375 default='',
376 )
376 )
377 coreconfigitem('devel', 'serverrequirecert',
377 coreconfigitem('devel', 'serverrequirecert',
378 default=False,
378 default=False,
379 )
379 )
380 coreconfigitem('devel', 'strip-obsmarkers',
380 coreconfigitem('devel', 'strip-obsmarkers',
381 default=True,
381 default=True,
382 )
382 )
383 coreconfigitem('devel', 'warn-config',
383 coreconfigitem('devel', 'warn-config',
384 default=None,
384 default=None,
385 )
385 )
386 coreconfigitem('devel', 'warn-config-default',
386 coreconfigitem('devel', 'warn-config-default',
387 default=None,
387 default=None,
388 )
388 )
389 coreconfigitem('devel', 'user.obsmarker',
389 coreconfigitem('devel', 'user.obsmarker',
390 default=None,
390 default=None,
391 )
391 )
392 coreconfigitem('devel', 'warn-config-unknown',
392 coreconfigitem('devel', 'warn-config-unknown',
393 default=None,
393 default=None,
394 )
394 )
395 coreconfigitem('devel', 'debug.copies',
395 coreconfigitem('devel', 'debug.copies',
396 default=False,
396 default=False,
397 )
397 )
398 coreconfigitem('devel', 'debug.extensions',
398 coreconfigitem('devel', 'debug.extensions',
399 default=False,
399 default=False,
400 )
400 )
401 coreconfigitem('devel', 'debug.peer-request',
401 coreconfigitem('devel', 'debug.peer-request',
402 default=False,
402 default=False,
403 )
403 )
404 coreconfigitem('diff', 'nodates',
404 coreconfigitem('diff', 'nodates',
405 default=False,
405 default=False,
406 )
406 )
407 coreconfigitem('diff', 'showfunc',
407 coreconfigitem('diff', 'showfunc',
408 default=False,
408 default=False,
409 )
409 )
410 coreconfigitem('diff', 'unified',
410 coreconfigitem('diff', 'unified',
411 default=None,
411 default=None,
412 )
412 )
413 coreconfigitem('diff', 'git',
413 coreconfigitem('diff', 'git',
414 default=False,
414 default=False,
415 )
415 )
416 coreconfigitem('diff', 'ignorews',
416 coreconfigitem('diff', 'ignorews',
417 default=False,
417 default=False,
418 )
418 )
419 coreconfigitem('diff', 'ignorewsamount',
419 coreconfigitem('diff', 'ignorewsamount',
420 default=False,
420 default=False,
421 )
421 )
422 coreconfigitem('diff', 'ignoreblanklines',
422 coreconfigitem('diff', 'ignoreblanklines',
423 default=False,
423 default=False,
424 )
424 )
425 coreconfigitem('diff', 'ignorewseol',
425 coreconfigitem('diff', 'ignorewseol',
426 default=False,
426 default=False,
427 )
427 )
428 coreconfigitem('diff', 'nobinary',
428 coreconfigitem('diff', 'nobinary',
429 default=False,
429 default=False,
430 )
430 )
431 coreconfigitem('diff', 'noprefix',
431 coreconfigitem('diff', 'noprefix',
432 default=False,
432 default=False,
433 )
433 )
434 coreconfigitem('diff', 'word-diff',
434 coreconfigitem('diff', 'word-diff',
435 default=False,
435 default=False,
436 )
436 )
437 coreconfigitem('email', 'bcc',
437 coreconfigitem('email', 'bcc',
438 default=None,
438 default=None,
439 )
439 )
440 coreconfigitem('email', 'cc',
440 coreconfigitem('email', 'cc',
441 default=None,
441 default=None,
442 )
442 )
443 coreconfigitem('email', 'charsets',
443 coreconfigitem('email', 'charsets',
444 default=list,
444 default=list,
445 )
445 )
446 coreconfigitem('email', 'from',
446 coreconfigitem('email', 'from',
447 default=None,
447 default=None,
448 )
448 )
449 coreconfigitem('email', 'method',
449 coreconfigitem('email', 'method',
450 default='smtp',
450 default='smtp',
451 )
451 )
452 coreconfigitem('email', 'reply-to',
452 coreconfigitem('email', 'reply-to',
453 default=None,
453 default=None,
454 )
454 )
455 coreconfigitem('email', 'to',
455 coreconfigitem('email', 'to',
456 default=None,
456 default=None,
457 )
457 )
458 coreconfigitem('experimental', 'archivemetatemplate',
458 coreconfigitem('experimental', 'archivemetatemplate',
459 default=dynamicdefault,
459 default=dynamicdefault,
460 )
460 )
461 coreconfigitem('experimental', 'auto-publish',
461 coreconfigitem('experimental', 'auto-publish',
462 default='publish',
462 default='publish',
463 )
463 )
464 coreconfigitem('experimental', 'bundle-phases',
464 coreconfigitem('experimental', 'bundle-phases',
465 default=False,
465 default=False,
466 )
466 )
467 coreconfigitem('experimental', 'bundle2-advertise',
467 coreconfigitem('experimental', 'bundle2-advertise',
468 default=True,
468 default=True,
469 )
469 )
470 coreconfigitem('experimental', 'bundle2-output-capture',
470 coreconfigitem('experimental', 'bundle2-output-capture',
471 default=False,
471 default=False,
472 )
472 )
473 coreconfigitem('experimental', 'bundle2.pushback',
473 coreconfigitem('experimental', 'bundle2.pushback',
474 default=False,
474 default=False,
475 )
475 )
476 coreconfigitem('experimental', 'bundle2lazylocking',
476 coreconfigitem('experimental', 'bundle2lazylocking',
477 default=False,
477 default=False,
478 )
478 )
479 coreconfigitem('experimental', 'bundlecomplevel',
479 coreconfigitem('experimental', 'bundlecomplevel',
480 default=None,
480 default=None,
481 )
481 )
482 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
482 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
483 default=None,
483 default=None,
484 )
484 )
485 coreconfigitem('experimental', 'bundlecomplevel.gzip',
485 coreconfigitem('experimental', 'bundlecomplevel.gzip',
486 default=None,
486 default=None,
487 )
487 )
488 coreconfigitem('experimental', 'bundlecomplevel.none',
488 coreconfigitem('experimental', 'bundlecomplevel.none',
489 default=None,
489 default=None,
490 )
490 )
491 coreconfigitem('experimental', 'bundlecomplevel.zstd',
491 coreconfigitem('experimental', 'bundlecomplevel.zstd',
492 default=None,
492 default=None,
493 )
493 )
494 coreconfigitem('experimental', 'changegroup3',
494 coreconfigitem('experimental', 'changegroup3',
495 default=False,
495 default=False,
496 )
496 )
497 coreconfigitem('experimental', 'clientcompressionengines',
497 coreconfigitem('experimental', 'clientcompressionengines',
498 default=list,
498 default=list,
499 )
499 )
500 coreconfigitem('experimental', 'copytrace',
500 coreconfigitem('experimental', 'copytrace',
501 default='on',
501 default='on',
502 )
502 )
503 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
503 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
504 default=100,
504 default=100,
505 )
505 )
506 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
506 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
507 default=100,
507 default=100,
508 )
508 )
509 coreconfigitem('experimental', 'crecordtest',
509 coreconfigitem('experimental', 'crecordtest',
510 default=None,
510 default=None,
511 )
511 )
512 coreconfigitem('experimental', 'directaccess',
512 coreconfigitem('experimental', 'directaccess',
513 default=False,
513 default=False,
514 )
514 )
515 coreconfigitem('experimental', 'directaccess.revnums',
515 coreconfigitem('experimental', 'directaccess.revnums',
516 default=False,
516 default=False,
517 )
517 )
518 coreconfigitem('experimental', 'editortmpinhg',
518 coreconfigitem('experimental', 'editortmpinhg',
519 default=False,
519 default=False,
520 )
520 )
521 coreconfigitem('experimental', 'evolution',
521 coreconfigitem('experimental', 'evolution',
522 default=list,
522 default=list,
523 )
523 )
524 coreconfigitem('experimental', 'evolution.allowdivergence',
524 coreconfigitem('experimental', 'evolution.allowdivergence',
525 default=False,
525 default=False,
526 alias=[('experimental', 'allowdivergence')]
526 alias=[('experimental', 'allowdivergence')]
527 )
527 )
528 coreconfigitem('experimental', 'evolution.allowunstable',
528 coreconfigitem('experimental', 'evolution.allowunstable',
529 default=None,
529 default=None,
530 )
530 )
531 coreconfigitem('experimental', 'evolution.createmarkers',
531 coreconfigitem('experimental', 'evolution.createmarkers',
532 default=None,
532 default=None,
533 )
533 )
534 coreconfigitem('experimental', 'evolution.effect-flags',
534 coreconfigitem('experimental', 'evolution.effect-flags',
535 default=True,
535 default=True,
536 alias=[('experimental', 'effect-flags')]
536 alias=[('experimental', 'effect-flags')]
537 )
537 )
538 coreconfigitem('experimental', 'evolution.exchange',
538 coreconfigitem('experimental', 'evolution.exchange',
539 default=None,
539 default=None,
540 )
540 )
541 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
541 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
542 default=False,
542 default=False,
543 )
543 )
544 coreconfigitem('experimental', 'evolution.report-instabilities',
544 coreconfigitem('experimental', 'evolution.report-instabilities',
545 default=True,
545 default=True,
546 )
546 )
547 coreconfigitem('experimental', 'evolution.track-operation',
547 coreconfigitem('experimental', 'evolution.track-operation',
548 default=True,
548 default=True,
549 )
549 )
550 coreconfigitem('experimental', 'maxdeltachainspan',
550 coreconfigitem('experimental', 'maxdeltachainspan',
551 default=-1,
551 default=-1,
552 )
552 )
553 coreconfigitem('experimental', 'mergetempdirprefix',
553 coreconfigitem('experimental', 'mergetempdirprefix',
554 default=None,
554 default=None,
555 )
555 )
556 coreconfigitem('experimental', 'narrow',
556 coreconfigitem('experimental', 'narrow',
557 default=False,
557 default=False,
558 )
558 )
559 coreconfigitem('experimental', 'nonnormalparanoidcheck',
559 coreconfigitem('experimental', 'nonnormalparanoidcheck',
560 default=False,
560 default=False,
561 )
561 )
562 coreconfigitem('experimental', 'exportableenviron',
562 coreconfigitem('experimental', 'exportableenviron',
563 default=list,
563 default=list,
564 )
564 )
565 coreconfigitem('experimental', 'extendedheader.index',
565 coreconfigitem('experimental', 'extendedheader.index',
566 default=None,
566 default=None,
567 )
567 )
568 coreconfigitem('experimental', 'extendedheader.similarity',
568 coreconfigitem('experimental', 'extendedheader.similarity',
569 default=False,
569 default=False,
570 )
570 )
571 coreconfigitem('experimental', 'format.compression',
571 coreconfigitem('experimental', 'format.compression',
572 default='zlib',
572 default='zlib',
573 )
573 )
574 coreconfigitem('experimental', 'graphshorten',
574 coreconfigitem('experimental', 'graphshorten',
575 default=False,
575 default=False,
576 )
576 )
577 coreconfigitem('experimental', 'graphstyle.parent',
577 coreconfigitem('experimental', 'graphstyle.parent',
578 default=dynamicdefault,
578 default=dynamicdefault,
579 )
579 )
580 coreconfigitem('experimental', 'graphstyle.missing',
580 coreconfigitem('experimental', 'graphstyle.missing',
581 default=dynamicdefault,
581 default=dynamicdefault,
582 )
582 )
583 coreconfigitem('experimental', 'graphstyle.grandparent',
583 coreconfigitem('experimental', 'graphstyle.grandparent',
584 default=dynamicdefault,
584 default=dynamicdefault,
585 )
585 )
586 coreconfigitem('experimental', 'hook-track-tags',
586 coreconfigitem('experimental', 'hook-track-tags',
587 default=False,
587 default=False,
588 )
588 )
589 coreconfigitem('experimental', 'httppeer.advertise-v2',
589 coreconfigitem('experimental', 'httppeer.advertise-v2',
590 default=False,
590 default=False,
591 )
591 )
592 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
592 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
593 default=None,
593 default=None,
594 )
594 )
595 coreconfigitem('experimental', 'httppostargs',
595 coreconfigitem('experimental', 'httppostargs',
596 default=False,
596 default=False,
597 )
597 )
598 coreconfigitem('experimental', 'mergedriver',
598 coreconfigitem('experimental', 'mergedriver',
599 default=None,
599 default=None,
600 )
600 )
601 coreconfigitem('experimental', 'nointerrupt', default=False)
601 coreconfigitem('experimental', 'nointerrupt', default=False)
602 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
602 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
603
603
604 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
604 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
605 default=False,
605 default=False,
606 )
606 )
607 coreconfigitem('experimental', 'remotenames',
607 coreconfigitem('experimental', 'remotenames',
608 default=False,
608 default=False,
609 )
609 )
610 coreconfigitem('experimental', 'removeemptydirs',
610 coreconfigitem('experimental', 'removeemptydirs',
611 default=True,
611 default=True,
612 )
612 )
613 coreconfigitem('experimental', 'revisions.prefixhexnode',
613 coreconfigitem('experimental', 'revisions.prefixhexnode',
614 default=False,
614 default=False,
615 )
615 )
616 coreconfigitem('experimental', 'revlogv2',
616 coreconfigitem('experimental', 'revlogv2',
617 default=None,
617 default=None,
618 )
618 )
619 coreconfigitem('experimental', 'revisions.disambiguatewithin',
619 coreconfigitem('experimental', 'revisions.disambiguatewithin',
620 default=None,
620 default=None,
621 )
621 )
622 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
622 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
623 default=50000,
623 default=50000,
624 )
624 )
625 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
625 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
626 default=100000,
626 default=100000,
627 )
627 )
628 coreconfigitem('experimental', 'server.stream-narrow-clones',
628 coreconfigitem('experimental', 'server.stream-narrow-clones',
629 default=False,
629 default=False,
630 )
630 )
631 coreconfigitem('experimental', 'single-head-per-branch',
631 coreconfigitem('experimental', 'single-head-per-branch',
632 default=False,
632 default=False,
633 )
633 )
634 coreconfigitem('experimental', 'sshserver.support-v2',
634 coreconfigitem('experimental', 'sshserver.support-v2',
635 default=False,
635 default=False,
636 )
636 )
637 coreconfigitem('experimental', 'sparse-read',
637 coreconfigitem('experimental', 'sparse-read',
638 default=False,
638 default=False,
639 )
639 )
640 coreconfigitem('experimental', 'sparse-read.density-threshold',
640 coreconfigitem('experimental', 'sparse-read.density-threshold',
641 default=0.50,
641 default=0.50,
642 )
642 )
643 coreconfigitem('experimental', 'sparse-read.min-gap-size',
643 coreconfigitem('experimental', 'sparse-read.min-gap-size',
644 default='65K',
644 default='65K',
645 )
645 )
646 coreconfigitem('experimental', 'treemanifest',
646 coreconfigitem('experimental', 'treemanifest',
647 default=False,
647 default=False,
648 )
648 )
649 coreconfigitem('experimental', 'update.atomic-file',
649 coreconfigitem('experimental', 'update.atomic-file',
650 default=False,
650 default=False,
651 )
651 )
652 coreconfigitem('experimental', 'sshpeer.advertise-v2',
652 coreconfigitem('experimental', 'sshpeer.advertise-v2',
653 default=False,
653 default=False,
654 )
654 )
655 coreconfigitem('experimental', 'web.apiserver',
655 coreconfigitem('experimental', 'web.apiserver',
656 default=False,
656 default=False,
657 )
657 )
658 coreconfigitem('experimental', 'web.api.http-v2',
658 coreconfigitem('experimental', 'web.api.http-v2',
659 default=False,
659 default=False,
660 )
660 )
661 coreconfigitem('experimental', 'web.api.debugreflect',
661 coreconfigitem('experimental', 'web.api.debugreflect',
662 default=False,
662 default=False,
663 )
663 )
664 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
664 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
665 default=False,
665 default=False,
666 )
666 )
667 coreconfigitem('experimental', 'xdiff',
667 coreconfigitem('experimental', 'xdiff',
668 default=False,
668 default=False,
669 )
669 )
670 coreconfigitem('extensions', '.*',
670 coreconfigitem('extensions', '.*',
671 default=None,
671 default=None,
672 generic=True,
672 generic=True,
673 )
673 )
674 coreconfigitem('extdata', '.*',
674 coreconfigitem('extdata', '.*',
675 default=None,
675 default=None,
676 generic=True,
676 generic=True,
677 )
677 )
678 coreconfigitem('format', 'chunkcachesize',
678 coreconfigitem('format', 'chunkcachesize',
679 default=None,
679 default=None,
680 )
680 )
681 coreconfigitem('format', 'dotencode',
681 coreconfigitem('format', 'dotencode',
682 default=True,
682 default=True,
683 )
683 )
684 coreconfigitem('format', 'generaldelta',
684 coreconfigitem('format', 'generaldelta',
685 default=False,
685 default=False,
686 )
686 )
687 coreconfigitem('format', 'manifestcachesize',
687 coreconfigitem('format', 'manifestcachesize',
688 default=None,
688 default=None,
689 )
689 )
690 coreconfigitem('format', 'maxchainlen',
690 coreconfigitem('format', 'maxchainlen',
691 default=dynamicdefault,
691 default=dynamicdefault,
692 )
692 )
693 coreconfigitem('format', 'obsstore-version',
693 coreconfigitem('format', 'obsstore-version',
694 default=None,
694 default=None,
695 )
695 )
696 coreconfigitem('format', 'sparse-revlog',
696 coreconfigitem('format', 'sparse-revlog',
697 default=True,
697 default=True,
698 )
698 )
699 coreconfigitem('format', 'usefncache',
699 coreconfigitem('format', 'usefncache',
700 default=True,
700 default=True,
701 )
701 )
702 coreconfigitem('format', 'usegeneraldelta',
702 coreconfigitem('format', 'usegeneraldelta',
703 default=True,
703 default=True,
704 )
704 )
705 coreconfigitem('format', 'usestore',
705 coreconfigitem('format', 'usestore',
706 default=True,
706 default=True,
707 )
707 )
708 coreconfigitem('format', 'internal-phase',
708 coreconfigitem('format', 'internal-phase',
709 default=False,
709 default=False,
710 )
710 )
711 coreconfigitem('fsmonitor', 'warn_when_unused',
711 coreconfigitem('fsmonitor', 'warn_when_unused',
712 default=True,
712 default=True,
713 )
713 )
714 coreconfigitem('fsmonitor', 'warn_update_file_count',
714 coreconfigitem('fsmonitor', 'warn_update_file_count',
715 default=50000,
715 default=50000,
716 )
716 )
717 coreconfigitem('help', 'hidden-command\..*',
717 coreconfigitem('help', 'hidden-command\..*',
718 default=False,
718 default=False,
719 generic=True,
719 generic=True,
720 )
720 )
721 coreconfigitem('help', 'hidden-topic\..*',
721 coreconfigitem('help', 'hidden-topic\..*',
722 default=False,
722 default=False,
723 generic=True,
723 generic=True,
724 )
724 )
725 coreconfigitem('hooks', '.*',
725 coreconfigitem('hooks', '.*',
726 default=dynamicdefault,
726 default=dynamicdefault,
727 generic=True,
727 generic=True,
728 )
728 )
729 coreconfigitem('hgweb-paths', '.*',
729 coreconfigitem('hgweb-paths', '.*',
730 default=list,
730 default=list,
731 generic=True,
731 generic=True,
732 )
732 )
733 coreconfigitem('hostfingerprints', '.*',
733 coreconfigitem('hostfingerprints', '.*',
734 default=list,
734 default=list,
735 generic=True,
735 generic=True,
736 )
736 )
737 coreconfigitem('hostsecurity', 'ciphers',
737 coreconfigitem('hostsecurity', 'ciphers',
738 default=None,
738 default=None,
739 )
739 )
740 coreconfigitem('hostsecurity', 'disabletls10warning',
740 coreconfigitem('hostsecurity', 'disabletls10warning',
741 default=False,
741 default=False,
742 )
742 )
743 coreconfigitem('hostsecurity', 'minimumprotocol',
743 coreconfigitem('hostsecurity', 'minimumprotocol',
744 default=dynamicdefault,
744 default=dynamicdefault,
745 )
745 )
746 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
746 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
747 default=dynamicdefault,
747 default=dynamicdefault,
748 generic=True,
748 generic=True,
749 )
749 )
750 coreconfigitem('hostsecurity', '.*:ciphers$',
750 coreconfigitem('hostsecurity', '.*:ciphers$',
751 default=dynamicdefault,
751 default=dynamicdefault,
752 generic=True,
752 generic=True,
753 )
753 )
754 coreconfigitem('hostsecurity', '.*:fingerprints$',
754 coreconfigitem('hostsecurity', '.*:fingerprints$',
755 default=list,
755 default=list,
756 generic=True,
756 generic=True,
757 )
757 )
758 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
758 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
759 default=None,
759 default=None,
760 generic=True,
760 generic=True,
761 )
761 )
762
762
763 coreconfigitem('http_proxy', 'always',
763 coreconfigitem('http_proxy', 'always',
764 default=False,
764 default=False,
765 )
765 )
766 coreconfigitem('http_proxy', 'host',
766 coreconfigitem('http_proxy', 'host',
767 default=None,
767 default=None,
768 )
768 )
769 coreconfigitem('http_proxy', 'no',
769 coreconfigitem('http_proxy', 'no',
770 default=list,
770 default=list,
771 )
771 )
772 coreconfigitem('http_proxy', 'passwd',
772 coreconfigitem('http_proxy', 'passwd',
773 default=None,
773 default=None,
774 )
774 )
775 coreconfigitem('http_proxy', 'user',
775 coreconfigitem('http_proxy', 'user',
776 default=None,
776 default=None,
777 )
777 )
778
778
779 coreconfigitem('http', 'timeout',
779 coreconfigitem('http', 'timeout',
780 default=None,
780 default=None,
781 )
781 )
782
782
783 coreconfigitem('logtoprocess', 'commandexception',
783 coreconfigitem('logtoprocess', 'commandexception',
784 default=None,
784 default=None,
785 )
785 )
786 coreconfigitem('logtoprocess', 'commandfinish',
786 coreconfigitem('logtoprocess', 'commandfinish',
787 default=None,
787 default=None,
788 )
788 )
789 coreconfigitem('logtoprocess', 'command',
789 coreconfigitem('logtoprocess', 'command',
790 default=None,
790 default=None,
791 )
791 )
792 coreconfigitem('logtoprocess', 'develwarn',
792 coreconfigitem('logtoprocess', 'develwarn',
793 default=None,
793 default=None,
794 )
794 )
795 coreconfigitem('logtoprocess', 'uiblocked',
795 coreconfigitem('logtoprocess', 'uiblocked',
796 default=None,
796 default=None,
797 )
797 )
798 coreconfigitem('merge', 'checkunknown',
798 coreconfigitem('merge', 'checkunknown',
799 default='abort',
799 default='abort',
800 )
800 )
801 coreconfigitem('merge', 'checkignored',
801 coreconfigitem('merge', 'checkignored',
802 default='abort',
802 default='abort',
803 )
803 )
804 coreconfigitem('experimental', 'merge.checkpathconflicts',
804 coreconfigitem('experimental', 'merge.checkpathconflicts',
805 default=False,
805 default=False,
806 )
806 )
807 coreconfigitem('merge', 'followcopies',
807 coreconfigitem('merge', 'followcopies',
808 default=True,
808 default=True,
809 )
809 )
810 coreconfigitem('merge', 'on-failure',
810 coreconfigitem('merge', 'on-failure',
811 default='continue',
811 default='continue',
812 )
812 )
813 coreconfigitem('merge', 'preferancestor',
813 coreconfigitem('merge', 'preferancestor',
814 default=lambda: ['*'],
814 default=lambda: ['*'],
815 )
815 )
816 coreconfigitem('merge', 'strict-capability-check',
816 coreconfigitem('merge', 'strict-capability-check',
817 default=False,
817 default=False,
818 )
818 )
819 coreconfigitem('merge-tools', '.*',
819 coreconfigitem('merge-tools', '.*',
820 default=None,
820 default=None,
821 generic=True,
821 generic=True,
822 )
822 )
823 coreconfigitem('merge-tools', br'.*\.args$',
823 coreconfigitem('merge-tools', br'.*\.args$',
824 default="$local $base $other",
824 default="$local $base $other",
825 generic=True,
825 generic=True,
826 priority=-1,
826 priority=-1,
827 )
827 )
828 coreconfigitem('merge-tools', br'.*\.binary$',
828 coreconfigitem('merge-tools', br'.*\.binary$',
829 default=False,
829 default=False,
830 generic=True,
830 generic=True,
831 priority=-1,
831 priority=-1,
832 )
832 )
833 coreconfigitem('merge-tools', br'.*\.check$',
833 coreconfigitem('merge-tools', br'.*\.check$',
834 default=list,
834 default=list,
835 generic=True,
835 generic=True,
836 priority=-1,
836 priority=-1,
837 )
837 )
838 coreconfigitem('merge-tools', br'.*\.checkchanged$',
838 coreconfigitem('merge-tools', br'.*\.checkchanged$',
839 default=False,
839 default=False,
840 generic=True,
840 generic=True,
841 priority=-1,
841 priority=-1,
842 )
842 )
843 coreconfigitem('merge-tools', br'.*\.executable$',
843 coreconfigitem('merge-tools', br'.*\.executable$',
844 default=dynamicdefault,
844 default=dynamicdefault,
845 generic=True,
845 generic=True,
846 priority=-1,
846 priority=-1,
847 )
847 )
848 coreconfigitem('merge-tools', br'.*\.fixeol$',
848 coreconfigitem('merge-tools', br'.*\.fixeol$',
849 default=False,
849 default=False,
850 generic=True,
850 generic=True,
851 priority=-1,
851 priority=-1,
852 )
852 )
853 coreconfigitem('merge-tools', br'.*\.gui$',
853 coreconfigitem('merge-tools', br'.*\.gui$',
854 default=False,
854 default=False,
855 generic=True,
855 generic=True,
856 priority=-1,
856 priority=-1,
857 )
857 )
858 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
858 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
859 default='basic',
859 default='basic',
860 generic=True,
860 generic=True,
861 priority=-1,
861 priority=-1,
862 )
862 )
863 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
863 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
864 default=dynamicdefault, # take from ui.mergemarkertemplate
864 default=dynamicdefault, # take from ui.mergemarkertemplate
865 generic=True,
865 generic=True,
866 priority=-1,
866 priority=-1,
867 )
867 )
868 coreconfigitem('merge-tools', br'.*\.priority$',
868 coreconfigitem('merge-tools', br'.*\.priority$',
869 default=0,
869 default=0,
870 generic=True,
870 generic=True,
871 priority=-1,
871 priority=-1,
872 )
872 )
873 coreconfigitem('merge-tools', br'.*\.premerge$',
873 coreconfigitem('merge-tools', br'.*\.premerge$',
874 default=dynamicdefault,
874 default=dynamicdefault,
875 generic=True,
875 generic=True,
876 priority=-1,
876 priority=-1,
877 )
877 )
878 coreconfigitem('merge-tools', br'.*\.symlink$',
878 coreconfigitem('merge-tools', br'.*\.symlink$',
879 default=False,
879 default=False,
880 generic=True,
880 generic=True,
881 priority=-1,
881 priority=-1,
882 )
882 )
883 coreconfigitem('pager', 'attend-.*',
883 coreconfigitem('pager', 'attend-.*',
884 default=dynamicdefault,
884 default=dynamicdefault,
885 generic=True,
885 generic=True,
886 )
886 )
887 coreconfigitem('pager', 'ignore',
887 coreconfigitem('pager', 'ignore',
888 default=list,
888 default=list,
889 )
889 )
890 coreconfigitem('pager', 'pager',
890 coreconfigitem('pager', 'pager',
891 default=dynamicdefault,
891 default=dynamicdefault,
892 )
892 )
893 coreconfigitem('patch', 'eol',
893 coreconfigitem('patch', 'eol',
894 default='strict',
894 default='strict',
895 )
895 )
896 coreconfigitem('patch', 'fuzz',
896 coreconfigitem('patch', 'fuzz',
897 default=2,
897 default=2,
898 )
898 )
899 coreconfigitem('paths', 'default',
899 coreconfigitem('paths', 'default',
900 default=None,
900 default=None,
901 )
901 )
902 coreconfigitem('paths', 'default-push',
902 coreconfigitem('paths', 'default-push',
903 default=None,
903 default=None,
904 )
904 )
905 coreconfigitem('paths', '.*',
905 coreconfigitem('paths', '.*',
906 default=None,
906 default=None,
907 generic=True,
907 generic=True,
908 )
908 )
909 coreconfigitem('phases', 'checksubrepos',
909 coreconfigitem('phases', 'checksubrepos',
910 default='follow',
910 default='follow',
911 )
911 )
912 coreconfigitem('phases', 'new-commit',
912 coreconfigitem('phases', 'new-commit',
913 default='draft',
913 default='draft',
914 )
914 )
915 coreconfigitem('phases', 'publish',
915 coreconfigitem('phases', 'publish',
916 default=True,
916 default=True,
917 )
917 )
918 coreconfigitem('profiling', 'enabled',
918 coreconfigitem('profiling', 'enabled',
919 default=False,
919 default=False,
920 )
920 )
921 coreconfigitem('profiling', 'format',
921 coreconfigitem('profiling', 'format',
922 default='text',
922 default='text',
923 )
923 )
924 coreconfigitem('profiling', 'freq',
924 coreconfigitem('profiling', 'freq',
925 default=1000,
925 default=1000,
926 )
926 )
927 coreconfigitem('profiling', 'limit',
927 coreconfigitem('profiling', 'limit',
928 default=30,
928 default=30,
929 )
929 )
930 coreconfigitem('profiling', 'nested',
930 coreconfigitem('profiling', 'nested',
931 default=0,
931 default=0,
932 )
932 )
933 coreconfigitem('profiling', 'output',
933 coreconfigitem('profiling', 'output',
934 default=None,
934 default=None,
935 )
935 )
936 coreconfigitem('profiling', 'showmax',
936 coreconfigitem('profiling', 'showmax',
937 default=0.999,
937 default=0.999,
938 )
938 )
939 coreconfigitem('profiling', 'showmin',
939 coreconfigitem('profiling', 'showmin',
940 default=dynamicdefault,
940 default=dynamicdefault,
941 )
941 )
942 coreconfigitem('profiling', 'sort',
942 coreconfigitem('profiling', 'sort',
943 default='inlinetime',
943 default='inlinetime',
944 )
944 )
945 coreconfigitem('profiling', 'statformat',
945 coreconfigitem('profiling', 'statformat',
946 default='hotpath',
946 default='hotpath',
947 )
947 )
948 coreconfigitem('profiling', 'time-track',
948 coreconfigitem('profiling', 'time-track',
949 default=dynamicdefault,
949 default=dynamicdefault,
950 )
950 )
951 coreconfigitem('profiling', 'type',
951 coreconfigitem('profiling', 'type',
952 default='stat',
952 default='stat',
953 )
953 )
954 coreconfigitem('progress', 'assume-tty',
954 coreconfigitem('progress', 'assume-tty',
955 default=False,
955 default=False,
956 )
956 )
957 coreconfigitem('progress', 'changedelay',
957 coreconfigitem('progress', 'changedelay',
958 default=1,
958 default=1,
959 )
959 )
960 coreconfigitem('progress', 'clear-complete',
960 coreconfigitem('progress', 'clear-complete',
961 default=True,
961 default=True,
962 )
962 )
963 coreconfigitem('progress', 'debug',
963 coreconfigitem('progress', 'debug',
964 default=False,
964 default=False,
965 )
965 )
966 coreconfigitem('progress', 'delay',
966 coreconfigitem('progress', 'delay',
967 default=3,
967 default=3,
968 )
968 )
969 coreconfigitem('progress', 'disable',
969 coreconfigitem('progress', 'disable',
970 default=False,
970 default=False,
971 )
971 )
972 coreconfigitem('progress', 'estimateinterval',
972 coreconfigitem('progress', 'estimateinterval',
973 default=60.0,
973 default=60.0,
974 )
974 )
975 coreconfigitem('progress', 'format',
975 coreconfigitem('progress', 'format',
976 default=lambda: ['topic', 'bar', 'number', 'estimate'],
976 default=lambda: ['topic', 'bar', 'number', 'estimate'],
977 )
977 )
978 coreconfigitem('progress', 'refresh',
978 coreconfigitem('progress', 'refresh',
979 default=0.1,
979 default=0.1,
980 )
980 )
981 coreconfigitem('progress', 'width',
981 coreconfigitem('progress', 'width',
982 default=dynamicdefault,
982 default=dynamicdefault,
983 )
983 )
984 coreconfigitem('push', 'pushvars.server',
984 coreconfigitem('push', 'pushvars.server',
985 default=False,
985 default=False,
986 )
986 )
987 coreconfigitem('storage', 'mmap-threshold',
987 coreconfigitem('storage', 'mmap-threshold',
988 default='1MB',
988 default='1MB',
989 alias=[('experimental', 'mmapindexthreshold')],
989 alias=[('experimental', 'mmapindexthreshold')],
990 )
990 )
991 coreconfigitem('storage', 'new-repo-backend',
991 coreconfigitem('storage', 'new-repo-backend',
992 default='revlogv1',
992 default='revlogv1',
993 )
993 )
994 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
994 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
995 default=True,
995 default=True,
996 alias=[('format', 'aggressivemergedeltas')],
996 alias=[('format', 'aggressivemergedeltas')],
997 )
997 )
998 coreconfigitem('server', 'bookmarks-pushkey-compat',
998 coreconfigitem('server', 'bookmarks-pushkey-compat',
999 default=True,
999 default=True,
1000 )
1000 )
1001 coreconfigitem('server', 'bundle1',
1001 coreconfigitem('server', 'bundle1',
1002 default=True,
1002 default=True,
1003 )
1003 )
1004 coreconfigitem('server', 'bundle1gd',
1004 coreconfigitem('server', 'bundle1gd',
1005 default=None,
1005 default=None,
1006 )
1006 )
1007 coreconfigitem('server', 'bundle1.pull',
1007 coreconfigitem('server', 'bundle1.pull',
1008 default=None,
1008 default=None,
1009 )
1009 )
1010 coreconfigitem('server', 'bundle1gd.pull',
1010 coreconfigitem('server', 'bundle1gd.pull',
1011 default=None,
1011 default=None,
1012 )
1012 )
1013 coreconfigitem('server', 'bundle1.push',
1013 coreconfigitem('server', 'bundle1.push',
1014 default=None,
1014 default=None,
1015 )
1015 )
1016 coreconfigitem('server', 'bundle1gd.push',
1016 coreconfigitem('server', 'bundle1gd.push',
1017 default=None,
1017 default=None,
1018 )
1018 )
1019 coreconfigitem('server', 'bundle2.stream',
1019 coreconfigitem('server', 'bundle2.stream',
1020 default=True,
1020 default=True,
1021 alias=[('experimental', 'bundle2.stream')]
1021 alias=[('experimental', 'bundle2.stream')]
1022 )
1022 )
1023 coreconfigitem('server', 'compressionengines',
1023 coreconfigitem('server', 'compressionengines',
1024 default=list,
1024 default=list,
1025 )
1025 )
1026 coreconfigitem('server', 'concurrent-push-mode',
1026 coreconfigitem('server', 'concurrent-push-mode',
1027 default='strict',
1027 default='strict',
1028 )
1028 )
1029 coreconfigitem('server', 'disablefullbundle',
1029 coreconfigitem('server', 'disablefullbundle',
1030 default=False,
1030 default=False,
1031 )
1031 )
1032 coreconfigitem('server', 'maxhttpheaderlen',
1032 coreconfigitem('server', 'maxhttpheaderlen',
1033 default=1024,
1033 default=1024,
1034 )
1034 )
1035 coreconfigitem('server', 'pullbundle',
1035 coreconfigitem('server', 'pullbundle',
1036 default=False,
1036 default=False,
1037 )
1037 )
1038 coreconfigitem('server', 'preferuncompressed',
1038 coreconfigitem('server', 'preferuncompressed',
1039 default=False,
1039 default=False,
1040 )
1040 )
1041 coreconfigitem('server', 'streamunbundle',
1041 coreconfigitem('server', 'streamunbundle',
1042 default=False,
1042 default=False,
1043 )
1043 )
1044 coreconfigitem('server', 'uncompressed',
1044 coreconfigitem('server', 'uncompressed',
1045 default=True,
1045 default=True,
1046 )
1046 )
1047 coreconfigitem('server', 'uncompressedallowsecret',
1047 coreconfigitem('server', 'uncompressedallowsecret',
1048 default=False,
1048 default=False,
1049 )
1049 )
1050 coreconfigitem('server', 'validate',
1050 coreconfigitem('server', 'validate',
1051 default=False,
1051 default=False,
1052 )
1052 )
1053 coreconfigitem('server', 'zliblevel',
1053 coreconfigitem('server', 'zliblevel',
1054 default=-1,
1054 default=-1,
1055 )
1055 )
1056 coreconfigitem('server', 'zstdlevel',
1056 coreconfigitem('server', 'zstdlevel',
1057 default=3,
1057 default=3,
1058 )
1058 )
1059 coreconfigitem('share', 'pool',
1059 coreconfigitem('share', 'pool',
1060 default=None,
1060 default=None,
1061 )
1061 )
1062 coreconfigitem('share', 'poolnaming',
1062 coreconfigitem('share', 'poolnaming',
1063 default='identity',
1063 default='identity',
1064 )
1064 )
1065 coreconfigitem('smtp', 'host',
1065 coreconfigitem('smtp', 'host',
1066 default=None,
1066 default=None,
1067 )
1067 )
1068 coreconfigitem('smtp', 'local_hostname',
1068 coreconfigitem('smtp', 'local_hostname',
1069 default=None,
1069 default=None,
1070 )
1070 )
1071 coreconfigitem('smtp', 'password',
1071 coreconfigitem('smtp', 'password',
1072 default=None,
1072 default=None,
1073 )
1073 )
1074 coreconfigitem('smtp', 'port',
1074 coreconfigitem('smtp', 'port',
1075 default=dynamicdefault,
1075 default=dynamicdefault,
1076 )
1076 )
1077 coreconfigitem('smtp', 'tls',
1077 coreconfigitem('smtp', 'tls',
1078 default='none',
1078 default='none',
1079 )
1079 )
1080 coreconfigitem('smtp', 'username',
1080 coreconfigitem('smtp', 'username',
1081 default=None,
1081 default=None,
1082 )
1082 )
1083 coreconfigitem('sparse', 'missingwarning',
1083 coreconfigitem('sparse', 'missingwarning',
1084 default=True,
1084 default=True,
1085 )
1085 )
1086 coreconfigitem('subrepos', 'allowed',
1086 coreconfigitem('subrepos', 'allowed',
1087 default=dynamicdefault, # to make backporting simpler
1087 default=dynamicdefault, # to make backporting simpler
1088 )
1088 )
1089 coreconfigitem('subrepos', 'hg:allowed',
1089 coreconfigitem('subrepos', 'hg:allowed',
1090 default=dynamicdefault,
1090 default=dynamicdefault,
1091 )
1091 )
1092 coreconfigitem('subrepos', 'git:allowed',
1092 coreconfigitem('subrepos', 'git:allowed',
1093 default=dynamicdefault,
1093 default=dynamicdefault,
1094 )
1094 )
1095 coreconfigitem('subrepos', 'svn:allowed',
1095 coreconfigitem('subrepos', 'svn:allowed',
1096 default=dynamicdefault,
1096 default=dynamicdefault,
1097 )
1097 )
1098 coreconfigitem('templates', '.*',
1098 coreconfigitem('templates', '.*',
1099 default=None,
1099 default=None,
1100 generic=True,
1100 generic=True,
1101 )
1101 )
1102 coreconfigitem('trusted', 'groups',
1102 coreconfigitem('trusted', 'groups',
1103 default=list,
1103 default=list,
1104 )
1104 )
1105 coreconfigitem('trusted', 'users',
1105 coreconfigitem('trusted', 'users',
1106 default=list,
1106 default=list,
1107 )
1107 )
1108 coreconfigitem('ui', '_usedassubrepo',
1108 coreconfigitem('ui', '_usedassubrepo',
1109 default=False,
1109 default=False,
1110 )
1110 )
1111 coreconfigitem('ui', 'allowemptycommit',
1111 coreconfigitem('ui', 'allowemptycommit',
1112 default=False,
1112 default=False,
1113 )
1113 )
1114 coreconfigitem('ui', 'archivemeta',
1114 coreconfigitem('ui', 'archivemeta',
1115 default=True,
1115 default=True,
1116 )
1116 )
1117 coreconfigitem('ui', 'askusername',
1117 coreconfigitem('ui', 'askusername',
1118 default=False,
1118 default=False,
1119 )
1119 )
1120 coreconfigitem('ui', 'clonebundlefallback',
1120 coreconfigitem('ui', 'clonebundlefallback',
1121 default=False,
1121 default=False,
1122 )
1122 )
1123 coreconfigitem('ui', 'clonebundleprefers',
1123 coreconfigitem('ui', 'clonebundleprefers',
1124 default=list,
1124 default=list,
1125 )
1125 )
1126 coreconfigitem('ui', 'clonebundles',
1126 coreconfigitem('ui', 'clonebundles',
1127 default=True,
1127 default=True,
1128 )
1128 )
1129 coreconfigitem('ui', 'color',
1129 coreconfigitem('ui', 'color',
1130 default='auto',
1130 default='auto',
1131 )
1131 )
1132 coreconfigitem('ui', 'commitsubrepos',
1132 coreconfigitem('ui', 'commitsubrepos',
1133 default=False,
1133 default=False,
1134 )
1134 )
1135 coreconfigitem('ui', 'debug',
1135 coreconfigitem('ui', 'debug',
1136 default=False,
1136 default=False,
1137 )
1137 )
1138 coreconfigitem('ui', 'debugger',
1138 coreconfigitem('ui', 'debugger',
1139 default=None,
1139 default=None,
1140 )
1140 )
1141 coreconfigitem('ui', 'editor',
1141 coreconfigitem('ui', 'editor',
1142 default=dynamicdefault,
1142 default=dynamicdefault,
1143 )
1143 )
1144 coreconfigitem('ui', 'fallbackencoding',
1144 coreconfigitem('ui', 'fallbackencoding',
1145 default=None,
1145 default=None,
1146 )
1146 )
1147 coreconfigitem('ui', 'forcecwd',
1147 coreconfigitem('ui', 'forcecwd',
1148 default=None,
1148 default=None,
1149 )
1149 )
1150 coreconfigitem('ui', 'forcemerge',
1150 coreconfigitem('ui', 'forcemerge',
1151 default=None,
1151 default=None,
1152 )
1152 )
1153 coreconfigitem('ui', 'formatdebug',
1153 coreconfigitem('ui', 'formatdebug',
1154 default=False,
1154 default=False,
1155 )
1155 )
1156 coreconfigitem('ui', 'formatjson',
1156 coreconfigitem('ui', 'formatjson',
1157 default=False,
1157 default=False,
1158 )
1158 )
1159 coreconfigitem('ui', 'formatted',
1159 coreconfigitem('ui', 'formatted',
1160 default=None,
1160 default=None,
1161 )
1161 )
1162 coreconfigitem('ui', 'graphnodetemplate',
1162 coreconfigitem('ui', 'graphnodetemplate',
1163 default=None,
1163 default=None,
1164 )
1164 )
1165 coreconfigitem('ui', 'history-editing-backup',
1165 coreconfigitem('ui', 'history-editing-backup',
1166 default=True,
1166 default=True,
1167 )
1167 )
1168 coreconfigitem('ui', 'interactive',
1168 coreconfigitem('ui', 'interactive',
1169 default=None,
1169 default=None,
1170 )
1170 )
1171 coreconfigitem('ui', 'interface',
1171 coreconfigitem('ui', 'interface',
1172 default=None,
1172 default=None,
1173 )
1173 )
1174 coreconfigitem('ui', 'interface.chunkselector',
1174 coreconfigitem('ui', 'interface.chunkselector',
1175 default=None,
1175 default=None,
1176 )
1176 )
1177 coreconfigitem('ui', 'large-file-limit',
1177 coreconfigitem('ui', 'large-file-limit',
1178 default=10000000,
1178 default=10000000,
1179 )
1179 )
1180 coreconfigitem('ui', 'logblockedtimes',
1180 coreconfigitem('ui', 'logblockedtimes',
1181 default=False,
1181 default=False,
1182 )
1182 )
1183 coreconfigitem('ui', 'logtemplate',
1183 coreconfigitem('ui', 'logtemplate',
1184 default=None,
1184 default=None,
1185 )
1185 )
1186 coreconfigitem('ui', 'merge',
1186 coreconfigitem('ui', 'merge',
1187 default=None,
1187 default=None,
1188 )
1188 )
1189 coreconfigitem('ui', 'mergemarkers',
1189 coreconfigitem('ui', 'mergemarkers',
1190 default='basic',
1190 default='basic',
1191 )
1191 )
1192 coreconfigitem('ui', 'mergemarkertemplate',
1192 coreconfigitem('ui', 'mergemarkertemplate',
1193 default=('{node|short} '
1193 default=('{node|short} '
1194 '{ifeq(tags, "tip", "", '
1194 '{ifeq(tags, "tip", "", '
1195 'ifeq(tags, "", "", "{tags} "))}'
1195 'ifeq(tags, "", "", "{tags} "))}'
1196 '{if(bookmarks, "{bookmarks} ")}'
1196 '{if(bookmarks, "{bookmarks} ")}'
1197 '{ifeq(branch, "default", "", "{branch} ")}'
1197 '{ifeq(branch, "default", "", "{branch} ")}'
1198 '- {author|user}: {desc|firstline}')
1198 '- {author|user}: {desc|firstline}')
1199 )
1199 )
1200 coreconfigitem('ui', 'message-output',
1200 coreconfigitem('ui', 'message-output',
1201 default='stdio',
1201 default='stdio',
1202 )
1202 )
1203 coreconfigitem('ui', 'nontty',
1203 coreconfigitem('ui', 'nontty',
1204 default=False,
1204 default=False,
1205 )
1205 )
1206 coreconfigitem('ui', 'origbackuppath',
1206 coreconfigitem('ui', 'origbackuppath',
1207 default=None,
1207 default=None,
1208 )
1208 )
1209 coreconfigitem('ui', 'paginate',
1209 coreconfigitem('ui', 'paginate',
1210 default=True,
1210 default=True,
1211 )
1211 )
1212 coreconfigitem('ui', 'patch',
1212 coreconfigitem('ui', 'patch',
1213 default=None,
1213 default=None,
1214 )
1214 )
1215 coreconfigitem('ui', 'pre-merge-tool-output-template',
1215 coreconfigitem('ui', 'pre-merge-tool-output-template',
1216 default=None,
1216 default=None,
1217 )
1217 )
1218 coreconfigitem('ui', 'portablefilenames',
1218 coreconfigitem('ui', 'portablefilenames',
1219 default='warn',
1219 default='warn',
1220 )
1220 )
1221 coreconfigitem('ui', 'promptecho',
1221 coreconfigitem('ui', 'promptecho',
1222 default=False,
1222 default=False,
1223 )
1223 )
1224 coreconfigitem('ui', 'quiet',
1224 coreconfigitem('ui', 'quiet',
1225 default=False,
1225 default=False,
1226 )
1226 )
1227 coreconfigitem('ui', 'quietbookmarkmove',
1227 coreconfigitem('ui', 'quietbookmarkmove',
1228 default=False,
1228 default=False,
1229 )
1229 )
1230 coreconfigitem('ui', 'remotecmd',
1230 coreconfigitem('ui', 'remotecmd',
1231 default='hg',
1231 default='hg',
1232 )
1232 )
1233 coreconfigitem('ui', 'report_untrusted',
1233 coreconfigitem('ui', 'report_untrusted',
1234 default=True,
1234 default=True,
1235 )
1235 )
1236 coreconfigitem('ui', 'rollback',
1236 coreconfigitem('ui', 'rollback',
1237 default=True,
1237 default=True,
1238 )
1238 )
1239 coreconfigitem('ui', 'signal-safe-lock',
1239 coreconfigitem('ui', 'signal-safe-lock',
1240 default=True,
1240 default=True,
1241 )
1241 )
1242 coreconfigitem('ui', 'slash',
1242 coreconfigitem('ui', 'slash',
1243 default=False,
1243 default=False,
1244 )
1244 )
1245 coreconfigitem('ui', 'ssh',
1245 coreconfigitem('ui', 'ssh',
1246 default='ssh',
1246 default='ssh',
1247 )
1247 )
1248 coreconfigitem('ui', 'ssherrorhint',
1248 coreconfigitem('ui', 'ssherrorhint',
1249 default=None,
1249 default=None,
1250 )
1250 )
1251 coreconfigitem('ui', 'statuscopies',
1251 coreconfigitem('ui', 'statuscopies',
1252 default=False,
1252 default=False,
1253 )
1253 )
1254 coreconfigitem('ui', 'strict',
1254 coreconfigitem('ui', 'strict',
1255 default=False,
1255 default=False,
1256 )
1256 )
1257 coreconfigitem('ui', 'style',
1257 coreconfigitem('ui', 'style',
1258 default='',
1258 default='',
1259 )
1259 )
1260 coreconfigitem('ui', 'supportcontact',
1260 coreconfigitem('ui', 'supportcontact',
1261 default=None,
1261 default=None,
1262 )
1262 )
1263 coreconfigitem('ui', 'textwidth',
1263 coreconfigitem('ui', 'textwidth',
1264 default=78,
1264 default=78,
1265 )
1265 )
1266 coreconfigitem('ui', 'timeout',
1266 coreconfigitem('ui', 'timeout',
1267 default='600',
1267 default='600',
1268 )
1268 )
1269 coreconfigitem('ui', 'timeout.warn',
1269 coreconfigitem('ui', 'timeout.warn',
1270 default=0,
1270 default=0,
1271 )
1271 )
1272 coreconfigitem('ui', 'traceback',
1272 coreconfigitem('ui', 'traceback',
1273 default=False,
1273 default=False,
1274 )
1274 )
1275 coreconfigitem('ui', 'tweakdefaults',
1275 coreconfigitem('ui', 'tweakdefaults',
1276 default=False,
1276 default=False,
1277 )
1277 )
1278 coreconfigitem('ui', 'username',
1278 coreconfigitem('ui', 'username',
1279 alias=[('ui', 'user')]
1279 alias=[('ui', 'user')]
1280 )
1280 )
1281 coreconfigitem('ui', 'verbose',
1281 coreconfigitem('ui', 'verbose',
1282 default=False,
1282 default=False,
1283 )
1283 )
1284 coreconfigitem('verify', 'skipflags',
1284 coreconfigitem('verify', 'skipflags',
1285 default=None,
1285 default=None,
1286 )
1286 )
1287 coreconfigitem('web', 'allowbz2',
1287 coreconfigitem('web', 'allowbz2',
1288 default=False,
1288 default=False,
1289 )
1289 )
1290 coreconfigitem('web', 'allowgz',
1290 coreconfigitem('web', 'allowgz',
1291 default=False,
1291 default=False,
1292 )
1292 )
1293 coreconfigitem('web', 'allow-pull',
1293 coreconfigitem('web', 'allow-pull',
1294 alias=[('web', 'allowpull')],
1294 alias=[('web', 'allowpull')],
1295 default=True,
1295 default=True,
1296 )
1296 )
1297 coreconfigitem('web', 'allow-push',
1297 coreconfigitem('web', 'allow-push',
1298 alias=[('web', 'allow_push')],
1298 alias=[('web', 'allow_push')],
1299 default=list,
1299 default=list,
1300 )
1300 )
1301 coreconfigitem('web', 'allowzip',
1301 coreconfigitem('web', 'allowzip',
1302 default=False,
1302 default=False,
1303 )
1303 )
1304 coreconfigitem('web', 'archivesubrepos',
1304 coreconfigitem('web', 'archivesubrepos',
1305 default=False,
1305 default=False,
1306 )
1306 )
1307 coreconfigitem('web', 'cache',
1307 coreconfigitem('web', 'cache',
1308 default=True,
1308 default=True,
1309 )
1309 )
1310 coreconfigitem('web', 'comparisoncontext',
1311 default=5,
1312 )
1310 coreconfigitem('web', 'contact',
1313 coreconfigitem('web', 'contact',
1311 default=None,
1314 default=None,
1312 )
1315 )
1313 coreconfigitem('web', 'deny_push',
1316 coreconfigitem('web', 'deny_push',
1314 default=list,
1317 default=list,
1315 )
1318 )
1316 coreconfigitem('web', 'guessmime',
1319 coreconfigitem('web', 'guessmime',
1317 default=False,
1320 default=False,
1318 )
1321 )
1319 coreconfigitem('web', 'hidden',
1322 coreconfigitem('web', 'hidden',
1320 default=False,
1323 default=False,
1321 )
1324 )
1322 coreconfigitem('web', 'labels',
1325 coreconfigitem('web', 'labels',
1323 default=list,
1326 default=list,
1324 )
1327 )
1325 coreconfigitem('web', 'logoimg',
1328 coreconfigitem('web', 'logoimg',
1326 default='hglogo.png',
1329 default='hglogo.png',
1327 )
1330 )
1328 coreconfigitem('web', 'logourl',
1331 coreconfigitem('web', 'logourl',
1329 default='https://mercurial-scm.org/',
1332 default='https://mercurial-scm.org/',
1330 )
1333 )
1331 coreconfigitem('web', 'accesslog',
1334 coreconfigitem('web', 'accesslog',
1332 default='-',
1335 default='-',
1333 )
1336 )
1334 coreconfigitem('web', 'address',
1337 coreconfigitem('web', 'address',
1335 default='',
1338 default='',
1336 )
1339 )
1337 coreconfigitem('web', 'allow-archive',
1340 coreconfigitem('web', 'allow-archive',
1338 alias=[('web', 'allow_archive')],
1341 alias=[('web', 'allow_archive')],
1339 default=list,
1342 default=list,
1340 )
1343 )
1341 coreconfigitem('web', 'allow_read',
1344 coreconfigitem('web', 'allow_read',
1342 default=list,
1345 default=list,
1343 )
1346 )
1344 coreconfigitem('web', 'baseurl',
1347 coreconfigitem('web', 'baseurl',
1345 default=None,
1348 default=None,
1346 )
1349 )
1347 coreconfigitem('web', 'cacerts',
1350 coreconfigitem('web', 'cacerts',
1348 default=None,
1351 default=None,
1349 )
1352 )
1350 coreconfigitem('web', 'certificate',
1353 coreconfigitem('web', 'certificate',
1351 default=None,
1354 default=None,
1352 )
1355 )
1353 coreconfigitem('web', 'collapse',
1356 coreconfigitem('web', 'collapse',
1354 default=False,
1357 default=False,
1355 )
1358 )
1356 coreconfigitem('web', 'csp',
1359 coreconfigitem('web', 'csp',
1357 default=None,
1360 default=None,
1358 )
1361 )
1359 coreconfigitem('web', 'deny_read',
1362 coreconfigitem('web', 'deny_read',
1360 default=list,
1363 default=list,
1361 )
1364 )
1362 coreconfigitem('web', 'descend',
1365 coreconfigitem('web', 'descend',
1363 default=True,
1366 default=True,
1364 )
1367 )
1365 coreconfigitem('web', 'description',
1368 coreconfigitem('web', 'description',
1366 default="",
1369 default="",
1367 )
1370 )
1368 coreconfigitem('web', 'encoding',
1371 coreconfigitem('web', 'encoding',
1369 default=lambda: encoding.encoding,
1372 default=lambda: encoding.encoding,
1370 )
1373 )
1371 coreconfigitem('web', 'errorlog',
1374 coreconfigitem('web', 'errorlog',
1372 default='-',
1375 default='-',
1373 )
1376 )
1374 coreconfigitem('web', 'ipv6',
1377 coreconfigitem('web', 'ipv6',
1375 default=False,
1378 default=False,
1376 )
1379 )
1377 coreconfigitem('web', 'maxchanges',
1380 coreconfigitem('web', 'maxchanges',
1378 default=10,
1381 default=10,
1379 )
1382 )
1380 coreconfigitem('web', 'maxfiles',
1383 coreconfigitem('web', 'maxfiles',
1381 default=10,
1384 default=10,
1382 )
1385 )
1383 coreconfigitem('web', 'maxshortchanges',
1386 coreconfigitem('web', 'maxshortchanges',
1384 default=60,
1387 default=60,
1385 )
1388 )
1386 coreconfigitem('web', 'motd',
1389 coreconfigitem('web', 'motd',
1387 default='',
1390 default='',
1388 )
1391 )
1389 coreconfigitem('web', 'name',
1392 coreconfigitem('web', 'name',
1390 default=dynamicdefault,
1393 default=dynamicdefault,
1391 )
1394 )
1392 coreconfigitem('web', 'port',
1395 coreconfigitem('web', 'port',
1393 default=8000,
1396 default=8000,
1394 )
1397 )
1395 coreconfigitem('web', 'prefix',
1398 coreconfigitem('web', 'prefix',
1396 default='',
1399 default='',
1397 )
1400 )
1398 coreconfigitem('web', 'push_ssl',
1401 coreconfigitem('web', 'push_ssl',
1399 default=True,
1402 default=True,
1400 )
1403 )
1401 coreconfigitem('web', 'refreshinterval',
1404 coreconfigitem('web', 'refreshinterval',
1402 default=20,
1405 default=20,
1403 )
1406 )
1404 coreconfigitem('web', 'server-header',
1407 coreconfigitem('web', 'server-header',
1405 default=None,
1408 default=None,
1406 )
1409 )
1407 coreconfigitem('web', 'static',
1410 coreconfigitem('web', 'static',
1408 default=None,
1411 default=None,
1409 )
1412 )
1410 coreconfigitem('web', 'staticurl',
1413 coreconfigitem('web', 'staticurl',
1411 default=None,
1414 default=None,
1412 )
1415 )
1413 coreconfigitem('web', 'stripes',
1416 coreconfigitem('web', 'stripes',
1414 default=1,
1417 default=1,
1415 )
1418 )
1416 coreconfigitem('web', 'style',
1419 coreconfigitem('web', 'style',
1417 default='paper',
1420 default='paper',
1418 )
1421 )
1419 coreconfigitem('web', 'templates',
1422 coreconfigitem('web', 'templates',
1420 default=None,
1423 default=None,
1421 )
1424 )
1422 coreconfigitem('web', 'view',
1425 coreconfigitem('web', 'view',
1423 default='served',
1426 default='served',
1424 )
1427 )
1425 coreconfigitem('worker', 'backgroundclose',
1428 coreconfigitem('worker', 'backgroundclose',
1426 default=dynamicdefault,
1429 default=dynamicdefault,
1427 )
1430 )
1428 # Windows defaults to a limit of 512 open files. A buffer of 128
1431 # Windows defaults to a limit of 512 open files. A buffer of 128
1429 # should give us enough headway.
1432 # should give us enough headway.
1430 coreconfigitem('worker', 'backgroundclosemaxqueue',
1433 coreconfigitem('worker', 'backgroundclosemaxqueue',
1431 default=384,
1434 default=384,
1432 )
1435 )
1433 coreconfigitem('worker', 'backgroundcloseminfilecount',
1436 coreconfigitem('worker', 'backgroundcloseminfilecount',
1434 default=2048,
1437 default=2048,
1435 )
1438 )
1436 coreconfigitem('worker', 'backgroundclosethreadcount',
1439 coreconfigitem('worker', 'backgroundclosethreadcount',
1437 default=4,
1440 default=4,
1438 )
1441 )
1439 coreconfigitem('worker', 'enabled',
1442 coreconfigitem('worker', 'enabled',
1440 default=True,
1443 default=True,
1441 )
1444 )
1442 coreconfigitem('worker', 'numcpus',
1445 coreconfigitem('worker', 'numcpus',
1443 default=None,
1446 default=None,
1444 )
1447 )
1445
1448
1446 # Rebase related configuration moved to core because other extension are doing
1449 # Rebase related configuration moved to core because other extension are doing
1447 # strange things. For example, shelve import the extensions to reuse some bit
1450 # strange things. For example, shelve import the extensions to reuse some bit
1448 # without formally loading it.
1451 # without formally loading it.
1449 coreconfigitem('commands', 'rebase.requiredest',
1452 coreconfigitem('commands', 'rebase.requiredest',
1450 default=False,
1453 default=False,
1451 )
1454 )
1452 coreconfigitem('experimental', 'rebaseskipobsolete',
1455 coreconfigitem('experimental', 'rebaseskipobsolete',
1453 default=True,
1456 default=True,
1454 )
1457 )
1455 coreconfigitem('rebase', 'singletransaction',
1458 coreconfigitem('rebase', 'singletransaction',
1456 default=False,
1459 default=False,
1457 )
1460 )
1458 coreconfigitem('rebase', 'experimental.inmemory',
1461 coreconfigitem('rebase', 'experimental.inmemory',
1459 default=False,
1462 default=False,
1460 )
1463 )
@@ -1,1484 +1,1484 b''
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 copy
10 import copy
11 import mimetypes
11 import mimetypes
12 import os
12 import os
13 import re
13 import re
14
14
15 from ..i18n import _
15 from ..i18n import _
16 from ..node import hex, short
16 from ..node import hex, short
17
17
18 from .common import (
18 from .common import (
19 ErrorResponse,
19 ErrorResponse,
20 HTTP_FORBIDDEN,
20 HTTP_FORBIDDEN,
21 HTTP_NOT_FOUND,
21 HTTP_NOT_FOUND,
22 get_contact,
22 get_contact,
23 paritygen,
23 paritygen,
24 staticfile,
24 staticfile,
25 )
25 )
26
26
27 from .. import (
27 from .. import (
28 archival,
28 archival,
29 dagop,
29 dagop,
30 encoding,
30 encoding,
31 error,
31 error,
32 graphmod,
32 graphmod,
33 pycompat,
33 pycompat,
34 revset,
34 revset,
35 revsetlang,
35 revsetlang,
36 scmutil,
36 scmutil,
37 smartset,
37 smartset,
38 templater,
38 templater,
39 templateutil,
39 templateutil,
40 )
40 )
41
41
42 from ..utils import (
42 from ..utils import (
43 stringutil,
43 stringutil,
44 )
44 )
45
45
46 from . import (
46 from . import (
47 webutil,
47 webutil,
48 )
48 )
49
49
50 __all__ = []
50 __all__ = []
51 commands = {}
51 commands = {}
52
52
53 class webcommand(object):
53 class webcommand(object):
54 """Decorator used to register a web command handler.
54 """Decorator used to register a web command handler.
55
55
56 The decorator takes as its positional arguments the name/path the
56 The decorator takes as its positional arguments the name/path the
57 command should be accessible under.
57 command should be accessible under.
58
58
59 When called, functions receive as arguments a ``requestcontext``,
59 When called, functions receive as arguments a ``requestcontext``,
60 ``wsgirequest``, and a templater instance for generatoring output.
60 ``wsgirequest``, and a templater instance for generatoring output.
61 The functions should populate the ``rctx.res`` object with details
61 The functions should populate the ``rctx.res`` object with details
62 about the HTTP response.
62 about the HTTP response.
63
63
64 The function returns a generator to be consumed by the WSGI application.
64 The function returns a generator to be consumed by the WSGI application.
65 For most commands, this should be the result from
65 For most commands, this should be the result from
66 ``web.res.sendresponse()``. Many commands will call ``web.sendtemplate()``
66 ``web.res.sendresponse()``. Many commands will call ``web.sendtemplate()``
67 to render a template.
67 to render a template.
68
68
69 Usage:
69 Usage:
70
70
71 @webcommand('mycommand')
71 @webcommand('mycommand')
72 def mycommand(web):
72 def mycommand(web):
73 pass
73 pass
74 """
74 """
75
75
76 def __init__(self, name):
76 def __init__(self, name):
77 self.name = name
77 self.name = name
78
78
79 def __call__(self, func):
79 def __call__(self, func):
80 __all__.append(self.name)
80 __all__.append(self.name)
81 commands[self.name] = func
81 commands[self.name] = func
82 return func
82 return func
83
83
84 @webcommand('log')
84 @webcommand('log')
85 def log(web):
85 def log(web):
86 """
86 """
87 /log[/{revision}[/{path}]]
87 /log[/{revision}[/{path}]]
88 --------------------------
88 --------------------------
89
89
90 Show repository or file history.
90 Show repository or file history.
91
91
92 For URLs of the form ``/log/{revision}``, a list of changesets starting at
92 For URLs of the form ``/log/{revision}``, a list of changesets starting at
93 the specified changeset identifier is shown. If ``{revision}`` is not
93 the specified changeset identifier is shown. If ``{revision}`` is not
94 defined, the default is ``tip``. This form is equivalent to the
94 defined, the default is ``tip``. This form is equivalent to the
95 ``changelog`` handler.
95 ``changelog`` handler.
96
96
97 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
97 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
98 file will be shown. This form is equivalent to the ``filelog`` handler.
98 file will be shown. This form is equivalent to the ``filelog`` handler.
99 """
99 """
100
100
101 if web.req.qsparams.get('file'):
101 if web.req.qsparams.get('file'):
102 return filelog(web)
102 return filelog(web)
103 else:
103 else:
104 return changelog(web)
104 return changelog(web)
105
105
106 @webcommand('rawfile')
106 @webcommand('rawfile')
107 def rawfile(web):
107 def rawfile(web):
108 guessmime = web.configbool('web', 'guessmime')
108 guessmime = web.configbool('web', 'guessmime')
109
109
110 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
110 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
111 if not path:
111 if not path:
112 return manifest(web)
112 return manifest(web)
113
113
114 try:
114 try:
115 fctx = webutil.filectx(web.repo, web.req)
115 fctx = webutil.filectx(web.repo, web.req)
116 except error.LookupError as inst:
116 except error.LookupError as inst:
117 try:
117 try:
118 return manifest(web)
118 return manifest(web)
119 except ErrorResponse:
119 except ErrorResponse:
120 raise inst
120 raise inst
121
121
122 path = fctx.path()
122 path = fctx.path()
123 text = fctx.data()
123 text = fctx.data()
124 mt = 'application/binary'
124 mt = 'application/binary'
125 if guessmime:
125 if guessmime:
126 mt = mimetypes.guess_type(pycompat.fsdecode(path))[0]
126 mt = mimetypes.guess_type(pycompat.fsdecode(path))[0]
127 if mt is None:
127 if mt is None:
128 if stringutil.binary(text):
128 if stringutil.binary(text):
129 mt = 'application/binary'
129 mt = 'application/binary'
130 else:
130 else:
131 mt = 'text/plain'
131 mt = 'text/plain'
132 else:
132 else:
133 mt = pycompat.sysbytes(mt)
133 mt = pycompat.sysbytes(mt)
134
134
135 if mt.startswith('text/'):
135 if mt.startswith('text/'):
136 mt += '; charset="%s"' % encoding.encoding
136 mt += '; charset="%s"' % encoding.encoding
137
137
138 web.res.headers['Content-Type'] = mt
138 web.res.headers['Content-Type'] = mt
139 filename = (path.rpartition('/')[-1]
139 filename = (path.rpartition('/')[-1]
140 .replace('\\', '\\\\').replace('"', '\\"'))
140 .replace('\\', '\\\\').replace('"', '\\"'))
141 web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename
141 web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename
142 web.res.setbodybytes(text)
142 web.res.setbodybytes(text)
143 return web.res.sendresponse()
143 return web.res.sendresponse()
144
144
145 def _filerevision(web, fctx):
145 def _filerevision(web, fctx):
146 f = fctx.path()
146 f = fctx.path()
147 text = fctx.data()
147 text = fctx.data()
148 parity = paritygen(web.stripecount)
148 parity = paritygen(web.stripecount)
149 ishead = fctx.filenode() in fctx.filelog().heads()
149 ishead = fctx.filenode() in fctx.filelog().heads()
150
150
151 if stringutil.binary(text):
151 if stringutil.binary(text):
152 mt = pycompat.sysbytes(
152 mt = pycompat.sysbytes(
153 mimetypes.guess_type(pycompat.fsdecode(f))[0]
153 mimetypes.guess_type(pycompat.fsdecode(f))[0]
154 or r'application/octet-stream')
154 or r'application/octet-stream')
155 text = '(binary:%s)' % mt
155 text = '(binary:%s)' % mt
156
156
157 def lines(context):
157 def lines(context):
158 for lineno, t in enumerate(text.splitlines(True)):
158 for lineno, t in enumerate(text.splitlines(True)):
159 yield {"line": t,
159 yield {"line": t,
160 "lineid": "l%d" % (lineno + 1),
160 "lineid": "l%d" % (lineno + 1),
161 "linenumber": "% 6d" % (lineno + 1),
161 "linenumber": "% 6d" % (lineno + 1),
162 "parity": next(parity)}
162 "parity": next(parity)}
163
163
164 return web.sendtemplate(
164 return web.sendtemplate(
165 'filerevision',
165 'filerevision',
166 file=f,
166 file=f,
167 path=webutil.up(f),
167 path=webutil.up(f),
168 text=templateutil.mappinggenerator(lines),
168 text=templateutil.mappinggenerator(lines),
169 symrev=webutil.symrevorshortnode(web.req, fctx),
169 symrev=webutil.symrevorshortnode(web.req, fctx),
170 rename=webutil.renamelink(fctx),
170 rename=webutil.renamelink(fctx),
171 permissions=fctx.manifest().flags(f),
171 permissions=fctx.manifest().flags(f),
172 ishead=int(ishead),
172 ishead=int(ishead),
173 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
173 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
174
174
175 @webcommand('file')
175 @webcommand('file')
176 def file(web):
176 def file(web):
177 """
177 """
178 /file/{revision}[/{path}]
178 /file/{revision}[/{path}]
179 -------------------------
179 -------------------------
180
180
181 Show information about a directory or file in the repository.
181 Show information about a directory or file in the repository.
182
182
183 Info about the ``path`` given as a URL parameter will be rendered.
183 Info about the ``path`` given as a URL parameter will be rendered.
184
184
185 If ``path`` is a directory, information about the entries in that
185 If ``path`` is a directory, information about the entries in that
186 directory will be rendered. This form is equivalent to the ``manifest``
186 directory will be rendered. This form is equivalent to the ``manifest``
187 handler.
187 handler.
188
188
189 If ``path`` is a file, information about that file will be shown via
189 If ``path`` is a file, information about that file will be shown via
190 the ``filerevision`` template.
190 the ``filerevision`` template.
191
191
192 If ``path`` is not defined, information about the root directory will
192 If ``path`` is not defined, information about the root directory will
193 be rendered.
193 be rendered.
194 """
194 """
195 if web.req.qsparams.get('style') == 'raw':
195 if web.req.qsparams.get('style') == 'raw':
196 return rawfile(web)
196 return rawfile(web)
197
197
198 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
198 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
199 if not path:
199 if not path:
200 return manifest(web)
200 return manifest(web)
201 try:
201 try:
202 return _filerevision(web, webutil.filectx(web.repo, web.req))
202 return _filerevision(web, webutil.filectx(web.repo, web.req))
203 except error.LookupError as inst:
203 except error.LookupError as inst:
204 try:
204 try:
205 return manifest(web)
205 return manifest(web)
206 except ErrorResponse:
206 except ErrorResponse:
207 raise inst
207 raise inst
208
208
209 def _search(web):
209 def _search(web):
210 MODE_REVISION = 'rev'
210 MODE_REVISION = 'rev'
211 MODE_KEYWORD = 'keyword'
211 MODE_KEYWORD = 'keyword'
212 MODE_REVSET = 'revset'
212 MODE_REVSET = 'revset'
213
213
214 def revsearch(ctx):
214 def revsearch(ctx):
215 yield ctx
215 yield ctx
216
216
217 def keywordsearch(query):
217 def keywordsearch(query):
218 lower = encoding.lower
218 lower = encoding.lower
219 qw = lower(query).split()
219 qw = lower(query).split()
220
220
221 def revgen():
221 def revgen():
222 cl = web.repo.changelog
222 cl = web.repo.changelog
223 for i in pycompat.xrange(len(web.repo) - 1, 0, -100):
223 for i in pycompat.xrange(len(web.repo) - 1, 0, -100):
224 l = []
224 l = []
225 for j in cl.revs(max(0, i - 99), i):
225 for j in cl.revs(max(0, i - 99), i):
226 ctx = web.repo[j]
226 ctx = web.repo[j]
227 l.append(ctx)
227 l.append(ctx)
228 l.reverse()
228 l.reverse()
229 for e in l:
229 for e in l:
230 yield e
230 yield e
231
231
232 for ctx in revgen():
232 for ctx in revgen():
233 miss = 0
233 miss = 0
234 for q in qw:
234 for q in qw:
235 if not (q in lower(ctx.user()) or
235 if not (q in lower(ctx.user()) or
236 q in lower(ctx.description()) or
236 q in lower(ctx.description()) or
237 q in lower(" ".join(ctx.files()))):
237 q in lower(" ".join(ctx.files()))):
238 miss = 1
238 miss = 1
239 break
239 break
240 if miss:
240 if miss:
241 continue
241 continue
242
242
243 yield ctx
243 yield ctx
244
244
245 def revsetsearch(revs):
245 def revsetsearch(revs):
246 for r in revs:
246 for r in revs:
247 yield web.repo[r]
247 yield web.repo[r]
248
248
249 searchfuncs = {
249 searchfuncs = {
250 MODE_REVISION: (revsearch, 'exact revision search'),
250 MODE_REVISION: (revsearch, 'exact revision search'),
251 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
251 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
252 MODE_REVSET: (revsetsearch, 'revset expression search'),
252 MODE_REVSET: (revsetsearch, 'revset expression search'),
253 }
253 }
254
254
255 def getsearchmode(query):
255 def getsearchmode(query):
256 try:
256 try:
257 ctx = scmutil.revsymbol(web.repo, query)
257 ctx = scmutil.revsymbol(web.repo, query)
258 except (error.RepoError, error.LookupError):
258 except (error.RepoError, error.LookupError):
259 # query is not an exact revision pointer, need to
259 # query is not an exact revision pointer, need to
260 # decide if it's a revset expression or keywords
260 # decide if it's a revset expression or keywords
261 pass
261 pass
262 else:
262 else:
263 return MODE_REVISION, ctx
263 return MODE_REVISION, ctx
264
264
265 revdef = 'reverse(%s)' % query
265 revdef = 'reverse(%s)' % query
266 try:
266 try:
267 tree = revsetlang.parse(revdef)
267 tree = revsetlang.parse(revdef)
268 except error.ParseError:
268 except error.ParseError:
269 # can't parse to a revset tree
269 # can't parse to a revset tree
270 return MODE_KEYWORD, query
270 return MODE_KEYWORD, query
271
271
272 if revsetlang.depth(tree) <= 2:
272 if revsetlang.depth(tree) <= 2:
273 # no revset syntax used
273 # no revset syntax used
274 return MODE_KEYWORD, query
274 return MODE_KEYWORD, query
275
275
276 if any((token, (value or '')[:3]) == ('string', 're:')
276 if any((token, (value or '')[:3]) == ('string', 're:')
277 for token, value, pos in revsetlang.tokenize(revdef)):
277 for token, value, pos in revsetlang.tokenize(revdef)):
278 return MODE_KEYWORD, query
278 return MODE_KEYWORD, query
279
279
280 funcsused = revsetlang.funcsused(tree)
280 funcsused = revsetlang.funcsused(tree)
281 if not funcsused.issubset(revset.safesymbols):
281 if not funcsused.issubset(revset.safesymbols):
282 return MODE_KEYWORD, query
282 return MODE_KEYWORD, query
283
283
284 try:
284 try:
285 mfunc = revset.match(web.repo.ui, revdef,
285 mfunc = revset.match(web.repo.ui, revdef,
286 lookup=revset.lookupfn(web.repo))
286 lookup=revset.lookupfn(web.repo))
287 revs = mfunc(web.repo)
287 revs = mfunc(web.repo)
288 return MODE_REVSET, revs
288 return MODE_REVSET, revs
289 # ParseError: wrongly placed tokens, wrongs arguments, etc
289 # ParseError: wrongly placed tokens, wrongs arguments, etc
290 # RepoLookupError: no such revision, e.g. in 'revision:'
290 # RepoLookupError: no such revision, e.g. in 'revision:'
291 # Abort: bookmark/tag not exists
291 # Abort: bookmark/tag not exists
292 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
292 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
293 except (error.ParseError, error.RepoLookupError, error.Abort,
293 except (error.ParseError, error.RepoLookupError, error.Abort,
294 LookupError):
294 LookupError):
295 return MODE_KEYWORD, query
295 return MODE_KEYWORD, query
296
296
297 def changelist(context):
297 def changelist(context):
298 count = 0
298 count = 0
299
299
300 for ctx in searchfunc[0](funcarg):
300 for ctx in searchfunc[0](funcarg):
301 count += 1
301 count += 1
302 n = scmutil.binnode(ctx)
302 n = scmutil.binnode(ctx)
303 showtags = webutil.showtag(web.repo, 'changelogtag', n)
303 showtags = webutil.showtag(web.repo, 'changelogtag', n)
304 files = webutil.listfilediffs(ctx.files(), n, web.maxfiles)
304 files = webutil.listfilediffs(ctx.files(), n, web.maxfiles)
305
305
306 lm = webutil.commonentry(web.repo, ctx)
306 lm = webutil.commonentry(web.repo, ctx)
307 lm.update({
307 lm.update({
308 'parity': next(parity),
308 'parity': next(parity),
309 'changelogtag': showtags,
309 'changelogtag': showtags,
310 'files': files,
310 'files': files,
311 })
311 })
312 yield lm
312 yield lm
313
313
314 if count >= revcount:
314 if count >= revcount:
315 break
315 break
316
316
317 query = web.req.qsparams['rev']
317 query = web.req.qsparams['rev']
318 revcount = web.maxchanges
318 revcount = web.maxchanges
319 if 'revcount' in web.req.qsparams:
319 if 'revcount' in web.req.qsparams:
320 try:
320 try:
321 revcount = int(web.req.qsparams.get('revcount', revcount))
321 revcount = int(web.req.qsparams.get('revcount', revcount))
322 revcount = max(revcount, 1)
322 revcount = max(revcount, 1)
323 web.tmpl.defaults['sessionvars']['revcount'] = revcount
323 web.tmpl.defaults['sessionvars']['revcount'] = revcount
324 except ValueError:
324 except ValueError:
325 pass
325 pass
326
326
327 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
327 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
328 lessvars['revcount'] = max(revcount // 2, 1)
328 lessvars['revcount'] = max(revcount // 2, 1)
329 lessvars['rev'] = query
329 lessvars['rev'] = query
330 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
330 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
331 morevars['revcount'] = revcount * 2
331 morevars['revcount'] = revcount * 2
332 morevars['rev'] = query
332 morevars['rev'] = query
333
333
334 mode, funcarg = getsearchmode(query)
334 mode, funcarg = getsearchmode(query)
335
335
336 if 'forcekw' in web.req.qsparams:
336 if 'forcekw' in web.req.qsparams:
337 showforcekw = ''
337 showforcekw = ''
338 showunforcekw = searchfuncs[mode][1]
338 showunforcekw = searchfuncs[mode][1]
339 mode = MODE_KEYWORD
339 mode = MODE_KEYWORD
340 funcarg = query
340 funcarg = query
341 else:
341 else:
342 if mode != MODE_KEYWORD:
342 if mode != MODE_KEYWORD:
343 showforcekw = searchfuncs[MODE_KEYWORD][1]
343 showforcekw = searchfuncs[MODE_KEYWORD][1]
344 else:
344 else:
345 showforcekw = ''
345 showforcekw = ''
346 showunforcekw = ''
346 showunforcekw = ''
347
347
348 searchfunc = searchfuncs[mode]
348 searchfunc = searchfuncs[mode]
349
349
350 tip = web.repo['tip']
350 tip = web.repo['tip']
351 parity = paritygen(web.stripecount)
351 parity = paritygen(web.stripecount)
352
352
353 return web.sendtemplate(
353 return web.sendtemplate(
354 'search',
354 'search',
355 query=query,
355 query=query,
356 node=tip.hex(),
356 node=tip.hex(),
357 symrev='tip',
357 symrev='tip',
358 entries=templateutil.mappinggenerator(changelist, name='searchentry'),
358 entries=templateutil.mappinggenerator(changelist, name='searchentry'),
359 archives=web.archivelist('tip'),
359 archives=web.archivelist('tip'),
360 morevars=morevars,
360 morevars=morevars,
361 lessvars=lessvars,
361 lessvars=lessvars,
362 modedesc=searchfunc[1],
362 modedesc=searchfunc[1],
363 showforcekw=showforcekw,
363 showforcekw=showforcekw,
364 showunforcekw=showunforcekw)
364 showunforcekw=showunforcekw)
365
365
366 @webcommand('changelog')
366 @webcommand('changelog')
367 def changelog(web, shortlog=False):
367 def changelog(web, shortlog=False):
368 """
368 """
369 /changelog[/{revision}]
369 /changelog[/{revision}]
370 -----------------------
370 -----------------------
371
371
372 Show information about multiple changesets.
372 Show information about multiple changesets.
373
373
374 If the optional ``revision`` URL argument is absent, information about
374 If the optional ``revision`` URL argument is absent, information about
375 all changesets starting at ``tip`` will be rendered. If the ``revision``
375 all changesets starting at ``tip`` will be rendered. If the ``revision``
376 argument is present, changesets will be shown starting from the specified
376 argument is present, changesets will be shown starting from the specified
377 revision.
377 revision.
378
378
379 If ``revision`` is absent, the ``rev`` query string argument may be
379 If ``revision`` is absent, the ``rev`` query string argument may be
380 defined. This will perform a search for changesets.
380 defined. This will perform a search for changesets.
381
381
382 The argument for ``rev`` can be a single revision, a revision set,
382 The argument for ``rev`` can be a single revision, a revision set,
383 or a literal keyword to search for in changeset data (equivalent to
383 or a literal keyword to search for in changeset data (equivalent to
384 :hg:`log -k`).
384 :hg:`log -k`).
385
385
386 The ``revcount`` query string argument defines the maximum numbers of
386 The ``revcount`` query string argument defines the maximum numbers of
387 changesets to render.
387 changesets to render.
388
388
389 For non-searches, the ``changelog`` template will be rendered.
389 For non-searches, the ``changelog`` template will be rendered.
390 """
390 """
391
391
392 query = ''
392 query = ''
393 if 'node' in web.req.qsparams:
393 if 'node' in web.req.qsparams:
394 ctx = webutil.changectx(web.repo, web.req)
394 ctx = webutil.changectx(web.repo, web.req)
395 symrev = webutil.symrevorshortnode(web.req, ctx)
395 symrev = webutil.symrevorshortnode(web.req, ctx)
396 elif 'rev' in web.req.qsparams:
396 elif 'rev' in web.req.qsparams:
397 return _search(web)
397 return _search(web)
398 else:
398 else:
399 ctx = web.repo['tip']
399 ctx = web.repo['tip']
400 symrev = 'tip'
400 symrev = 'tip'
401
401
402 def changelist(maxcount):
402 def changelist(maxcount):
403 revs = []
403 revs = []
404 if pos != -1:
404 if pos != -1:
405 revs = web.repo.changelog.revs(pos, 0)
405 revs = web.repo.changelog.revs(pos, 0)
406
406
407 for entry in webutil.changelistentries(web, revs, maxcount, parity):
407 for entry in webutil.changelistentries(web, revs, maxcount, parity):
408 yield entry
408 yield entry
409
409
410 if shortlog:
410 if shortlog:
411 revcount = web.maxshortchanges
411 revcount = web.maxshortchanges
412 else:
412 else:
413 revcount = web.maxchanges
413 revcount = web.maxchanges
414
414
415 if 'revcount' in web.req.qsparams:
415 if 'revcount' in web.req.qsparams:
416 try:
416 try:
417 revcount = int(web.req.qsparams.get('revcount', revcount))
417 revcount = int(web.req.qsparams.get('revcount', revcount))
418 revcount = max(revcount, 1)
418 revcount = max(revcount, 1)
419 web.tmpl.defaults['sessionvars']['revcount'] = revcount
419 web.tmpl.defaults['sessionvars']['revcount'] = revcount
420 except ValueError:
420 except ValueError:
421 pass
421 pass
422
422
423 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
423 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
424 lessvars['revcount'] = max(revcount // 2, 1)
424 lessvars['revcount'] = max(revcount // 2, 1)
425 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
425 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
426 morevars['revcount'] = revcount * 2
426 morevars['revcount'] = revcount * 2
427
427
428 count = len(web.repo)
428 count = len(web.repo)
429 pos = ctx.rev()
429 pos = ctx.rev()
430 parity = paritygen(web.stripecount)
430 parity = paritygen(web.stripecount)
431
431
432 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
432 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
433
433
434 entries = list(changelist(revcount + 1))
434 entries = list(changelist(revcount + 1))
435 latestentry = entries[:1]
435 latestentry = entries[:1]
436 if len(entries) > revcount:
436 if len(entries) > revcount:
437 nextentry = entries[-1:]
437 nextentry = entries[-1:]
438 entries = entries[:-1]
438 entries = entries[:-1]
439 else:
439 else:
440 nextentry = []
440 nextentry = []
441
441
442 return web.sendtemplate(
442 return web.sendtemplate(
443 'shortlog' if shortlog else 'changelog',
443 'shortlog' if shortlog else 'changelog',
444 changenav=changenav,
444 changenav=changenav,
445 node=ctx.hex(),
445 node=ctx.hex(),
446 rev=pos,
446 rev=pos,
447 symrev=symrev,
447 symrev=symrev,
448 changesets=count,
448 changesets=count,
449 entries=templateutil.mappinglist(entries),
449 entries=templateutil.mappinglist(entries),
450 latestentry=templateutil.mappinglist(latestentry),
450 latestentry=templateutil.mappinglist(latestentry),
451 nextentry=templateutil.mappinglist(nextentry),
451 nextentry=templateutil.mappinglist(nextentry),
452 archives=web.archivelist('tip'),
452 archives=web.archivelist('tip'),
453 revcount=revcount,
453 revcount=revcount,
454 morevars=morevars,
454 morevars=morevars,
455 lessvars=lessvars,
455 lessvars=lessvars,
456 query=query)
456 query=query)
457
457
458 @webcommand('shortlog')
458 @webcommand('shortlog')
459 def shortlog(web):
459 def shortlog(web):
460 """
460 """
461 /shortlog
461 /shortlog
462 ---------
462 ---------
463
463
464 Show basic information about a set of changesets.
464 Show basic information about a set of changesets.
465
465
466 This accepts the same parameters as the ``changelog`` handler. The only
466 This accepts the same parameters as the ``changelog`` handler. The only
467 difference is the ``shortlog`` template will be rendered instead of the
467 difference is the ``shortlog`` template will be rendered instead of the
468 ``changelog`` template.
468 ``changelog`` template.
469 """
469 """
470 return changelog(web, shortlog=True)
470 return changelog(web, shortlog=True)
471
471
472 @webcommand('changeset')
472 @webcommand('changeset')
473 def changeset(web):
473 def changeset(web):
474 """
474 """
475 /changeset[/{revision}]
475 /changeset[/{revision}]
476 -----------------------
476 -----------------------
477
477
478 Show information about a single changeset.
478 Show information about a single changeset.
479
479
480 A URL path argument is the changeset identifier to show. See ``hg help
480 A URL path argument is the changeset identifier to show. See ``hg help
481 revisions`` for possible values. If not defined, the ``tip`` changeset
481 revisions`` for possible values. If not defined, the ``tip`` changeset
482 will be shown.
482 will be shown.
483
483
484 The ``changeset`` template is rendered. Contents of the ``changesettag``,
484 The ``changeset`` template is rendered. Contents of the ``changesettag``,
485 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
485 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
486 templates related to diffs may all be used to produce the output.
486 templates related to diffs may all be used to produce the output.
487 """
487 """
488 ctx = webutil.changectx(web.repo, web.req)
488 ctx = webutil.changectx(web.repo, web.req)
489
489
490 return web.sendtemplate(
490 return web.sendtemplate(
491 'changeset',
491 'changeset',
492 **webutil.changesetentry(web, ctx))
492 **webutil.changesetentry(web, ctx))
493
493
494 rev = webcommand('rev')(changeset)
494 rev = webcommand('rev')(changeset)
495
495
496 def decodepath(path):
496 def decodepath(path):
497 """Hook for mapping a path in the repository to a path in the
497 """Hook for mapping a path in the repository to a path in the
498 working copy.
498 working copy.
499
499
500 Extensions (e.g., largefiles) can override this to remap files in
500 Extensions (e.g., largefiles) can override this to remap files in
501 the virtual file system presented by the manifest command below."""
501 the virtual file system presented by the manifest command below."""
502 return path
502 return path
503
503
504 @webcommand('manifest')
504 @webcommand('manifest')
505 def manifest(web):
505 def manifest(web):
506 """
506 """
507 /manifest[/{revision}[/{path}]]
507 /manifest[/{revision}[/{path}]]
508 -------------------------------
508 -------------------------------
509
509
510 Show information about a directory.
510 Show information about a directory.
511
511
512 If the URL path arguments are omitted, information about the root
512 If the URL path arguments are omitted, information about the root
513 directory for the ``tip`` changeset will be shown.
513 directory for the ``tip`` changeset will be shown.
514
514
515 Because this handler can only show information for directories, it
515 Because this handler can only show information for directories, it
516 is recommended to use the ``file`` handler instead, as it can handle both
516 is recommended to use the ``file`` handler instead, as it can handle both
517 directories and files.
517 directories and files.
518
518
519 The ``manifest`` template will be rendered for this handler.
519 The ``manifest`` template will be rendered for this handler.
520 """
520 """
521 if 'node' in web.req.qsparams:
521 if 'node' in web.req.qsparams:
522 ctx = webutil.changectx(web.repo, web.req)
522 ctx = webutil.changectx(web.repo, web.req)
523 symrev = webutil.symrevorshortnode(web.req, ctx)
523 symrev = webutil.symrevorshortnode(web.req, ctx)
524 else:
524 else:
525 ctx = web.repo['tip']
525 ctx = web.repo['tip']
526 symrev = 'tip'
526 symrev = 'tip'
527 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
527 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
528 mf = ctx.manifest()
528 mf = ctx.manifest()
529 node = scmutil.binnode(ctx)
529 node = scmutil.binnode(ctx)
530
530
531 files = {}
531 files = {}
532 dirs = {}
532 dirs = {}
533 parity = paritygen(web.stripecount)
533 parity = paritygen(web.stripecount)
534
534
535 if path and path[-1:] != "/":
535 if path and path[-1:] != "/":
536 path += "/"
536 path += "/"
537 l = len(path)
537 l = len(path)
538 abspath = "/" + path
538 abspath = "/" + path
539
539
540 for full, n in mf.iteritems():
540 for full, n in mf.iteritems():
541 # the virtual path (working copy path) used for the full
541 # the virtual path (working copy path) used for the full
542 # (repository) path
542 # (repository) path
543 f = decodepath(full)
543 f = decodepath(full)
544
544
545 if f[:l] != path:
545 if f[:l] != path:
546 continue
546 continue
547 remain = f[l:]
547 remain = f[l:]
548 elements = remain.split('/')
548 elements = remain.split('/')
549 if len(elements) == 1:
549 if len(elements) == 1:
550 files[remain] = full
550 files[remain] = full
551 else:
551 else:
552 h = dirs # need to retain ref to dirs (root)
552 h = dirs # need to retain ref to dirs (root)
553 for elem in elements[0:-1]:
553 for elem in elements[0:-1]:
554 if elem not in h:
554 if elem not in h:
555 h[elem] = {}
555 h[elem] = {}
556 h = h[elem]
556 h = h[elem]
557 if len(h) > 1:
557 if len(h) > 1:
558 break
558 break
559 h[None] = None # denotes files present
559 h[None] = None # denotes files present
560
560
561 if mf and not files and not dirs:
561 if mf and not files and not dirs:
562 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
562 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
563
563
564 def filelist(context):
564 def filelist(context):
565 for f in sorted(files):
565 for f in sorted(files):
566 full = files[f]
566 full = files[f]
567
567
568 fctx = ctx.filectx(full)
568 fctx = ctx.filectx(full)
569 yield {"file": full,
569 yield {"file": full,
570 "parity": next(parity),
570 "parity": next(parity),
571 "basename": f,
571 "basename": f,
572 "date": fctx.date(),
572 "date": fctx.date(),
573 "size": fctx.size(),
573 "size": fctx.size(),
574 "permissions": mf.flags(full)}
574 "permissions": mf.flags(full)}
575
575
576 def dirlist(context):
576 def dirlist(context):
577 for d in sorted(dirs):
577 for d in sorted(dirs):
578
578
579 emptydirs = []
579 emptydirs = []
580 h = dirs[d]
580 h = dirs[d]
581 while isinstance(h, dict) and len(h) == 1:
581 while isinstance(h, dict) and len(h) == 1:
582 k, v = next(iter(h.items()))
582 k, v = next(iter(h.items()))
583 if v:
583 if v:
584 emptydirs.append(k)
584 emptydirs.append(k)
585 h = v
585 h = v
586
586
587 path = "%s%s" % (abspath, d)
587 path = "%s%s" % (abspath, d)
588 yield {"parity": next(parity),
588 yield {"parity": next(parity),
589 "path": path,
589 "path": path,
590 "emptydirs": "/".join(emptydirs),
590 "emptydirs": "/".join(emptydirs),
591 "basename": d}
591 "basename": d}
592
592
593 return web.sendtemplate(
593 return web.sendtemplate(
594 'manifest',
594 'manifest',
595 symrev=symrev,
595 symrev=symrev,
596 path=abspath,
596 path=abspath,
597 up=webutil.up(abspath),
597 up=webutil.up(abspath),
598 upparity=next(parity),
598 upparity=next(parity),
599 fentries=templateutil.mappinggenerator(filelist),
599 fentries=templateutil.mappinggenerator(filelist),
600 dentries=templateutil.mappinggenerator(dirlist),
600 dentries=templateutil.mappinggenerator(dirlist),
601 archives=web.archivelist(hex(node)),
601 archives=web.archivelist(hex(node)),
602 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
602 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
603
603
604 @webcommand('tags')
604 @webcommand('tags')
605 def tags(web):
605 def tags(web):
606 """
606 """
607 /tags
607 /tags
608 -----
608 -----
609
609
610 Show information about tags.
610 Show information about tags.
611
611
612 No arguments are accepted.
612 No arguments are accepted.
613
613
614 The ``tags`` template is rendered.
614 The ``tags`` template is rendered.
615 """
615 """
616 i = list(reversed(web.repo.tagslist()))
616 i = list(reversed(web.repo.tagslist()))
617 parity = paritygen(web.stripecount)
617 parity = paritygen(web.stripecount)
618
618
619 def entries(context, notip, latestonly):
619 def entries(context, notip, latestonly):
620 t = i
620 t = i
621 if notip:
621 if notip:
622 t = [(k, n) for k, n in i if k != "tip"]
622 t = [(k, n) for k, n in i if k != "tip"]
623 if latestonly:
623 if latestonly:
624 t = t[:1]
624 t = t[:1]
625 for k, n in t:
625 for k, n in t:
626 yield {"parity": next(parity),
626 yield {"parity": next(parity),
627 "tag": k,
627 "tag": k,
628 "date": web.repo[n].date(),
628 "date": web.repo[n].date(),
629 "node": hex(n)}
629 "node": hex(n)}
630
630
631 return web.sendtemplate(
631 return web.sendtemplate(
632 'tags',
632 'tags',
633 node=hex(web.repo.changelog.tip()),
633 node=hex(web.repo.changelog.tip()),
634 entries=templateutil.mappinggenerator(entries, args=(False, False)),
634 entries=templateutil.mappinggenerator(entries, args=(False, False)),
635 entriesnotip=templateutil.mappinggenerator(entries,
635 entriesnotip=templateutil.mappinggenerator(entries,
636 args=(True, False)),
636 args=(True, False)),
637 latestentry=templateutil.mappinggenerator(entries, args=(True, True)))
637 latestentry=templateutil.mappinggenerator(entries, args=(True, True)))
638
638
639 @webcommand('bookmarks')
639 @webcommand('bookmarks')
640 def bookmarks(web):
640 def bookmarks(web):
641 """
641 """
642 /bookmarks
642 /bookmarks
643 ----------
643 ----------
644
644
645 Show information about bookmarks.
645 Show information about bookmarks.
646
646
647 No arguments are accepted.
647 No arguments are accepted.
648
648
649 The ``bookmarks`` template is rendered.
649 The ``bookmarks`` template is rendered.
650 """
650 """
651 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
651 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
652 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
652 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
653 i = sorted(i, key=sortkey, reverse=True)
653 i = sorted(i, key=sortkey, reverse=True)
654 parity = paritygen(web.stripecount)
654 parity = paritygen(web.stripecount)
655
655
656 def entries(context, latestonly):
656 def entries(context, latestonly):
657 t = i
657 t = i
658 if latestonly:
658 if latestonly:
659 t = i[:1]
659 t = i[:1]
660 for k, n in t:
660 for k, n in t:
661 yield {"parity": next(parity),
661 yield {"parity": next(parity),
662 "bookmark": k,
662 "bookmark": k,
663 "date": web.repo[n].date(),
663 "date": web.repo[n].date(),
664 "node": hex(n)}
664 "node": hex(n)}
665
665
666 if i:
666 if i:
667 latestrev = i[0][1]
667 latestrev = i[0][1]
668 else:
668 else:
669 latestrev = -1
669 latestrev = -1
670 lastdate = web.repo[latestrev].date()
670 lastdate = web.repo[latestrev].date()
671
671
672 return web.sendtemplate(
672 return web.sendtemplate(
673 'bookmarks',
673 'bookmarks',
674 node=hex(web.repo.changelog.tip()),
674 node=hex(web.repo.changelog.tip()),
675 lastchange=templateutil.mappinglist([{'date': lastdate}]),
675 lastchange=templateutil.mappinglist([{'date': lastdate}]),
676 entries=templateutil.mappinggenerator(entries, args=(False,)),
676 entries=templateutil.mappinggenerator(entries, args=(False,)),
677 latestentry=templateutil.mappinggenerator(entries, args=(True,)))
677 latestentry=templateutil.mappinggenerator(entries, args=(True,)))
678
678
679 @webcommand('branches')
679 @webcommand('branches')
680 def branches(web):
680 def branches(web):
681 """
681 """
682 /branches
682 /branches
683 ---------
683 ---------
684
684
685 Show information about branches.
685 Show information about branches.
686
686
687 All known branches are contained in the output, even closed branches.
687 All known branches are contained in the output, even closed branches.
688
688
689 No arguments are accepted.
689 No arguments are accepted.
690
690
691 The ``branches`` template is rendered.
691 The ``branches`` template is rendered.
692 """
692 """
693 entries = webutil.branchentries(web.repo, web.stripecount)
693 entries = webutil.branchentries(web.repo, web.stripecount)
694 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
694 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
695
695
696 return web.sendtemplate(
696 return web.sendtemplate(
697 'branches',
697 'branches',
698 node=hex(web.repo.changelog.tip()),
698 node=hex(web.repo.changelog.tip()),
699 entries=entries,
699 entries=entries,
700 latestentry=latestentry)
700 latestentry=latestentry)
701
701
702 @webcommand('summary')
702 @webcommand('summary')
703 def summary(web):
703 def summary(web):
704 """
704 """
705 /summary
705 /summary
706 --------
706 --------
707
707
708 Show a summary of repository state.
708 Show a summary of repository state.
709
709
710 Information about the latest changesets, bookmarks, tags, and branches
710 Information about the latest changesets, bookmarks, tags, and branches
711 is captured by this handler.
711 is captured by this handler.
712
712
713 The ``summary`` template is rendered.
713 The ``summary`` template is rendered.
714 """
714 """
715 i = reversed(web.repo.tagslist())
715 i = reversed(web.repo.tagslist())
716
716
717 def tagentries(context):
717 def tagentries(context):
718 parity = paritygen(web.stripecount)
718 parity = paritygen(web.stripecount)
719 count = 0
719 count = 0
720 for k, n in i:
720 for k, n in i:
721 if k == "tip": # skip tip
721 if k == "tip": # skip tip
722 continue
722 continue
723
723
724 count += 1
724 count += 1
725 if count > 10: # limit to 10 tags
725 if count > 10: # limit to 10 tags
726 break
726 break
727
727
728 yield {
728 yield {
729 'parity': next(parity),
729 'parity': next(parity),
730 'tag': k,
730 'tag': k,
731 'node': hex(n),
731 'node': hex(n),
732 'date': web.repo[n].date(),
732 'date': web.repo[n].date(),
733 }
733 }
734
734
735 def bookmarks(context):
735 def bookmarks(context):
736 parity = paritygen(web.stripecount)
736 parity = paritygen(web.stripecount)
737 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
737 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
738 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
738 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
739 marks = sorted(marks, key=sortkey, reverse=True)
739 marks = sorted(marks, key=sortkey, reverse=True)
740 for k, n in marks[:10]: # limit to 10 bookmarks
740 for k, n in marks[:10]: # limit to 10 bookmarks
741 yield {'parity': next(parity),
741 yield {'parity': next(parity),
742 'bookmark': k,
742 'bookmark': k,
743 'date': web.repo[n].date(),
743 'date': web.repo[n].date(),
744 'node': hex(n)}
744 'node': hex(n)}
745
745
746 def changelist(context):
746 def changelist(context):
747 parity = paritygen(web.stripecount, offset=start - end)
747 parity = paritygen(web.stripecount, offset=start - end)
748 l = [] # build a list in forward order for efficiency
748 l = [] # build a list in forward order for efficiency
749 revs = []
749 revs = []
750 if start < end:
750 if start < end:
751 revs = web.repo.changelog.revs(start, end - 1)
751 revs = web.repo.changelog.revs(start, end - 1)
752 for i in revs:
752 for i in revs:
753 ctx = web.repo[i]
753 ctx = web.repo[i]
754 lm = webutil.commonentry(web.repo, ctx)
754 lm = webutil.commonentry(web.repo, ctx)
755 lm['parity'] = next(parity)
755 lm['parity'] = next(parity)
756 l.append(lm)
756 l.append(lm)
757
757
758 for entry in reversed(l):
758 for entry in reversed(l):
759 yield entry
759 yield entry
760
760
761 tip = web.repo['tip']
761 tip = web.repo['tip']
762 count = len(web.repo)
762 count = len(web.repo)
763 start = max(0, count - web.maxchanges)
763 start = max(0, count - web.maxchanges)
764 end = min(count, start + web.maxchanges)
764 end = min(count, start + web.maxchanges)
765
765
766 desc = web.config("web", "description")
766 desc = web.config("web", "description")
767 if not desc:
767 if not desc:
768 desc = 'unknown'
768 desc = 'unknown'
769 labels = web.configlist('web', 'labels')
769 labels = web.configlist('web', 'labels')
770
770
771 return web.sendtemplate(
771 return web.sendtemplate(
772 'summary',
772 'summary',
773 desc=desc,
773 desc=desc,
774 owner=get_contact(web.config) or 'unknown',
774 owner=get_contact(web.config) or 'unknown',
775 lastchange=tip.date(),
775 lastchange=tip.date(),
776 tags=templateutil.mappinggenerator(tagentries, name='tagentry'),
776 tags=templateutil.mappinggenerator(tagentries, name='tagentry'),
777 bookmarks=templateutil.mappinggenerator(bookmarks),
777 bookmarks=templateutil.mappinggenerator(bookmarks),
778 branches=webutil.branchentries(web.repo, web.stripecount, 10),
778 branches=webutil.branchentries(web.repo, web.stripecount, 10),
779 shortlog=templateutil.mappinggenerator(changelist,
779 shortlog=templateutil.mappinggenerator(changelist,
780 name='shortlogentry'),
780 name='shortlogentry'),
781 node=tip.hex(),
781 node=tip.hex(),
782 symrev='tip',
782 symrev='tip',
783 archives=web.archivelist('tip'),
783 archives=web.archivelist('tip'),
784 labels=templateutil.hybridlist(labels, name='label'))
784 labels=templateutil.hybridlist(labels, name='label'))
785
785
786 @webcommand('filediff')
786 @webcommand('filediff')
787 def filediff(web):
787 def filediff(web):
788 """
788 """
789 /diff/{revision}/{path}
789 /diff/{revision}/{path}
790 -----------------------
790 -----------------------
791
791
792 Show how a file changed in a particular commit.
792 Show how a file changed in a particular commit.
793
793
794 The ``filediff`` template is rendered.
794 The ``filediff`` template is rendered.
795
795
796 This handler is registered under both the ``/diff`` and ``/filediff``
796 This handler is registered under both the ``/diff`` and ``/filediff``
797 paths. ``/diff`` is used in modern code.
797 paths. ``/diff`` is used in modern code.
798 """
798 """
799 fctx, ctx = None, None
799 fctx, ctx = None, None
800 try:
800 try:
801 fctx = webutil.filectx(web.repo, web.req)
801 fctx = webutil.filectx(web.repo, web.req)
802 except LookupError:
802 except LookupError:
803 ctx = webutil.changectx(web.repo, web.req)
803 ctx = webutil.changectx(web.repo, web.req)
804 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
804 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
805 if path not in ctx.files():
805 if path not in ctx.files():
806 raise
806 raise
807
807
808 if fctx is not None:
808 if fctx is not None:
809 path = fctx.path()
809 path = fctx.path()
810 ctx = fctx.changectx()
810 ctx = fctx.changectx()
811 basectx = ctx.p1()
811 basectx = ctx.p1()
812
812
813 style = web.config('web', 'style')
813 style = web.config('web', 'style')
814 if 'style' in web.req.qsparams:
814 if 'style' in web.req.qsparams:
815 style = web.req.qsparams['style']
815 style = web.req.qsparams['style']
816
816
817 diffs = webutil.diffs(web, ctx, basectx, [path], style)
817 diffs = webutil.diffs(web, ctx, basectx, [path], style)
818 if fctx is not None:
818 if fctx is not None:
819 rename = webutil.renamelink(fctx)
819 rename = webutil.renamelink(fctx)
820 ctx = fctx
820 ctx = fctx
821 else:
821 else:
822 rename = templateutil.mappinglist([])
822 rename = templateutil.mappinglist([])
823 ctx = ctx
823 ctx = ctx
824
824
825 return web.sendtemplate(
825 return web.sendtemplate(
826 'filediff',
826 'filediff',
827 file=path,
827 file=path,
828 symrev=webutil.symrevorshortnode(web.req, ctx),
828 symrev=webutil.symrevorshortnode(web.req, ctx),
829 rename=rename,
829 rename=rename,
830 diff=diffs,
830 diff=diffs,
831 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
831 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
832
832
833 diff = webcommand('diff')(filediff)
833 diff = webcommand('diff')(filediff)
834
834
835 @webcommand('comparison')
835 @webcommand('comparison')
836 def comparison(web):
836 def comparison(web):
837 """
837 """
838 /comparison/{revision}/{path}
838 /comparison/{revision}/{path}
839 -----------------------------
839 -----------------------------
840
840
841 Show a comparison between the old and new versions of a file from changes
841 Show a comparison between the old and new versions of a file from changes
842 made on a particular revision.
842 made on a particular revision.
843
843
844 This is similar to the ``diff`` handler. However, this form features
844 This is similar to the ``diff`` handler. However, this form features
845 a split or side-by-side diff rather than a unified diff.
845 a split or side-by-side diff rather than a unified diff.
846
846
847 The ``context`` query string argument can be used to control the lines of
847 The ``context`` query string argument can be used to control the lines of
848 context in the diff.
848 context in the diff.
849
849
850 The ``filecomparison`` template is rendered.
850 The ``filecomparison`` template is rendered.
851 """
851 """
852 ctx = webutil.changectx(web.repo, web.req)
852 ctx = webutil.changectx(web.repo, web.req)
853 if 'file' not in web.req.qsparams:
853 if 'file' not in web.req.qsparams:
854 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
854 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
855 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
855 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
856
856
857 parsecontext = lambda v: v == 'full' and -1 or int(v)
857 parsecontext = lambda v: v == 'full' and -1 or int(v)
858 if 'context' in web.req.qsparams:
858 if 'context' in web.req.qsparams:
859 context = parsecontext(web.req.qsparams['context'])
859 context = parsecontext(web.req.qsparams['context'])
860 else:
860 else:
861 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
861 context = parsecontext(web.config('web', 'comparisoncontext'))
862
862
863 def filelines(f):
863 def filelines(f):
864 if f.isbinary():
864 if f.isbinary():
865 mt = pycompat.sysbytes(
865 mt = pycompat.sysbytes(
866 mimetypes.guess_type(pycompat.fsdecode(f.path()))[0]
866 mimetypes.guess_type(pycompat.fsdecode(f.path()))[0]
867 or r'application/octet-stream')
867 or r'application/octet-stream')
868 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
868 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
869 return f.data().splitlines()
869 return f.data().splitlines()
870
870
871 fctx = None
871 fctx = None
872 parent = ctx.p1()
872 parent = ctx.p1()
873 leftrev = parent.rev()
873 leftrev = parent.rev()
874 leftnode = parent.node()
874 leftnode = parent.node()
875 rightrev = ctx.rev()
875 rightrev = ctx.rev()
876 rightnode = scmutil.binnode(ctx)
876 rightnode = scmutil.binnode(ctx)
877 if path in ctx:
877 if path in ctx:
878 fctx = ctx[path]
878 fctx = ctx[path]
879 rightlines = filelines(fctx)
879 rightlines = filelines(fctx)
880 if path not in parent:
880 if path not in parent:
881 leftlines = ()
881 leftlines = ()
882 else:
882 else:
883 pfctx = parent[path]
883 pfctx = parent[path]
884 leftlines = filelines(pfctx)
884 leftlines = filelines(pfctx)
885 else:
885 else:
886 rightlines = ()
886 rightlines = ()
887 pfctx = ctx.parents()[0][path]
887 pfctx = ctx.parents()[0][path]
888 leftlines = filelines(pfctx)
888 leftlines = filelines(pfctx)
889
889
890 comparison = webutil.compare(context, leftlines, rightlines)
890 comparison = webutil.compare(context, leftlines, rightlines)
891 if fctx is not None:
891 if fctx is not None:
892 rename = webutil.renamelink(fctx)
892 rename = webutil.renamelink(fctx)
893 ctx = fctx
893 ctx = fctx
894 else:
894 else:
895 rename = templateutil.mappinglist([])
895 rename = templateutil.mappinglist([])
896 ctx = ctx
896 ctx = ctx
897
897
898 return web.sendtemplate(
898 return web.sendtemplate(
899 'filecomparison',
899 'filecomparison',
900 file=path,
900 file=path,
901 symrev=webutil.symrevorshortnode(web.req, ctx),
901 symrev=webutil.symrevorshortnode(web.req, ctx),
902 rename=rename,
902 rename=rename,
903 leftrev=leftrev,
903 leftrev=leftrev,
904 leftnode=hex(leftnode),
904 leftnode=hex(leftnode),
905 rightrev=rightrev,
905 rightrev=rightrev,
906 rightnode=hex(rightnode),
906 rightnode=hex(rightnode),
907 comparison=comparison,
907 comparison=comparison,
908 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
908 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
909
909
910 @webcommand('annotate')
910 @webcommand('annotate')
911 def annotate(web):
911 def annotate(web):
912 """
912 """
913 /annotate/{revision}/{path}
913 /annotate/{revision}/{path}
914 ---------------------------
914 ---------------------------
915
915
916 Show changeset information for each line in a file.
916 Show changeset information for each line in a file.
917
917
918 The ``ignorews``, ``ignorewsamount``, ``ignorewseol``, and
918 The ``ignorews``, ``ignorewsamount``, ``ignorewseol``, and
919 ``ignoreblanklines`` query string arguments have the same meaning as
919 ``ignoreblanklines`` query string arguments have the same meaning as
920 their ``[annotate]`` config equivalents. It uses the hgrc boolean
920 their ``[annotate]`` config equivalents. It uses the hgrc boolean
921 parsing logic to interpret the value. e.g. ``0`` and ``false`` are
921 parsing logic to interpret the value. e.g. ``0`` and ``false`` are
922 false and ``1`` and ``true`` are true. If not defined, the server
922 false and ``1`` and ``true`` are true. If not defined, the server
923 default settings are used.
923 default settings are used.
924
924
925 The ``fileannotate`` template is rendered.
925 The ``fileannotate`` template is rendered.
926 """
926 """
927 fctx = webutil.filectx(web.repo, web.req)
927 fctx = webutil.filectx(web.repo, web.req)
928 f = fctx.path()
928 f = fctx.path()
929 parity = paritygen(web.stripecount)
929 parity = paritygen(web.stripecount)
930 ishead = fctx.filenode() in fctx.filelog().heads()
930 ishead = fctx.filenode() in fctx.filelog().heads()
931
931
932 # parents() is called once per line and several lines likely belong to
932 # parents() is called once per line and several lines likely belong to
933 # same revision. So it is worth caching.
933 # same revision. So it is worth caching.
934 # TODO there are still redundant operations within basefilectx.parents()
934 # TODO there are still redundant operations within basefilectx.parents()
935 # and from the fctx.annotate() call itself that could be cached.
935 # and from the fctx.annotate() call itself that could be cached.
936 parentscache = {}
936 parentscache = {}
937 def parents(context, f):
937 def parents(context, f):
938 rev = f.rev()
938 rev = f.rev()
939 if rev not in parentscache:
939 if rev not in parentscache:
940 parentscache[rev] = []
940 parentscache[rev] = []
941 for p in f.parents():
941 for p in f.parents():
942 entry = {
942 entry = {
943 'node': p.hex(),
943 'node': p.hex(),
944 'rev': p.rev(),
944 'rev': p.rev(),
945 }
945 }
946 parentscache[rev].append(entry)
946 parentscache[rev].append(entry)
947
947
948 for p in parentscache[rev]:
948 for p in parentscache[rev]:
949 yield p
949 yield p
950
950
951 def annotate(context):
951 def annotate(context):
952 if fctx.isbinary():
952 if fctx.isbinary():
953 mt = pycompat.sysbytes(
953 mt = pycompat.sysbytes(
954 mimetypes.guess_type(pycompat.fsdecode(fctx.path()))[0]
954 mimetypes.guess_type(pycompat.fsdecode(fctx.path()))[0]
955 or r'application/octet-stream')
955 or r'application/octet-stream')
956 lines = [dagop.annotateline(fctx=fctx.filectx(fctx.filerev()),
956 lines = [dagop.annotateline(fctx=fctx.filectx(fctx.filerev()),
957 lineno=1, text='(binary:%s)' % mt)]
957 lineno=1, text='(binary:%s)' % mt)]
958 else:
958 else:
959 lines = webutil.annotate(web.req, fctx, web.repo.ui)
959 lines = webutil.annotate(web.req, fctx, web.repo.ui)
960
960
961 previousrev = None
961 previousrev = None
962 blockparitygen = paritygen(1)
962 blockparitygen = paritygen(1)
963 for lineno, aline in enumerate(lines):
963 for lineno, aline in enumerate(lines):
964 f = aline.fctx
964 f = aline.fctx
965 rev = f.rev()
965 rev = f.rev()
966 if rev != previousrev:
966 if rev != previousrev:
967 blockhead = True
967 blockhead = True
968 blockparity = next(blockparitygen)
968 blockparity = next(blockparitygen)
969 else:
969 else:
970 blockhead = None
970 blockhead = None
971 previousrev = rev
971 previousrev = rev
972 yield {"parity": next(parity),
972 yield {"parity": next(parity),
973 "node": f.hex(),
973 "node": f.hex(),
974 "rev": rev,
974 "rev": rev,
975 "author": f.user(),
975 "author": f.user(),
976 "parents": templateutil.mappinggenerator(parents, args=(f,)),
976 "parents": templateutil.mappinggenerator(parents, args=(f,)),
977 "desc": f.description(),
977 "desc": f.description(),
978 "extra": f.extra(),
978 "extra": f.extra(),
979 "file": f.path(),
979 "file": f.path(),
980 "blockhead": blockhead,
980 "blockhead": blockhead,
981 "blockparity": blockparity,
981 "blockparity": blockparity,
982 "targetline": aline.lineno,
982 "targetline": aline.lineno,
983 "line": aline.text,
983 "line": aline.text,
984 "lineno": lineno + 1,
984 "lineno": lineno + 1,
985 "lineid": "l%d" % (lineno + 1),
985 "lineid": "l%d" % (lineno + 1),
986 "linenumber": "% 6d" % (lineno + 1),
986 "linenumber": "% 6d" % (lineno + 1),
987 "revdate": f.date()}
987 "revdate": f.date()}
988
988
989 diffopts = webutil.difffeatureopts(web.req, web.repo.ui, 'annotate')
989 diffopts = webutil.difffeatureopts(web.req, web.repo.ui, 'annotate')
990 diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults}
990 diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults}
991
991
992 return web.sendtemplate(
992 return web.sendtemplate(
993 'fileannotate',
993 'fileannotate',
994 file=f,
994 file=f,
995 annotate=templateutil.mappinggenerator(annotate),
995 annotate=templateutil.mappinggenerator(annotate),
996 path=webutil.up(f),
996 path=webutil.up(f),
997 symrev=webutil.symrevorshortnode(web.req, fctx),
997 symrev=webutil.symrevorshortnode(web.req, fctx),
998 rename=webutil.renamelink(fctx),
998 rename=webutil.renamelink(fctx),
999 permissions=fctx.manifest().flags(f),
999 permissions=fctx.manifest().flags(f),
1000 ishead=int(ishead),
1000 ishead=int(ishead),
1001 diffopts=templateutil.hybriddict(diffopts),
1001 diffopts=templateutil.hybriddict(diffopts),
1002 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
1002 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
1003
1003
1004 @webcommand('filelog')
1004 @webcommand('filelog')
1005 def filelog(web):
1005 def filelog(web):
1006 """
1006 """
1007 /filelog/{revision}/{path}
1007 /filelog/{revision}/{path}
1008 --------------------------
1008 --------------------------
1009
1009
1010 Show information about the history of a file in the repository.
1010 Show information about the history of a file in the repository.
1011
1011
1012 The ``revcount`` query string argument can be defined to control the
1012 The ``revcount`` query string argument can be defined to control the
1013 maximum number of entries to show.
1013 maximum number of entries to show.
1014
1014
1015 The ``filelog`` template will be rendered.
1015 The ``filelog`` template will be rendered.
1016 """
1016 """
1017
1017
1018 try:
1018 try:
1019 fctx = webutil.filectx(web.repo, web.req)
1019 fctx = webutil.filectx(web.repo, web.req)
1020 f = fctx.path()
1020 f = fctx.path()
1021 fl = fctx.filelog()
1021 fl = fctx.filelog()
1022 except error.LookupError:
1022 except error.LookupError:
1023 f = webutil.cleanpath(web.repo, web.req.qsparams['file'])
1023 f = webutil.cleanpath(web.repo, web.req.qsparams['file'])
1024 fl = web.repo.file(f)
1024 fl = web.repo.file(f)
1025 numrevs = len(fl)
1025 numrevs = len(fl)
1026 if not numrevs: # file doesn't exist at all
1026 if not numrevs: # file doesn't exist at all
1027 raise
1027 raise
1028 rev = webutil.changectx(web.repo, web.req).rev()
1028 rev = webutil.changectx(web.repo, web.req).rev()
1029 first = fl.linkrev(0)
1029 first = fl.linkrev(0)
1030 if rev < first: # current rev is from before file existed
1030 if rev < first: # current rev is from before file existed
1031 raise
1031 raise
1032 frev = numrevs - 1
1032 frev = numrevs - 1
1033 while fl.linkrev(frev) > rev:
1033 while fl.linkrev(frev) > rev:
1034 frev -= 1
1034 frev -= 1
1035 fctx = web.repo.filectx(f, fl.linkrev(frev))
1035 fctx = web.repo.filectx(f, fl.linkrev(frev))
1036
1036
1037 revcount = web.maxshortchanges
1037 revcount = web.maxshortchanges
1038 if 'revcount' in web.req.qsparams:
1038 if 'revcount' in web.req.qsparams:
1039 try:
1039 try:
1040 revcount = int(web.req.qsparams.get('revcount', revcount))
1040 revcount = int(web.req.qsparams.get('revcount', revcount))
1041 revcount = max(revcount, 1)
1041 revcount = max(revcount, 1)
1042 web.tmpl.defaults['sessionvars']['revcount'] = revcount
1042 web.tmpl.defaults['sessionvars']['revcount'] = revcount
1043 except ValueError:
1043 except ValueError:
1044 pass
1044 pass
1045
1045
1046 lrange = webutil.linerange(web.req)
1046 lrange = webutil.linerange(web.req)
1047
1047
1048 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
1048 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
1049 lessvars['revcount'] = max(revcount // 2, 1)
1049 lessvars['revcount'] = max(revcount // 2, 1)
1050 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
1050 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
1051 morevars['revcount'] = revcount * 2
1051 morevars['revcount'] = revcount * 2
1052
1052
1053 patch = 'patch' in web.req.qsparams
1053 patch = 'patch' in web.req.qsparams
1054 if patch:
1054 if patch:
1055 lessvars['patch'] = morevars['patch'] = web.req.qsparams['patch']
1055 lessvars['patch'] = morevars['patch'] = web.req.qsparams['patch']
1056 descend = 'descend' in web.req.qsparams
1056 descend = 'descend' in web.req.qsparams
1057 if descend:
1057 if descend:
1058 lessvars['descend'] = morevars['descend'] = web.req.qsparams['descend']
1058 lessvars['descend'] = morevars['descend'] = web.req.qsparams['descend']
1059
1059
1060 count = fctx.filerev() + 1
1060 count = fctx.filerev() + 1
1061 start = max(0, count - revcount) # first rev on this page
1061 start = max(0, count - revcount) # first rev on this page
1062 end = min(count, start + revcount) # last rev on this page
1062 end = min(count, start + revcount) # last rev on this page
1063 parity = paritygen(web.stripecount, offset=start - end)
1063 parity = paritygen(web.stripecount, offset=start - end)
1064
1064
1065 repo = web.repo
1065 repo = web.repo
1066 filelog = fctx.filelog()
1066 filelog = fctx.filelog()
1067 revs = [filerev for filerev in filelog.revs(start, end - 1)
1067 revs = [filerev for filerev in filelog.revs(start, end - 1)
1068 if filelog.linkrev(filerev) in repo]
1068 if filelog.linkrev(filerev) in repo]
1069 entries = []
1069 entries = []
1070
1070
1071 diffstyle = web.config('web', 'style')
1071 diffstyle = web.config('web', 'style')
1072 if 'style' in web.req.qsparams:
1072 if 'style' in web.req.qsparams:
1073 diffstyle = web.req.qsparams['style']
1073 diffstyle = web.req.qsparams['style']
1074
1074
1075 def diff(fctx, linerange=None):
1075 def diff(fctx, linerange=None):
1076 ctx = fctx.changectx()
1076 ctx = fctx.changectx()
1077 basectx = ctx.p1()
1077 basectx = ctx.p1()
1078 path = fctx.path()
1078 path = fctx.path()
1079 return webutil.diffs(web, ctx, basectx, [path], diffstyle,
1079 return webutil.diffs(web, ctx, basectx, [path], diffstyle,
1080 linerange=linerange,
1080 linerange=linerange,
1081 lineidprefix='%s-' % ctx.hex()[:12])
1081 lineidprefix='%s-' % ctx.hex()[:12])
1082
1082
1083 linerange = None
1083 linerange = None
1084 if lrange is not None:
1084 if lrange is not None:
1085 linerange = webutil.formatlinerange(*lrange)
1085 linerange = webutil.formatlinerange(*lrange)
1086 # deactivate numeric nav links when linerange is specified as this
1086 # deactivate numeric nav links when linerange is specified as this
1087 # would required a dedicated "revnav" class
1087 # would required a dedicated "revnav" class
1088 nav = templateutil.mappinglist([])
1088 nav = templateutil.mappinglist([])
1089 if descend:
1089 if descend:
1090 it = dagop.blockdescendants(fctx, *lrange)
1090 it = dagop.blockdescendants(fctx, *lrange)
1091 else:
1091 else:
1092 it = dagop.blockancestors(fctx, *lrange)
1092 it = dagop.blockancestors(fctx, *lrange)
1093 for i, (c, lr) in enumerate(it, 1):
1093 for i, (c, lr) in enumerate(it, 1):
1094 diffs = None
1094 diffs = None
1095 if patch:
1095 if patch:
1096 diffs = diff(c, linerange=lr)
1096 diffs = diff(c, linerange=lr)
1097 # follow renames accross filtered (not in range) revisions
1097 # follow renames accross filtered (not in range) revisions
1098 path = c.path()
1098 path = c.path()
1099 lm = webutil.commonentry(repo, c)
1099 lm = webutil.commonentry(repo, c)
1100 lm.update({
1100 lm.update({
1101 'parity': next(parity),
1101 'parity': next(parity),
1102 'filerev': c.rev(),
1102 'filerev': c.rev(),
1103 'file': path,
1103 'file': path,
1104 'diff': diffs,
1104 'diff': diffs,
1105 'linerange': webutil.formatlinerange(*lr),
1105 'linerange': webutil.formatlinerange(*lr),
1106 'rename': templateutil.mappinglist([]),
1106 'rename': templateutil.mappinglist([]),
1107 })
1107 })
1108 entries.append(lm)
1108 entries.append(lm)
1109 if i == revcount:
1109 if i == revcount:
1110 break
1110 break
1111 lessvars['linerange'] = webutil.formatlinerange(*lrange)
1111 lessvars['linerange'] = webutil.formatlinerange(*lrange)
1112 morevars['linerange'] = lessvars['linerange']
1112 morevars['linerange'] = lessvars['linerange']
1113 else:
1113 else:
1114 for i in revs:
1114 for i in revs:
1115 iterfctx = fctx.filectx(i)
1115 iterfctx = fctx.filectx(i)
1116 diffs = None
1116 diffs = None
1117 if patch:
1117 if patch:
1118 diffs = diff(iterfctx)
1118 diffs = diff(iterfctx)
1119 lm = webutil.commonentry(repo, iterfctx)
1119 lm = webutil.commonentry(repo, iterfctx)
1120 lm.update({
1120 lm.update({
1121 'parity': next(parity),
1121 'parity': next(parity),
1122 'filerev': i,
1122 'filerev': i,
1123 'file': f,
1123 'file': f,
1124 'diff': diffs,
1124 'diff': diffs,
1125 'rename': webutil.renamelink(iterfctx),
1125 'rename': webutil.renamelink(iterfctx),
1126 })
1126 })
1127 entries.append(lm)
1127 entries.append(lm)
1128 entries.reverse()
1128 entries.reverse()
1129 revnav = webutil.filerevnav(web.repo, fctx.path())
1129 revnav = webutil.filerevnav(web.repo, fctx.path())
1130 nav = revnav.gen(end - 1, revcount, count)
1130 nav = revnav.gen(end - 1, revcount, count)
1131
1131
1132 latestentry = entries[:1]
1132 latestentry = entries[:1]
1133
1133
1134 return web.sendtemplate(
1134 return web.sendtemplate(
1135 'filelog',
1135 'filelog',
1136 file=f,
1136 file=f,
1137 nav=nav,
1137 nav=nav,
1138 symrev=webutil.symrevorshortnode(web.req, fctx),
1138 symrev=webutil.symrevorshortnode(web.req, fctx),
1139 entries=templateutil.mappinglist(entries),
1139 entries=templateutil.mappinglist(entries),
1140 descend=descend,
1140 descend=descend,
1141 patch=patch,
1141 patch=patch,
1142 latestentry=templateutil.mappinglist(latestentry),
1142 latestentry=templateutil.mappinglist(latestentry),
1143 linerange=linerange,
1143 linerange=linerange,
1144 revcount=revcount,
1144 revcount=revcount,
1145 morevars=morevars,
1145 morevars=morevars,
1146 lessvars=lessvars,
1146 lessvars=lessvars,
1147 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
1147 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))
1148
1148
1149 @webcommand('archive')
1149 @webcommand('archive')
1150 def archive(web):
1150 def archive(web):
1151 """
1151 """
1152 /archive/{revision}.{format}[/{path}]
1152 /archive/{revision}.{format}[/{path}]
1153 -------------------------------------
1153 -------------------------------------
1154
1154
1155 Obtain an archive of repository content.
1155 Obtain an archive of repository content.
1156
1156
1157 The content and type of the archive is defined by a URL path parameter.
1157 The content and type of the archive is defined by a URL path parameter.
1158 ``format`` is the file extension of the archive type to be generated. e.g.
1158 ``format`` is the file extension of the archive type to be generated. e.g.
1159 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1159 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1160 server configuration.
1160 server configuration.
1161
1161
1162 The optional ``path`` URL parameter controls content to include in the
1162 The optional ``path`` URL parameter controls content to include in the
1163 archive. If omitted, every file in the specified revision is present in the
1163 archive. If omitted, every file in the specified revision is present in the
1164 archive. If included, only the specified file or contents of the specified
1164 archive. If included, only the specified file or contents of the specified
1165 directory will be included in the archive.
1165 directory will be included in the archive.
1166
1166
1167 No template is used for this handler. Raw, binary content is generated.
1167 No template is used for this handler. Raw, binary content is generated.
1168 """
1168 """
1169
1169
1170 type_ = web.req.qsparams.get('type')
1170 type_ = web.req.qsparams.get('type')
1171 allowed = web.configlist("web", "allow-archive")
1171 allowed = web.configlist("web", "allow-archive")
1172 key = web.req.qsparams['node']
1172 key = web.req.qsparams['node']
1173
1173
1174 if type_ not in webutil.archivespecs:
1174 if type_ not in webutil.archivespecs:
1175 msg = 'Unsupported archive type: %s' % stringutil.pprint(type_)
1175 msg = 'Unsupported archive type: %s' % stringutil.pprint(type_)
1176 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1176 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1177
1177
1178 if not ((type_ in allowed or
1178 if not ((type_ in allowed or
1179 web.configbool("web", "allow" + type_))):
1179 web.configbool("web", "allow" + type_))):
1180 msg = 'Archive type not allowed: %s' % type_
1180 msg = 'Archive type not allowed: %s' % type_
1181 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1181 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1182
1182
1183 reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame))
1183 reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame))
1184 cnode = web.repo.lookup(key)
1184 cnode = web.repo.lookup(key)
1185 arch_version = key
1185 arch_version = key
1186 if cnode == key or key == 'tip':
1186 if cnode == key or key == 'tip':
1187 arch_version = short(cnode)
1187 arch_version = short(cnode)
1188 name = "%s-%s" % (reponame, arch_version)
1188 name = "%s-%s" % (reponame, arch_version)
1189
1189
1190 ctx = webutil.changectx(web.repo, web.req)
1190 ctx = webutil.changectx(web.repo, web.req)
1191 pats = []
1191 pats = []
1192 match = scmutil.match(ctx, [])
1192 match = scmutil.match(ctx, [])
1193 file = web.req.qsparams.get('file')
1193 file = web.req.qsparams.get('file')
1194 if file:
1194 if file:
1195 pats = ['path:' + file]
1195 pats = ['path:' + file]
1196 match = scmutil.match(ctx, pats, default='path')
1196 match = scmutil.match(ctx, pats, default='path')
1197 if pats:
1197 if pats:
1198 files = [f for f in ctx.manifest().keys() if match(f)]
1198 files = [f for f in ctx.manifest().keys() if match(f)]
1199 if not files:
1199 if not files:
1200 raise ErrorResponse(HTTP_NOT_FOUND,
1200 raise ErrorResponse(HTTP_NOT_FOUND,
1201 'file(s) not found: %s' % file)
1201 'file(s) not found: %s' % file)
1202
1202
1203 mimetype, artype, extension, encoding = webutil.archivespecs[type_]
1203 mimetype, artype, extension, encoding = webutil.archivespecs[type_]
1204
1204
1205 web.res.headers['Content-Type'] = mimetype
1205 web.res.headers['Content-Type'] = mimetype
1206 web.res.headers['Content-Disposition'] = 'attachment; filename=%s%s' % (
1206 web.res.headers['Content-Disposition'] = 'attachment; filename=%s%s' % (
1207 name, extension)
1207 name, extension)
1208
1208
1209 if encoding:
1209 if encoding:
1210 web.res.headers['Content-Encoding'] = encoding
1210 web.res.headers['Content-Encoding'] = encoding
1211
1211
1212 web.res.setbodywillwrite()
1212 web.res.setbodywillwrite()
1213 if list(web.res.sendresponse()):
1213 if list(web.res.sendresponse()):
1214 raise error.ProgrammingError('sendresponse() should not emit data '
1214 raise error.ProgrammingError('sendresponse() should not emit data '
1215 'if writing later')
1215 'if writing later')
1216
1216
1217 bodyfh = web.res.getbodyfile()
1217 bodyfh = web.res.getbodyfile()
1218
1218
1219 archival.archive(web.repo, bodyfh, cnode, artype, prefix=name, match=match,
1219 archival.archive(web.repo, bodyfh, cnode, artype, prefix=name, match=match,
1220 subrepos=web.configbool("web", "archivesubrepos"))
1220 subrepos=web.configbool("web", "archivesubrepos"))
1221
1221
1222 return []
1222 return []
1223
1223
1224 @webcommand('static')
1224 @webcommand('static')
1225 def static(web):
1225 def static(web):
1226 fname = web.req.qsparams['file']
1226 fname = web.req.qsparams['file']
1227 # a repo owner may set web.static in .hg/hgrc to get any file
1227 # a repo owner may set web.static in .hg/hgrc to get any file
1228 # readable by the user running the CGI script
1228 # readable by the user running the CGI script
1229 static = web.config("web", "static", untrusted=False)
1229 static = web.config("web", "static", untrusted=False)
1230 if not static:
1230 if not static:
1231 tp = web.templatepath or templater.templatepaths()
1231 tp = web.templatepath or templater.templatepaths()
1232 if isinstance(tp, str):
1232 if isinstance(tp, str):
1233 tp = [tp]
1233 tp = [tp]
1234 static = [os.path.join(p, 'static') for p in tp]
1234 static = [os.path.join(p, 'static') for p in tp]
1235
1235
1236 staticfile(static, fname, web.res)
1236 staticfile(static, fname, web.res)
1237 return web.res.sendresponse()
1237 return web.res.sendresponse()
1238
1238
1239 @webcommand('graph')
1239 @webcommand('graph')
1240 def graph(web):
1240 def graph(web):
1241 """
1241 """
1242 /graph[/{revision}]
1242 /graph[/{revision}]
1243 -------------------
1243 -------------------
1244
1244
1245 Show information about the graphical topology of the repository.
1245 Show information about the graphical topology of the repository.
1246
1246
1247 Information rendered by this handler can be used to create visual
1247 Information rendered by this handler can be used to create visual
1248 representations of repository topology.
1248 representations of repository topology.
1249
1249
1250 The ``revision`` URL parameter controls the starting changeset. If it's
1250 The ``revision`` URL parameter controls the starting changeset. If it's
1251 absent, the default is ``tip``.
1251 absent, the default is ``tip``.
1252
1252
1253 The ``revcount`` query string argument can define the number of changesets
1253 The ``revcount`` query string argument can define the number of changesets
1254 to show information for.
1254 to show information for.
1255
1255
1256 The ``graphtop`` query string argument can specify the starting changeset
1256 The ``graphtop`` query string argument can specify the starting changeset
1257 for producing ``jsdata`` variable that is used for rendering graph in
1257 for producing ``jsdata`` variable that is used for rendering graph in
1258 JavaScript. By default it has the same value as ``revision``.
1258 JavaScript. By default it has the same value as ``revision``.
1259
1259
1260 This handler will render the ``graph`` template.
1260 This handler will render the ``graph`` template.
1261 """
1261 """
1262
1262
1263 if 'node' in web.req.qsparams:
1263 if 'node' in web.req.qsparams:
1264 ctx = webutil.changectx(web.repo, web.req)
1264 ctx = webutil.changectx(web.repo, web.req)
1265 symrev = webutil.symrevorshortnode(web.req, ctx)
1265 symrev = webutil.symrevorshortnode(web.req, ctx)
1266 else:
1266 else:
1267 ctx = web.repo['tip']
1267 ctx = web.repo['tip']
1268 symrev = 'tip'
1268 symrev = 'tip'
1269 rev = ctx.rev()
1269 rev = ctx.rev()
1270
1270
1271 bg_height = 39
1271 bg_height = 39
1272 revcount = web.maxshortchanges
1272 revcount = web.maxshortchanges
1273 if 'revcount' in web.req.qsparams:
1273 if 'revcount' in web.req.qsparams:
1274 try:
1274 try:
1275 revcount = int(web.req.qsparams.get('revcount', revcount))
1275 revcount = int(web.req.qsparams.get('revcount', revcount))
1276 revcount = max(revcount, 1)
1276 revcount = max(revcount, 1)
1277 web.tmpl.defaults['sessionvars']['revcount'] = revcount
1277 web.tmpl.defaults['sessionvars']['revcount'] = revcount
1278 except ValueError:
1278 except ValueError:
1279 pass
1279 pass
1280
1280
1281 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
1281 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
1282 lessvars['revcount'] = max(revcount // 2, 1)
1282 lessvars['revcount'] = max(revcount // 2, 1)
1283 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
1283 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
1284 morevars['revcount'] = revcount * 2
1284 morevars['revcount'] = revcount * 2
1285
1285
1286 graphtop = web.req.qsparams.get('graphtop', ctx.hex())
1286 graphtop = web.req.qsparams.get('graphtop', ctx.hex())
1287 graphvars = copy.copy(web.tmpl.defaults['sessionvars'])
1287 graphvars = copy.copy(web.tmpl.defaults['sessionvars'])
1288 graphvars['graphtop'] = graphtop
1288 graphvars['graphtop'] = graphtop
1289
1289
1290 count = len(web.repo)
1290 count = len(web.repo)
1291 pos = rev
1291 pos = rev
1292
1292
1293 uprev = min(max(0, count - 1), rev + revcount)
1293 uprev = min(max(0, count - 1), rev + revcount)
1294 downrev = max(0, rev - revcount)
1294 downrev = max(0, rev - revcount)
1295 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1295 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1296
1296
1297 tree = []
1297 tree = []
1298 nextentry = []
1298 nextentry = []
1299 lastrev = 0
1299 lastrev = 0
1300 if pos != -1:
1300 if pos != -1:
1301 allrevs = web.repo.changelog.revs(pos, 0)
1301 allrevs = web.repo.changelog.revs(pos, 0)
1302 revs = []
1302 revs = []
1303 for i in allrevs:
1303 for i in allrevs:
1304 revs.append(i)
1304 revs.append(i)
1305 if len(revs) >= revcount + 1:
1305 if len(revs) >= revcount + 1:
1306 break
1306 break
1307
1307
1308 if len(revs) > revcount:
1308 if len(revs) > revcount:
1309 nextentry = [webutil.commonentry(web.repo, web.repo[revs[-1]])]
1309 nextentry = [webutil.commonentry(web.repo, web.repo[revs[-1]])]
1310 revs = revs[:-1]
1310 revs = revs[:-1]
1311
1311
1312 lastrev = revs[-1]
1312 lastrev = revs[-1]
1313
1313
1314 # We have to feed a baseset to dagwalker as it is expecting smartset
1314 # We have to feed a baseset to dagwalker as it is expecting smartset
1315 # object. This does not have a big impact on hgweb performance itself
1315 # object. This does not have a big impact on hgweb performance itself
1316 # since hgweb graphing code is not itself lazy yet.
1316 # since hgweb graphing code is not itself lazy yet.
1317 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1317 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1318 # As we said one line above... not lazy.
1318 # As we said one line above... not lazy.
1319 tree = list(item for item in graphmod.colored(dag, web.repo)
1319 tree = list(item for item in graphmod.colored(dag, web.repo)
1320 if item[1] == graphmod.CHANGESET)
1320 if item[1] == graphmod.CHANGESET)
1321
1321
1322 def fulltree():
1322 def fulltree():
1323 pos = web.repo[graphtop].rev()
1323 pos = web.repo[graphtop].rev()
1324 tree = []
1324 tree = []
1325 if pos != -1:
1325 if pos != -1:
1326 revs = web.repo.changelog.revs(pos, lastrev)
1326 revs = web.repo.changelog.revs(pos, lastrev)
1327 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1327 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1328 tree = list(item for item in graphmod.colored(dag, web.repo)
1328 tree = list(item for item in graphmod.colored(dag, web.repo)
1329 if item[1] == graphmod.CHANGESET)
1329 if item[1] == graphmod.CHANGESET)
1330 return tree
1330 return tree
1331
1331
1332 def jsdata(context):
1332 def jsdata(context):
1333 for (id, type, ctx, vtx, edges) in fulltree():
1333 for (id, type, ctx, vtx, edges) in fulltree():
1334 yield {'node': pycompat.bytestr(ctx),
1334 yield {'node': pycompat.bytestr(ctx),
1335 'graphnode': webutil.getgraphnode(web.repo, ctx),
1335 'graphnode': webutil.getgraphnode(web.repo, ctx),
1336 'vertex': vtx,
1336 'vertex': vtx,
1337 'edges': edges}
1337 'edges': edges}
1338
1338
1339 def nodes(context):
1339 def nodes(context):
1340 parity = paritygen(web.stripecount)
1340 parity = paritygen(web.stripecount)
1341 for row, (id, type, ctx, vtx, edges) in enumerate(tree):
1341 for row, (id, type, ctx, vtx, edges) in enumerate(tree):
1342 entry = webutil.commonentry(web.repo, ctx)
1342 entry = webutil.commonentry(web.repo, ctx)
1343 edgedata = [{'col': edge[0],
1343 edgedata = [{'col': edge[0],
1344 'nextcol': edge[1],
1344 'nextcol': edge[1],
1345 'color': (edge[2] - 1) % 6 + 1,
1345 'color': (edge[2] - 1) % 6 + 1,
1346 'width': edge[3],
1346 'width': edge[3],
1347 'bcolor': edge[4]}
1347 'bcolor': edge[4]}
1348 for edge in edges]
1348 for edge in edges]
1349
1349
1350 entry.update({'col': vtx[0],
1350 entry.update({'col': vtx[0],
1351 'color': (vtx[1] - 1) % 6 + 1,
1351 'color': (vtx[1] - 1) % 6 + 1,
1352 'parity': next(parity),
1352 'parity': next(parity),
1353 'edges': templateutil.mappinglist(edgedata),
1353 'edges': templateutil.mappinglist(edgedata),
1354 'row': row,
1354 'row': row,
1355 'nextrow': row + 1})
1355 'nextrow': row + 1})
1356
1356
1357 yield entry
1357 yield entry
1358
1358
1359 rows = len(tree)
1359 rows = len(tree)
1360
1360
1361 return web.sendtemplate(
1361 return web.sendtemplate(
1362 'graph',
1362 'graph',
1363 rev=rev,
1363 rev=rev,
1364 symrev=symrev,
1364 symrev=symrev,
1365 revcount=revcount,
1365 revcount=revcount,
1366 uprev=uprev,
1366 uprev=uprev,
1367 lessvars=lessvars,
1367 lessvars=lessvars,
1368 morevars=morevars,
1368 morevars=morevars,
1369 downrev=downrev,
1369 downrev=downrev,
1370 graphvars=graphvars,
1370 graphvars=graphvars,
1371 rows=rows,
1371 rows=rows,
1372 bg_height=bg_height,
1372 bg_height=bg_height,
1373 changesets=count,
1373 changesets=count,
1374 nextentry=templateutil.mappinglist(nextentry),
1374 nextentry=templateutil.mappinglist(nextentry),
1375 jsdata=templateutil.mappinggenerator(jsdata),
1375 jsdata=templateutil.mappinggenerator(jsdata),
1376 nodes=templateutil.mappinggenerator(nodes),
1376 nodes=templateutil.mappinggenerator(nodes),
1377 node=ctx.hex(),
1377 node=ctx.hex(),
1378 archives=web.archivelist('tip'),
1378 archives=web.archivelist('tip'),
1379 changenav=changenav)
1379 changenav=changenav)
1380
1380
1381 def _getdoc(e):
1381 def _getdoc(e):
1382 doc = e[0].__doc__
1382 doc = e[0].__doc__
1383 if doc:
1383 if doc:
1384 doc = _(doc).partition('\n')[0]
1384 doc = _(doc).partition('\n')[0]
1385 else:
1385 else:
1386 doc = _('(no help text available)')
1386 doc = _('(no help text available)')
1387 return doc
1387 return doc
1388
1388
1389 @webcommand('help')
1389 @webcommand('help')
1390 def help(web):
1390 def help(web):
1391 """
1391 """
1392 /help[/{topic}]
1392 /help[/{topic}]
1393 ---------------
1393 ---------------
1394
1394
1395 Render help documentation.
1395 Render help documentation.
1396
1396
1397 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1397 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1398 is defined, that help topic will be rendered. If not, an index of
1398 is defined, that help topic will be rendered. If not, an index of
1399 available help topics will be rendered.
1399 available help topics will be rendered.
1400
1400
1401 The ``help`` template will be rendered when requesting help for a topic.
1401 The ``help`` template will be rendered when requesting help for a topic.
1402 ``helptopics`` will be rendered for the index of help topics.
1402 ``helptopics`` will be rendered for the index of help topics.
1403 """
1403 """
1404 from .. import commands, help as helpmod # avoid cycle
1404 from .. import commands, help as helpmod # avoid cycle
1405
1405
1406 topicname = web.req.qsparams.get('node')
1406 topicname = web.req.qsparams.get('node')
1407 if not topicname:
1407 if not topicname:
1408 def topics(context):
1408 def topics(context):
1409 for h in helpmod.helptable:
1409 for h in helpmod.helptable:
1410 entries, summary, _doc = h[0:3]
1410 entries, summary, _doc = h[0:3]
1411 yield {'topic': entries[0], 'summary': summary}
1411 yield {'topic': entries[0], 'summary': summary}
1412
1412
1413 early, other = [], []
1413 early, other = [], []
1414 primary = lambda s: s.partition('|')[0]
1414 primary = lambda s: s.partition('|')[0]
1415 for c, e in commands.table.iteritems():
1415 for c, e in commands.table.iteritems():
1416 doc = _getdoc(e)
1416 doc = _getdoc(e)
1417 if 'DEPRECATED' in doc or c.startswith('debug'):
1417 if 'DEPRECATED' in doc or c.startswith('debug'):
1418 continue
1418 continue
1419 cmd = primary(c)
1419 cmd = primary(c)
1420 if getattr(e[0], 'helpbasic', False):
1420 if getattr(e[0], 'helpbasic', False):
1421 early.append((cmd, doc))
1421 early.append((cmd, doc))
1422 else:
1422 else:
1423 other.append((cmd, doc))
1423 other.append((cmd, doc))
1424
1424
1425 early.sort()
1425 early.sort()
1426 other.sort()
1426 other.sort()
1427
1427
1428 def earlycommands(context):
1428 def earlycommands(context):
1429 for c, doc in early:
1429 for c, doc in early:
1430 yield {'topic': c, 'summary': doc}
1430 yield {'topic': c, 'summary': doc}
1431
1431
1432 def othercommands(context):
1432 def othercommands(context):
1433 for c, doc in other:
1433 for c, doc in other:
1434 yield {'topic': c, 'summary': doc}
1434 yield {'topic': c, 'summary': doc}
1435
1435
1436 return web.sendtemplate(
1436 return web.sendtemplate(
1437 'helptopics',
1437 'helptopics',
1438 topics=templateutil.mappinggenerator(topics),
1438 topics=templateutil.mappinggenerator(topics),
1439 earlycommands=templateutil.mappinggenerator(earlycommands),
1439 earlycommands=templateutil.mappinggenerator(earlycommands),
1440 othercommands=templateutil.mappinggenerator(othercommands),
1440 othercommands=templateutil.mappinggenerator(othercommands),
1441 title='Index')
1441 title='Index')
1442
1442
1443 # Render an index of sub-topics.
1443 # Render an index of sub-topics.
1444 if topicname in helpmod.subtopics:
1444 if topicname in helpmod.subtopics:
1445 topics = []
1445 topics = []
1446 for entries, summary, _doc in helpmod.subtopics[topicname]:
1446 for entries, summary, _doc in helpmod.subtopics[topicname]:
1447 topics.append({
1447 topics.append({
1448 'topic': '%s.%s' % (topicname, entries[0]),
1448 'topic': '%s.%s' % (topicname, entries[0]),
1449 'basename': entries[0],
1449 'basename': entries[0],
1450 'summary': summary,
1450 'summary': summary,
1451 })
1451 })
1452
1452
1453 return web.sendtemplate(
1453 return web.sendtemplate(
1454 'helptopics',
1454 'helptopics',
1455 topics=templateutil.mappinglist(topics),
1455 topics=templateutil.mappinglist(topics),
1456 title=topicname,
1456 title=topicname,
1457 subindex=True)
1457 subindex=True)
1458
1458
1459 u = webutil.wsgiui.load()
1459 u = webutil.wsgiui.load()
1460 u.verbose = True
1460 u.verbose = True
1461
1461
1462 # Render a page from a sub-topic.
1462 # Render a page from a sub-topic.
1463 if '.' in topicname:
1463 if '.' in topicname:
1464 # TODO implement support for rendering sections, like
1464 # TODO implement support for rendering sections, like
1465 # `hg help` works.
1465 # `hg help` works.
1466 topic, subtopic = topicname.split('.', 1)
1466 topic, subtopic = topicname.split('.', 1)
1467 if topic not in helpmod.subtopics:
1467 if topic not in helpmod.subtopics:
1468 raise ErrorResponse(HTTP_NOT_FOUND)
1468 raise ErrorResponse(HTTP_NOT_FOUND)
1469 else:
1469 else:
1470 topic = topicname
1470 topic = topicname
1471 subtopic = None
1471 subtopic = None
1472
1472
1473 try:
1473 try:
1474 doc = helpmod.help_(u, commands, topic, subtopic=subtopic)
1474 doc = helpmod.help_(u, commands, topic, subtopic=subtopic)
1475 except error.Abort:
1475 except error.Abort:
1476 raise ErrorResponse(HTTP_NOT_FOUND)
1476 raise ErrorResponse(HTTP_NOT_FOUND)
1477
1477
1478 return web.sendtemplate(
1478 return web.sendtemplate(
1479 'help',
1479 'help',
1480 topic=topicname,
1480 topic=topicname,
1481 doc=doc)
1481 doc=doc)
1482
1482
1483 # tell hggettext to extract docstrings from these functions:
1483 # tell hggettext to extract docstrings from these functions:
1484 i18nfunctions = commands.values()
1484 i18nfunctions = commands.values()
@@ -1,937 +1,937 b''
1 #require serve zstd
1 #require serve zstd
2
2
3 Client version is embedded in HTTP request and is effectively dynamic. Pin the
3 Client version is embedded in HTTP request and is effectively dynamic. Pin the
4 version so behavior is deterministic.
4 version so behavior is deterministic.
5
5
6 $ cat > fakeversion.py << EOF
6 $ cat > fakeversion.py << EOF
7 > from mercurial import util
7 > from mercurial import util
8 > util.version = lambda: '4.2'
8 > util.version = lambda: '4.2'
9 > EOF
9 > EOF
10
10
11 $ cat >> $HGRCPATH << EOF
11 $ cat >> $HGRCPATH << EOF
12 > [extensions]
12 > [extensions]
13 > fakeversion = `pwd`/fakeversion.py
13 > fakeversion = `pwd`/fakeversion.py
14 > [format]
14 > [format]
15 > sparse-revlog = no
15 > sparse-revlog = no
16 > [devel]
16 > [devel]
17 > legacy.exchange = phases
17 > legacy.exchange = phases
18 > EOF
18 > EOF
19
19
20 $ hg init server0
20 $ hg init server0
21 $ cd server0
21 $ cd server0
22 $ touch foo
22 $ touch foo
23 $ hg -q commit -A -m initial
23 $ hg -q commit -A -m initial
24
24
25 Also disable compression because zstd is optional and causes output to vary
25 Also disable compression because zstd is optional and causes output to vary
26 and because debugging partial responses is hard when compression is involved
26 and because debugging partial responses is hard when compression is involved
27
27
28 $ cat > .hg/hgrc << EOF
28 $ cat > .hg/hgrc << EOF
29 > [extensions]
29 > [extensions]
30 > badserver = $TESTDIR/badserverext.py
30 > badserver = $TESTDIR/badserverext.py
31 > [server]
31 > [server]
32 > compressionengines = none
32 > compressionengines = none
33 > EOF
33 > EOF
34
34
35 Failure to accept() socket should result in connection related error message
35 Failure to accept() socket should result in connection related error message
36
36
37 $ hg serve --config badserver.closebeforeaccept=true -p $HGPORT -d --pid-file=hg.pid
37 $ hg serve --config badserver.closebeforeaccept=true -p $HGPORT -d --pid-file=hg.pid
38 $ cat hg.pid > $DAEMON_PIDS
38 $ cat hg.pid > $DAEMON_PIDS
39
39
40 $ hg clone http://localhost:$HGPORT/ clone
40 $ hg clone http://localhost:$HGPORT/ clone
41 abort: error: $ECONNRESET$ (?)
41 abort: error: $ECONNRESET$ (?)
42 abort: error: $EADDRNOTAVAIL$ (?)
42 abort: error: $EADDRNOTAVAIL$ (?)
43 [255]
43 [255]
44
44
45 (The server exits on its own, but there is a race between that and starting a new server.
45 (The server exits on its own, but there is a race between that and starting a new server.
46 So ensure the process is dead.)
46 So ensure the process is dead.)
47
47
48 $ killdaemons.py $DAEMON_PIDS
48 $ killdaemons.py $DAEMON_PIDS
49
49
50 Failure immediately after accept() should yield connection related error message
50 Failure immediately after accept() should yield connection related error message
51
51
52 $ hg serve --config badserver.closeafteraccept=true -p $HGPORT -d --pid-file=hg.pid
52 $ hg serve --config badserver.closeafteraccept=true -p $HGPORT -d --pid-file=hg.pid
53 $ cat hg.pid > $DAEMON_PIDS
53 $ cat hg.pid > $DAEMON_PIDS
54
54
55 TODO: this usually outputs good results, but sometimes emits abort:
55 TODO: this usually outputs good results, but sometimes emits abort:
56 error: '' on FreeBSD and OS X.
56 error: '' on FreeBSD and OS X.
57 What we ideally want are:
57 What we ideally want are:
58
58
59 abort: error: $ECONNRESET$
59 abort: error: $ECONNRESET$
60
60
61 The flakiness in this output was observable easily with
61 The flakiness in this output was observable easily with
62 --runs-per-test=20 on macOS 10.12 during the freeze for 4.2.
62 --runs-per-test=20 on macOS 10.12 during the freeze for 4.2.
63 $ hg clone http://localhost:$HGPORT/ clone
63 $ hg clone http://localhost:$HGPORT/ clone
64 abort: error: * (glob)
64 abort: error: * (glob)
65 [255]
65 [255]
66
66
67 $ killdaemons.py $DAEMON_PIDS
67 $ killdaemons.py $DAEMON_PIDS
68
68
69 Failure to read all bytes in initial HTTP request should yield connection related error message
69 Failure to read all bytes in initial HTTP request should yield connection related error message
70
70
71 $ hg serve --config badserver.closeafterrecvbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
71 $ hg serve --config badserver.closeafterrecvbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
72 $ cat hg.pid > $DAEMON_PIDS
72 $ cat hg.pid > $DAEMON_PIDS
73
73
74 $ hg clone http://localhost:$HGPORT/ clone
74 $ hg clone http://localhost:$HGPORT/ clone
75 abort: error: bad HTTP status line: ''
75 abort: error: bad HTTP status line: * (glob)
76 [255]
76 [255]
77
77
78 $ killdaemons.py $DAEMON_PIDS
78 $ killdaemons.py $DAEMON_PIDS
79
79
80 $ cat error.log
80 $ cat error.log
81 readline(1 from 65537) -> (1) G
81 readline(1 from 65537) -> (1) G
82 read limit reached; closing socket
82 read limit reached; closing socket
83
83
84 $ rm -f error.log
84 $ rm -f error.log
85
85
86 Same failure, but server reads full HTTP request line
86 Same failure, but server reads full HTTP request line
87
87
88 $ hg serve --config badserver.closeafterrecvbytes=40 -p $HGPORT -d --pid-file=hg.pid -E error.log
88 $ hg serve --config badserver.closeafterrecvbytes=40 -p $HGPORT -d --pid-file=hg.pid -E error.log
89 $ cat hg.pid > $DAEMON_PIDS
89 $ cat hg.pid > $DAEMON_PIDS
90 $ hg clone http://localhost:$HGPORT/ clone
90 $ hg clone http://localhost:$HGPORT/ clone
91 abort: error: bad HTTP status line: ''
91 abort: error: bad HTTP status line: * (glob)
92 [255]
92 [255]
93
93
94 $ killdaemons.py $DAEMON_PIDS
94 $ killdaemons.py $DAEMON_PIDS
95
95
96 $ cat error.log
96 $ cat error.log
97 readline(40 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
97 readline(40 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
98 readline(7 from -1) -> (7) Accept-
98 readline(7 from -1) -> (7) Accept-
99 read limit reached; closing socket
99 read limit reached; closing socket
100
100
101 $ rm -f error.log
101 $ rm -f error.log
102
102
103 Failure on subsequent HTTP request on the same socket (cmd?batch)
103 Failure on subsequent HTTP request on the same socket (cmd?batch)
104
104
105 $ hg serve --config badserver.closeafterrecvbytes=210,223 -p $HGPORT -d --pid-file=hg.pid -E error.log
105 $ hg serve --config badserver.closeafterrecvbytes=210,223 -p $HGPORT -d --pid-file=hg.pid -E error.log
106 $ cat hg.pid > $DAEMON_PIDS
106 $ cat hg.pid > $DAEMON_PIDS
107 $ hg clone http://localhost:$HGPORT/ clone
107 $ hg clone http://localhost:$HGPORT/ clone
108 abort: error: bad HTTP status line: ''
108 abort: error: bad HTTP status line: * (glob)
109 [255]
109 [255]
110
110
111 $ killdaemons.py $DAEMON_PIDS
111 $ killdaemons.py $DAEMON_PIDS
112
112
113 $ cat error.log
113 $ cat error.log
114 readline(210 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
114 readline(210 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
115 readline(177 from -1) -> (27) Accept-Encoding: identity\r\n
115 readline(177 from -1) -> (27) Accept-Encoding: identity\r\n
116 readline(150 from -1) -> (35) accept: application/mercurial-0.1\r\n
116 readline(150 from -1) -> (35) accept: application/mercurial-0.1\r\n
117 readline(115 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
117 readline(115 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
118 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
118 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
119 readline(* from -1) -> (2) \r\n (glob)
119 readline(* from -1) -> (2) \r\n (glob)
120 write(36) -> HTTP/1.1 200 Script output follows\r\n
120 write(36) -> HTTP/1.1 200 Script output follows\r\n
121 write(23) -> Server: badhttpserver\r\n
121 write(23) -> Server: badhttpserver\r\n
122 write(37) -> Date: $HTTP_DATE$\r\n
122 write(37) -> Date: $HTTP_DATE$\r\n
123 write(41) -> Content-Type: application/mercurial-0.1\r\n
123 write(41) -> Content-Type: application/mercurial-0.1\r\n
124 write(21) -> Content-Length: 450\r\n
124 write(21) -> Content-Length: 450\r\n
125 write(2) -> \r\n
125 write(2) -> \r\n
126 write(450) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
126 write(450) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
127 readline(4? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
127 readline(4? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
128 readline(1? from -1) -> (1?) Accept-Encoding* (glob)
128 readline(1? from -1) -> (1?) Accept-Encoding* (glob)
129 read limit reached; closing socket
129 read limit reached; closing socket
130 readline(223 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
130 readline(223 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
131 readline(197 from -1) -> (27) Accept-Encoding: identity\r\n
131 readline(197 from -1) -> (27) Accept-Encoding: identity\r\n
132 readline(170 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
132 readline(170 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
133 readline(141 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
133 readline(141 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
134 readline(100 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
134 readline(100 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
135 readline(39 from -1) -> (35) accept: application/mercurial-0.1\r\n
135 readline(39 from -1) -> (35) accept: application/mercurial-0.1\r\n
136 readline(4 from -1) -> (4) host
136 readline(4 from -1) -> (4) host
137 read limit reached; closing socket
137 read limit reached; closing socket
138
138
139 $ rm -f error.log
139 $ rm -f error.log
140
140
141 Failure to read getbundle HTTP request
141 Failure to read getbundle HTTP request
142
142
143 $ hg serve --config badserver.closeafterrecvbytes=308,317,304 -p $HGPORT -d --pid-file=hg.pid -E error.log
143 $ hg serve --config badserver.closeafterrecvbytes=308,317,304 -p $HGPORT -d --pid-file=hg.pid -E error.log
144 $ cat hg.pid > $DAEMON_PIDS
144 $ cat hg.pid > $DAEMON_PIDS
145 $ hg clone http://localhost:$HGPORT/ clone
145 $ hg clone http://localhost:$HGPORT/ clone
146 requesting all changes
146 requesting all changes
147 abort: error: bad HTTP status line: ''
147 abort: error: bad HTTP status line: * (glob)
148 [255]
148 [255]
149
149
150 $ killdaemons.py $DAEMON_PIDS
150 $ killdaemons.py $DAEMON_PIDS
151
151
152 $ cat error.log
152 $ cat error.log
153 readline(1 from -1) -> (1) x (?)
153 readline(1 from -1) -> (1) x (?)
154 readline(1 from -1) -> (1) x (?)
154 readline(1 from -1) -> (1) x (?)
155 readline(308 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
155 readline(308 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
156 readline(275 from -1) -> (27) Accept-Encoding: identity\r\n
156 readline(275 from -1) -> (27) Accept-Encoding: identity\r\n
157 readline(248 from -1) -> (35) accept: application/mercurial-0.1\r\n
157 readline(248 from -1) -> (35) accept: application/mercurial-0.1\r\n
158 readline(213 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
158 readline(213 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
159 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
159 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
160 readline(* from -1) -> (2) \r\n (glob)
160 readline(* from -1) -> (2) \r\n (glob)
161 write(36) -> HTTP/1.1 200 Script output follows\r\n
161 write(36) -> HTTP/1.1 200 Script output follows\r\n
162 write(23) -> Server: badhttpserver\r\n
162 write(23) -> Server: badhttpserver\r\n
163 write(37) -> Date: $HTTP_DATE$\r\n
163 write(37) -> Date: $HTTP_DATE$\r\n
164 write(41) -> Content-Type: application/mercurial-0.1\r\n
164 write(41) -> Content-Type: application/mercurial-0.1\r\n
165 write(21) -> Content-Length: 450\r\n
165 write(21) -> Content-Length: 450\r\n
166 write(2) -> \r\n
166 write(2) -> \r\n
167 write(450) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
167 write(450) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
168 readline(13? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
168 readline(13? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
169 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
169 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
170 readline(8? from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n (glob)
170 readline(8? from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n (glob)
171 readline(5? from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n (glob)
171 readline(5? from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n (glob)
172 readline(1? from -1) -> (1?) x-hgproto-1:* (glob)
172 readline(1? from -1) -> (1?) x-hgproto-1:* (glob)
173 read limit reached; closing socket
173 read limit reached; closing socket
174 readline(317 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
174 readline(317 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
175 readline(291 from -1) -> (27) Accept-Encoding: identity\r\n
175 readline(291 from -1) -> (27) Accept-Encoding: identity\r\n
176 readline(264 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
176 readline(264 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
177 readline(235 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
177 readline(235 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
178 readline(194 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
178 readline(194 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
179 readline(133 from -1) -> (35) accept: application/mercurial-0.1\r\n
179 readline(133 from -1) -> (35) accept: application/mercurial-0.1\r\n
180 readline(98 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
180 readline(98 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
181 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
181 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
182 readline(* from -1) -> (2) \r\n (glob)
182 readline(* from -1) -> (2) \r\n (glob)
183 write(36) -> HTTP/1.1 200 Script output follows\r\n
183 write(36) -> HTTP/1.1 200 Script output follows\r\n
184 write(23) -> Server: badhttpserver\r\n
184 write(23) -> Server: badhttpserver\r\n
185 write(37) -> Date: $HTTP_DATE$\r\n
185 write(37) -> Date: $HTTP_DATE$\r\n
186 write(41) -> Content-Type: application/mercurial-0.1\r\n
186 write(41) -> Content-Type: application/mercurial-0.1\r\n
187 write(20) -> Content-Length: 42\r\n
187 write(20) -> Content-Length: 42\r\n
188 write(2) -> \r\n
188 write(2) -> \r\n
189 write(42) -> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
189 write(42) -> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
190 readline(* from 65537) -> (*) GET /?cmd=getbundle HTTP* (glob)
190 readline(* from 65537) -> (*) GET /?cmd=getbundle HTTP* (glob)
191 read limit reached; closing socket
191 read limit reached; closing socket
192 readline(304 from 65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
192 readline(304 from 65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
193 readline(274 from -1) -> (27) Accept-Encoding: identity\r\n
193 readline(274 from -1) -> (27) Accept-Encoding: identity\r\n
194 readline(247 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
194 readline(247 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
195 readline(218 from -1) -> (218) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtag
195 readline(218 from -1) -> (218) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtag
196 read limit reached; closing socket
196 read limit reached; closing socket
197
197
198 $ rm -f error.log
198 $ rm -f error.log
199
199
200 Now do a variation using POST to send arguments
200 Now do a variation using POST to send arguments
201
201
202 $ hg serve --config experimental.httppostargs=true --config badserver.closeafterrecvbytes=329,344 -p $HGPORT -d --pid-file=hg.pid -E error.log
202 $ hg serve --config experimental.httppostargs=true --config badserver.closeafterrecvbytes=329,344 -p $HGPORT -d --pid-file=hg.pid -E error.log
203 $ cat hg.pid > $DAEMON_PIDS
203 $ cat hg.pid > $DAEMON_PIDS
204
204
205 $ hg clone http://localhost:$HGPORT/ clone
205 $ hg clone http://localhost:$HGPORT/ clone
206 abort: error: bad HTTP status line: ''
206 abort: error: bad HTTP status line: * (glob)
207 [255]
207 [255]
208
208
209 $ killdaemons.py $DAEMON_PIDS
209 $ killdaemons.py $DAEMON_PIDS
210
210
211 $ cat error.log
211 $ cat error.log
212 readline(329 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
212 readline(329 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
213 readline(296 from -1) -> (27) Accept-Encoding: identity\r\n
213 readline(296 from -1) -> (27) Accept-Encoding: identity\r\n
214 readline(269 from -1) -> (35) accept: application/mercurial-0.1\r\n
214 readline(269 from -1) -> (35) accept: application/mercurial-0.1\r\n
215 readline(234 from -1) -> (2?) host: localhost:$HGPORT\r\n (glob)
215 readline(234 from -1) -> (2?) host: localhost:$HGPORT\r\n (glob)
216 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
216 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
217 readline(* from -1) -> (2) \r\n (glob)
217 readline(* from -1) -> (2) \r\n (glob)
218 write(36) -> HTTP/1.1 200 Script output follows\r\n
218 write(36) -> HTTP/1.1 200 Script output follows\r\n
219 write(23) -> Server: badhttpserver\r\n
219 write(23) -> Server: badhttpserver\r\n
220 write(37) -> Date: $HTTP_DATE$\r\n
220 write(37) -> Date: $HTTP_DATE$\r\n
221 write(41) -> Content-Type: application/mercurial-0.1\r\n
221 write(41) -> Content-Type: application/mercurial-0.1\r\n
222 write(21) -> Content-Length: 463\r\n
222 write(21) -> Content-Length: 463\r\n
223 write(2) -> \r\n
223 write(2) -> \r\n
224 write(463) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx httppostargs known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
224 write(463) -> batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx httppostargs known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
225 readline(1?? from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n (glob)
225 readline(1?? from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n (glob)
226 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
226 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
227 readline(1?? from -1) -> (41) content-type: application/mercurial-0.1\r\n (glob)
227 readline(1?? from -1) -> (41) content-type: application/mercurial-0.1\r\n (glob)
228 readline(6? from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n (glob)
228 readline(6? from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n (glob)
229 readline(3? from -1) -> (19) x-hgargs-post: 28\r\n (glob)
229 readline(3? from -1) -> (19) x-hgargs-post: 28\r\n (glob)
230 readline(1? from -1) -> (1?) x-hgproto-1: * (glob)
230 readline(1? from -1) -> (1?) x-hgproto-1: * (glob)
231 read limit reached; closing socket
231 read limit reached; closing socket
232 readline(344 from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n
232 readline(344 from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n
233 readline(317 from -1) -> (27) Accept-Encoding: identity\r\n
233 readline(317 from -1) -> (27) Accept-Encoding: identity\r\n
234 readline(290 from -1) -> (41) content-type: application/mercurial-0.1\r\n
234 readline(290 from -1) -> (41) content-type: application/mercurial-0.1\r\n
235 readline(249 from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n
235 readline(249 from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n
236 readline(216 from -1) -> (19) x-hgargs-post: 28\r\n
236 readline(216 from -1) -> (19) x-hgargs-post: 28\r\n
237 readline(197 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
237 readline(197 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
238 readline(136 from -1) -> (35) accept: application/mercurial-0.1\r\n
238 readline(136 from -1) -> (35) accept: application/mercurial-0.1\r\n
239 readline(101 from -1) -> (20) content-length: 28\r\n
239 readline(101 from -1) -> (20) content-length: 28\r\n
240 readline(81 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
240 readline(81 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
241 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
241 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
242 readline(* from -1) -> (2) \r\n (glob)
242 readline(* from -1) -> (2) \r\n (glob)
243 read(* from 28) -> (*) cmds=* (glob)
243 read(* from 28) -> (*) cmds=* (glob)
244 read limit reached, closing socket
244 read limit reached, closing socket
245 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
245 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
246
246
247 $ rm -f error.log
247 $ rm -f error.log
248
248
249 Now move on to partial server responses
249 Now move on to partial server responses
250
250
251 Server sends a single character from the HTTP response line
251 Server sends a single character from the HTTP response line
252
252
253 $ hg serve --config badserver.closeaftersendbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
253 $ hg serve --config badserver.closeaftersendbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
254 $ cat hg.pid > $DAEMON_PIDS
254 $ cat hg.pid > $DAEMON_PIDS
255
255
256 $ hg clone http://localhost:$HGPORT/ clone
256 $ hg clone http://localhost:$HGPORT/ clone
257 abort: error: bad HTTP status line: H
257 abort: error: bad HTTP status line: H
258 [255]
258 [255]
259
259
260 $ killdaemons.py $DAEMON_PIDS
260 $ killdaemons.py $DAEMON_PIDS
261
261
262 $ cat error.log
262 $ cat error.log
263 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
263 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
264 readline(-1) -> (27) Accept-Encoding: identity\r\n
264 readline(-1) -> (27) Accept-Encoding: identity\r\n
265 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
265 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
266 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
266 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
267 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
267 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
268 readline(-1) -> (2) \r\n
268 readline(-1) -> (2) \r\n
269 write(1 from 36) -> (0) H
269 write(1 from 36) -> (0) H
270 write limit reached; closing socket
270 write limit reached; closing socket
271 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
271 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
272
272
273 $ rm -f error.log
273 $ rm -f error.log
274
274
275 Server sends an incomplete capabilities response body
275 Server sends an incomplete capabilities response body
276
276
277 $ hg serve --config badserver.closeaftersendbytes=180 -p $HGPORT -d --pid-file=hg.pid -E error.log
277 $ hg serve --config badserver.closeaftersendbytes=180 -p $HGPORT -d --pid-file=hg.pid -E error.log
278 $ cat hg.pid > $DAEMON_PIDS
278 $ cat hg.pid > $DAEMON_PIDS
279
279
280 $ hg clone http://localhost:$HGPORT/ clone
280 $ hg clone http://localhost:$HGPORT/ clone
281 abort: HTTP request error (incomplete response; expected 450 bytes got 20)
281 abort: HTTP request error (incomplete response; expected 450 bytes got 20)
282 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
282 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
283 [255]
283 [255]
284
284
285 $ killdaemons.py $DAEMON_PIDS
285 $ killdaemons.py $DAEMON_PIDS
286
286
287 $ cat error.log
287 $ cat error.log
288 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
288 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
289 readline(-1) -> (27) Accept-Encoding: identity\r\n
289 readline(-1) -> (27) Accept-Encoding: identity\r\n
290 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
290 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
291 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
291 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
292 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
292 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
293 readline(-1) -> (2) \r\n
293 readline(-1) -> (2) \r\n
294 write(36 from 36) -> (144) HTTP/1.1 200 Script output follows\r\n
294 write(36 from 36) -> (144) HTTP/1.1 200 Script output follows\r\n
295 write(23 from 23) -> (121) Server: badhttpserver\r\n
295 write(23 from 23) -> (121) Server: badhttpserver\r\n
296 write(37 from 37) -> (84) Date: $HTTP_DATE$\r\n
296 write(37 from 37) -> (84) Date: $HTTP_DATE$\r\n
297 write(41 from 41) -> (43) Content-Type: application/mercurial-0.1\r\n
297 write(41 from 41) -> (43) Content-Type: application/mercurial-0.1\r\n
298 write(21 from 21) -> (22) Content-Length: 450\r\n
298 write(21 from 21) -> (22) Content-Length: 450\r\n
299 write(2 from 2) -> (20) \r\n
299 write(2 from 2) -> (20) \r\n
300 write(20 from 450) -> (0) batch branchmap bund
300 write(20 from 450) -> (0) batch branchmap bund
301 write limit reached; closing socket
301 write limit reached; closing socket
302
302
303 $ rm -f error.log
303 $ rm -f error.log
304
304
305 Server sends incomplete headers for batch request
305 Server sends incomplete headers for batch request
306
306
307 $ hg serve --config badserver.closeaftersendbytes=728 -p $HGPORT -d --pid-file=hg.pid -E error.log
307 $ hg serve --config badserver.closeaftersendbytes=728 -p $HGPORT -d --pid-file=hg.pid -E error.log
308 $ cat hg.pid > $DAEMON_PIDS
308 $ cat hg.pid > $DAEMON_PIDS
309
309
310 TODO this output is horrible
310 TODO this output is horrible
311
311
312 $ hg clone http://localhost:$HGPORT/ clone
312 $ hg clone http://localhost:$HGPORT/ clone
313 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
313 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
314 ---%<--- (applicat)
314 ---%<--- (applicat)
315
315
316 ---%<---
316 ---%<---
317 !
317 !
318 [255]
318 [255]
319
319
320 $ killdaemons.py $DAEMON_PIDS
320 $ killdaemons.py $DAEMON_PIDS
321
321
322 $ cat error.log
322 $ cat error.log
323 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
323 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
324 readline(-1) -> (27) Accept-Encoding: identity\r\n
324 readline(-1) -> (27) Accept-Encoding: identity\r\n
325 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
325 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
326 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
326 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
327 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
327 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
328 readline(-1) -> (2) \r\n
328 readline(-1) -> (2) \r\n
329 write(36 from 36) -> (692) HTTP/1.1 200 Script output follows\r\n
329 write(36 from 36) -> (692) HTTP/1.1 200 Script output follows\r\n
330 write(23 from 23) -> (669) Server: badhttpserver\r\n
330 write(23 from 23) -> (669) Server: badhttpserver\r\n
331 write(37 from 37) -> (632) Date: $HTTP_DATE$\r\n
331 write(37 from 37) -> (632) Date: $HTTP_DATE$\r\n
332 write(41 from 41) -> (591) Content-Type: application/mercurial-0.1\r\n
332 write(41 from 41) -> (591) Content-Type: application/mercurial-0.1\r\n
333 write(21 from 21) -> (570) Content-Length: 450\r\n
333 write(21 from 21) -> (570) Content-Length: 450\r\n
334 write(2 from 2) -> (568) \r\n
334 write(2 from 2) -> (568) \r\n
335 write(450 from 450) -> (118) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
335 write(450 from 450) -> (118) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
336 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
336 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
337 readline(-1) -> (27) Accept-Encoding: identity\r\n
337 readline(-1) -> (27) Accept-Encoding: identity\r\n
338 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
338 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
339 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
339 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
340 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
340 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
341 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
341 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
342 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
342 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
343 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
343 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
344 readline(-1) -> (2) \r\n
344 readline(-1) -> (2) \r\n
345 write(36 from 36) -> (82) HTTP/1.1 200 Script output follows\r\n
345 write(36 from 36) -> (82) HTTP/1.1 200 Script output follows\r\n
346 write(23 from 23) -> (59) Server: badhttpserver\r\n
346 write(23 from 23) -> (59) Server: badhttpserver\r\n
347 write(37 from 37) -> (22) Date: $HTTP_DATE$\r\n
347 write(37 from 37) -> (22) Date: $HTTP_DATE$\r\n
348 write(22 from 41) -> (0) Content-Type: applicat
348 write(22 from 41) -> (0) Content-Type: applicat
349 write limit reached; closing socket
349 write limit reached; closing socket
350 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
350 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
351
351
352 $ rm -f error.log
352 $ rm -f error.log
353
353
354 Server sends an incomplete HTTP response body to batch request
354 Server sends an incomplete HTTP response body to batch request
355
355
356 $ hg serve --config badserver.closeaftersendbytes=793 -p $HGPORT -d --pid-file=hg.pid -E error.log
356 $ hg serve --config badserver.closeaftersendbytes=793 -p $HGPORT -d --pid-file=hg.pid -E error.log
357 $ cat hg.pid > $DAEMON_PIDS
357 $ cat hg.pid > $DAEMON_PIDS
358
358
359 TODO client spews a stack due to uncaught ValueError in batch.results()
359 TODO client spews a stack due to uncaught ValueError in batch.results()
360 #if no-chg
360 #if no-chg
361 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
361 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
362 [1]
362 [1]
363 #else
363 #else
364 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
364 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
365 [255]
365 [255]
366 #endif
366 #endif
367
367
368 $ killdaemons.py $DAEMON_PIDS
368 $ killdaemons.py $DAEMON_PIDS
369
369
370 $ cat error.log
370 $ cat error.log
371 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
371 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
372 readline(-1) -> (27) Accept-Encoding: identity\r\n
372 readline(-1) -> (27) Accept-Encoding: identity\r\n
373 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
373 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
374 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
374 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
375 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
375 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
376 readline(-1) -> (2) \r\n
376 readline(-1) -> (2) \r\n
377 write(36 from 36) -> (757) HTTP/1.1 200 Script output follows\r\n
377 write(36 from 36) -> (757) HTTP/1.1 200 Script output follows\r\n
378 write(23 from 23) -> (734) Server: badhttpserver\r\n
378 write(23 from 23) -> (734) Server: badhttpserver\r\n
379 write(37 from 37) -> (697) Date: $HTTP_DATE$\r\n
379 write(37 from 37) -> (697) Date: $HTTP_DATE$\r\n
380 write(41 from 41) -> (656) Content-Type: application/mercurial-0.1\r\n
380 write(41 from 41) -> (656) Content-Type: application/mercurial-0.1\r\n
381 write(21 from 21) -> (635) Content-Length: 450\r\n
381 write(21 from 21) -> (635) Content-Length: 450\r\n
382 write(2 from 2) -> (633) \r\n
382 write(2 from 2) -> (633) \r\n
383 write(450 from 450) -> (183) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
383 write(450 from 450) -> (183) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
384 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
384 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
385 readline(-1) -> (27) Accept-Encoding: identity\r\n
385 readline(-1) -> (27) Accept-Encoding: identity\r\n
386 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
386 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
387 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
387 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
388 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
388 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
389 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
389 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
390 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
390 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
391 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
391 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
392 readline(-1) -> (2) \r\n
392 readline(-1) -> (2) \r\n
393 write(36 from 36) -> (147) HTTP/1.1 200 Script output follows\r\n
393 write(36 from 36) -> (147) HTTP/1.1 200 Script output follows\r\n
394 write(23 from 23) -> (124) Server: badhttpserver\r\n
394 write(23 from 23) -> (124) Server: badhttpserver\r\n
395 write(37 from 37) -> (87) Date: $HTTP_DATE$\r\n
395 write(37 from 37) -> (87) Date: $HTTP_DATE$\r\n
396 write(41 from 41) -> (46) Content-Type: application/mercurial-0.1\r\n
396 write(41 from 41) -> (46) Content-Type: application/mercurial-0.1\r\n
397 write(20 from 20) -> (26) Content-Length: 42\r\n
397 write(20 from 20) -> (26) Content-Length: 42\r\n
398 write(2 from 2) -> (24) \r\n
398 write(2 from 2) -> (24) \r\n
399 write(24 from 42) -> (0) 96ee1d7354c4ad7372047672
399 write(24 from 42) -> (0) 96ee1d7354c4ad7372047672
400 write limit reached; closing socket
400 write limit reached; closing socket
401
401
402 $ rm -f error.log
402 $ rm -f error.log
403
403
404 Server sends incomplete headers for getbundle response
404 Server sends incomplete headers for getbundle response
405
405
406 $ hg serve --config badserver.closeaftersendbytes=940 -p $HGPORT -d --pid-file=hg.pid -E error.log
406 $ hg serve --config badserver.closeaftersendbytes=940 -p $HGPORT -d --pid-file=hg.pid -E error.log
407 $ cat hg.pid > $DAEMON_PIDS
407 $ cat hg.pid > $DAEMON_PIDS
408
408
409 TODO this output is terrible
409 TODO this output is terrible
410
410
411 $ hg clone http://localhost:$HGPORT/ clone
411 $ hg clone http://localhost:$HGPORT/ clone
412 requesting all changes
412 requesting all changes
413 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
413 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
414 ---%<--- (application/mercuri)
414 ---%<--- (application/mercuri)
415
415
416 ---%<---
416 ---%<---
417 !
417 !
418 [255]
418 [255]
419
419
420 $ killdaemons.py $DAEMON_PIDS
420 $ killdaemons.py $DAEMON_PIDS
421
421
422 $ cat error.log
422 $ cat error.log
423 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
423 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
424 readline(-1) -> (27) Accept-Encoding: identity\r\n
424 readline(-1) -> (27) Accept-Encoding: identity\r\n
425 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
425 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
426 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
426 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
427 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
427 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
428 readline(-1) -> (2) \r\n
428 readline(-1) -> (2) \r\n
429 write(36 from 36) -> (904) HTTP/1.1 200 Script output follows\r\n
429 write(36 from 36) -> (904) HTTP/1.1 200 Script output follows\r\n
430 write(23 from 23) -> (881) Server: badhttpserver\r\n
430 write(23 from 23) -> (881) Server: badhttpserver\r\n
431 write(37 from 37) -> (844) Date: $HTTP_DATE$\r\n
431 write(37 from 37) -> (844) Date: $HTTP_DATE$\r\n
432 write(41 from 41) -> (803) Content-Type: application/mercurial-0.1\r\n
432 write(41 from 41) -> (803) Content-Type: application/mercurial-0.1\r\n
433 write(21 from 21) -> (782) Content-Length: 450\r\n
433 write(21 from 21) -> (782) Content-Length: 450\r\n
434 write(2 from 2) -> (780) \r\n
434 write(2 from 2) -> (780) \r\n
435 write(450 from 450) -> (330) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
435 write(450 from 450) -> (330) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
436 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
436 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
437 readline(-1) -> (27) Accept-Encoding: identity\r\n
437 readline(-1) -> (27) Accept-Encoding: identity\r\n
438 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
438 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
439 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
439 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
440 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
440 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
441 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
441 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
442 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
442 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
443 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
443 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
444 readline(-1) -> (2) \r\n
444 readline(-1) -> (2) \r\n
445 write(36 from 36) -> (294) HTTP/1.1 200 Script output follows\r\n
445 write(36 from 36) -> (294) HTTP/1.1 200 Script output follows\r\n
446 write(23 from 23) -> (271) Server: badhttpserver\r\n
446 write(23 from 23) -> (271) Server: badhttpserver\r\n
447 write(37 from 37) -> (234) Date: $HTTP_DATE$\r\n
447 write(37 from 37) -> (234) Date: $HTTP_DATE$\r\n
448 write(41 from 41) -> (193) Content-Type: application/mercurial-0.1\r\n
448 write(41 from 41) -> (193) Content-Type: application/mercurial-0.1\r\n
449 write(20 from 20) -> (173) Content-Length: 42\r\n
449 write(20 from 20) -> (173) Content-Length: 42\r\n
450 write(2 from 2) -> (171) \r\n
450 write(2 from 2) -> (171) \r\n
451 write(42 from 42) -> (129) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
451 write(42 from 42) -> (129) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
452 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
452 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
453 readline(-1) -> (27) Accept-Encoding: identity\r\n
453 readline(-1) -> (27) Accept-Encoding: identity\r\n
454 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
454 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
455 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
455 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
456 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
456 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
457 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
457 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
458 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
458 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
459 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
459 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
460 readline(-1) -> (2) \r\n
460 readline(-1) -> (2) \r\n
461 write(36 from 36) -> (93) HTTP/1.1 200 Script output follows\r\n
461 write(36 from 36) -> (93) HTTP/1.1 200 Script output follows\r\n
462 write(23 from 23) -> (70) Server: badhttpserver\r\n
462 write(23 from 23) -> (70) Server: badhttpserver\r\n
463 write(37 from 37) -> (33) Date: $HTTP_DATE$\r\n
463 write(37 from 37) -> (33) Date: $HTTP_DATE$\r\n
464 write(33 from 41) -> (0) Content-Type: application/mercuri
464 write(33 from 41) -> (0) Content-Type: application/mercuri
465 write limit reached; closing socket
465 write limit reached; closing socket
466 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
466 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
467
467
468 $ rm -f error.log
468 $ rm -f error.log
469
469
470 Server stops before it sends transfer encoding
470 Server stops before it sends transfer encoding
471
471
472 $ hg serve --config badserver.closeaftersendbytes=973 -p $HGPORT -d --pid-file=hg.pid -E error.log
472 $ hg serve --config badserver.closeaftersendbytes=973 -p $HGPORT -d --pid-file=hg.pid -E error.log
473 $ cat hg.pid > $DAEMON_PIDS
473 $ cat hg.pid > $DAEMON_PIDS
474
474
475 $ hg clone http://localhost:$HGPORT/ clone
475 $ hg clone http://localhost:$HGPORT/ clone
476 requesting all changes
476 requesting all changes
477 abort: stream ended unexpectedly (got 0 bytes, expected 1)
477 abort: stream ended unexpectedly (got 0 bytes, expected 1)
478 [255]
478 [255]
479
479
480 $ killdaemons.py $DAEMON_PIDS
480 $ killdaemons.py $DAEMON_PIDS
481
481
482 $ tail -4 error.log
482 $ tail -4 error.log
483 write(41 from 41) -> (25) Content-Type: application/mercurial-0.2\r\n
483 write(41 from 41) -> (25) Content-Type: application/mercurial-0.2\r\n
484 write(25 from 28) -> (0) Transfer-Encoding: chunke
484 write(25 from 28) -> (0) Transfer-Encoding: chunke
485 write limit reached; closing socket
485 write limit reached; closing socket
486 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
486 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
487
487
488 $ rm -f error.log
488 $ rm -f error.log
489
489
490 Server sends empty HTTP body for getbundle
490 Server sends empty HTTP body for getbundle
491
491
492 $ hg serve --config badserver.closeaftersendbytes=978 -p $HGPORT -d --pid-file=hg.pid -E error.log
492 $ hg serve --config badserver.closeaftersendbytes=978 -p $HGPORT -d --pid-file=hg.pid -E error.log
493 $ cat hg.pid > $DAEMON_PIDS
493 $ cat hg.pid > $DAEMON_PIDS
494
494
495 $ hg clone http://localhost:$HGPORT/ clone
495 $ hg clone http://localhost:$HGPORT/ clone
496 requesting all changes
496 requesting all changes
497 abort: HTTP request error (incomplete response)
497 abort: HTTP request error (incomplete response)
498 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
498 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
499 [255]
499 [255]
500
500
501 $ killdaemons.py $DAEMON_PIDS
501 $ killdaemons.py $DAEMON_PIDS
502
502
503 $ cat error.log
503 $ cat error.log
504 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
504 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
505 readline(-1) -> (27) Accept-Encoding: identity\r\n
505 readline(-1) -> (27) Accept-Encoding: identity\r\n
506 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
506 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
507 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
507 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
508 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
508 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
509 readline(-1) -> (2) \r\n
509 readline(-1) -> (2) \r\n
510 write(36 from 36) -> (942) HTTP/1.1 200 Script output follows\r\n
510 write(36 from 36) -> (942) HTTP/1.1 200 Script output follows\r\n
511 write(23 from 23) -> (919) Server: badhttpserver\r\n
511 write(23 from 23) -> (919) Server: badhttpserver\r\n
512 write(37 from 37) -> (882) Date: $HTTP_DATE$\r\n
512 write(37 from 37) -> (882) Date: $HTTP_DATE$\r\n
513 write(41 from 41) -> (841) Content-Type: application/mercurial-0.1\r\n
513 write(41 from 41) -> (841) Content-Type: application/mercurial-0.1\r\n
514 write(21 from 21) -> (820) Content-Length: 450\r\n
514 write(21 from 21) -> (820) Content-Length: 450\r\n
515 write(2 from 2) -> (818) \r\n
515 write(2 from 2) -> (818) \r\n
516 write(450 from 450) -> (368) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
516 write(450 from 450) -> (368) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
517 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
517 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
518 readline(-1) -> (27) Accept-Encoding: identity\r\n
518 readline(-1) -> (27) Accept-Encoding: identity\r\n
519 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
519 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
520 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
520 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
521 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
521 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
522 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
522 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
523 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
523 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
524 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
524 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
525 readline(-1) -> (2) \r\n
525 readline(-1) -> (2) \r\n
526 write(36 from 36) -> (332) HTTP/1.1 200 Script output follows\r\n
526 write(36 from 36) -> (332) HTTP/1.1 200 Script output follows\r\n
527 write(23 from 23) -> (309) Server: badhttpserver\r\n
527 write(23 from 23) -> (309) Server: badhttpserver\r\n
528 write(37 from 37) -> (272) Date: $HTTP_DATE$\r\n
528 write(37 from 37) -> (272) Date: $HTTP_DATE$\r\n
529 write(41 from 41) -> (231) Content-Type: application/mercurial-0.1\r\n
529 write(41 from 41) -> (231) Content-Type: application/mercurial-0.1\r\n
530 write(20 from 20) -> (211) Content-Length: 42\r\n
530 write(20 from 20) -> (211) Content-Length: 42\r\n
531 write(2 from 2) -> (209) \r\n
531 write(2 from 2) -> (209) \r\n
532 write(42 from 42) -> (167) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
532 write(42 from 42) -> (167) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
533 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
533 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
534 readline(-1) -> (27) Accept-Encoding: identity\r\n
534 readline(-1) -> (27) Accept-Encoding: identity\r\n
535 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
535 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
536 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
536 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
537 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
537 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
538 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
538 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
539 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
539 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
540 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
540 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
541 readline(-1) -> (2) \r\n
541 readline(-1) -> (2) \r\n
542 write(36 from 36) -> (131) HTTP/1.1 200 Script output follows\r\n
542 write(36 from 36) -> (131) HTTP/1.1 200 Script output follows\r\n
543 write(23 from 23) -> (108) Server: badhttpserver\r\n
543 write(23 from 23) -> (108) Server: badhttpserver\r\n
544 write(37 from 37) -> (71) Date: $HTTP_DATE$\r\n
544 write(37 from 37) -> (71) Date: $HTTP_DATE$\r\n
545 write(41 from 41) -> (30) Content-Type: application/mercurial-0.2\r\n
545 write(41 from 41) -> (30) Content-Type: application/mercurial-0.2\r\n
546 write(28 from 28) -> (2) Transfer-Encoding: chunked\r\n
546 write(28 from 28) -> (2) Transfer-Encoding: chunked\r\n
547 write(2 from 2) -> (0) \r\n
547 write(2 from 2) -> (0) \r\n
548 write limit reached; closing socket
548 write limit reached; closing socket
549 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
549 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
550
550
551 $ rm -f error.log
551 $ rm -f error.log
552
552
553 Server sends partial compression string
553 Server sends partial compression string
554
554
555 $ hg serve --config badserver.closeaftersendbytes=1002 -p $HGPORT -d --pid-file=hg.pid -E error.log
555 $ hg serve --config badserver.closeaftersendbytes=1002 -p $HGPORT -d --pid-file=hg.pid -E error.log
556 $ cat hg.pid > $DAEMON_PIDS
556 $ cat hg.pid > $DAEMON_PIDS
557
557
558 $ hg clone http://localhost:$HGPORT/ clone
558 $ hg clone http://localhost:$HGPORT/ clone
559 requesting all changes
559 requesting all changes
560 abort: HTTP request error (incomplete response)
560 abort: HTTP request error (incomplete response)
561 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
561 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
562 [255]
562 [255]
563
563
564 $ killdaemons.py $DAEMON_PIDS
564 $ killdaemons.py $DAEMON_PIDS
565
565
566 $ cat error.log
566 $ cat error.log
567 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
567 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
568 readline(-1) -> (27) Accept-Encoding: identity\r\n
568 readline(-1) -> (27) Accept-Encoding: identity\r\n
569 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
569 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
570 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
570 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
571 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
571 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
572 readline(-1) -> (2) \r\n
572 readline(-1) -> (2) \r\n
573 write(36 from 36) -> (966) HTTP/1.1 200 Script output follows\r\n
573 write(36 from 36) -> (966) HTTP/1.1 200 Script output follows\r\n
574 write(23 from 23) -> (943) Server: badhttpserver\r\n
574 write(23 from 23) -> (943) Server: badhttpserver\r\n
575 write(37 from 37) -> (906) Date: $HTTP_DATE$\r\n
575 write(37 from 37) -> (906) Date: $HTTP_DATE$\r\n
576 write(41 from 41) -> (865) Content-Type: application/mercurial-0.1\r\n
576 write(41 from 41) -> (865) Content-Type: application/mercurial-0.1\r\n
577 write(21 from 21) -> (844) Content-Length: 450\r\n
577 write(21 from 21) -> (844) Content-Length: 450\r\n
578 write(2 from 2) -> (842) \r\n
578 write(2 from 2) -> (842) \r\n
579 write(450 from 450) -> (392) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
579 write(450 from 450) -> (392) batch branchmap $USUAL_BUNDLE2_CAPS_NO_PHASES$ changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
580 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
580 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
581 readline(-1) -> (27) Accept-Encoding: identity\r\n
581 readline(-1) -> (27) Accept-Encoding: identity\r\n
582 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
582 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
583 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
583 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
584 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
584 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
585 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
585 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
586 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
586 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
587 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
587 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
588 readline(-1) -> (2) \r\n
588 readline(-1) -> (2) \r\n
589 write(36 from 36) -> (356) HTTP/1.1 200 Script output follows\r\n
589 write(36 from 36) -> (356) HTTP/1.1 200 Script output follows\r\n
590 write(23 from 23) -> (333) Server: badhttpserver\r\n
590 write(23 from 23) -> (333) Server: badhttpserver\r\n
591 write(37 from 37) -> (296) Date: $HTTP_DATE$\r\n
591 write(37 from 37) -> (296) Date: $HTTP_DATE$\r\n
592 write(41 from 41) -> (255) Content-Type: application/mercurial-0.1\r\n
592 write(41 from 41) -> (255) Content-Type: application/mercurial-0.1\r\n
593 write(20 from 20) -> (235) Content-Length: 42\r\n
593 write(20 from 20) -> (235) Content-Length: 42\r\n
594 write(2 from 2) -> (233) \r\n
594 write(2 from 2) -> (233) \r\n
595 write(42 from 42) -> (191) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
595 write(42 from 42) -> (191) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
596 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
596 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
597 readline(-1) -> (27) Accept-Encoding: identity\r\n
597 readline(-1) -> (27) Accept-Encoding: identity\r\n
598 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
598 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
599 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
599 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
600 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
600 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
601 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
601 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
602 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
602 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
603 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
603 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
604 readline(-1) -> (2) \r\n
604 readline(-1) -> (2) \r\n
605 write(36 from 36) -> (155) HTTP/1.1 200 Script output follows\r\n
605 write(36 from 36) -> (155) HTTP/1.1 200 Script output follows\r\n
606 write(23 from 23) -> (132) Server: badhttpserver\r\n
606 write(23 from 23) -> (132) Server: badhttpserver\r\n
607 write(37 from 37) -> (95) Date: $HTTP_DATE$\r\n
607 write(37 from 37) -> (95) Date: $HTTP_DATE$\r\n
608 write(41 from 41) -> (54) Content-Type: application/mercurial-0.2\r\n
608 write(41 from 41) -> (54) Content-Type: application/mercurial-0.2\r\n
609 write(28 from 28) -> (26) Transfer-Encoding: chunked\r\n
609 write(28 from 28) -> (26) Transfer-Encoding: chunked\r\n
610 write(2 from 2) -> (24) \r\n
610 write(2 from 2) -> (24) \r\n
611 write(6 from 6) -> (18) 1\\r\\n\x04\\r\\n (esc)
611 write(6 from 6) -> (18) 1\\r\\n\x04\\r\\n (esc)
612 write(9 from 9) -> (9) 4\r\nnone\r\n
612 write(9 from 9) -> (9) 4\r\nnone\r\n
613 write(9 from 9) -> (0) 4\r\nHG20\r\n
613 write(9 from 9) -> (0) 4\r\nHG20\r\n
614 write limit reached; closing socket
614 write limit reached; closing socket
615 write(27) -> 15\r\nInternal Server Error\r\n
615 write(27) -> 15\r\nInternal Server Error\r\n
616
616
617 $ rm -f error.log
617 $ rm -f error.log
618
618
619 Server sends partial bundle2 header magic
619 Server sends partial bundle2 header magic
620
620
621 $ hg serve --config badserver.closeaftersendbytes=999 -p $HGPORT -d --pid-file=hg.pid -E error.log
621 $ hg serve --config badserver.closeaftersendbytes=999 -p $HGPORT -d --pid-file=hg.pid -E error.log
622 $ cat hg.pid > $DAEMON_PIDS
622 $ cat hg.pid > $DAEMON_PIDS
623
623
624 $ hg clone http://localhost:$HGPORT/ clone
624 $ hg clone http://localhost:$HGPORT/ clone
625 requesting all changes
625 requesting all changes
626 abort: HTTP request error (incomplete response; expected 4 bytes got 3)
626 abort: HTTP request error (incomplete response; expected 4 bytes got 3)
627 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
627 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
628 [255]
628 [255]
629
629
630 $ killdaemons.py $DAEMON_PIDS
630 $ killdaemons.py $DAEMON_PIDS
631
631
632 $ tail -7 error.log
632 $ tail -7 error.log
633 write(28 from 28) -> (23) Transfer-Encoding: chunked\r\n
633 write(28 from 28) -> (23) Transfer-Encoding: chunked\r\n
634 write(2 from 2) -> (21) \r\n
634 write(2 from 2) -> (21) \r\n
635 write(6 from 6) -> (15) 1\\r\\n\x04\\r\\n (esc)
635 write(6 from 6) -> (15) 1\\r\\n\x04\\r\\n (esc)
636 write(9 from 9) -> (6) 4\r\nnone\r\n
636 write(9 from 9) -> (6) 4\r\nnone\r\n
637 write(6 from 9) -> (0) 4\r\nHG2
637 write(6 from 9) -> (0) 4\r\nHG2
638 write limit reached; closing socket
638 write limit reached; closing socket
639 write(27) -> 15\r\nInternal Server Error\r\n
639 write(27) -> 15\r\nInternal Server Error\r\n
640
640
641 $ rm -f error.log
641 $ rm -f error.log
642
642
643 Server sends incomplete bundle2 stream params length
643 Server sends incomplete bundle2 stream params length
644
644
645 $ hg serve --config badserver.closeaftersendbytes=1008 -p $HGPORT -d --pid-file=hg.pid -E error.log
645 $ hg serve --config badserver.closeaftersendbytes=1008 -p $HGPORT -d --pid-file=hg.pid -E error.log
646 $ cat hg.pid > $DAEMON_PIDS
646 $ cat hg.pid > $DAEMON_PIDS
647
647
648 $ hg clone http://localhost:$HGPORT/ clone
648 $ hg clone http://localhost:$HGPORT/ clone
649 requesting all changes
649 requesting all changes
650 abort: HTTP request error (incomplete response; expected 4 bytes got 3)
650 abort: HTTP request error (incomplete response; expected 4 bytes got 3)
651 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
651 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
652 [255]
652 [255]
653
653
654 $ killdaemons.py $DAEMON_PIDS
654 $ killdaemons.py $DAEMON_PIDS
655
655
656 $ tail -8 error.log
656 $ tail -8 error.log
657 write(28 from 28) -> (32) Transfer-Encoding: chunked\r\n
657 write(28 from 28) -> (32) Transfer-Encoding: chunked\r\n
658 write(2 from 2) -> (30) \r\n
658 write(2 from 2) -> (30) \r\n
659 write(6 from 6) -> (24) 1\\r\\n\x04\\r\\n (esc)
659 write(6 from 6) -> (24) 1\\r\\n\x04\\r\\n (esc)
660 write(9 from 9) -> (15) 4\r\nnone\r\n
660 write(9 from 9) -> (15) 4\r\nnone\r\n
661 write(9 from 9) -> (6) 4\r\nHG20\r\n
661 write(9 from 9) -> (6) 4\r\nHG20\r\n
662 write(6 from 9) -> (0) 4\\r\\n\x00\x00\x00 (esc)
662 write(6 from 9) -> (0) 4\\r\\n\x00\x00\x00 (esc)
663 write limit reached; closing socket
663 write limit reached; closing socket
664 write(27) -> 15\r\nInternal Server Error\r\n
664 write(27) -> 15\r\nInternal Server Error\r\n
665
665
666 $ rm -f error.log
666 $ rm -f error.log
667
667
668 Servers stops after bundle2 stream params header
668 Servers stops after bundle2 stream params header
669
669
670 $ hg serve --config badserver.closeaftersendbytes=1011 -p $HGPORT -d --pid-file=hg.pid -E error.log
670 $ hg serve --config badserver.closeaftersendbytes=1011 -p $HGPORT -d --pid-file=hg.pid -E error.log
671 $ cat hg.pid > $DAEMON_PIDS
671 $ cat hg.pid > $DAEMON_PIDS
672
672
673 $ hg clone http://localhost:$HGPORT/ clone
673 $ hg clone http://localhost:$HGPORT/ clone
674 requesting all changes
674 requesting all changes
675 abort: HTTP request error (incomplete response)
675 abort: HTTP request error (incomplete response)
676 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
676 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
677 [255]
677 [255]
678
678
679 $ killdaemons.py $DAEMON_PIDS
679 $ killdaemons.py $DAEMON_PIDS
680
680
681 $ tail -8 error.log
681 $ tail -8 error.log
682 write(28 from 28) -> (35) Transfer-Encoding: chunked\r\n
682 write(28 from 28) -> (35) Transfer-Encoding: chunked\r\n
683 write(2 from 2) -> (33) \r\n
683 write(2 from 2) -> (33) \r\n
684 write(6 from 6) -> (27) 1\\r\\n\x04\\r\\n (esc)
684 write(6 from 6) -> (27) 1\\r\\n\x04\\r\\n (esc)
685 write(9 from 9) -> (18) 4\r\nnone\r\n
685 write(9 from 9) -> (18) 4\r\nnone\r\n
686 write(9 from 9) -> (9) 4\r\nHG20\r\n
686 write(9 from 9) -> (9) 4\r\nHG20\r\n
687 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
687 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
688 write limit reached; closing socket
688 write limit reached; closing socket
689 write(27) -> 15\r\nInternal Server Error\r\n
689 write(27) -> 15\r\nInternal Server Error\r\n
690
690
691 $ rm -f error.log
691 $ rm -f error.log
692
692
693 Server stops sending after bundle2 part header length
693 Server stops sending after bundle2 part header length
694
694
695 $ hg serve --config badserver.closeaftersendbytes=1020 -p $HGPORT -d --pid-file=hg.pid -E error.log
695 $ hg serve --config badserver.closeaftersendbytes=1020 -p $HGPORT -d --pid-file=hg.pid -E error.log
696 $ cat hg.pid > $DAEMON_PIDS
696 $ cat hg.pid > $DAEMON_PIDS
697
697
698 $ hg clone http://localhost:$HGPORT/ clone
698 $ hg clone http://localhost:$HGPORT/ clone
699 requesting all changes
699 requesting all changes
700 abort: HTTP request error (incomplete response)
700 abort: HTTP request error (incomplete response)
701 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
701 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
702 [255]
702 [255]
703
703
704 $ killdaemons.py $DAEMON_PIDS
704 $ killdaemons.py $DAEMON_PIDS
705
705
706 $ tail -9 error.log
706 $ tail -9 error.log
707 write(28 from 28) -> (44) Transfer-Encoding: chunked\r\n
707 write(28 from 28) -> (44) Transfer-Encoding: chunked\r\n
708 write(2 from 2) -> (42) \r\n
708 write(2 from 2) -> (42) \r\n
709 write(6 from 6) -> (36) 1\\r\\n\x04\\r\\n (esc)
709 write(6 from 6) -> (36) 1\\r\\n\x04\\r\\n (esc)
710 write(9 from 9) -> (27) 4\r\nnone\r\n
710 write(9 from 9) -> (27) 4\r\nnone\r\n
711 write(9 from 9) -> (18) 4\r\nHG20\r\n
711 write(9 from 9) -> (18) 4\r\nHG20\r\n
712 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
712 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
713 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
713 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
714 write limit reached; closing socket
714 write limit reached; closing socket
715 write(27) -> 15\r\nInternal Server Error\r\n
715 write(27) -> 15\r\nInternal Server Error\r\n
716
716
717 $ rm -f error.log
717 $ rm -f error.log
718
718
719 Server stops sending after bundle2 part header
719 Server stops sending after bundle2 part header
720
720
721 $ hg serve --config badserver.closeaftersendbytes=1067 -p $HGPORT -d --pid-file=hg.pid -E error.log
721 $ hg serve --config badserver.closeaftersendbytes=1067 -p $HGPORT -d --pid-file=hg.pid -E error.log
722 $ cat hg.pid > $DAEMON_PIDS
722 $ cat hg.pid > $DAEMON_PIDS
723
723
724 $ hg clone http://localhost:$HGPORT/ clone
724 $ hg clone http://localhost:$HGPORT/ clone
725 requesting all changes
725 requesting all changes
726 adding changesets
726 adding changesets
727 transaction abort!
727 transaction abort!
728 rollback completed
728 rollback completed
729 abort: HTTP request error (incomplete response)
729 abort: HTTP request error (incomplete response)
730 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
730 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
731 [255]
731 [255]
732
732
733 $ killdaemons.py $DAEMON_PIDS
733 $ killdaemons.py $DAEMON_PIDS
734
734
735 $ tail -10 error.log
735 $ tail -10 error.log
736 write(28 from 28) -> (91) Transfer-Encoding: chunked\r\n
736 write(28 from 28) -> (91) Transfer-Encoding: chunked\r\n
737 write(2 from 2) -> (89) \r\n
737 write(2 from 2) -> (89) \r\n
738 write(6 from 6) -> (83) 1\\r\\n\x04\\r\\n (esc)
738 write(6 from 6) -> (83) 1\\r\\n\x04\\r\\n (esc)
739 write(9 from 9) -> (74) 4\r\nnone\r\n
739 write(9 from 9) -> (74) 4\r\nnone\r\n
740 write(9 from 9) -> (65) 4\r\nHG20\r\n
740 write(9 from 9) -> (65) 4\r\nHG20\r\n
741 write(9 from 9) -> (56) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
741 write(9 from 9) -> (56) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
742 write(9 from 9) -> (47) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
742 write(9 from 9) -> (47) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
743 write(47 from 47) -> (0) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
743 write(47 from 47) -> (0) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
744 write limit reached; closing socket
744 write limit reached; closing socket
745 write(27) -> 15\r\nInternal Server Error\r\n
745 write(27) -> 15\r\nInternal Server Error\r\n
746
746
747 $ rm -f error.log
747 $ rm -f error.log
748
748
749 Server stops after bundle2 part payload chunk size
749 Server stops after bundle2 part payload chunk size
750
750
751 $ hg serve --config badserver.closeaftersendbytes=1088 -p $HGPORT -d --pid-file=hg.pid -E error.log
751 $ hg serve --config badserver.closeaftersendbytes=1088 -p $HGPORT -d --pid-file=hg.pid -E error.log
752 $ cat hg.pid > $DAEMON_PIDS
752 $ cat hg.pid > $DAEMON_PIDS
753
753
754 $ hg clone http://localhost:$HGPORT/ clone
754 $ hg clone http://localhost:$HGPORT/ clone
755 requesting all changes
755 requesting all changes
756 adding changesets
756 adding changesets
757 transaction abort!
757 transaction abort!
758 rollback completed
758 rollback completed
759 abort: HTTP request error (incomplete response; expected 466 bytes got 7)
759 abort: HTTP request error (incomplete response; expected 466 bytes got 7)
760 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
760 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
761 [255]
761 [255]
762
762
763 $ killdaemons.py $DAEMON_PIDS
763 $ killdaemons.py $DAEMON_PIDS
764
764
765 $ tail -11 error.log
765 $ tail -11 error.log
766 write(2 from 2) -> (110) \r\n
766 write(2 from 2) -> (110) \r\n
767 write(6 from 6) -> (104) 1\\r\\n\x04\\r\\n (esc)
767 write(6 from 6) -> (104) 1\\r\\n\x04\\r\\n (esc)
768 write(9 from 9) -> (95) 4\r\nnone\r\n
768 write(9 from 9) -> (95) 4\r\nnone\r\n
769 write(9 from 9) -> (86) 4\r\nHG20\r\n
769 write(9 from 9) -> (86) 4\r\nHG20\r\n
770 write(9 from 9) -> (77) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
770 write(9 from 9) -> (77) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
771 write(9 from 9) -> (68) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
771 write(9 from 9) -> (68) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
772 write(47 from 47) -> (21) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
772 write(47 from 47) -> (21) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
773 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
773 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
774 write(12 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1d (esc)
774 write(12 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1d (esc)
775 write limit reached; closing socket
775 write limit reached; closing socket
776 write(27) -> 15\r\nInternal Server Error\r\n
776 write(27) -> 15\r\nInternal Server Error\r\n
777
777
778 $ rm -f error.log
778 $ rm -f error.log
779
779
780 Server stops sending in middle of bundle2 payload chunk
780 Server stops sending in middle of bundle2 payload chunk
781
781
782 $ hg serve --config badserver.closeaftersendbytes=1549 -p $HGPORT -d --pid-file=hg.pid -E error.log
782 $ hg serve --config badserver.closeaftersendbytes=1549 -p $HGPORT -d --pid-file=hg.pid -E error.log
783 $ cat hg.pid > $DAEMON_PIDS
783 $ cat hg.pid > $DAEMON_PIDS
784
784
785 $ hg clone http://localhost:$HGPORT/ clone
785 $ hg clone http://localhost:$HGPORT/ clone
786 requesting all changes
786 requesting all changes
787 adding changesets
787 adding changesets
788 transaction abort!
788 transaction abort!
789 rollback completed
789 rollback completed
790 abort: HTTP request error (incomplete response)
790 abort: HTTP request error (incomplete response)
791 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
791 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
792 [255]
792 [255]
793
793
794 $ killdaemons.py $DAEMON_PIDS
794 $ killdaemons.py $DAEMON_PIDS
795
795
796 $ tail -12 error.log
796 $ tail -12 error.log
797 write(28 from 28) -> (573) Transfer-Encoding: chunked\r\n
797 write(28 from 28) -> (573) Transfer-Encoding: chunked\r\n
798 write(2 from 2) -> (571) \r\n
798 write(2 from 2) -> (571) \r\n
799 write(6 from 6) -> (565) 1\\r\\n\x04\\r\\n (esc)
799 write(6 from 6) -> (565) 1\\r\\n\x04\\r\\n (esc)
800 write(9 from 9) -> (556) 4\r\nnone\r\n
800 write(9 from 9) -> (556) 4\r\nnone\r\n
801 write(9 from 9) -> (547) 4\r\nHG20\r\n
801 write(9 from 9) -> (547) 4\r\nHG20\r\n
802 write(9 from 9) -> (538) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
802 write(9 from 9) -> (538) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
803 write(9 from 9) -> (529) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
803 write(9 from 9) -> (529) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
804 write(47 from 47) -> (482) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
804 write(47 from 47) -> (482) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
805 write(9 from 9) -> (473) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
805 write(9 from 9) -> (473) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
806 write(473 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
806 write(473 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
807 write limit reached; closing socket
807 write limit reached; closing socket
808 write(27) -> 15\r\nInternal Server Error\r\n
808 write(27) -> 15\r\nInternal Server Error\r\n
809
809
810 $ rm -f error.log
810 $ rm -f error.log
811
811
812 Server stops sending after 0 length payload chunk size
812 Server stops sending after 0 length payload chunk size
813
813
814 $ hg serve --config badserver.closeaftersendbytes=1580 -p $HGPORT -d --pid-file=hg.pid -E error.log
814 $ hg serve --config badserver.closeaftersendbytes=1580 -p $HGPORT -d --pid-file=hg.pid -E error.log
815 $ cat hg.pid > $DAEMON_PIDS
815 $ cat hg.pid > $DAEMON_PIDS
816
816
817 $ hg clone http://localhost:$HGPORT/ clone
817 $ hg clone http://localhost:$HGPORT/ clone
818 requesting all changes
818 requesting all changes
819 adding changesets
819 adding changesets
820 adding manifests
820 adding manifests
821 adding file changes
821 adding file changes
822 added 1 changesets with 1 changes to 1 files
822 added 1 changesets with 1 changes to 1 files
823 transaction abort!
823 transaction abort!
824 rollback completed
824 rollback completed
825 abort: HTTP request error (incomplete response; expected 32 bytes got 9)
825 abort: HTTP request error (incomplete response; expected 32 bytes got 9)
826 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
826 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
827 [255]
827 [255]
828
828
829 $ killdaemons.py $DAEMON_PIDS
829 $ killdaemons.py $DAEMON_PIDS
830
830
831 $ tail -13 error.log
831 $ tail -13 error.log
832 write(6 from 6) -> (596) 1\\r\\n\x04\\r\\n (esc)
832 write(6 from 6) -> (596) 1\\r\\n\x04\\r\\n (esc)
833 write(9 from 9) -> (587) 4\r\nnone\r\n
833 write(9 from 9) -> (587) 4\r\nnone\r\n
834 write(9 from 9) -> (578) 4\r\nHG20\r\n
834 write(9 from 9) -> (578) 4\r\nHG20\r\n
835 write(9 from 9) -> (569) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
835 write(9 from 9) -> (569) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
836 write(9 from 9) -> (560) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
836 write(9 from 9) -> (560) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
837 write(47 from 47) -> (513) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
837 write(47 from 47) -> (513) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
838 write(9 from 9) -> (504) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
838 write(9 from 9) -> (504) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
839 write(473 from 473) -> (31) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
839 write(473 from 473) -> (31) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
840 write(9 from 9) -> (22) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
840 write(9 from 9) -> (22) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
841 write(9 from 9) -> (13) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
841 write(9 from 9) -> (13) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
842 write(13 from 38) -> (0) 20\\r\\n\x08LISTKEYS (esc)
842 write(13 from 38) -> (0) 20\\r\\n\x08LISTKEYS (esc)
843 write limit reached; closing socket
843 write limit reached; closing socket
844 write(27) -> 15\r\nInternal Server Error\r\n
844 write(27) -> 15\r\nInternal Server Error\r\n
845
845
846 $ rm -f error.log
846 $ rm -f error.log
847
847
848 Server stops sending after 0 part bundle part header (indicating end of bundle2 payload)
848 Server stops sending after 0 part bundle part header (indicating end of bundle2 payload)
849 This is before the 0 size chunked transfer part that signals end of HTTP response.
849 This is before the 0 size chunked transfer part that signals end of HTTP response.
850
850
851 # $ hg serve --config badserver.closeaftersendbytes=1755 -p $HGPORT -d --pid-file=hg.pid -E error.log
851 # $ hg serve --config badserver.closeaftersendbytes=1755 -p $HGPORT -d --pid-file=hg.pid -E error.log
852 $ hg serve --config badserver.closeaftersendbytes=1862 -p $HGPORT -d --pid-file=hg.pid -E error.log
852 $ hg serve --config badserver.closeaftersendbytes=1862 -p $HGPORT -d --pid-file=hg.pid -E error.log
853 $ cat hg.pid > $DAEMON_PIDS
853 $ cat hg.pid > $DAEMON_PIDS
854
854
855 $ hg clone http://localhost:$HGPORT/ clone
855 $ hg clone http://localhost:$HGPORT/ clone
856 requesting all changes
856 requesting all changes
857 adding changesets
857 adding changesets
858 adding manifests
858 adding manifests
859 adding file changes
859 adding file changes
860 added 1 changesets with 1 changes to 1 files
860 added 1 changesets with 1 changes to 1 files
861 new changesets 96ee1d7354c4
861 new changesets 96ee1d7354c4
862 updating to branch default
862 updating to branch default
863 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
863 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
864
864
865 $ killdaemons.py $DAEMON_PIDS
865 $ killdaemons.py $DAEMON_PIDS
866
866
867 $ tail -22 error.log
867 $ tail -22 error.log
868 write(9 from 9) -> (851) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
868 write(9 from 9) -> (851) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
869 write(9 from 9) -> (842) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
869 write(9 from 9) -> (842) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
870 write(47 from 47) -> (795) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
870 write(47 from 47) -> (795) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
871 write(9 from 9) -> (786) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
871 write(9 from 9) -> (786) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
872 write(473 from 473) -> (313) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
872 write(473 from 473) -> (313) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
873 write(9 from 9) -> (304) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
873 write(9 from 9) -> (304) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
874 write(9 from 9) -> (295) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
874 write(9 from 9) -> (295) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
875 write(38 from 38) -> (257) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
875 write(38 from 38) -> (257) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
876 write(9 from 9) -> (248) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
876 write(9 from 9) -> (248) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
877 write(64 from 64) -> (184) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
877 write(64 from 64) -> (184) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
878 write(9 from 9) -> (175) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
878 write(9 from 9) -> (175) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
879 write(9 from 9) -> (166) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
879 write(9 from 9) -> (166) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
880 write(41 from 41) -> (125) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
880 write(41 from 41) -> (125) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
881 write(9 from 9) -> (116) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
881 write(9 from 9) -> (116) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
882 write(9 from 9) -> (107) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
882 write(9 from 9) -> (107) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
883 write(35 from 35) -> (72) 1d\\r\\n\x16cache:rev-branch-cache\x00\x00\x00\x03\x00\x00\\r\\n (esc)
883 write(35 from 35) -> (72) 1d\\r\\n\x16cache:rev-branch-cache\x00\x00\x00\x03\x00\x00\\r\\n (esc)
884 write(9 from 9) -> (63) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
884 write(9 from 9) -> (63) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
885 write(45 from 45) -> (18) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
885 write(45 from 45) -> (18) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
886 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
886 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
887 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
887 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
888 write limit reached; closing socket
888 write limit reached; closing socket
889 write(27) -> 15\r\nInternal Server Error\r\n
889 write(27) -> 15\r\nInternal Server Error\r\n
890
890
891 $ rm -f error.log
891 $ rm -f error.log
892 $ rm -rf clone
892 $ rm -rf clone
893
893
894 Server sends a size 0 chunked-transfer size without terminating \r\n
894 Server sends a size 0 chunked-transfer size without terminating \r\n
895
895
896 $ hg serve --config badserver.closeaftersendbytes=1865 -p $HGPORT -d --pid-file=hg.pid -E error.log
896 $ hg serve --config badserver.closeaftersendbytes=1865 -p $HGPORT -d --pid-file=hg.pid -E error.log
897 $ cat hg.pid > $DAEMON_PIDS
897 $ cat hg.pid > $DAEMON_PIDS
898
898
899 $ hg clone http://localhost:$HGPORT/ clone
899 $ hg clone http://localhost:$HGPORT/ clone
900 requesting all changes
900 requesting all changes
901 adding changesets
901 adding changesets
902 adding manifests
902 adding manifests
903 adding file changes
903 adding file changes
904 added 1 changesets with 1 changes to 1 files
904 added 1 changesets with 1 changes to 1 files
905 new changesets 96ee1d7354c4
905 new changesets 96ee1d7354c4
906 updating to branch default
906 updating to branch default
907 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
907 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
908
908
909 $ killdaemons.py $DAEMON_PIDS
909 $ killdaemons.py $DAEMON_PIDS
910
910
911 $ tail -23 error.log
911 $ tail -23 error.log
912 write(9 from 9) -> (854) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
912 write(9 from 9) -> (854) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
913 write(9 from 9) -> (845) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
913 write(9 from 9) -> (845) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
914 write(47 from 47) -> (798) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
914 write(47 from 47) -> (798) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
915 write(9 from 9) -> (789) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
915 write(9 from 9) -> (789) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
916 write(473 from 473) -> (316) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
916 write(473 from 473) -> (316) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
917 write(9 from 9) -> (307) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
917 write(9 from 9) -> (307) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
918 write(9 from 9) -> (298) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
918 write(9 from 9) -> (298) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
919 write(38 from 38) -> (260) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
919 write(38 from 38) -> (260) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
920 write(9 from 9) -> (251) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
920 write(9 from 9) -> (251) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
921 write(64 from 64) -> (187) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
921 write(64 from 64) -> (187) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
922 write(9 from 9) -> (178) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
922 write(9 from 9) -> (178) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
923 write(9 from 9) -> (169) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
923 write(9 from 9) -> (169) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
924 write(41 from 41) -> (128) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
924 write(41 from 41) -> (128) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
925 write(9 from 9) -> (119) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
925 write(9 from 9) -> (119) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
926 write(9 from 9) -> (110) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
926 write(9 from 9) -> (110) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
927 write(35 from 35) -> (75) 1d\\r\\n\x16cache:rev-branch-cache\x00\x00\x00\x03\x00\x00\\r\\n (esc)
927 write(35 from 35) -> (75) 1d\\r\\n\x16cache:rev-branch-cache\x00\x00\x00\x03\x00\x00\\r\\n (esc)
928 write(9 from 9) -> (66) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
928 write(9 from 9) -> (66) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
929 write(45 from 45) -> (21) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
929 write(45 from 45) -> (21) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
930 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
930 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
931 write(9 from 9) -> (3) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
931 write(9 from 9) -> (3) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
932 write(3 from 5) -> (0) 0\r\n
932 write(3 from 5) -> (0) 0\r\n
933 write limit reached; closing socket
933 write limit reached; closing socket
934 write(27) -> 15\r\nInternal Server Error\r\n
934 write(27) -> 15\r\nInternal Server Error\r\n
935
935
936 $ rm -f error.log
936 $ rm -f error.log
937 $ rm -rf clone
937 $ rm -rf clone
General Comments 0
You need to be logged in to leave comments. Login now