##// END OF EJS Templates
commandserver: preload repository in master server and reuse its file cache...
Yuya Nishihara -
r41035:dcac24ec default
parent child Browse files
Show More
@@ -0,0 +1,131 b''
1 # repocache.py - in-memory repository cache for long-running services
2 #
3 # Copyright 2018 Yuya Nishihara <yuya@tcha.org>
4 #
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.
7
8 from __future__ import absolute_import
9
10 import collections
11 import gc
12 import threading
13
14 from . import (
15 error,
16 hg,
17 obsolete,
18 scmutil,
19 util,
20 )
21
22 class repoloader(object):
23 """Load repositories in background thread
24
25 This is designed for a forking server. A cached repo cannot be obtained
26 until the server fork()s a worker and the loader thread stops.
27 """
28
29 def __init__(self, ui, maxlen):
30 self._ui = ui.copy()
31 self._cache = util.lrucachedict(max=maxlen)
32 # use deque and Event instead of Queue since deque can discard
33 # old items to keep at most maxlen items.
34 self._inqueue = collections.deque(maxlen=maxlen)
35 self._accepting = False
36 self._newentry = threading.Event()
37 self._thread = None
38
39 def start(self):
40 assert not self._thread
41 if self._inqueue.maxlen == 0:
42 # no need to spawn loader thread as the cache is disabled
43 return
44 self._accepting = True
45 self._thread = threading.Thread(target=self._mainloop)
46 self._thread.start()
47
48 def stop(self):
49 if not self._thread:
50 return
51 self._accepting = False
52 self._newentry.set()
53 self._thread.join()
54 self._thread = None
55 self._cache.clear()
56 self._inqueue.clear()
57
58 def load(self, path):
59 """Request to load the specified repository in background"""
60 self._inqueue.append(path)
61 self._newentry.set()
62
63 def get(self, path):
64 """Return a cached repo if available
65
66 This function must be called after fork(), where the loader thread
67 is stopped. Otherwise, the returned repo might be updated by the
68 loader thread.
69 """
70 if self._thread and self._thread.is_alive():
71 raise error.ProgrammingError(b'cannot obtain cached repo while '
72 b'loader is active')
73 return self._cache.peek(path, None)
74
75 def _mainloop(self):
76 while self._accepting:
77 # Avoid heavy GC after fork(), which would cancel the benefit of
78 # COW. We assume that GIL is acquired while GC is underway in the
79 # loader thread. If that isn't true, we might have to move
80 # gc.collect() to the main thread so that fork() would never stop
81 # the thread where GC is in progress.
82 gc.collect()
83
84 self._newentry.wait()
85 while self._accepting:
86 self._newentry.clear()
87 try:
88 path = self._inqueue.popleft()
89 except IndexError:
90 break
91 scmutil.callcatch(self._ui, lambda: self._load(path))
92
93 def _load(self, path):
94 start = util.timer()
95 # TODO: repo should be recreated if storage configuration changed
96 try:
97 # pop before loading so inconsistent state wouldn't be exposed
98 repo = self._cache.pop(path)
99 except KeyError:
100 repo = hg.repository(self._ui, path).unfiltered()
101 _warmupcache(repo)
102 repo.ui.log(b'repocache', b'loaded repo into cache: %s (in %.3fs)\n',
103 path, util.timer() - start)
104 self._cache.insert(path, repo)
105
106 # TODO: think about proper API of preloading cache
107 def _warmupcache(repo):
108 repo.invalidateall()
109 repo.changelog
110 repo.obsstore._all
111 repo.obsstore.successors
112 repo.obsstore.predecessors
113 repo.obsstore.children
114 for name in obsolete.cachefuncs:
115 obsolete.getrevs(repo, name)
116 repo._phasecache.loadphaserevs(repo)
117
118 # TODO: think about proper API of attaching preloaded attributes
119 def copycache(srcrepo, destrepo):
120 """Copy cached attributes from srcrepo to destrepo"""
121 destfilecache = destrepo._filecache
122 srcfilecache = srcrepo._filecache
123 if 'changelog' in srcfilecache:
124 destfilecache['changelog'] = ce = srcfilecache['changelog']
125 ce.obj.opener = ce.obj._realopener = destrepo.svfs
126 if 'obsstore' in srcfilecache:
127 destfilecache['obsstore'] = ce = srcfilecache['obsstore']
128 ce.obj.svfs = destrepo.svfs
129 if '_phasecache' in srcfilecache:
130 destfilecache['_phasecache'] = ce = srcfilecache['_phasecache']
131 ce.obj.opener = destrepo.svfs
@@ -1,673 +1,690 b''
1 # commandserver.py - communicate with Mercurial's API over a pipe
1 # commandserver.py - communicate with Mercurial's API over a pipe
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright 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 errno
10 import errno
11 import gc
11 import gc
12 import os
12 import os
13 import random
13 import random
14 import signal
14 import signal
15 import socket
15 import socket
16 import struct
16 import struct
17 import traceback
17 import traceback
18
18
19 try:
19 try:
20 import selectors
20 import selectors
21 selectors.BaseSelector
21 selectors.BaseSelector
22 except ImportError:
22 except ImportError:
23 from .thirdparty import selectors2 as selectors
23 from .thirdparty import selectors2 as selectors
24
24
25 from .i18n import _
25 from .i18n import _
26 from . import (
26 from . import (
27 encoding,
27 encoding,
28 error,
28 error,
29 loggingutil,
29 loggingutil,
30 pycompat,
30 pycompat,
31 repocache,
31 util,
32 util,
32 vfs as vfsmod,
33 vfs as vfsmod,
33 )
34 )
34 from .utils import (
35 from .utils import (
35 cborutil,
36 cborutil,
36 procutil,
37 procutil,
37 )
38 )
38
39
39 class channeledoutput(object):
40 class channeledoutput(object):
40 """
41 """
41 Write data to out in the following format:
42 Write data to out in the following format:
42
43
43 data length (unsigned int),
44 data length (unsigned int),
44 data
45 data
45 """
46 """
46 def __init__(self, out, channel):
47 def __init__(self, out, channel):
47 self.out = out
48 self.out = out
48 self.channel = channel
49 self.channel = channel
49
50
50 @property
51 @property
51 def name(self):
52 def name(self):
52 return '<%c-channel>' % self.channel
53 return '<%c-channel>' % self.channel
53
54
54 def write(self, data):
55 def write(self, data):
55 if not data:
56 if not data:
56 return
57 return
57 # single write() to guarantee the same atomicity as the underlying file
58 # single write() to guarantee the same atomicity as the underlying file
58 self.out.write(struct.pack('>cI', self.channel, len(data)) + data)
59 self.out.write(struct.pack('>cI', self.channel, len(data)) + data)
59 self.out.flush()
60 self.out.flush()
60
61
61 def __getattr__(self, attr):
62 def __getattr__(self, attr):
62 if attr in (r'isatty', r'fileno', r'tell', r'seek'):
63 if attr in (r'isatty', r'fileno', r'tell', r'seek'):
63 raise AttributeError(attr)
64 raise AttributeError(attr)
64 return getattr(self.out, attr)
65 return getattr(self.out, attr)
65
66
66 class channeledmessage(object):
67 class channeledmessage(object):
67 """
68 """
68 Write encoded message and metadata to out in the following format:
69 Write encoded message and metadata to out in the following format:
69
70
70 data length (unsigned int),
71 data length (unsigned int),
71 encoded message and metadata, as a flat key-value dict.
72 encoded message and metadata, as a flat key-value dict.
72
73
73 Each message should have 'type' attribute. Messages of unknown type
74 Each message should have 'type' attribute. Messages of unknown type
74 should be ignored.
75 should be ignored.
75 """
76 """
76
77
77 # teach ui that write() can take **opts
78 # teach ui that write() can take **opts
78 structured = True
79 structured = True
79
80
80 def __init__(self, out, channel, encodename, encodefn):
81 def __init__(self, out, channel, encodename, encodefn):
81 self._cout = channeledoutput(out, channel)
82 self._cout = channeledoutput(out, channel)
82 self.encoding = encodename
83 self.encoding = encodename
83 self._encodefn = encodefn
84 self._encodefn = encodefn
84
85
85 def write(self, data, **opts):
86 def write(self, data, **opts):
86 opts = pycompat.byteskwargs(opts)
87 opts = pycompat.byteskwargs(opts)
87 if data is not None:
88 if data is not None:
88 opts[b'data'] = data
89 opts[b'data'] = data
89 self._cout.write(self._encodefn(opts))
90 self._cout.write(self._encodefn(opts))
90
91
91 def __getattr__(self, attr):
92 def __getattr__(self, attr):
92 return getattr(self._cout, attr)
93 return getattr(self._cout, attr)
93
94
94 class channeledinput(object):
95 class channeledinput(object):
95 """
96 """
96 Read data from in_.
97 Read data from in_.
97
98
98 Requests for input are written to out in the following format:
99 Requests for input are written to out in the following format:
99 channel identifier - 'I' for plain input, 'L' line based (1 byte)
100 channel identifier - 'I' for plain input, 'L' line based (1 byte)
100 how many bytes to send at most (unsigned int),
101 how many bytes to send at most (unsigned int),
101
102
102 The client replies with:
103 The client replies with:
103 data length (unsigned int), 0 meaning EOF
104 data length (unsigned int), 0 meaning EOF
104 data
105 data
105 """
106 """
106
107
107 maxchunksize = 4 * 1024
108 maxchunksize = 4 * 1024
108
109
109 def __init__(self, in_, out, channel):
110 def __init__(self, in_, out, channel):
110 self.in_ = in_
111 self.in_ = in_
111 self.out = out
112 self.out = out
112 self.channel = channel
113 self.channel = channel
113
114
114 @property
115 @property
115 def name(self):
116 def name(self):
116 return '<%c-channel>' % self.channel
117 return '<%c-channel>' % self.channel
117
118
118 def read(self, size=-1):
119 def read(self, size=-1):
119 if size < 0:
120 if size < 0:
120 # if we need to consume all the clients input, ask for 4k chunks
121 # if we need to consume all the clients input, ask for 4k chunks
121 # so the pipe doesn't fill up risking a deadlock
122 # so the pipe doesn't fill up risking a deadlock
122 size = self.maxchunksize
123 size = self.maxchunksize
123 s = self._read(size, self.channel)
124 s = self._read(size, self.channel)
124 buf = s
125 buf = s
125 while s:
126 while s:
126 s = self._read(size, self.channel)
127 s = self._read(size, self.channel)
127 buf += s
128 buf += s
128
129
129 return buf
130 return buf
130 else:
131 else:
131 return self._read(size, self.channel)
132 return self._read(size, self.channel)
132
133
133 def _read(self, size, channel):
134 def _read(self, size, channel):
134 if not size:
135 if not size:
135 return ''
136 return ''
136 assert size > 0
137 assert size > 0
137
138
138 # tell the client we need at most size bytes
139 # tell the client we need at most size bytes
139 self.out.write(struct.pack('>cI', channel, size))
140 self.out.write(struct.pack('>cI', channel, size))
140 self.out.flush()
141 self.out.flush()
141
142
142 length = self.in_.read(4)
143 length = self.in_.read(4)
143 length = struct.unpack('>I', length)[0]
144 length = struct.unpack('>I', length)[0]
144 if not length:
145 if not length:
145 return ''
146 return ''
146 else:
147 else:
147 return self.in_.read(length)
148 return self.in_.read(length)
148
149
149 def readline(self, size=-1):
150 def readline(self, size=-1):
150 if size < 0:
151 if size < 0:
151 size = self.maxchunksize
152 size = self.maxchunksize
152 s = self._read(size, 'L')
153 s = self._read(size, 'L')
153 buf = s
154 buf = s
154 # keep asking for more until there's either no more or
155 # keep asking for more until there's either no more or
155 # we got a full line
156 # we got a full line
156 while s and s[-1] != '\n':
157 while s and s[-1] != '\n':
157 s = self._read(size, 'L')
158 s = self._read(size, 'L')
158 buf += s
159 buf += s
159
160
160 return buf
161 return buf
161 else:
162 else:
162 return self._read(size, 'L')
163 return self._read(size, 'L')
163
164
164 def __iter__(self):
165 def __iter__(self):
165 return self
166 return self
166
167
167 def next(self):
168 def next(self):
168 l = self.readline()
169 l = self.readline()
169 if not l:
170 if not l:
170 raise StopIteration
171 raise StopIteration
171 return l
172 return l
172
173
173 __next__ = next
174 __next__ = next
174
175
175 def __getattr__(self, attr):
176 def __getattr__(self, attr):
176 if attr in (r'isatty', r'fileno', r'tell', r'seek'):
177 if attr in (r'isatty', r'fileno', r'tell', r'seek'):
177 raise AttributeError(attr)
178 raise AttributeError(attr)
178 return getattr(self.in_, attr)
179 return getattr(self.in_, attr)
179
180
180 _messageencoders = {
181 _messageencoders = {
181 b'cbor': lambda v: b''.join(cborutil.streamencode(v)),
182 b'cbor': lambda v: b''.join(cborutil.streamencode(v)),
182 }
183 }
183
184
184 def _selectmessageencoder(ui):
185 def _selectmessageencoder(ui):
185 # experimental config: cmdserver.message-encodings
186 # experimental config: cmdserver.message-encodings
186 encnames = ui.configlist(b'cmdserver', b'message-encodings')
187 encnames = ui.configlist(b'cmdserver', b'message-encodings')
187 for n in encnames:
188 for n in encnames:
188 f = _messageencoders.get(n)
189 f = _messageencoders.get(n)
189 if f:
190 if f:
190 return n, f
191 return n, f
191 raise error.Abort(b'no supported message encodings: %s'
192 raise error.Abort(b'no supported message encodings: %s'
192 % b' '.join(encnames))
193 % b' '.join(encnames))
193
194
194 class server(object):
195 class server(object):
195 """
196 """
196 Listens for commands on fin, runs them and writes the output on a channel
197 Listens for commands on fin, runs them and writes the output on a channel
197 based stream to fout.
198 based stream to fout.
198 """
199 """
199 def __init__(self, ui, repo, fin, fout, prereposetups=None):
200 def __init__(self, ui, repo, fin, fout, prereposetups=None):
200 self.cwd = encoding.getcwd()
201 self.cwd = encoding.getcwd()
201
202
202 if repo:
203 if repo:
203 # the ui here is really the repo ui so take its baseui so we don't
204 # the ui here is really the repo ui so take its baseui so we don't
204 # end up with its local configuration
205 # end up with its local configuration
205 self.ui = repo.baseui
206 self.ui = repo.baseui
206 self.repo = repo
207 self.repo = repo
207 self.repoui = repo.ui
208 self.repoui = repo.ui
208 else:
209 else:
209 self.ui = ui
210 self.ui = ui
210 self.repo = self.repoui = None
211 self.repo = self.repoui = None
211 self._prereposetups = prereposetups
212 self._prereposetups = prereposetups
212
213
213 self.cdebug = channeledoutput(fout, 'd')
214 self.cdebug = channeledoutput(fout, 'd')
214 self.cerr = channeledoutput(fout, 'e')
215 self.cerr = channeledoutput(fout, 'e')
215 self.cout = channeledoutput(fout, 'o')
216 self.cout = channeledoutput(fout, 'o')
216 self.cin = channeledinput(fin, fout, 'I')
217 self.cin = channeledinput(fin, fout, 'I')
217 self.cresult = channeledoutput(fout, 'r')
218 self.cresult = channeledoutput(fout, 'r')
218
219
219 if self.ui.config(b'cmdserver', b'log') == b'-':
220 if self.ui.config(b'cmdserver', b'log') == b'-':
220 # switch log stream of server's ui to the 'd' (debug) channel
221 # switch log stream of server's ui to the 'd' (debug) channel
221 # (don't touch repo.ui as its lifetime is longer than the server)
222 # (don't touch repo.ui as its lifetime is longer than the server)
222 self.ui = self.ui.copy()
223 self.ui = self.ui.copy()
223 setuplogging(self.ui, repo=None, fp=self.cdebug)
224 setuplogging(self.ui, repo=None, fp=self.cdebug)
224
225
225 # TODO: add this to help/config.txt when stabilized
226 # TODO: add this to help/config.txt when stabilized
226 # ``channel``
227 # ``channel``
227 # Use separate channel for structured output. (Command-server only)
228 # Use separate channel for structured output. (Command-server only)
228 self.cmsg = None
229 self.cmsg = None
229 if ui.config(b'ui', b'message-output') == b'channel':
230 if ui.config(b'ui', b'message-output') == b'channel':
230 encname, encfn = _selectmessageencoder(ui)
231 encname, encfn = _selectmessageencoder(ui)
231 self.cmsg = channeledmessage(fout, b'm', encname, encfn)
232 self.cmsg = channeledmessage(fout, b'm', encname, encfn)
232
233
233 self.client = fin
234 self.client = fin
234
235
235 def cleanup(self):
236 def cleanup(self):
236 """release and restore resources taken during server session"""
237 """release and restore resources taken during server session"""
237
238
238 def _read(self, size):
239 def _read(self, size):
239 if not size:
240 if not size:
240 return ''
241 return ''
241
242
242 data = self.client.read(size)
243 data = self.client.read(size)
243
244
244 # is the other end closed?
245 # is the other end closed?
245 if not data:
246 if not data:
246 raise EOFError
247 raise EOFError
247
248
248 return data
249 return data
249
250
250 def _readstr(self):
251 def _readstr(self):
251 """read a string from the channel
252 """read a string from the channel
252
253
253 format:
254 format:
254 data length (uint32), data
255 data length (uint32), data
255 """
256 """
256 length = struct.unpack('>I', self._read(4))[0]
257 length = struct.unpack('>I', self._read(4))[0]
257 if not length:
258 if not length:
258 return ''
259 return ''
259 return self._read(length)
260 return self._read(length)
260
261
261 def _readlist(self):
262 def _readlist(self):
262 """read a list of NULL separated strings from the channel"""
263 """read a list of NULL separated strings from the channel"""
263 s = self._readstr()
264 s = self._readstr()
264 if s:
265 if s:
265 return s.split('\0')
266 return s.split('\0')
266 else:
267 else:
267 return []
268 return []
268
269
269 def runcommand(self):
270 def runcommand(self):
270 """ reads a list of \0 terminated arguments, executes
271 """ reads a list of \0 terminated arguments, executes
271 and writes the return code to the result channel """
272 and writes the return code to the result channel """
272 from . import dispatch # avoid cycle
273 from . import dispatch # avoid cycle
273
274
274 args = self._readlist()
275 args = self._readlist()
275
276
276 # copy the uis so changes (e.g. --config or --verbose) don't
277 # copy the uis so changes (e.g. --config or --verbose) don't
277 # persist between requests
278 # persist between requests
278 copiedui = self.ui.copy()
279 copiedui = self.ui.copy()
279 uis = [copiedui]
280 uis = [copiedui]
280 if self.repo:
281 if self.repo:
281 self.repo.baseui = copiedui
282 self.repo.baseui = copiedui
282 # clone ui without using ui.copy because this is protected
283 # clone ui without using ui.copy because this is protected
283 repoui = self.repoui.__class__(self.repoui)
284 repoui = self.repoui.__class__(self.repoui)
284 repoui.copy = copiedui.copy # redo copy protection
285 repoui.copy = copiedui.copy # redo copy protection
285 uis.append(repoui)
286 uis.append(repoui)
286 self.repo.ui = self.repo.dirstate._ui = repoui
287 self.repo.ui = self.repo.dirstate._ui = repoui
287 self.repo.invalidateall()
288 self.repo.invalidateall()
288
289
289 for ui in uis:
290 for ui in uis:
290 ui.resetstate()
291 ui.resetstate()
291 # any kind of interaction must use server channels, but chg may
292 # any kind of interaction must use server channels, but chg may
292 # replace channels by fully functional tty files. so nontty is
293 # replace channels by fully functional tty files. so nontty is
293 # enforced only if cin is a channel.
294 # enforced only if cin is a channel.
294 if not util.safehasattr(self.cin, 'fileno'):
295 if not util.safehasattr(self.cin, 'fileno'):
295 ui.setconfig('ui', 'nontty', 'true', 'commandserver')
296 ui.setconfig('ui', 'nontty', 'true', 'commandserver')
296
297
297 req = dispatch.request(args[:], copiedui, self.repo, self.cin,
298 req = dispatch.request(args[:], copiedui, self.repo, self.cin,
298 self.cout, self.cerr, self.cmsg,
299 self.cout, self.cerr, self.cmsg,
299 prereposetups=self._prereposetups)
300 prereposetups=self._prereposetups)
300
301
301 try:
302 try:
302 ret = dispatch.dispatch(req) & 255
303 ret = dispatch.dispatch(req) & 255
303 self.cresult.write(struct.pack('>i', int(ret)))
304 self.cresult.write(struct.pack('>i', int(ret)))
304 finally:
305 finally:
305 # restore old cwd
306 # restore old cwd
306 if '--cwd' in args:
307 if '--cwd' in args:
307 os.chdir(self.cwd)
308 os.chdir(self.cwd)
308
309
309 def getencoding(self):
310 def getencoding(self):
310 """ writes the current encoding to the result channel """
311 """ writes the current encoding to the result channel """
311 self.cresult.write(encoding.encoding)
312 self.cresult.write(encoding.encoding)
312
313
313 def serveone(self):
314 def serveone(self):
314 cmd = self.client.readline()[:-1]
315 cmd = self.client.readline()[:-1]
315 if cmd:
316 if cmd:
316 handler = self.capabilities.get(cmd)
317 handler = self.capabilities.get(cmd)
317 if handler:
318 if handler:
318 handler(self)
319 handler(self)
319 else:
320 else:
320 # clients are expected to check what commands are supported by
321 # clients are expected to check what commands are supported by
321 # looking at the servers capabilities
322 # looking at the servers capabilities
322 raise error.Abort(_('unknown command %s') % cmd)
323 raise error.Abort(_('unknown command %s') % cmd)
323
324
324 return cmd != ''
325 return cmd != ''
325
326
326 capabilities = {'runcommand': runcommand,
327 capabilities = {'runcommand': runcommand,
327 'getencoding': getencoding}
328 'getencoding': getencoding}
328
329
329 def serve(self):
330 def serve(self):
330 hellomsg = 'capabilities: ' + ' '.join(sorted(self.capabilities))
331 hellomsg = 'capabilities: ' + ' '.join(sorted(self.capabilities))
331 hellomsg += '\n'
332 hellomsg += '\n'
332 hellomsg += 'encoding: ' + encoding.encoding
333 hellomsg += 'encoding: ' + encoding.encoding
333 hellomsg += '\n'
334 hellomsg += '\n'
334 if self.cmsg:
335 if self.cmsg:
335 hellomsg += 'message-encoding: %s\n' % self.cmsg.encoding
336 hellomsg += 'message-encoding: %s\n' % self.cmsg.encoding
336 hellomsg += 'pid: %d' % procutil.getpid()
337 hellomsg += 'pid: %d' % procutil.getpid()
337 if util.safehasattr(os, 'getpgid'):
338 if util.safehasattr(os, 'getpgid'):
338 hellomsg += '\n'
339 hellomsg += '\n'
339 hellomsg += 'pgid: %d' % os.getpgid(0)
340 hellomsg += 'pgid: %d' % os.getpgid(0)
340
341
341 # write the hello msg in -one- chunk
342 # write the hello msg in -one- chunk
342 self.cout.write(hellomsg)
343 self.cout.write(hellomsg)
343
344
344 try:
345 try:
345 while self.serveone():
346 while self.serveone():
346 pass
347 pass
347 except EOFError:
348 except EOFError:
348 # we'll get here if the client disconnected while we were reading
349 # we'll get here if the client disconnected while we were reading
349 # its request
350 # its request
350 return 1
351 return 1
351
352
352 return 0
353 return 0
353
354
354 def setuplogging(ui, repo=None, fp=None):
355 def setuplogging(ui, repo=None, fp=None):
355 """Set up server logging facility
356 """Set up server logging facility
356
357
357 If cmdserver.log is '-', log messages will be sent to the given fp.
358 If cmdserver.log is '-', log messages will be sent to the given fp.
358 It should be the 'd' channel while a client is connected, and otherwise
359 It should be the 'd' channel while a client is connected, and otherwise
359 is the stderr of the server process.
360 is the stderr of the server process.
360 """
361 """
361 # developer config: cmdserver.log
362 # developer config: cmdserver.log
362 logpath = ui.config(b'cmdserver', b'log')
363 logpath = ui.config(b'cmdserver', b'log')
363 if not logpath:
364 if not logpath:
364 return
365 return
365 # developer config: cmdserver.track-log
366 # developer config: cmdserver.track-log
366 tracked = set(ui.configlist(b'cmdserver', b'track-log'))
367 tracked = set(ui.configlist(b'cmdserver', b'track-log'))
367
368
368 if logpath == b'-' and fp:
369 if logpath == b'-' and fp:
369 logger = loggingutil.fileobjectlogger(fp, tracked)
370 logger = loggingutil.fileobjectlogger(fp, tracked)
370 elif logpath == b'-':
371 elif logpath == b'-':
371 logger = loggingutil.fileobjectlogger(ui.ferr, tracked)
372 logger = loggingutil.fileobjectlogger(ui.ferr, tracked)
372 else:
373 else:
373 logpath = os.path.abspath(util.expandpath(logpath))
374 logpath = os.path.abspath(util.expandpath(logpath))
374 # developer config: cmdserver.max-log-files
375 # developer config: cmdserver.max-log-files
375 maxfiles = ui.configint(b'cmdserver', b'max-log-files')
376 maxfiles = ui.configint(b'cmdserver', b'max-log-files')
376 # developer config: cmdserver.max-log-size
377 # developer config: cmdserver.max-log-size
377 maxsize = ui.configbytes(b'cmdserver', b'max-log-size')
378 maxsize = ui.configbytes(b'cmdserver', b'max-log-size')
378 vfs = vfsmod.vfs(os.path.dirname(logpath))
379 vfs = vfsmod.vfs(os.path.dirname(logpath))
379 logger = loggingutil.filelogger(vfs, os.path.basename(logpath), tracked,
380 logger = loggingutil.filelogger(vfs, os.path.basename(logpath), tracked,
380 maxfiles=maxfiles, maxsize=maxsize)
381 maxfiles=maxfiles, maxsize=maxsize)
381
382
382 targetuis = {ui}
383 targetuis = {ui}
383 if repo:
384 if repo:
384 targetuis.add(repo.baseui)
385 targetuis.add(repo.baseui)
385 targetuis.add(repo.ui)
386 targetuis.add(repo.ui)
386 for u in targetuis:
387 for u in targetuis:
387 u.setlogger(b'cmdserver', logger)
388 u.setlogger(b'cmdserver', logger)
388
389
389 class pipeservice(object):
390 class pipeservice(object):
390 def __init__(self, ui, repo, opts):
391 def __init__(self, ui, repo, opts):
391 self.ui = ui
392 self.ui = ui
392 self.repo = repo
393 self.repo = repo
393
394
394 def init(self):
395 def init(self):
395 pass
396 pass
396
397
397 def run(self):
398 def run(self):
398 ui = self.ui
399 ui = self.ui
399 # redirect stdio to null device so that broken extensions or in-process
400 # redirect stdio to null device so that broken extensions or in-process
400 # hooks will never cause corruption of channel protocol.
401 # hooks will never cause corruption of channel protocol.
401 with procutil.protectedstdio(ui.fin, ui.fout) as (fin, fout):
402 with procutil.protectedstdio(ui.fin, ui.fout) as (fin, fout):
402 sv = server(ui, self.repo, fin, fout)
403 sv = server(ui, self.repo, fin, fout)
403 try:
404 try:
404 return sv.serve()
405 return sv.serve()
405 finally:
406 finally:
406 sv.cleanup()
407 sv.cleanup()
407
408
408 def _initworkerprocess():
409 def _initworkerprocess():
409 # use a different process group from the master process, in order to:
410 # use a different process group from the master process, in order to:
410 # 1. make the current process group no longer "orphaned" (because the
411 # 1. make the current process group no longer "orphaned" (because the
411 # parent of this process is in a different process group while
412 # parent of this process is in a different process group while
412 # remains in a same session)
413 # remains in a same session)
413 # according to POSIX 2.2.2.52, orphaned process group will ignore
414 # according to POSIX 2.2.2.52, orphaned process group will ignore
414 # terminal-generated stop signals like SIGTSTP (Ctrl+Z), which will
415 # terminal-generated stop signals like SIGTSTP (Ctrl+Z), which will
415 # cause trouble for things like ncurses.
416 # cause trouble for things like ncurses.
416 # 2. the client can use kill(-pgid, sig) to simulate terminal-generated
417 # 2. the client can use kill(-pgid, sig) to simulate terminal-generated
417 # SIGINT (Ctrl+C) and process-exit-generated SIGHUP. our child
418 # SIGINT (Ctrl+C) and process-exit-generated SIGHUP. our child
418 # processes like ssh will be killed properly, without affecting
419 # processes like ssh will be killed properly, without affecting
419 # unrelated processes.
420 # unrelated processes.
420 os.setpgid(0, 0)
421 os.setpgid(0, 0)
421 # change random state otherwise forked request handlers would have a
422 # change random state otherwise forked request handlers would have a
422 # same state inherited from parent.
423 # same state inherited from parent.
423 random.seed()
424 random.seed()
424
425
425 def _serverequest(ui, repo, conn, createcmdserver, prereposetups):
426 def _serverequest(ui, repo, conn, createcmdserver, prereposetups):
426 fin = conn.makefile(r'rb')
427 fin = conn.makefile(r'rb')
427 fout = conn.makefile(r'wb')
428 fout = conn.makefile(r'wb')
428 sv = None
429 sv = None
429 try:
430 try:
430 sv = createcmdserver(repo, conn, fin, fout, prereposetups)
431 sv = createcmdserver(repo, conn, fin, fout, prereposetups)
431 try:
432 try:
432 sv.serve()
433 sv.serve()
433 # handle exceptions that may be raised by command server. most of
434 # handle exceptions that may be raised by command server. most of
434 # known exceptions are caught by dispatch.
435 # known exceptions are caught by dispatch.
435 except error.Abort as inst:
436 except error.Abort as inst:
436 ui.error(_('abort: %s\n') % inst)
437 ui.error(_('abort: %s\n') % inst)
437 except IOError as inst:
438 except IOError as inst:
438 if inst.errno != errno.EPIPE:
439 if inst.errno != errno.EPIPE:
439 raise
440 raise
440 except KeyboardInterrupt:
441 except KeyboardInterrupt:
441 pass
442 pass
442 finally:
443 finally:
443 sv.cleanup()
444 sv.cleanup()
444 except: # re-raises
445 except: # re-raises
445 # also write traceback to error channel. otherwise client cannot
446 # also write traceback to error channel. otherwise client cannot
446 # see it because it is written to server's stderr by default.
447 # see it because it is written to server's stderr by default.
447 if sv:
448 if sv:
448 cerr = sv.cerr
449 cerr = sv.cerr
449 else:
450 else:
450 cerr = channeledoutput(fout, 'e')
451 cerr = channeledoutput(fout, 'e')
451 cerr.write(encoding.strtolocal(traceback.format_exc()))
452 cerr.write(encoding.strtolocal(traceback.format_exc()))
452 raise
453 raise
453 finally:
454 finally:
454 fin.close()
455 fin.close()
455 try:
456 try:
456 fout.close() # implicit flush() may cause another EPIPE
457 fout.close() # implicit flush() may cause another EPIPE
457 except IOError as inst:
458 except IOError as inst:
458 if inst.errno != errno.EPIPE:
459 if inst.errno != errno.EPIPE:
459 raise
460 raise
460
461
461 class unixservicehandler(object):
462 class unixservicehandler(object):
462 """Set of pluggable operations for unix-mode services
463 """Set of pluggable operations for unix-mode services
463
464
464 Almost all methods except for createcmdserver() are called in the main
465 Almost all methods except for createcmdserver() are called in the main
465 process. You can't pass mutable resource back from createcmdserver().
466 process. You can't pass mutable resource back from createcmdserver().
466 """
467 """
467
468
468 pollinterval = None
469 pollinterval = None
469
470
470 def __init__(self, ui):
471 def __init__(self, ui):
471 self.ui = ui
472 self.ui = ui
472
473
473 def bindsocket(self, sock, address):
474 def bindsocket(self, sock, address):
474 util.bindunixsocket(sock, address)
475 util.bindunixsocket(sock, address)
475 sock.listen(socket.SOMAXCONN)
476 sock.listen(socket.SOMAXCONN)
476 self.ui.status(_('listening at %s\n') % address)
477 self.ui.status(_('listening at %s\n') % address)
477 self.ui.flush() # avoid buffering of status message
478 self.ui.flush() # avoid buffering of status message
478
479
479 def unlinksocket(self, address):
480 def unlinksocket(self, address):
480 os.unlink(address)
481 os.unlink(address)
481
482
482 def shouldexit(self):
483 def shouldexit(self):
483 """True if server should shut down; checked per pollinterval"""
484 """True if server should shut down; checked per pollinterval"""
484 return False
485 return False
485
486
486 def newconnection(self):
487 def newconnection(self):
487 """Called when main process notices new connection"""
488 """Called when main process notices new connection"""
488
489
489 def createcmdserver(self, repo, conn, fin, fout, prereposetups):
490 def createcmdserver(self, repo, conn, fin, fout, prereposetups):
490 """Create new command server instance; called in the process that
491 """Create new command server instance; called in the process that
491 serves for the current connection"""
492 serves for the current connection"""
492 return server(self.ui, repo, fin, fout, prereposetups)
493 return server(self.ui, repo, fin, fout, prereposetups)
493
494
494 class unixforkingservice(object):
495 class unixforkingservice(object):
495 """
496 """
496 Listens on unix domain socket and forks server per connection
497 Listens on unix domain socket and forks server per connection
497 """
498 """
498
499
499 def __init__(self, ui, repo, opts, handler=None):
500 def __init__(self, ui, repo, opts, handler=None):
500 self.ui = ui
501 self.ui = ui
501 self.repo = repo
502 self.repo = repo
502 self.address = opts['address']
503 self.address = opts['address']
503 if not util.safehasattr(socket, 'AF_UNIX'):
504 if not util.safehasattr(socket, 'AF_UNIX'):
504 raise error.Abort(_('unsupported platform'))
505 raise error.Abort(_('unsupported platform'))
505 if not self.address:
506 if not self.address:
506 raise error.Abort(_('no socket path specified with --address'))
507 raise error.Abort(_('no socket path specified with --address'))
507 self._servicehandler = handler or unixservicehandler(ui)
508 self._servicehandler = handler or unixservicehandler(ui)
508 self._sock = None
509 self._sock = None
509 self._mainipc = None
510 self._mainipc = None
510 self._workeripc = None
511 self._workeripc = None
511 self._oldsigchldhandler = None
512 self._oldsigchldhandler = None
512 self._workerpids = set() # updated by signal handler; do not iterate
513 self._workerpids = set() # updated by signal handler; do not iterate
513 self._socketunlinked = None
514 self._socketunlinked = None
515 # experimental config: cmdserver.max-repo-cache
516 maxlen = ui.configint(b'cmdserver', b'max-repo-cache')
517 if maxlen < 0:
518 raise error.Abort(_('negative max-repo-cache size not allowed'))
519 self._repoloader = repocache.repoloader(ui, maxlen)
514
520
515 def init(self):
521 def init(self):
516 self._sock = socket.socket(socket.AF_UNIX)
522 self._sock = socket.socket(socket.AF_UNIX)
517 # IPC channel from many workers to one main process; this is actually
523 # IPC channel from many workers to one main process; this is actually
518 # a uni-directional pipe, but is backed by a DGRAM socket so each
524 # a uni-directional pipe, but is backed by a DGRAM socket so each
519 # message can be easily separated.
525 # message can be easily separated.
520 o = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM)
526 o = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM)
521 self._mainipc, self._workeripc = o
527 self._mainipc, self._workeripc = o
522 self._servicehandler.bindsocket(self._sock, self.address)
528 self._servicehandler.bindsocket(self._sock, self.address)
523 if util.safehasattr(procutil, 'unblocksignal'):
529 if util.safehasattr(procutil, 'unblocksignal'):
524 procutil.unblocksignal(signal.SIGCHLD)
530 procutil.unblocksignal(signal.SIGCHLD)
525 o = signal.signal(signal.SIGCHLD, self._sigchldhandler)
531 o = signal.signal(signal.SIGCHLD, self._sigchldhandler)
526 self._oldsigchldhandler = o
532 self._oldsigchldhandler = o
527 self._socketunlinked = False
533 self._socketunlinked = False
534 self._repoloader.start()
528
535
529 def _unlinksocket(self):
536 def _unlinksocket(self):
530 if not self._socketunlinked:
537 if not self._socketunlinked:
531 self._servicehandler.unlinksocket(self.address)
538 self._servicehandler.unlinksocket(self.address)
532 self._socketunlinked = True
539 self._socketunlinked = True
533
540
534 def _cleanup(self):
541 def _cleanup(self):
535 signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
542 signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
536 self._sock.close()
543 self._sock.close()
537 self._mainipc.close()
544 self._mainipc.close()
538 self._workeripc.close()
545 self._workeripc.close()
539 self._unlinksocket()
546 self._unlinksocket()
547 self._repoloader.stop()
540 # don't kill child processes as they have active clients, just wait
548 # don't kill child processes as they have active clients, just wait
541 self._reapworkers(0)
549 self._reapworkers(0)
542
550
543 def run(self):
551 def run(self):
544 try:
552 try:
545 self._mainloop()
553 self._mainloop()
546 finally:
554 finally:
547 self._cleanup()
555 self._cleanup()
548
556
549 def _mainloop(self):
557 def _mainloop(self):
550 exiting = False
558 exiting = False
551 h = self._servicehandler
559 h = self._servicehandler
552 selector = selectors.DefaultSelector()
560 selector = selectors.DefaultSelector()
553 selector.register(self._sock, selectors.EVENT_READ,
561 selector.register(self._sock, selectors.EVENT_READ,
554 self._acceptnewconnection)
562 self._acceptnewconnection)
555 selector.register(self._mainipc, selectors.EVENT_READ,
563 selector.register(self._mainipc, selectors.EVENT_READ,
556 self._handlemainipc)
564 self._handlemainipc)
557 while True:
565 while True:
558 if not exiting and h.shouldexit():
566 if not exiting and h.shouldexit():
559 # clients can no longer connect() to the domain socket, so
567 # clients can no longer connect() to the domain socket, so
560 # we stop queuing new requests.
568 # we stop queuing new requests.
561 # for requests that are queued (connect()-ed, but haven't been
569 # for requests that are queued (connect()-ed, but haven't been
562 # accept()-ed), handle them before exit. otherwise, clients
570 # accept()-ed), handle them before exit. otherwise, clients
563 # waiting for recv() will receive ECONNRESET.
571 # waiting for recv() will receive ECONNRESET.
564 self._unlinksocket()
572 self._unlinksocket()
565 exiting = True
573 exiting = True
566 try:
574 try:
567 events = selector.select(timeout=h.pollinterval)
575 events = selector.select(timeout=h.pollinterval)
568 except OSError as inst:
576 except OSError as inst:
569 # selectors2 raises ETIMEDOUT if timeout exceeded while
577 # selectors2 raises ETIMEDOUT if timeout exceeded while
570 # handling signal interrupt. That's probably wrong, but
578 # handling signal interrupt. That's probably wrong, but
571 # we can easily get around it.
579 # we can easily get around it.
572 if inst.errno != errno.ETIMEDOUT:
580 if inst.errno != errno.ETIMEDOUT:
573 raise
581 raise
574 events = []
582 events = []
575 if not events:
583 if not events:
576 # only exit if we completed all queued requests
584 # only exit if we completed all queued requests
577 if exiting:
585 if exiting:
578 break
586 break
579 continue
587 continue
580 for key, _mask in events:
588 for key, _mask in events:
581 key.data(key.fileobj, selector)
589 key.data(key.fileobj, selector)
582 selector.close()
590 selector.close()
583
591
584 def _acceptnewconnection(self, sock, selector):
592 def _acceptnewconnection(self, sock, selector):
585 h = self._servicehandler
593 h = self._servicehandler
586 try:
594 try:
587 conn, _addr = sock.accept()
595 conn, _addr = sock.accept()
588 except socket.error as inst:
596 except socket.error as inst:
589 if inst.args[0] == errno.EINTR:
597 if inst.args[0] == errno.EINTR:
590 return
598 return
591 raise
599 raise
592
600
601 # Future improvement: On Python 3.7, maybe gc.freeze() can be used
602 # to prevent COW memory from being touched by GC.
603 # https://instagram-engineering.com/
604 # copy-on-write-friendly-python-garbage-collection-ad6ed5233ddf
593 pid = os.fork()
605 pid = os.fork()
594 if pid:
606 if pid:
595 try:
607 try:
596 self.ui.log(b'cmdserver', b'forked worker process (pid=%d)\n',
608 self.ui.log(b'cmdserver', b'forked worker process (pid=%d)\n',
597 pid)
609 pid)
598 self._workerpids.add(pid)
610 self._workerpids.add(pid)
599 h.newconnection()
611 h.newconnection()
600 finally:
612 finally:
601 conn.close() # release handle in parent process
613 conn.close() # release handle in parent process
602 else:
614 else:
603 try:
615 try:
604 selector.close()
616 selector.close()
605 sock.close()
617 sock.close()
606 self._mainipc.close()
618 self._mainipc.close()
607 self._runworker(conn)
619 self._runworker(conn)
608 conn.close()
620 conn.close()
609 self._workeripc.close()
621 self._workeripc.close()
610 os._exit(0)
622 os._exit(0)
611 except: # never return, hence no re-raises
623 except: # never return, hence no re-raises
612 try:
624 try:
613 self.ui.traceback(force=True)
625 self.ui.traceback(force=True)
614 finally:
626 finally:
615 os._exit(255)
627 os._exit(255)
616
628
617 def _handlemainipc(self, sock, selector):
629 def _handlemainipc(self, sock, selector):
618 """Process messages sent from a worker"""
630 """Process messages sent from a worker"""
619 try:
631 try:
620 path = sock.recv(32768) # large enough to receive path
632 path = sock.recv(32768) # large enough to receive path
621 except socket.error as inst:
633 except socket.error as inst:
622 if inst.args[0] == errno.EINTR:
634 if inst.args[0] == errno.EINTR:
623 return
635 return
624 raise
636 raise
625
637 self._repoloader.load(path)
626 self.ui.log(b'cmdserver', b'repository: %s\n', path)
627
638
628 def _sigchldhandler(self, signal, frame):
639 def _sigchldhandler(self, signal, frame):
629 self._reapworkers(os.WNOHANG)
640 self._reapworkers(os.WNOHANG)
630
641
631 def _reapworkers(self, options):
642 def _reapworkers(self, options):
632 while self._workerpids:
643 while self._workerpids:
633 try:
644 try:
634 pid, _status = os.waitpid(-1, options)
645 pid, _status = os.waitpid(-1, options)
635 except OSError as inst:
646 except OSError as inst:
636 if inst.errno == errno.EINTR:
647 if inst.errno == errno.EINTR:
637 continue
648 continue
638 if inst.errno != errno.ECHILD:
649 if inst.errno != errno.ECHILD:
639 raise
650 raise
640 # no child processes at all (reaped by other waitpid()?)
651 # no child processes at all (reaped by other waitpid()?)
641 self._workerpids.clear()
652 self._workerpids.clear()
642 return
653 return
643 if pid == 0:
654 if pid == 0:
644 # no waitable child processes
655 # no waitable child processes
645 return
656 return
646 self.ui.log(b'cmdserver', b'worker process exited (pid=%d)\n', pid)
657 self.ui.log(b'cmdserver', b'worker process exited (pid=%d)\n', pid)
647 self._workerpids.discard(pid)
658 self._workerpids.discard(pid)
648
659
649 def _runworker(self, conn):
660 def _runworker(self, conn):
650 signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
661 signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
651 _initworkerprocess()
662 _initworkerprocess()
652 h = self._servicehandler
663 h = self._servicehandler
653 try:
664 try:
654 _serverequest(self.ui, self.repo, conn, h.createcmdserver,
665 _serverequest(self.ui, self.repo, conn, h.createcmdserver,
655 prereposetups=[self._reposetup])
666 prereposetups=[self._reposetup])
656 finally:
667 finally:
657 gc.collect() # trigger __del__ since worker process uses os._exit
668 gc.collect() # trigger __del__ since worker process uses os._exit
658
669
659 def _reposetup(self, ui, repo):
670 def _reposetup(self, ui, repo):
660 if not repo.local():
671 if not repo.local():
661 return
672 return
662
673
663 class unixcmdserverrepo(repo.__class__):
674 class unixcmdserverrepo(repo.__class__):
664 def close(self):
675 def close(self):
665 super(unixcmdserverrepo, self).close()
676 super(unixcmdserverrepo, self).close()
666 try:
677 try:
667 self._cmdserveripc.send(self.root)
678 self._cmdserveripc.send(self.root)
668 except socket.error:
679 except socket.error:
669 self.ui.log(b'cmdserver',
680 self.ui.log(b'cmdserver',
670 b'failed to send repo root to master\n')
681 b'failed to send repo root to master\n')
671
682
672 repo.__class__ = unixcmdserverrepo
683 repo.__class__ = unixcmdserverrepo
673 repo._cmdserveripc = self._workeripc
684 repo._cmdserveripc = self._workeripc
685
686 cachedrepo = self._repoloader.get(repo.root)
687 if cachedrepo is None:
688 return
689 repo.ui.log(b'repocache', b'repo from cache: %s\n', repo.root)
690 repocache.copycache(cachedrepo, repo)
@@ -1,1463 +1,1466 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', 'max-repo-cache',
183 default=0,
184 )
182 coreconfigitem('cmdserver', 'message-encodings',
185 coreconfigitem('cmdserver', 'message-encodings',
183 default=list,
186 default=list,
184 )
187 )
185 coreconfigitem('cmdserver', 'track-log',
188 coreconfigitem('cmdserver', 'track-log',
186 default=lambda: ['chgserver', 'cmdserver'],
189 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
187 )
190 )
188 coreconfigitem('color', '.*',
191 coreconfigitem('color', '.*',
189 default=None,
192 default=None,
190 generic=True,
193 generic=True,
191 )
194 )
192 coreconfigitem('color', 'mode',
195 coreconfigitem('color', 'mode',
193 default='auto',
196 default='auto',
194 )
197 )
195 coreconfigitem('color', 'pagermode',
198 coreconfigitem('color', 'pagermode',
196 default=dynamicdefault,
199 default=dynamicdefault,
197 )
200 )
198 coreconfigitem('commands', 'grep.all-files',
201 coreconfigitem('commands', 'grep.all-files',
199 default=False,
202 default=False,
200 )
203 )
201 coreconfigitem('commands', 'resolve.confirm',
204 coreconfigitem('commands', 'resolve.confirm',
202 default=False,
205 default=False,
203 )
206 )
204 coreconfigitem('commands', 'resolve.explicit-re-merge',
207 coreconfigitem('commands', 'resolve.explicit-re-merge',
205 default=False,
208 default=False,
206 )
209 )
207 coreconfigitem('commands', 'resolve.mark-check',
210 coreconfigitem('commands', 'resolve.mark-check',
208 default='none',
211 default='none',
209 )
212 )
210 coreconfigitem('commands', 'show.aliasprefix',
213 coreconfigitem('commands', 'show.aliasprefix',
211 default=list,
214 default=list,
212 )
215 )
213 coreconfigitem('commands', 'status.relative',
216 coreconfigitem('commands', 'status.relative',
214 default=False,
217 default=False,
215 )
218 )
216 coreconfigitem('commands', 'status.skipstates',
219 coreconfigitem('commands', 'status.skipstates',
217 default=[],
220 default=[],
218 )
221 )
219 coreconfigitem('commands', 'status.terse',
222 coreconfigitem('commands', 'status.terse',
220 default='',
223 default='',
221 )
224 )
222 coreconfigitem('commands', 'status.verbose',
225 coreconfigitem('commands', 'status.verbose',
223 default=False,
226 default=False,
224 )
227 )
225 coreconfigitem('commands', 'update.check',
228 coreconfigitem('commands', 'update.check',
226 default=None,
229 default=None,
227 )
230 )
228 coreconfigitem('commands', 'update.requiredest',
231 coreconfigitem('commands', 'update.requiredest',
229 default=False,
232 default=False,
230 )
233 )
231 coreconfigitem('committemplate', '.*',
234 coreconfigitem('committemplate', '.*',
232 default=None,
235 default=None,
233 generic=True,
236 generic=True,
234 )
237 )
235 coreconfigitem('convert', 'bzr.saverev',
238 coreconfigitem('convert', 'bzr.saverev',
236 default=True,
239 default=True,
237 )
240 )
238 coreconfigitem('convert', 'cvsps.cache',
241 coreconfigitem('convert', 'cvsps.cache',
239 default=True,
242 default=True,
240 )
243 )
241 coreconfigitem('convert', 'cvsps.fuzz',
244 coreconfigitem('convert', 'cvsps.fuzz',
242 default=60,
245 default=60,
243 )
246 )
244 coreconfigitem('convert', 'cvsps.logencoding',
247 coreconfigitem('convert', 'cvsps.logencoding',
245 default=None,
248 default=None,
246 )
249 )
247 coreconfigitem('convert', 'cvsps.mergefrom',
250 coreconfigitem('convert', 'cvsps.mergefrom',
248 default=None,
251 default=None,
249 )
252 )
250 coreconfigitem('convert', 'cvsps.mergeto',
253 coreconfigitem('convert', 'cvsps.mergeto',
251 default=None,
254 default=None,
252 )
255 )
253 coreconfigitem('convert', 'git.committeractions',
256 coreconfigitem('convert', 'git.committeractions',
254 default=lambda: ['messagedifferent'],
257 default=lambda: ['messagedifferent'],
255 )
258 )
256 coreconfigitem('convert', 'git.extrakeys',
259 coreconfigitem('convert', 'git.extrakeys',
257 default=list,
260 default=list,
258 )
261 )
259 coreconfigitem('convert', 'git.findcopiesharder',
262 coreconfigitem('convert', 'git.findcopiesharder',
260 default=False,
263 default=False,
261 )
264 )
262 coreconfigitem('convert', 'git.remoteprefix',
265 coreconfigitem('convert', 'git.remoteprefix',
263 default='remote',
266 default='remote',
264 )
267 )
265 coreconfigitem('convert', 'git.renamelimit',
268 coreconfigitem('convert', 'git.renamelimit',
266 default=400,
269 default=400,
267 )
270 )
268 coreconfigitem('convert', 'git.saverev',
271 coreconfigitem('convert', 'git.saverev',
269 default=True,
272 default=True,
270 )
273 )
271 coreconfigitem('convert', 'git.similarity',
274 coreconfigitem('convert', 'git.similarity',
272 default=50,
275 default=50,
273 )
276 )
274 coreconfigitem('convert', 'git.skipsubmodules',
277 coreconfigitem('convert', 'git.skipsubmodules',
275 default=False,
278 default=False,
276 )
279 )
277 coreconfigitem('convert', 'hg.clonebranches',
280 coreconfigitem('convert', 'hg.clonebranches',
278 default=False,
281 default=False,
279 )
282 )
280 coreconfigitem('convert', 'hg.ignoreerrors',
283 coreconfigitem('convert', 'hg.ignoreerrors',
281 default=False,
284 default=False,
282 )
285 )
283 coreconfigitem('convert', 'hg.revs',
286 coreconfigitem('convert', 'hg.revs',
284 default=None,
287 default=None,
285 )
288 )
286 coreconfigitem('convert', 'hg.saverev',
289 coreconfigitem('convert', 'hg.saverev',
287 default=False,
290 default=False,
288 )
291 )
289 coreconfigitem('convert', 'hg.sourcename',
292 coreconfigitem('convert', 'hg.sourcename',
290 default=None,
293 default=None,
291 )
294 )
292 coreconfigitem('convert', 'hg.startrev',
295 coreconfigitem('convert', 'hg.startrev',
293 default=None,
296 default=None,
294 )
297 )
295 coreconfigitem('convert', 'hg.tagsbranch',
298 coreconfigitem('convert', 'hg.tagsbranch',
296 default='default',
299 default='default',
297 )
300 )
298 coreconfigitem('convert', 'hg.usebranchnames',
301 coreconfigitem('convert', 'hg.usebranchnames',
299 default=True,
302 default=True,
300 )
303 )
301 coreconfigitem('convert', 'ignoreancestorcheck',
304 coreconfigitem('convert', 'ignoreancestorcheck',
302 default=False,
305 default=False,
303 )
306 )
304 coreconfigitem('convert', 'localtimezone',
307 coreconfigitem('convert', 'localtimezone',
305 default=False,
308 default=False,
306 )
309 )
307 coreconfigitem('convert', 'p4.encoding',
310 coreconfigitem('convert', 'p4.encoding',
308 default=dynamicdefault,
311 default=dynamicdefault,
309 )
312 )
310 coreconfigitem('convert', 'p4.startrev',
313 coreconfigitem('convert', 'p4.startrev',
311 default=0,
314 default=0,
312 )
315 )
313 coreconfigitem('convert', 'skiptags',
316 coreconfigitem('convert', 'skiptags',
314 default=False,
317 default=False,
315 )
318 )
316 coreconfigitem('convert', 'svn.debugsvnlog',
319 coreconfigitem('convert', 'svn.debugsvnlog',
317 default=True,
320 default=True,
318 )
321 )
319 coreconfigitem('convert', 'svn.trunk',
322 coreconfigitem('convert', 'svn.trunk',
320 default=None,
323 default=None,
321 )
324 )
322 coreconfigitem('convert', 'svn.tags',
325 coreconfigitem('convert', 'svn.tags',
323 default=None,
326 default=None,
324 )
327 )
325 coreconfigitem('convert', 'svn.branches',
328 coreconfigitem('convert', 'svn.branches',
326 default=None,
329 default=None,
327 )
330 )
328 coreconfigitem('convert', 'svn.startrev',
331 coreconfigitem('convert', 'svn.startrev',
329 default=0,
332 default=0,
330 )
333 )
331 coreconfigitem('debug', 'dirstate.delaywrite',
334 coreconfigitem('debug', 'dirstate.delaywrite',
332 default=0,
335 default=0,
333 )
336 )
334 coreconfigitem('defaults', '.*',
337 coreconfigitem('defaults', '.*',
335 default=None,
338 default=None,
336 generic=True,
339 generic=True,
337 )
340 )
338 coreconfigitem('devel', 'all-warnings',
341 coreconfigitem('devel', 'all-warnings',
339 default=False,
342 default=False,
340 )
343 )
341 coreconfigitem('devel', 'bundle2.debug',
344 coreconfigitem('devel', 'bundle2.debug',
342 default=False,
345 default=False,
343 )
346 )
344 coreconfigitem('devel', 'bundle.delta',
347 coreconfigitem('devel', 'bundle.delta',
345 default='',
348 default='',
346 )
349 )
347 coreconfigitem('devel', 'cache-vfs',
350 coreconfigitem('devel', 'cache-vfs',
348 default=None,
351 default=None,
349 )
352 )
350 coreconfigitem('devel', 'check-locks',
353 coreconfigitem('devel', 'check-locks',
351 default=False,
354 default=False,
352 )
355 )
353 coreconfigitem('devel', 'check-relroot',
356 coreconfigitem('devel', 'check-relroot',
354 default=False,
357 default=False,
355 )
358 )
356 coreconfigitem('devel', 'default-date',
359 coreconfigitem('devel', 'default-date',
357 default=None,
360 default=None,
358 )
361 )
359 coreconfigitem('devel', 'deprec-warn',
362 coreconfigitem('devel', 'deprec-warn',
360 default=False,
363 default=False,
361 )
364 )
362 coreconfigitem('devel', 'disableloaddefaultcerts',
365 coreconfigitem('devel', 'disableloaddefaultcerts',
363 default=False,
366 default=False,
364 )
367 )
365 coreconfigitem('devel', 'warn-empty-changegroup',
368 coreconfigitem('devel', 'warn-empty-changegroup',
366 default=False,
369 default=False,
367 )
370 )
368 coreconfigitem('devel', 'legacy.exchange',
371 coreconfigitem('devel', 'legacy.exchange',
369 default=list,
372 default=list,
370 )
373 )
371 coreconfigitem('devel', 'servercafile',
374 coreconfigitem('devel', 'servercafile',
372 default='',
375 default='',
373 )
376 )
374 coreconfigitem('devel', 'serverexactprotocol',
377 coreconfigitem('devel', 'serverexactprotocol',
375 default='',
378 default='',
376 )
379 )
377 coreconfigitem('devel', 'serverrequirecert',
380 coreconfigitem('devel', 'serverrequirecert',
378 default=False,
381 default=False,
379 )
382 )
380 coreconfigitem('devel', 'strip-obsmarkers',
383 coreconfigitem('devel', 'strip-obsmarkers',
381 default=True,
384 default=True,
382 )
385 )
383 coreconfigitem('devel', 'warn-config',
386 coreconfigitem('devel', 'warn-config',
384 default=None,
387 default=None,
385 )
388 )
386 coreconfigitem('devel', 'warn-config-default',
389 coreconfigitem('devel', 'warn-config-default',
387 default=None,
390 default=None,
388 )
391 )
389 coreconfigitem('devel', 'user.obsmarker',
392 coreconfigitem('devel', 'user.obsmarker',
390 default=None,
393 default=None,
391 )
394 )
392 coreconfigitem('devel', 'warn-config-unknown',
395 coreconfigitem('devel', 'warn-config-unknown',
393 default=None,
396 default=None,
394 )
397 )
395 coreconfigitem('devel', 'debug.copies',
398 coreconfigitem('devel', 'debug.copies',
396 default=False,
399 default=False,
397 )
400 )
398 coreconfigitem('devel', 'debug.extensions',
401 coreconfigitem('devel', 'debug.extensions',
399 default=False,
402 default=False,
400 )
403 )
401 coreconfigitem('devel', 'debug.peer-request',
404 coreconfigitem('devel', 'debug.peer-request',
402 default=False,
405 default=False,
403 )
406 )
404 coreconfigitem('diff', 'nodates',
407 coreconfigitem('diff', 'nodates',
405 default=False,
408 default=False,
406 )
409 )
407 coreconfigitem('diff', 'showfunc',
410 coreconfigitem('diff', 'showfunc',
408 default=False,
411 default=False,
409 )
412 )
410 coreconfigitem('diff', 'unified',
413 coreconfigitem('diff', 'unified',
411 default=None,
414 default=None,
412 )
415 )
413 coreconfigitem('diff', 'git',
416 coreconfigitem('diff', 'git',
414 default=False,
417 default=False,
415 )
418 )
416 coreconfigitem('diff', 'ignorews',
419 coreconfigitem('diff', 'ignorews',
417 default=False,
420 default=False,
418 )
421 )
419 coreconfigitem('diff', 'ignorewsamount',
422 coreconfigitem('diff', 'ignorewsamount',
420 default=False,
423 default=False,
421 )
424 )
422 coreconfigitem('diff', 'ignoreblanklines',
425 coreconfigitem('diff', 'ignoreblanklines',
423 default=False,
426 default=False,
424 )
427 )
425 coreconfigitem('diff', 'ignorewseol',
428 coreconfigitem('diff', 'ignorewseol',
426 default=False,
429 default=False,
427 )
430 )
428 coreconfigitem('diff', 'nobinary',
431 coreconfigitem('diff', 'nobinary',
429 default=False,
432 default=False,
430 )
433 )
431 coreconfigitem('diff', 'noprefix',
434 coreconfigitem('diff', 'noprefix',
432 default=False,
435 default=False,
433 )
436 )
434 coreconfigitem('diff', 'word-diff',
437 coreconfigitem('diff', 'word-diff',
435 default=False,
438 default=False,
436 )
439 )
437 coreconfigitem('email', 'bcc',
440 coreconfigitem('email', 'bcc',
438 default=None,
441 default=None,
439 )
442 )
440 coreconfigitem('email', 'cc',
443 coreconfigitem('email', 'cc',
441 default=None,
444 default=None,
442 )
445 )
443 coreconfigitem('email', 'charsets',
446 coreconfigitem('email', 'charsets',
444 default=list,
447 default=list,
445 )
448 )
446 coreconfigitem('email', 'from',
449 coreconfigitem('email', 'from',
447 default=None,
450 default=None,
448 )
451 )
449 coreconfigitem('email', 'method',
452 coreconfigitem('email', 'method',
450 default='smtp',
453 default='smtp',
451 )
454 )
452 coreconfigitem('email', 'reply-to',
455 coreconfigitem('email', 'reply-to',
453 default=None,
456 default=None,
454 )
457 )
455 coreconfigitem('email', 'to',
458 coreconfigitem('email', 'to',
456 default=None,
459 default=None,
457 )
460 )
458 coreconfigitem('experimental', 'archivemetatemplate',
461 coreconfigitem('experimental', 'archivemetatemplate',
459 default=dynamicdefault,
462 default=dynamicdefault,
460 )
463 )
461 coreconfigitem('experimental', 'auto-publish',
464 coreconfigitem('experimental', 'auto-publish',
462 default='publish',
465 default='publish',
463 )
466 )
464 coreconfigitem('experimental', 'bundle-phases',
467 coreconfigitem('experimental', 'bundle-phases',
465 default=False,
468 default=False,
466 )
469 )
467 coreconfigitem('experimental', 'bundle2-advertise',
470 coreconfigitem('experimental', 'bundle2-advertise',
468 default=True,
471 default=True,
469 )
472 )
470 coreconfigitem('experimental', 'bundle2-output-capture',
473 coreconfigitem('experimental', 'bundle2-output-capture',
471 default=False,
474 default=False,
472 )
475 )
473 coreconfigitem('experimental', 'bundle2.pushback',
476 coreconfigitem('experimental', 'bundle2.pushback',
474 default=False,
477 default=False,
475 )
478 )
476 coreconfigitem('experimental', 'bundle2lazylocking',
479 coreconfigitem('experimental', 'bundle2lazylocking',
477 default=False,
480 default=False,
478 )
481 )
479 coreconfigitem('experimental', 'bundlecomplevel',
482 coreconfigitem('experimental', 'bundlecomplevel',
480 default=None,
483 default=None,
481 )
484 )
482 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
485 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
483 default=None,
486 default=None,
484 )
487 )
485 coreconfigitem('experimental', 'bundlecomplevel.gzip',
488 coreconfigitem('experimental', 'bundlecomplevel.gzip',
486 default=None,
489 default=None,
487 )
490 )
488 coreconfigitem('experimental', 'bundlecomplevel.none',
491 coreconfigitem('experimental', 'bundlecomplevel.none',
489 default=None,
492 default=None,
490 )
493 )
491 coreconfigitem('experimental', 'bundlecomplevel.zstd',
494 coreconfigitem('experimental', 'bundlecomplevel.zstd',
492 default=None,
495 default=None,
493 )
496 )
494 coreconfigitem('experimental', 'changegroup3',
497 coreconfigitem('experimental', 'changegroup3',
495 default=False,
498 default=False,
496 )
499 )
497 coreconfigitem('experimental', 'clientcompressionengines',
500 coreconfigitem('experimental', 'clientcompressionengines',
498 default=list,
501 default=list,
499 )
502 )
500 coreconfigitem('experimental', 'copytrace',
503 coreconfigitem('experimental', 'copytrace',
501 default='on',
504 default='on',
502 )
505 )
503 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
506 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
504 default=100,
507 default=100,
505 )
508 )
506 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
509 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
507 default=100,
510 default=100,
508 )
511 )
509 coreconfigitem('experimental', 'crecordtest',
512 coreconfigitem('experimental', 'crecordtest',
510 default=None,
513 default=None,
511 )
514 )
512 coreconfigitem('experimental', 'directaccess',
515 coreconfigitem('experimental', 'directaccess',
513 default=False,
516 default=False,
514 )
517 )
515 coreconfigitem('experimental', 'directaccess.revnums',
518 coreconfigitem('experimental', 'directaccess.revnums',
516 default=False,
519 default=False,
517 )
520 )
518 coreconfigitem('experimental', 'editortmpinhg',
521 coreconfigitem('experimental', 'editortmpinhg',
519 default=False,
522 default=False,
520 )
523 )
521 coreconfigitem('experimental', 'evolution',
524 coreconfigitem('experimental', 'evolution',
522 default=list,
525 default=list,
523 )
526 )
524 coreconfigitem('experimental', 'evolution.allowdivergence',
527 coreconfigitem('experimental', 'evolution.allowdivergence',
525 default=False,
528 default=False,
526 alias=[('experimental', 'allowdivergence')]
529 alias=[('experimental', 'allowdivergence')]
527 )
530 )
528 coreconfigitem('experimental', 'evolution.allowunstable',
531 coreconfigitem('experimental', 'evolution.allowunstable',
529 default=None,
532 default=None,
530 )
533 )
531 coreconfigitem('experimental', 'evolution.createmarkers',
534 coreconfigitem('experimental', 'evolution.createmarkers',
532 default=None,
535 default=None,
533 )
536 )
534 coreconfigitem('experimental', 'evolution.effect-flags',
537 coreconfigitem('experimental', 'evolution.effect-flags',
535 default=True,
538 default=True,
536 alias=[('experimental', 'effect-flags')]
539 alias=[('experimental', 'effect-flags')]
537 )
540 )
538 coreconfigitem('experimental', 'evolution.exchange',
541 coreconfigitem('experimental', 'evolution.exchange',
539 default=None,
542 default=None,
540 )
543 )
541 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
544 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
542 default=False,
545 default=False,
543 )
546 )
544 coreconfigitem('experimental', 'evolution.report-instabilities',
547 coreconfigitem('experimental', 'evolution.report-instabilities',
545 default=True,
548 default=True,
546 )
549 )
547 coreconfigitem('experimental', 'evolution.track-operation',
550 coreconfigitem('experimental', 'evolution.track-operation',
548 default=True,
551 default=True,
549 )
552 )
550 coreconfigitem('experimental', 'maxdeltachainspan',
553 coreconfigitem('experimental', 'maxdeltachainspan',
551 default=-1,
554 default=-1,
552 )
555 )
553 coreconfigitem('experimental', 'mergetempdirprefix',
556 coreconfigitem('experimental', 'mergetempdirprefix',
554 default=None,
557 default=None,
555 )
558 )
556 coreconfigitem('experimental', 'narrow',
559 coreconfigitem('experimental', 'narrow',
557 default=False,
560 default=False,
558 )
561 )
559 coreconfigitem('experimental', 'nonnormalparanoidcheck',
562 coreconfigitem('experimental', 'nonnormalparanoidcheck',
560 default=False,
563 default=False,
561 )
564 )
562 coreconfigitem('experimental', 'exportableenviron',
565 coreconfigitem('experimental', 'exportableenviron',
563 default=list,
566 default=list,
564 )
567 )
565 coreconfigitem('experimental', 'extendedheader.index',
568 coreconfigitem('experimental', 'extendedheader.index',
566 default=None,
569 default=None,
567 )
570 )
568 coreconfigitem('experimental', 'extendedheader.similarity',
571 coreconfigitem('experimental', 'extendedheader.similarity',
569 default=False,
572 default=False,
570 )
573 )
571 coreconfigitem('experimental', 'format.compression',
574 coreconfigitem('experimental', 'format.compression',
572 default='zlib',
575 default='zlib',
573 )
576 )
574 coreconfigitem('experimental', 'graphshorten',
577 coreconfigitem('experimental', 'graphshorten',
575 default=False,
578 default=False,
576 )
579 )
577 coreconfigitem('experimental', 'graphstyle.parent',
580 coreconfigitem('experimental', 'graphstyle.parent',
578 default=dynamicdefault,
581 default=dynamicdefault,
579 )
582 )
580 coreconfigitem('experimental', 'graphstyle.missing',
583 coreconfigitem('experimental', 'graphstyle.missing',
581 default=dynamicdefault,
584 default=dynamicdefault,
582 )
585 )
583 coreconfigitem('experimental', 'graphstyle.grandparent',
586 coreconfigitem('experimental', 'graphstyle.grandparent',
584 default=dynamicdefault,
587 default=dynamicdefault,
585 )
588 )
586 coreconfigitem('experimental', 'hook-track-tags',
589 coreconfigitem('experimental', 'hook-track-tags',
587 default=False,
590 default=False,
588 )
591 )
589 coreconfigitem('experimental', 'httppeer.advertise-v2',
592 coreconfigitem('experimental', 'httppeer.advertise-v2',
590 default=False,
593 default=False,
591 )
594 )
592 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
595 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
593 default=None,
596 default=None,
594 )
597 )
595 coreconfigitem('experimental', 'httppostargs',
598 coreconfigitem('experimental', 'httppostargs',
596 default=False,
599 default=False,
597 )
600 )
598 coreconfigitem('experimental', 'mergedriver',
601 coreconfigitem('experimental', 'mergedriver',
599 default=None,
602 default=None,
600 )
603 )
601 coreconfigitem('experimental', 'nointerrupt', default=False)
604 coreconfigitem('experimental', 'nointerrupt', default=False)
602 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
605 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
603
606
604 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
607 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
605 default=False,
608 default=False,
606 )
609 )
607 coreconfigitem('experimental', 'remotenames',
610 coreconfigitem('experimental', 'remotenames',
608 default=False,
611 default=False,
609 )
612 )
610 coreconfigitem('experimental', 'removeemptydirs',
613 coreconfigitem('experimental', 'removeemptydirs',
611 default=True,
614 default=True,
612 )
615 )
613 coreconfigitem('experimental', 'revisions.prefixhexnode',
616 coreconfigitem('experimental', 'revisions.prefixhexnode',
614 default=False,
617 default=False,
615 )
618 )
616 coreconfigitem('experimental', 'revlogv2',
619 coreconfigitem('experimental', 'revlogv2',
617 default=None,
620 default=None,
618 )
621 )
619 coreconfigitem('experimental', 'revisions.disambiguatewithin',
622 coreconfigitem('experimental', 'revisions.disambiguatewithin',
620 default=None,
623 default=None,
621 )
624 )
622 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
625 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
623 default=50000,
626 default=50000,
624 )
627 )
625 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
628 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
626 default=100000,
629 default=100000,
627 )
630 )
628 coreconfigitem('experimental', 'server.stream-narrow-clones',
631 coreconfigitem('experimental', 'server.stream-narrow-clones',
629 default=False,
632 default=False,
630 )
633 )
631 coreconfigitem('experimental', 'single-head-per-branch',
634 coreconfigitem('experimental', 'single-head-per-branch',
632 default=False,
635 default=False,
633 )
636 )
634 coreconfigitem('experimental', 'sshserver.support-v2',
637 coreconfigitem('experimental', 'sshserver.support-v2',
635 default=False,
638 default=False,
636 )
639 )
637 coreconfigitem('experimental', 'sparse-read',
640 coreconfigitem('experimental', 'sparse-read',
638 default=False,
641 default=False,
639 )
642 )
640 coreconfigitem('experimental', 'sparse-read.density-threshold',
643 coreconfigitem('experimental', 'sparse-read.density-threshold',
641 default=0.50,
644 default=0.50,
642 )
645 )
643 coreconfigitem('experimental', 'sparse-read.min-gap-size',
646 coreconfigitem('experimental', 'sparse-read.min-gap-size',
644 default='65K',
647 default='65K',
645 )
648 )
646 coreconfigitem('experimental', 'treemanifest',
649 coreconfigitem('experimental', 'treemanifest',
647 default=False,
650 default=False,
648 )
651 )
649 coreconfigitem('experimental', 'update.atomic-file',
652 coreconfigitem('experimental', 'update.atomic-file',
650 default=False,
653 default=False,
651 )
654 )
652 coreconfigitem('experimental', 'sshpeer.advertise-v2',
655 coreconfigitem('experimental', 'sshpeer.advertise-v2',
653 default=False,
656 default=False,
654 )
657 )
655 coreconfigitem('experimental', 'web.apiserver',
658 coreconfigitem('experimental', 'web.apiserver',
656 default=False,
659 default=False,
657 )
660 )
658 coreconfigitem('experimental', 'web.api.http-v2',
661 coreconfigitem('experimental', 'web.api.http-v2',
659 default=False,
662 default=False,
660 )
663 )
661 coreconfigitem('experimental', 'web.api.debugreflect',
664 coreconfigitem('experimental', 'web.api.debugreflect',
662 default=False,
665 default=False,
663 )
666 )
664 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
667 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
665 default=False,
668 default=False,
666 )
669 )
667 coreconfigitem('experimental', 'xdiff',
670 coreconfigitem('experimental', 'xdiff',
668 default=False,
671 default=False,
669 )
672 )
670 coreconfigitem('extensions', '.*',
673 coreconfigitem('extensions', '.*',
671 default=None,
674 default=None,
672 generic=True,
675 generic=True,
673 )
676 )
674 coreconfigitem('extdata', '.*',
677 coreconfigitem('extdata', '.*',
675 default=None,
678 default=None,
676 generic=True,
679 generic=True,
677 )
680 )
678 coreconfigitem('format', 'chunkcachesize',
681 coreconfigitem('format', 'chunkcachesize',
679 default=None,
682 default=None,
680 )
683 )
681 coreconfigitem('format', 'dotencode',
684 coreconfigitem('format', 'dotencode',
682 default=True,
685 default=True,
683 )
686 )
684 coreconfigitem('format', 'generaldelta',
687 coreconfigitem('format', 'generaldelta',
685 default=False,
688 default=False,
686 )
689 )
687 coreconfigitem('format', 'manifestcachesize',
690 coreconfigitem('format', 'manifestcachesize',
688 default=None,
691 default=None,
689 )
692 )
690 coreconfigitem('format', 'maxchainlen',
693 coreconfigitem('format', 'maxchainlen',
691 default=dynamicdefault,
694 default=dynamicdefault,
692 )
695 )
693 coreconfigitem('format', 'obsstore-version',
696 coreconfigitem('format', 'obsstore-version',
694 default=None,
697 default=None,
695 )
698 )
696 coreconfigitem('format', 'sparse-revlog',
699 coreconfigitem('format', 'sparse-revlog',
697 default=True,
700 default=True,
698 )
701 )
699 coreconfigitem('format', 'usefncache',
702 coreconfigitem('format', 'usefncache',
700 default=True,
703 default=True,
701 )
704 )
702 coreconfigitem('format', 'usegeneraldelta',
705 coreconfigitem('format', 'usegeneraldelta',
703 default=True,
706 default=True,
704 )
707 )
705 coreconfigitem('format', 'usestore',
708 coreconfigitem('format', 'usestore',
706 default=True,
709 default=True,
707 )
710 )
708 coreconfigitem('format', 'internal-phase',
711 coreconfigitem('format', 'internal-phase',
709 default=False,
712 default=False,
710 )
713 )
711 coreconfigitem('fsmonitor', 'warn_when_unused',
714 coreconfigitem('fsmonitor', 'warn_when_unused',
712 default=True,
715 default=True,
713 )
716 )
714 coreconfigitem('fsmonitor', 'warn_update_file_count',
717 coreconfigitem('fsmonitor', 'warn_update_file_count',
715 default=50000,
718 default=50000,
716 )
719 )
717 coreconfigitem('help', 'hidden-command\..*',
720 coreconfigitem('help', 'hidden-command\..*',
718 default=False,
721 default=False,
719 generic=True,
722 generic=True,
720 )
723 )
721 coreconfigitem('help', 'hidden-topic\..*',
724 coreconfigitem('help', 'hidden-topic\..*',
722 default=False,
725 default=False,
723 generic=True,
726 generic=True,
724 )
727 )
725 coreconfigitem('hooks', '.*',
728 coreconfigitem('hooks', '.*',
726 default=dynamicdefault,
729 default=dynamicdefault,
727 generic=True,
730 generic=True,
728 )
731 )
729 coreconfigitem('hgweb-paths', '.*',
732 coreconfigitem('hgweb-paths', '.*',
730 default=list,
733 default=list,
731 generic=True,
734 generic=True,
732 )
735 )
733 coreconfigitem('hostfingerprints', '.*',
736 coreconfigitem('hostfingerprints', '.*',
734 default=list,
737 default=list,
735 generic=True,
738 generic=True,
736 )
739 )
737 coreconfigitem('hostsecurity', 'ciphers',
740 coreconfigitem('hostsecurity', 'ciphers',
738 default=None,
741 default=None,
739 )
742 )
740 coreconfigitem('hostsecurity', 'disabletls10warning',
743 coreconfigitem('hostsecurity', 'disabletls10warning',
741 default=False,
744 default=False,
742 )
745 )
743 coreconfigitem('hostsecurity', 'minimumprotocol',
746 coreconfigitem('hostsecurity', 'minimumprotocol',
744 default=dynamicdefault,
747 default=dynamicdefault,
745 )
748 )
746 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
749 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
747 default=dynamicdefault,
750 default=dynamicdefault,
748 generic=True,
751 generic=True,
749 )
752 )
750 coreconfigitem('hostsecurity', '.*:ciphers$',
753 coreconfigitem('hostsecurity', '.*:ciphers$',
751 default=dynamicdefault,
754 default=dynamicdefault,
752 generic=True,
755 generic=True,
753 )
756 )
754 coreconfigitem('hostsecurity', '.*:fingerprints$',
757 coreconfigitem('hostsecurity', '.*:fingerprints$',
755 default=list,
758 default=list,
756 generic=True,
759 generic=True,
757 )
760 )
758 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
761 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
759 default=None,
762 default=None,
760 generic=True,
763 generic=True,
761 )
764 )
762
765
763 coreconfigitem('http_proxy', 'always',
766 coreconfigitem('http_proxy', 'always',
764 default=False,
767 default=False,
765 )
768 )
766 coreconfigitem('http_proxy', 'host',
769 coreconfigitem('http_proxy', 'host',
767 default=None,
770 default=None,
768 )
771 )
769 coreconfigitem('http_proxy', 'no',
772 coreconfigitem('http_proxy', 'no',
770 default=list,
773 default=list,
771 )
774 )
772 coreconfigitem('http_proxy', 'passwd',
775 coreconfigitem('http_proxy', 'passwd',
773 default=None,
776 default=None,
774 )
777 )
775 coreconfigitem('http_proxy', 'user',
778 coreconfigitem('http_proxy', 'user',
776 default=None,
779 default=None,
777 )
780 )
778
781
779 coreconfigitem('http', 'timeout',
782 coreconfigitem('http', 'timeout',
780 default=None,
783 default=None,
781 )
784 )
782
785
783 coreconfigitem('logtoprocess', 'commandexception',
786 coreconfigitem('logtoprocess', 'commandexception',
784 default=None,
787 default=None,
785 )
788 )
786 coreconfigitem('logtoprocess', 'commandfinish',
789 coreconfigitem('logtoprocess', 'commandfinish',
787 default=None,
790 default=None,
788 )
791 )
789 coreconfigitem('logtoprocess', 'command',
792 coreconfigitem('logtoprocess', 'command',
790 default=None,
793 default=None,
791 )
794 )
792 coreconfigitem('logtoprocess', 'develwarn',
795 coreconfigitem('logtoprocess', 'develwarn',
793 default=None,
796 default=None,
794 )
797 )
795 coreconfigitem('logtoprocess', 'uiblocked',
798 coreconfigitem('logtoprocess', 'uiblocked',
796 default=None,
799 default=None,
797 )
800 )
798 coreconfigitem('merge', 'checkunknown',
801 coreconfigitem('merge', 'checkunknown',
799 default='abort',
802 default='abort',
800 )
803 )
801 coreconfigitem('merge', 'checkignored',
804 coreconfigitem('merge', 'checkignored',
802 default='abort',
805 default='abort',
803 )
806 )
804 coreconfigitem('experimental', 'merge.checkpathconflicts',
807 coreconfigitem('experimental', 'merge.checkpathconflicts',
805 default=False,
808 default=False,
806 )
809 )
807 coreconfigitem('merge', 'followcopies',
810 coreconfigitem('merge', 'followcopies',
808 default=True,
811 default=True,
809 )
812 )
810 coreconfigitem('merge', 'on-failure',
813 coreconfigitem('merge', 'on-failure',
811 default='continue',
814 default='continue',
812 )
815 )
813 coreconfigitem('merge', 'preferancestor',
816 coreconfigitem('merge', 'preferancestor',
814 default=lambda: ['*'],
817 default=lambda: ['*'],
815 )
818 )
816 coreconfigitem('merge', 'strict-capability-check',
819 coreconfigitem('merge', 'strict-capability-check',
817 default=False,
820 default=False,
818 )
821 )
819 coreconfigitem('merge-tools', '.*',
822 coreconfigitem('merge-tools', '.*',
820 default=None,
823 default=None,
821 generic=True,
824 generic=True,
822 )
825 )
823 coreconfigitem('merge-tools', br'.*\.args$',
826 coreconfigitem('merge-tools', br'.*\.args$',
824 default="$local $base $other",
827 default="$local $base $other",
825 generic=True,
828 generic=True,
826 priority=-1,
829 priority=-1,
827 )
830 )
828 coreconfigitem('merge-tools', br'.*\.binary$',
831 coreconfigitem('merge-tools', br'.*\.binary$',
829 default=False,
832 default=False,
830 generic=True,
833 generic=True,
831 priority=-1,
834 priority=-1,
832 )
835 )
833 coreconfigitem('merge-tools', br'.*\.check$',
836 coreconfigitem('merge-tools', br'.*\.check$',
834 default=list,
837 default=list,
835 generic=True,
838 generic=True,
836 priority=-1,
839 priority=-1,
837 )
840 )
838 coreconfigitem('merge-tools', br'.*\.checkchanged$',
841 coreconfigitem('merge-tools', br'.*\.checkchanged$',
839 default=False,
842 default=False,
840 generic=True,
843 generic=True,
841 priority=-1,
844 priority=-1,
842 )
845 )
843 coreconfigitem('merge-tools', br'.*\.executable$',
846 coreconfigitem('merge-tools', br'.*\.executable$',
844 default=dynamicdefault,
847 default=dynamicdefault,
845 generic=True,
848 generic=True,
846 priority=-1,
849 priority=-1,
847 )
850 )
848 coreconfigitem('merge-tools', br'.*\.fixeol$',
851 coreconfigitem('merge-tools', br'.*\.fixeol$',
849 default=False,
852 default=False,
850 generic=True,
853 generic=True,
851 priority=-1,
854 priority=-1,
852 )
855 )
853 coreconfigitem('merge-tools', br'.*\.gui$',
856 coreconfigitem('merge-tools', br'.*\.gui$',
854 default=False,
857 default=False,
855 generic=True,
858 generic=True,
856 priority=-1,
859 priority=-1,
857 )
860 )
858 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
861 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
859 default='basic',
862 default='basic',
860 generic=True,
863 generic=True,
861 priority=-1,
864 priority=-1,
862 )
865 )
863 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
866 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
864 default=dynamicdefault, # take from ui.mergemarkertemplate
867 default=dynamicdefault, # take from ui.mergemarkertemplate
865 generic=True,
868 generic=True,
866 priority=-1,
869 priority=-1,
867 )
870 )
868 coreconfigitem('merge-tools', br'.*\.priority$',
871 coreconfigitem('merge-tools', br'.*\.priority$',
869 default=0,
872 default=0,
870 generic=True,
873 generic=True,
871 priority=-1,
874 priority=-1,
872 )
875 )
873 coreconfigitem('merge-tools', br'.*\.premerge$',
876 coreconfigitem('merge-tools', br'.*\.premerge$',
874 default=dynamicdefault,
877 default=dynamicdefault,
875 generic=True,
878 generic=True,
876 priority=-1,
879 priority=-1,
877 )
880 )
878 coreconfigitem('merge-tools', br'.*\.symlink$',
881 coreconfigitem('merge-tools', br'.*\.symlink$',
879 default=False,
882 default=False,
880 generic=True,
883 generic=True,
881 priority=-1,
884 priority=-1,
882 )
885 )
883 coreconfigitem('pager', 'attend-.*',
886 coreconfigitem('pager', 'attend-.*',
884 default=dynamicdefault,
887 default=dynamicdefault,
885 generic=True,
888 generic=True,
886 )
889 )
887 coreconfigitem('pager', 'ignore',
890 coreconfigitem('pager', 'ignore',
888 default=list,
891 default=list,
889 )
892 )
890 coreconfigitem('pager', 'pager',
893 coreconfigitem('pager', 'pager',
891 default=dynamicdefault,
894 default=dynamicdefault,
892 )
895 )
893 coreconfigitem('patch', 'eol',
896 coreconfigitem('patch', 'eol',
894 default='strict',
897 default='strict',
895 )
898 )
896 coreconfigitem('patch', 'fuzz',
899 coreconfigitem('patch', 'fuzz',
897 default=2,
900 default=2,
898 )
901 )
899 coreconfigitem('paths', 'default',
902 coreconfigitem('paths', 'default',
900 default=None,
903 default=None,
901 )
904 )
902 coreconfigitem('paths', 'default-push',
905 coreconfigitem('paths', 'default-push',
903 default=None,
906 default=None,
904 )
907 )
905 coreconfigitem('paths', '.*',
908 coreconfigitem('paths', '.*',
906 default=None,
909 default=None,
907 generic=True,
910 generic=True,
908 )
911 )
909 coreconfigitem('phases', 'checksubrepos',
912 coreconfigitem('phases', 'checksubrepos',
910 default='follow',
913 default='follow',
911 )
914 )
912 coreconfigitem('phases', 'new-commit',
915 coreconfigitem('phases', 'new-commit',
913 default='draft',
916 default='draft',
914 )
917 )
915 coreconfigitem('phases', 'publish',
918 coreconfigitem('phases', 'publish',
916 default=True,
919 default=True,
917 )
920 )
918 coreconfigitem('profiling', 'enabled',
921 coreconfigitem('profiling', 'enabled',
919 default=False,
922 default=False,
920 )
923 )
921 coreconfigitem('profiling', 'format',
924 coreconfigitem('profiling', 'format',
922 default='text',
925 default='text',
923 )
926 )
924 coreconfigitem('profiling', 'freq',
927 coreconfigitem('profiling', 'freq',
925 default=1000,
928 default=1000,
926 )
929 )
927 coreconfigitem('profiling', 'limit',
930 coreconfigitem('profiling', 'limit',
928 default=30,
931 default=30,
929 )
932 )
930 coreconfigitem('profiling', 'nested',
933 coreconfigitem('profiling', 'nested',
931 default=0,
934 default=0,
932 )
935 )
933 coreconfigitem('profiling', 'output',
936 coreconfigitem('profiling', 'output',
934 default=None,
937 default=None,
935 )
938 )
936 coreconfigitem('profiling', 'showmax',
939 coreconfigitem('profiling', 'showmax',
937 default=0.999,
940 default=0.999,
938 )
941 )
939 coreconfigitem('profiling', 'showmin',
942 coreconfigitem('profiling', 'showmin',
940 default=dynamicdefault,
943 default=dynamicdefault,
941 )
944 )
942 coreconfigitem('profiling', 'sort',
945 coreconfigitem('profiling', 'sort',
943 default='inlinetime',
946 default='inlinetime',
944 )
947 )
945 coreconfigitem('profiling', 'statformat',
948 coreconfigitem('profiling', 'statformat',
946 default='hotpath',
949 default='hotpath',
947 )
950 )
948 coreconfigitem('profiling', 'time-track',
951 coreconfigitem('profiling', 'time-track',
949 default=dynamicdefault,
952 default=dynamicdefault,
950 )
953 )
951 coreconfigitem('profiling', 'type',
954 coreconfigitem('profiling', 'type',
952 default='stat',
955 default='stat',
953 )
956 )
954 coreconfigitem('progress', 'assume-tty',
957 coreconfigitem('progress', 'assume-tty',
955 default=False,
958 default=False,
956 )
959 )
957 coreconfigitem('progress', 'changedelay',
960 coreconfigitem('progress', 'changedelay',
958 default=1,
961 default=1,
959 )
962 )
960 coreconfigitem('progress', 'clear-complete',
963 coreconfigitem('progress', 'clear-complete',
961 default=True,
964 default=True,
962 )
965 )
963 coreconfigitem('progress', 'debug',
966 coreconfigitem('progress', 'debug',
964 default=False,
967 default=False,
965 )
968 )
966 coreconfigitem('progress', 'delay',
969 coreconfigitem('progress', 'delay',
967 default=3,
970 default=3,
968 )
971 )
969 coreconfigitem('progress', 'disable',
972 coreconfigitem('progress', 'disable',
970 default=False,
973 default=False,
971 )
974 )
972 coreconfigitem('progress', 'estimateinterval',
975 coreconfigitem('progress', 'estimateinterval',
973 default=60.0,
976 default=60.0,
974 )
977 )
975 coreconfigitem('progress', 'format',
978 coreconfigitem('progress', 'format',
976 default=lambda: ['topic', 'bar', 'number', 'estimate'],
979 default=lambda: ['topic', 'bar', 'number', 'estimate'],
977 )
980 )
978 coreconfigitem('progress', 'refresh',
981 coreconfigitem('progress', 'refresh',
979 default=0.1,
982 default=0.1,
980 )
983 )
981 coreconfigitem('progress', 'width',
984 coreconfigitem('progress', 'width',
982 default=dynamicdefault,
985 default=dynamicdefault,
983 )
986 )
984 coreconfigitem('push', 'pushvars.server',
987 coreconfigitem('push', 'pushvars.server',
985 default=False,
988 default=False,
986 )
989 )
987 coreconfigitem('storage', 'mmap-threshold',
990 coreconfigitem('storage', 'mmap-threshold',
988 default='1MB',
991 default='1MB',
989 alias=[('experimental', 'mmapindexthreshold')],
992 alias=[('experimental', 'mmapindexthreshold')],
990 )
993 )
991 coreconfigitem('storage', 'new-repo-backend',
994 coreconfigitem('storage', 'new-repo-backend',
992 default='revlogv1',
995 default='revlogv1',
993 )
996 )
994 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
997 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
995 default=True,
998 default=True,
996 alias=[('format', 'aggressivemergedeltas')],
999 alias=[('format', 'aggressivemergedeltas')],
997 )
1000 )
998 coreconfigitem('server', 'bookmarks-pushkey-compat',
1001 coreconfigitem('server', 'bookmarks-pushkey-compat',
999 default=True,
1002 default=True,
1000 )
1003 )
1001 coreconfigitem('server', 'bundle1',
1004 coreconfigitem('server', 'bundle1',
1002 default=True,
1005 default=True,
1003 )
1006 )
1004 coreconfigitem('server', 'bundle1gd',
1007 coreconfigitem('server', 'bundle1gd',
1005 default=None,
1008 default=None,
1006 )
1009 )
1007 coreconfigitem('server', 'bundle1.pull',
1010 coreconfigitem('server', 'bundle1.pull',
1008 default=None,
1011 default=None,
1009 )
1012 )
1010 coreconfigitem('server', 'bundle1gd.pull',
1013 coreconfigitem('server', 'bundle1gd.pull',
1011 default=None,
1014 default=None,
1012 )
1015 )
1013 coreconfigitem('server', 'bundle1.push',
1016 coreconfigitem('server', 'bundle1.push',
1014 default=None,
1017 default=None,
1015 )
1018 )
1016 coreconfigitem('server', 'bundle1gd.push',
1019 coreconfigitem('server', 'bundle1gd.push',
1017 default=None,
1020 default=None,
1018 )
1021 )
1019 coreconfigitem('server', 'bundle2.stream',
1022 coreconfigitem('server', 'bundle2.stream',
1020 default=True,
1023 default=True,
1021 alias=[('experimental', 'bundle2.stream')]
1024 alias=[('experimental', 'bundle2.stream')]
1022 )
1025 )
1023 coreconfigitem('server', 'compressionengines',
1026 coreconfigitem('server', 'compressionengines',
1024 default=list,
1027 default=list,
1025 )
1028 )
1026 coreconfigitem('server', 'concurrent-push-mode',
1029 coreconfigitem('server', 'concurrent-push-mode',
1027 default='strict',
1030 default='strict',
1028 )
1031 )
1029 coreconfigitem('server', 'disablefullbundle',
1032 coreconfigitem('server', 'disablefullbundle',
1030 default=False,
1033 default=False,
1031 )
1034 )
1032 coreconfigitem('server', 'maxhttpheaderlen',
1035 coreconfigitem('server', 'maxhttpheaderlen',
1033 default=1024,
1036 default=1024,
1034 )
1037 )
1035 coreconfigitem('server', 'pullbundle',
1038 coreconfigitem('server', 'pullbundle',
1036 default=False,
1039 default=False,
1037 )
1040 )
1038 coreconfigitem('server', 'preferuncompressed',
1041 coreconfigitem('server', 'preferuncompressed',
1039 default=False,
1042 default=False,
1040 )
1043 )
1041 coreconfigitem('server', 'streamunbundle',
1044 coreconfigitem('server', 'streamunbundle',
1042 default=False,
1045 default=False,
1043 )
1046 )
1044 coreconfigitem('server', 'uncompressed',
1047 coreconfigitem('server', 'uncompressed',
1045 default=True,
1048 default=True,
1046 )
1049 )
1047 coreconfigitem('server', 'uncompressedallowsecret',
1050 coreconfigitem('server', 'uncompressedallowsecret',
1048 default=False,
1051 default=False,
1049 )
1052 )
1050 coreconfigitem('server', 'validate',
1053 coreconfigitem('server', 'validate',
1051 default=False,
1054 default=False,
1052 )
1055 )
1053 coreconfigitem('server', 'zliblevel',
1056 coreconfigitem('server', 'zliblevel',
1054 default=-1,
1057 default=-1,
1055 )
1058 )
1056 coreconfigitem('server', 'zstdlevel',
1059 coreconfigitem('server', 'zstdlevel',
1057 default=3,
1060 default=3,
1058 )
1061 )
1059 coreconfigitem('share', 'pool',
1062 coreconfigitem('share', 'pool',
1060 default=None,
1063 default=None,
1061 )
1064 )
1062 coreconfigitem('share', 'poolnaming',
1065 coreconfigitem('share', 'poolnaming',
1063 default='identity',
1066 default='identity',
1064 )
1067 )
1065 coreconfigitem('smtp', 'host',
1068 coreconfigitem('smtp', 'host',
1066 default=None,
1069 default=None,
1067 )
1070 )
1068 coreconfigitem('smtp', 'local_hostname',
1071 coreconfigitem('smtp', 'local_hostname',
1069 default=None,
1072 default=None,
1070 )
1073 )
1071 coreconfigitem('smtp', 'password',
1074 coreconfigitem('smtp', 'password',
1072 default=None,
1075 default=None,
1073 )
1076 )
1074 coreconfigitem('smtp', 'port',
1077 coreconfigitem('smtp', 'port',
1075 default=dynamicdefault,
1078 default=dynamicdefault,
1076 )
1079 )
1077 coreconfigitem('smtp', 'tls',
1080 coreconfigitem('smtp', 'tls',
1078 default='none',
1081 default='none',
1079 )
1082 )
1080 coreconfigitem('smtp', 'username',
1083 coreconfigitem('smtp', 'username',
1081 default=None,
1084 default=None,
1082 )
1085 )
1083 coreconfigitem('sparse', 'missingwarning',
1086 coreconfigitem('sparse', 'missingwarning',
1084 default=True,
1087 default=True,
1085 )
1088 )
1086 coreconfigitem('subrepos', 'allowed',
1089 coreconfigitem('subrepos', 'allowed',
1087 default=dynamicdefault, # to make backporting simpler
1090 default=dynamicdefault, # to make backporting simpler
1088 )
1091 )
1089 coreconfigitem('subrepos', 'hg:allowed',
1092 coreconfigitem('subrepos', 'hg:allowed',
1090 default=dynamicdefault,
1093 default=dynamicdefault,
1091 )
1094 )
1092 coreconfigitem('subrepos', 'git:allowed',
1095 coreconfigitem('subrepos', 'git:allowed',
1093 default=dynamicdefault,
1096 default=dynamicdefault,
1094 )
1097 )
1095 coreconfigitem('subrepos', 'svn:allowed',
1098 coreconfigitem('subrepos', 'svn:allowed',
1096 default=dynamicdefault,
1099 default=dynamicdefault,
1097 )
1100 )
1098 coreconfigitem('templates', '.*',
1101 coreconfigitem('templates', '.*',
1099 default=None,
1102 default=None,
1100 generic=True,
1103 generic=True,
1101 )
1104 )
1102 coreconfigitem('trusted', 'groups',
1105 coreconfigitem('trusted', 'groups',
1103 default=list,
1106 default=list,
1104 )
1107 )
1105 coreconfigitem('trusted', 'users',
1108 coreconfigitem('trusted', 'users',
1106 default=list,
1109 default=list,
1107 )
1110 )
1108 coreconfigitem('ui', '_usedassubrepo',
1111 coreconfigitem('ui', '_usedassubrepo',
1109 default=False,
1112 default=False,
1110 )
1113 )
1111 coreconfigitem('ui', 'allowemptycommit',
1114 coreconfigitem('ui', 'allowemptycommit',
1112 default=False,
1115 default=False,
1113 )
1116 )
1114 coreconfigitem('ui', 'archivemeta',
1117 coreconfigitem('ui', 'archivemeta',
1115 default=True,
1118 default=True,
1116 )
1119 )
1117 coreconfigitem('ui', 'askusername',
1120 coreconfigitem('ui', 'askusername',
1118 default=False,
1121 default=False,
1119 )
1122 )
1120 coreconfigitem('ui', 'clonebundlefallback',
1123 coreconfigitem('ui', 'clonebundlefallback',
1121 default=False,
1124 default=False,
1122 )
1125 )
1123 coreconfigitem('ui', 'clonebundleprefers',
1126 coreconfigitem('ui', 'clonebundleprefers',
1124 default=list,
1127 default=list,
1125 )
1128 )
1126 coreconfigitem('ui', 'clonebundles',
1129 coreconfigitem('ui', 'clonebundles',
1127 default=True,
1130 default=True,
1128 )
1131 )
1129 coreconfigitem('ui', 'color',
1132 coreconfigitem('ui', 'color',
1130 default='auto',
1133 default='auto',
1131 )
1134 )
1132 coreconfigitem('ui', 'commitsubrepos',
1135 coreconfigitem('ui', 'commitsubrepos',
1133 default=False,
1136 default=False,
1134 )
1137 )
1135 coreconfigitem('ui', 'debug',
1138 coreconfigitem('ui', 'debug',
1136 default=False,
1139 default=False,
1137 )
1140 )
1138 coreconfigitem('ui', 'debugger',
1141 coreconfigitem('ui', 'debugger',
1139 default=None,
1142 default=None,
1140 )
1143 )
1141 coreconfigitem('ui', 'editor',
1144 coreconfigitem('ui', 'editor',
1142 default=dynamicdefault,
1145 default=dynamicdefault,
1143 )
1146 )
1144 coreconfigitem('ui', 'fallbackencoding',
1147 coreconfigitem('ui', 'fallbackencoding',
1145 default=None,
1148 default=None,
1146 )
1149 )
1147 coreconfigitem('ui', 'forcecwd',
1150 coreconfigitem('ui', 'forcecwd',
1148 default=None,
1151 default=None,
1149 )
1152 )
1150 coreconfigitem('ui', 'forcemerge',
1153 coreconfigitem('ui', 'forcemerge',
1151 default=None,
1154 default=None,
1152 )
1155 )
1153 coreconfigitem('ui', 'formatdebug',
1156 coreconfigitem('ui', 'formatdebug',
1154 default=False,
1157 default=False,
1155 )
1158 )
1156 coreconfigitem('ui', 'formatjson',
1159 coreconfigitem('ui', 'formatjson',
1157 default=False,
1160 default=False,
1158 )
1161 )
1159 coreconfigitem('ui', 'formatted',
1162 coreconfigitem('ui', 'formatted',
1160 default=None,
1163 default=None,
1161 )
1164 )
1162 coreconfigitem('ui', 'graphnodetemplate',
1165 coreconfigitem('ui', 'graphnodetemplate',
1163 default=None,
1166 default=None,
1164 )
1167 )
1165 coreconfigitem('ui', 'history-editing-backup',
1168 coreconfigitem('ui', 'history-editing-backup',
1166 default=True,
1169 default=True,
1167 )
1170 )
1168 coreconfigitem('ui', 'interactive',
1171 coreconfigitem('ui', 'interactive',
1169 default=None,
1172 default=None,
1170 )
1173 )
1171 coreconfigitem('ui', 'interface',
1174 coreconfigitem('ui', 'interface',
1172 default=None,
1175 default=None,
1173 )
1176 )
1174 coreconfigitem('ui', 'interface.chunkselector',
1177 coreconfigitem('ui', 'interface.chunkselector',
1175 default=None,
1178 default=None,
1176 )
1179 )
1177 coreconfigitem('ui', 'large-file-limit',
1180 coreconfigitem('ui', 'large-file-limit',
1178 default=10000000,
1181 default=10000000,
1179 )
1182 )
1180 coreconfigitem('ui', 'logblockedtimes',
1183 coreconfigitem('ui', 'logblockedtimes',
1181 default=False,
1184 default=False,
1182 )
1185 )
1183 coreconfigitem('ui', 'logtemplate',
1186 coreconfigitem('ui', 'logtemplate',
1184 default=None,
1187 default=None,
1185 )
1188 )
1186 coreconfigitem('ui', 'merge',
1189 coreconfigitem('ui', 'merge',
1187 default=None,
1190 default=None,
1188 )
1191 )
1189 coreconfigitem('ui', 'mergemarkers',
1192 coreconfigitem('ui', 'mergemarkers',
1190 default='basic',
1193 default='basic',
1191 )
1194 )
1192 coreconfigitem('ui', 'mergemarkertemplate',
1195 coreconfigitem('ui', 'mergemarkertemplate',
1193 default=('{node|short} '
1196 default=('{node|short} '
1194 '{ifeq(tags, "tip", "", '
1197 '{ifeq(tags, "tip", "", '
1195 'ifeq(tags, "", "", "{tags} "))}'
1198 'ifeq(tags, "", "", "{tags} "))}'
1196 '{if(bookmarks, "{bookmarks} ")}'
1199 '{if(bookmarks, "{bookmarks} ")}'
1197 '{ifeq(branch, "default", "", "{branch} ")}'
1200 '{ifeq(branch, "default", "", "{branch} ")}'
1198 '- {author|user}: {desc|firstline}')
1201 '- {author|user}: {desc|firstline}')
1199 )
1202 )
1200 coreconfigitem('ui', 'message-output',
1203 coreconfigitem('ui', 'message-output',
1201 default='stdio',
1204 default='stdio',
1202 )
1205 )
1203 coreconfigitem('ui', 'nontty',
1206 coreconfigitem('ui', 'nontty',
1204 default=False,
1207 default=False,
1205 )
1208 )
1206 coreconfigitem('ui', 'origbackuppath',
1209 coreconfigitem('ui', 'origbackuppath',
1207 default=None,
1210 default=None,
1208 )
1211 )
1209 coreconfigitem('ui', 'paginate',
1212 coreconfigitem('ui', 'paginate',
1210 default=True,
1213 default=True,
1211 )
1214 )
1212 coreconfigitem('ui', 'patch',
1215 coreconfigitem('ui', 'patch',
1213 default=None,
1216 default=None,
1214 )
1217 )
1215 coreconfigitem('ui', 'pre-merge-tool-output-template',
1218 coreconfigitem('ui', 'pre-merge-tool-output-template',
1216 default=None,
1219 default=None,
1217 )
1220 )
1218 coreconfigitem('ui', 'portablefilenames',
1221 coreconfigitem('ui', 'portablefilenames',
1219 default='warn',
1222 default='warn',
1220 )
1223 )
1221 coreconfigitem('ui', 'promptecho',
1224 coreconfigitem('ui', 'promptecho',
1222 default=False,
1225 default=False,
1223 )
1226 )
1224 coreconfigitem('ui', 'quiet',
1227 coreconfigitem('ui', 'quiet',
1225 default=False,
1228 default=False,
1226 )
1229 )
1227 coreconfigitem('ui', 'quietbookmarkmove',
1230 coreconfigitem('ui', 'quietbookmarkmove',
1228 default=False,
1231 default=False,
1229 )
1232 )
1230 coreconfigitem('ui', 'remotecmd',
1233 coreconfigitem('ui', 'remotecmd',
1231 default='hg',
1234 default='hg',
1232 )
1235 )
1233 coreconfigitem('ui', 'report_untrusted',
1236 coreconfigitem('ui', 'report_untrusted',
1234 default=True,
1237 default=True,
1235 )
1238 )
1236 coreconfigitem('ui', 'rollback',
1239 coreconfigitem('ui', 'rollback',
1237 default=True,
1240 default=True,
1238 )
1241 )
1239 coreconfigitem('ui', 'signal-safe-lock',
1242 coreconfigitem('ui', 'signal-safe-lock',
1240 default=True,
1243 default=True,
1241 )
1244 )
1242 coreconfigitem('ui', 'slash',
1245 coreconfigitem('ui', 'slash',
1243 default=False,
1246 default=False,
1244 )
1247 )
1245 coreconfigitem('ui', 'ssh',
1248 coreconfigitem('ui', 'ssh',
1246 default='ssh',
1249 default='ssh',
1247 )
1250 )
1248 coreconfigitem('ui', 'ssherrorhint',
1251 coreconfigitem('ui', 'ssherrorhint',
1249 default=None,
1252 default=None,
1250 )
1253 )
1251 coreconfigitem('ui', 'statuscopies',
1254 coreconfigitem('ui', 'statuscopies',
1252 default=False,
1255 default=False,
1253 )
1256 )
1254 coreconfigitem('ui', 'strict',
1257 coreconfigitem('ui', 'strict',
1255 default=False,
1258 default=False,
1256 )
1259 )
1257 coreconfigitem('ui', 'style',
1260 coreconfigitem('ui', 'style',
1258 default='',
1261 default='',
1259 )
1262 )
1260 coreconfigitem('ui', 'supportcontact',
1263 coreconfigitem('ui', 'supportcontact',
1261 default=None,
1264 default=None,
1262 )
1265 )
1263 coreconfigitem('ui', 'textwidth',
1266 coreconfigitem('ui', 'textwidth',
1264 default=78,
1267 default=78,
1265 )
1268 )
1266 coreconfigitem('ui', 'timeout',
1269 coreconfigitem('ui', 'timeout',
1267 default='600',
1270 default='600',
1268 )
1271 )
1269 coreconfigitem('ui', 'timeout.warn',
1272 coreconfigitem('ui', 'timeout.warn',
1270 default=0,
1273 default=0,
1271 )
1274 )
1272 coreconfigitem('ui', 'traceback',
1275 coreconfigitem('ui', 'traceback',
1273 default=False,
1276 default=False,
1274 )
1277 )
1275 coreconfigitem('ui', 'tweakdefaults',
1278 coreconfigitem('ui', 'tweakdefaults',
1276 default=False,
1279 default=False,
1277 )
1280 )
1278 coreconfigitem('ui', 'username',
1281 coreconfigitem('ui', 'username',
1279 alias=[('ui', 'user')]
1282 alias=[('ui', 'user')]
1280 )
1283 )
1281 coreconfigitem('ui', 'verbose',
1284 coreconfigitem('ui', 'verbose',
1282 default=False,
1285 default=False,
1283 )
1286 )
1284 coreconfigitem('verify', 'skipflags',
1287 coreconfigitem('verify', 'skipflags',
1285 default=None,
1288 default=None,
1286 )
1289 )
1287 coreconfigitem('web', 'allowbz2',
1290 coreconfigitem('web', 'allowbz2',
1288 default=False,
1291 default=False,
1289 )
1292 )
1290 coreconfigitem('web', 'allowgz',
1293 coreconfigitem('web', 'allowgz',
1291 default=False,
1294 default=False,
1292 )
1295 )
1293 coreconfigitem('web', 'allow-pull',
1296 coreconfigitem('web', 'allow-pull',
1294 alias=[('web', 'allowpull')],
1297 alias=[('web', 'allowpull')],
1295 default=True,
1298 default=True,
1296 )
1299 )
1297 coreconfigitem('web', 'allow-push',
1300 coreconfigitem('web', 'allow-push',
1298 alias=[('web', 'allow_push')],
1301 alias=[('web', 'allow_push')],
1299 default=list,
1302 default=list,
1300 )
1303 )
1301 coreconfigitem('web', 'allowzip',
1304 coreconfigitem('web', 'allowzip',
1302 default=False,
1305 default=False,
1303 )
1306 )
1304 coreconfigitem('web', 'archivesubrepos',
1307 coreconfigitem('web', 'archivesubrepos',
1305 default=False,
1308 default=False,
1306 )
1309 )
1307 coreconfigitem('web', 'cache',
1310 coreconfigitem('web', 'cache',
1308 default=True,
1311 default=True,
1309 )
1312 )
1310 coreconfigitem('web', 'comparisoncontext',
1313 coreconfigitem('web', 'comparisoncontext',
1311 default=5,
1314 default=5,
1312 )
1315 )
1313 coreconfigitem('web', 'contact',
1316 coreconfigitem('web', 'contact',
1314 default=None,
1317 default=None,
1315 )
1318 )
1316 coreconfigitem('web', 'deny_push',
1319 coreconfigitem('web', 'deny_push',
1317 default=list,
1320 default=list,
1318 )
1321 )
1319 coreconfigitem('web', 'guessmime',
1322 coreconfigitem('web', 'guessmime',
1320 default=False,
1323 default=False,
1321 )
1324 )
1322 coreconfigitem('web', 'hidden',
1325 coreconfigitem('web', 'hidden',
1323 default=False,
1326 default=False,
1324 )
1327 )
1325 coreconfigitem('web', 'labels',
1328 coreconfigitem('web', 'labels',
1326 default=list,
1329 default=list,
1327 )
1330 )
1328 coreconfigitem('web', 'logoimg',
1331 coreconfigitem('web', 'logoimg',
1329 default='hglogo.png',
1332 default='hglogo.png',
1330 )
1333 )
1331 coreconfigitem('web', 'logourl',
1334 coreconfigitem('web', 'logourl',
1332 default='https://mercurial-scm.org/',
1335 default='https://mercurial-scm.org/',
1333 )
1336 )
1334 coreconfigitem('web', 'accesslog',
1337 coreconfigitem('web', 'accesslog',
1335 default='-',
1338 default='-',
1336 )
1339 )
1337 coreconfigitem('web', 'address',
1340 coreconfigitem('web', 'address',
1338 default='',
1341 default='',
1339 )
1342 )
1340 coreconfigitem('web', 'allow-archive',
1343 coreconfigitem('web', 'allow-archive',
1341 alias=[('web', 'allow_archive')],
1344 alias=[('web', 'allow_archive')],
1342 default=list,
1345 default=list,
1343 )
1346 )
1344 coreconfigitem('web', 'allow_read',
1347 coreconfigitem('web', 'allow_read',
1345 default=list,
1348 default=list,
1346 )
1349 )
1347 coreconfigitem('web', 'baseurl',
1350 coreconfigitem('web', 'baseurl',
1348 default=None,
1351 default=None,
1349 )
1352 )
1350 coreconfigitem('web', 'cacerts',
1353 coreconfigitem('web', 'cacerts',
1351 default=None,
1354 default=None,
1352 )
1355 )
1353 coreconfigitem('web', 'certificate',
1356 coreconfigitem('web', 'certificate',
1354 default=None,
1357 default=None,
1355 )
1358 )
1356 coreconfigitem('web', 'collapse',
1359 coreconfigitem('web', 'collapse',
1357 default=False,
1360 default=False,
1358 )
1361 )
1359 coreconfigitem('web', 'csp',
1362 coreconfigitem('web', 'csp',
1360 default=None,
1363 default=None,
1361 )
1364 )
1362 coreconfigitem('web', 'deny_read',
1365 coreconfigitem('web', 'deny_read',
1363 default=list,
1366 default=list,
1364 )
1367 )
1365 coreconfigitem('web', 'descend',
1368 coreconfigitem('web', 'descend',
1366 default=True,
1369 default=True,
1367 )
1370 )
1368 coreconfigitem('web', 'description',
1371 coreconfigitem('web', 'description',
1369 default="",
1372 default="",
1370 )
1373 )
1371 coreconfigitem('web', 'encoding',
1374 coreconfigitem('web', 'encoding',
1372 default=lambda: encoding.encoding,
1375 default=lambda: encoding.encoding,
1373 )
1376 )
1374 coreconfigitem('web', 'errorlog',
1377 coreconfigitem('web', 'errorlog',
1375 default='-',
1378 default='-',
1376 )
1379 )
1377 coreconfigitem('web', 'ipv6',
1380 coreconfigitem('web', 'ipv6',
1378 default=False,
1381 default=False,
1379 )
1382 )
1380 coreconfigitem('web', 'maxchanges',
1383 coreconfigitem('web', 'maxchanges',
1381 default=10,
1384 default=10,
1382 )
1385 )
1383 coreconfigitem('web', 'maxfiles',
1386 coreconfigitem('web', 'maxfiles',
1384 default=10,
1387 default=10,
1385 )
1388 )
1386 coreconfigitem('web', 'maxshortchanges',
1389 coreconfigitem('web', 'maxshortchanges',
1387 default=60,
1390 default=60,
1388 )
1391 )
1389 coreconfigitem('web', 'motd',
1392 coreconfigitem('web', 'motd',
1390 default='',
1393 default='',
1391 )
1394 )
1392 coreconfigitem('web', 'name',
1395 coreconfigitem('web', 'name',
1393 default=dynamicdefault,
1396 default=dynamicdefault,
1394 )
1397 )
1395 coreconfigitem('web', 'port',
1398 coreconfigitem('web', 'port',
1396 default=8000,
1399 default=8000,
1397 )
1400 )
1398 coreconfigitem('web', 'prefix',
1401 coreconfigitem('web', 'prefix',
1399 default='',
1402 default='',
1400 )
1403 )
1401 coreconfigitem('web', 'push_ssl',
1404 coreconfigitem('web', 'push_ssl',
1402 default=True,
1405 default=True,
1403 )
1406 )
1404 coreconfigitem('web', 'refreshinterval',
1407 coreconfigitem('web', 'refreshinterval',
1405 default=20,
1408 default=20,
1406 )
1409 )
1407 coreconfigitem('web', 'server-header',
1410 coreconfigitem('web', 'server-header',
1408 default=None,
1411 default=None,
1409 )
1412 )
1410 coreconfigitem('web', 'static',
1413 coreconfigitem('web', 'static',
1411 default=None,
1414 default=None,
1412 )
1415 )
1413 coreconfigitem('web', 'staticurl',
1416 coreconfigitem('web', 'staticurl',
1414 default=None,
1417 default=None,
1415 )
1418 )
1416 coreconfigitem('web', 'stripes',
1419 coreconfigitem('web', 'stripes',
1417 default=1,
1420 default=1,
1418 )
1421 )
1419 coreconfigitem('web', 'style',
1422 coreconfigitem('web', 'style',
1420 default='paper',
1423 default='paper',
1421 )
1424 )
1422 coreconfigitem('web', 'templates',
1425 coreconfigitem('web', 'templates',
1423 default=None,
1426 default=None,
1424 )
1427 )
1425 coreconfigitem('web', 'view',
1428 coreconfigitem('web', 'view',
1426 default='served',
1429 default='served',
1427 )
1430 )
1428 coreconfigitem('worker', 'backgroundclose',
1431 coreconfigitem('worker', 'backgroundclose',
1429 default=dynamicdefault,
1432 default=dynamicdefault,
1430 )
1433 )
1431 # Windows defaults to a limit of 512 open files. A buffer of 128
1434 # Windows defaults to a limit of 512 open files. A buffer of 128
1432 # should give us enough headway.
1435 # should give us enough headway.
1433 coreconfigitem('worker', 'backgroundclosemaxqueue',
1436 coreconfigitem('worker', 'backgroundclosemaxqueue',
1434 default=384,
1437 default=384,
1435 )
1438 )
1436 coreconfigitem('worker', 'backgroundcloseminfilecount',
1439 coreconfigitem('worker', 'backgroundcloseminfilecount',
1437 default=2048,
1440 default=2048,
1438 )
1441 )
1439 coreconfigitem('worker', 'backgroundclosethreadcount',
1442 coreconfigitem('worker', 'backgroundclosethreadcount',
1440 default=4,
1443 default=4,
1441 )
1444 )
1442 coreconfigitem('worker', 'enabled',
1445 coreconfigitem('worker', 'enabled',
1443 default=True,
1446 default=True,
1444 )
1447 )
1445 coreconfigitem('worker', 'numcpus',
1448 coreconfigitem('worker', 'numcpus',
1446 default=None,
1449 default=None,
1447 )
1450 )
1448
1451
1449 # Rebase related configuration moved to core because other extension are doing
1452 # Rebase related configuration moved to core because other extension are doing
1450 # strange things. For example, shelve import the extensions to reuse some bit
1453 # strange things. For example, shelve import the extensions to reuse some bit
1451 # without formally loading it.
1454 # without formally loading it.
1452 coreconfigitem('commands', 'rebase.requiredest',
1455 coreconfigitem('commands', 'rebase.requiredest',
1453 default=False,
1456 default=False,
1454 )
1457 )
1455 coreconfigitem('experimental', 'rebaseskipobsolete',
1458 coreconfigitem('experimental', 'rebaseskipobsolete',
1456 default=True,
1459 default=True,
1457 )
1460 )
1458 coreconfigitem('rebase', 'singletransaction',
1461 coreconfigitem('rebase', 'singletransaction',
1459 default=False,
1462 default=False,
1460 )
1463 )
1461 coreconfigitem('rebase', 'experimental.inmemory',
1464 coreconfigitem('rebase', 'experimental.inmemory',
1462 default=False,
1465 default=False,
1463 )
1466 )
@@ -1,242 +1,331 b''
1 #require chg
1 #require chg
2
2
3 $ mkdir log
3 $ mkdir log
4 $ cp $HGRCPATH $HGRCPATH.unconfigured
4 $ cat <<'EOF' >> $HGRCPATH
5 $ cat <<'EOF' >> $HGRCPATH
5 > [cmdserver]
6 > [cmdserver]
6 > log = $TESTTMP/log/server.log
7 > log = $TESTTMP/log/server.log
7 > max-log-files = 1
8 > max-log-files = 1
8 > max-log-size = 10 kB
9 > max-log-size = 10 kB
9 > EOF
10 > EOF
10 $ cp $HGRCPATH $HGRCPATH.orig
11 $ cp $HGRCPATH $HGRCPATH.orig
11
12
12 $ filterlog () {
13 $ filterlog () {
13 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
14 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
14 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
15 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
15 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
16 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
17 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
16 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
18 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
17 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
19 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
18 > }
20 > }
19
21
20 init repo
22 init repo
21
23
22 $ chg init foo
24 $ chg init foo
23 $ cd foo
25 $ cd foo
24
26
25 ill-formed config
27 ill-formed config
26
28
27 $ chg status
29 $ chg status
28 $ echo '=brokenconfig' >> $HGRCPATH
30 $ echo '=brokenconfig' >> $HGRCPATH
29 $ chg status
31 $ chg status
30 hg: parse error at * (glob)
32 hg: parse error at * (glob)
31 [255]
33 [255]
32
34
33 $ cp $HGRCPATH.orig $HGRCPATH
35 $ cp $HGRCPATH.orig $HGRCPATH
34
36
35 long socket path
37 long socket path
36
38
37 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
39 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
38 $ mkdir -p $sockpath
40 $ mkdir -p $sockpath
39 $ bakchgsockname=$CHGSOCKNAME
41 $ bakchgsockname=$CHGSOCKNAME
40 $ CHGSOCKNAME=$sockpath/server
42 $ CHGSOCKNAME=$sockpath/server
41 $ export CHGSOCKNAME
43 $ export CHGSOCKNAME
42 $ chg root
44 $ chg root
43 $TESTTMP/foo
45 $TESTTMP/foo
44 $ rm -rf $sockpath
46 $ rm -rf $sockpath
45 $ CHGSOCKNAME=$bakchgsockname
47 $ CHGSOCKNAME=$bakchgsockname
46 $ export CHGSOCKNAME
48 $ export CHGSOCKNAME
47
49
48 $ cd ..
50 $ cd ..
49
51
50 editor
52 editor
51 ------
53 ------
52
54
53 $ cat >> pushbuffer.py <<EOF
55 $ cat >> pushbuffer.py <<EOF
54 > def reposetup(ui, repo):
56 > def reposetup(ui, repo):
55 > repo.ui.pushbuffer(subproc=True)
57 > repo.ui.pushbuffer(subproc=True)
56 > EOF
58 > EOF
57
59
58 $ chg init editor
60 $ chg init editor
59 $ cd editor
61 $ cd editor
60
62
61 by default, system() should be redirected to the client:
63 by default, system() should be redirected to the client:
62
64
63 $ touch foo
65 $ touch foo
64 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
66 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
65 > | egrep "HG:|run 'cat"
67 > | egrep "HG:|run 'cat"
66 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
68 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
67 HG: Enter commit message. Lines beginning with 'HG:' are removed.
69 HG: Enter commit message. Lines beginning with 'HG:' are removed.
68 HG: Leave message empty to abort commit.
70 HG: Leave message empty to abort commit.
69 HG: --
71 HG: --
70 HG: user: test
72 HG: user: test
71 HG: branch 'default'
73 HG: branch 'default'
72 HG: added foo
74 HG: added foo
73
75
74 but no redirection should be made if output is captured:
76 but no redirection should be made if output is captured:
75
77
76 $ touch bar
78 $ touch bar
77 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
79 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
78 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
80 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
79 > | egrep "HG:|run 'cat"
81 > | egrep "HG:|run 'cat"
80 [1]
82 [1]
81
83
82 check that commit commands succeeded:
84 check that commit commands succeeded:
83
85
84 $ hg log -T '{rev}:{desc}\n'
86 $ hg log -T '{rev}:{desc}\n'
85 1:bufferred
87 1:bufferred
86 0:channeled
88 0:channeled
87
89
88 $ cd ..
90 $ cd ..
89
91
90 pager
92 pager
91 -----
93 -----
92
94
93 $ cat >> fakepager.py <<EOF
95 $ cat >> fakepager.py <<EOF
94 > import sys
96 > import sys
95 > for line in sys.stdin:
97 > for line in sys.stdin:
96 > sys.stdout.write('paged! %r\n' % line)
98 > sys.stdout.write('paged! %r\n' % line)
97 > EOF
99 > EOF
98
100
99 enable pager extension globally, but spawns the master server with no tty:
101 enable pager extension globally, but spawns the master server with no tty:
100
102
101 $ chg init pager
103 $ chg init pager
102 $ cd pager
104 $ cd pager
103 $ cat >> $HGRCPATH <<EOF
105 $ cat >> $HGRCPATH <<EOF
104 > [extensions]
106 > [extensions]
105 > pager =
107 > pager =
106 > [pager]
108 > [pager]
107 > pager = "$PYTHON" $TESTTMP/fakepager.py
109 > pager = "$PYTHON" $TESTTMP/fakepager.py
108 > EOF
110 > EOF
109 $ chg version > /dev/null
111 $ chg version > /dev/null
110 $ touch foo
112 $ touch foo
111 $ chg ci -qAm foo
113 $ chg ci -qAm foo
112
114
113 pager should be enabled if the attached client has a tty:
115 pager should be enabled if the attached client has a tty:
114
116
115 $ chg log -l1 -q --config ui.formatted=True
117 $ chg log -l1 -q --config ui.formatted=True
116 paged! '0:1f7b0de80e11\n'
118 paged! '0:1f7b0de80e11\n'
117 $ chg log -l1 -q --config ui.formatted=False
119 $ chg log -l1 -q --config ui.formatted=False
118 0:1f7b0de80e11
120 0:1f7b0de80e11
119
121
120 chg waits for pager if runcommand raises
122 chg waits for pager if runcommand raises
121
123
122 $ cat > $TESTTMP/crash.py <<EOF
124 $ cat > $TESTTMP/crash.py <<EOF
123 > from mercurial import registrar
125 > from mercurial import registrar
124 > cmdtable = {}
126 > cmdtable = {}
125 > command = registrar.command(cmdtable)
127 > command = registrar.command(cmdtable)
126 > @command(b'crash')
128 > @command(b'crash')
127 > def pagercrash(ui, repo, *pats, **opts):
129 > def pagercrash(ui, repo, *pats, **opts):
128 > ui.write('going to crash\n')
130 > ui.write('going to crash\n')
129 > raise Exception('.')
131 > raise Exception('.')
130 > EOF
132 > EOF
131
133
132 $ cat > $TESTTMP/fakepager.py <<EOF
134 $ cat > $TESTTMP/fakepager.py <<EOF
133 > from __future__ import absolute_import
135 > from __future__ import absolute_import
134 > import sys
136 > import sys
135 > import time
137 > import time
136 > for line in iter(sys.stdin.readline, ''):
138 > for line in iter(sys.stdin.readline, ''):
137 > if 'crash' in line: # only interested in lines containing 'crash'
139 > if 'crash' in line: # only interested in lines containing 'crash'
138 > # if chg exits when pager is sleeping (incorrectly), the output
140 > # if chg exits when pager is sleeping (incorrectly), the output
139 > # will be captured by the next test case
141 > # will be captured by the next test case
140 > time.sleep(1)
142 > time.sleep(1)
141 > sys.stdout.write('crash-pager: %s' % line)
143 > sys.stdout.write('crash-pager: %s' % line)
142 > EOF
144 > EOF
143
145
144 $ cat >> .hg/hgrc <<EOF
146 $ cat >> .hg/hgrc <<EOF
145 > [extensions]
147 > [extensions]
146 > crash = $TESTTMP/crash.py
148 > crash = $TESTTMP/crash.py
147 > EOF
149 > EOF
148
150
149 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
151 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
150 crash-pager: going to crash
152 crash-pager: going to crash
151 [255]
153 [255]
152
154
153 $ cd ..
155 $ cd ..
154
156
155 server lifecycle
157 server lifecycle
156 ----------------
158 ----------------
157
159
158 chg server should be restarted on code change, and old server will shut down
160 chg server should be restarted on code change, and old server will shut down
159 automatically. In this test, we use the following time parameters:
161 automatically. In this test, we use the following time parameters:
160
162
161 - "sleep 1" to make mtime different
163 - "sleep 1" to make mtime different
162 - "sleep 2" to notice mtime change (polling interval is 1 sec)
164 - "sleep 2" to notice mtime change (polling interval is 1 sec)
163
165
164 set up repository with an extension:
166 set up repository with an extension:
165
167
166 $ chg init extreload
168 $ chg init extreload
167 $ cd extreload
169 $ cd extreload
168 $ touch dummyext.py
170 $ touch dummyext.py
169 $ cat <<EOF >> .hg/hgrc
171 $ cat <<EOF >> .hg/hgrc
170 > [extensions]
172 > [extensions]
171 > dummyext = dummyext.py
173 > dummyext = dummyext.py
172 > EOF
174 > EOF
173
175
174 isolate socket directory for stable result:
176 isolate socket directory for stable result:
175
177
176 $ OLDCHGSOCKNAME=$CHGSOCKNAME
178 $ OLDCHGSOCKNAME=$CHGSOCKNAME
177 $ mkdir chgsock
179 $ mkdir chgsock
178 $ CHGSOCKNAME=`pwd`/chgsock/server
180 $ CHGSOCKNAME=`pwd`/chgsock/server
179
181
180 warm up server:
182 warm up server:
181
183
182 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
184 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
183 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
185 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
184
186
185 new server should be started if extension modified:
187 new server should be started if extension modified:
186
188
187 $ sleep 1
189 $ sleep 1
188 $ touch dummyext.py
190 $ touch dummyext.py
189 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
191 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
190 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
192 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
191 chg: debug: * instruction: reconnect (glob)
193 chg: debug: * instruction: reconnect (glob)
192 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
194 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
193
195
194 old server will shut down, while new server should still be reachable:
196 old server will shut down, while new server should still be reachable:
195
197
196 $ sleep 2
198 $ sleep 2
197 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
199 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
198
200
199 socket file should never be unlinked by old server:
201 socket file should never be unlinked by old server:
200 (simulates unowned socket by updating mtime, which makes sure server exits
202 (simulates unowned socket by updating mtime, which makes sure server exits
201 at polling cycle)
203 at polling cycle)
202
204
203 $ ls chgsock/server-*
205 $ ls chgsock/server-*
204 chgsock/server-* (glob)
206 chgsock/server-* (glob)
205 $ touch chgsock/server-*
207 $ touch chgsock/server-*
206 $ sleep 2
208 $ sleep 2
207 $ ls chgsock/server-*
209 $ ls chgsock/server-*
208 chgsock/server-* (glob)
210 chgsock/server-* (glob)
209
211
210 since no server is reachable from socket file, new server should be started:
212 since no server is reachable from socket file, new server should be started:
211 (this test makes sure that old server shut down automatically)
213 (this test makes sure that old server shut down automatically)
212
214
213 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
215 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
214 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
216 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
215
217
216 shut down servers and restore environment:
218 shut down servers and restore environment:
217
219
218 $ rm -R chgsock
220 $ rm -R chgsock
219 $ sleep 2
221 $ sleep 2
220 $ CHGSOCKNAME=$OLDCHGSOCKNAME
222 $ CHGSOCKNAME=$OLDCHGSOCKNAME
221 $ cd ..
223 $ cd ..
222
224
223 check that server events are recorded:
225 check that server events are recorded:
224
226
225 $ ls log
227 $ ls log
226 server.log
228 server.log
227 server.log.1
229 server.log.1
228
230
229 print only the last 10 lines, since we aren't sure how many records are
231 print only the last 10 lines, since we aren't sure how many records are
230 preserved:
232 preserved:
231
233
232 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
234 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
235 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
233 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ...
236 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ...
234 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
237 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
235 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
238 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
236 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
239 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
237 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
240 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
238 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
241 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
239 YYYY/MM/DD HH:MM:SS (PID)> validate: []
242 YYYY/MM/DD HH:MM:SS (PID)> validate: []
240 YYYY/MM/DD HH:MM:SS (PID)> repository: $TESTTMP/extreload
241 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
243 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
242 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
244 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
245
246 repository cache
247 ----------------
248
249 $ rm log/server.log*
250 $ cp $HGRCPATH.unconfigured $HGRCPATH
251 $ cat <<'EOF' >> $HGRCPATH
252 > [cmdserver]
253 > log = $TESTTMP/log/server.log
254 > max-repo-cache = 1
255 > track-log = command, repocache
256 > EOF
257
258 isolate socket directory for stable result:
259
260 $ OLDCHGSOCKNAME=$CHGSOCKNAME
261 $ mkdir chgsock
262 $ CHGSOCKNAME=`pwd`/chgsock/server
263
264 create empty repo and cache it:
265
266 $ hg init cached
267 $ hg id -R cached
268 000000000000 tip
269 $ sleep 1
270
271 modify repo (and cache will be invalidated):
272
273 $ touch cached/a
274 $ hg ci -R cached -Am 'add a'
275 adding a
276 $ sleep 1
277
278 read cached repo:
279
280 $ hg log -R cached
281 changeset: 0:ac82d8b1f7c4
282 tag: tip
283 user: test
284 date: Thu Jan 01 00:00:00 1970 +0000
285 summary: add a
286
287 $ sleep 1
288
289 discard cached from LRU cache:
290
291 $ hg clone cached cached2
292 updating to branch default
293 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 $ hg id -R cached2
295 ac82d8b1f7c4 tip
296 $ sleep 1
297
298 read uncached repo:
299
300 $ hg log -R cached
301 changeset: 0:ac82d8b1f7c4
302 tag: tip
303 user: test
304 date: Thu Jan 01 00:00:00 1970 +0000
305 summary: add a
306
307 $ sleep 1
308
309 shut down servers and restore environment:
310
311 $ rm -R chgsock
312 $ sleep 2
313 $ CHGSOCKNAME=$OLDCHGSOCKNAME
314
315 check server log:
316
317 $ cat log/server.log | filterlog
318 YYYY/MM/DD HH:MM:SS (PID)> init cached
319 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
320 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
321 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
322 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
323 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
324 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
325 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
326 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
327 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
328 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
329 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
330 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
331 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
General Comments 0
You need to be logged in to leave comments. Login now