##// END OF EJS Templates
devel-warn: add 'warn-' to 'devel.empty-changegroup' config...
Boris Feld -
r34735:3572b203 default
parent child Browse files
Show More
@@ -1,1005 +1,1005 b''
1 # changegroup.py - Mercurial changegroup manipulation functions
1 # changegroup.py - Mercurial changegroup manipulation functions
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import struct
11 import struct
12 import tempfile
12 import tempfile
13 import weakref
13 import weakref
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 )
20 )
21
21
22 from . import (
22 from . import (
23 dagutil,
23 dagutil,
24 error,
24 error,
25 mdiff,
25 mdiff,
26 phases,
26 phases,
27 pycompat,
27 pycompat,
28 util,
28 util,
29 )
29 )
30
30
31 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
31 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
32 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
32 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
33 _CHANGEGROUPV3_DELTA_HEADER = ">20s20s20s20s20sH"
33 _CHANGEGROUPV3_DELTA_HEADER = ">20s20s20s20s20sH"
34
34
35 def readexactly(stream, n):
35 def readexactly(stream, n):
36 '''read n bytes from stream.read and abort if less was available'''
36 '''read n bytes from stream.read and abort if less was available'''
37 s = stream.read(n)
37 s = stream.read(n)
38 if len(s) < n:
38 if len(s) < n:
39 raise error.Abort(_("stream ended unexpectedly"
39 raise error.Abort(_("stream ended unexpectedly"
40 " (got %d bytes, expected %d)")
40 " (got %d bytes, expected %d)")
41 % (len(s), n))
41 % (len(s), n))
42 return s
42 return s
43
43
44 def getchunk(stream):
44 def getchunk(stream):
45 """return the next chunk from stream as a string"""
45 """return the next chunk from stream as a string"""
46 d = readexactly(stream, 4)
46 d = readexactly(stream, 4)
47 l = struct.unpack(">l", d)[0]
47 l = struct.unpack(">l", d)[0]
48 if l <= 4:
48 if l <= 4:
49 if l:
49 if l:
50 raise error.Abort(_("invalid chunk length %d") % l)
50 raise error.Abort(_("invalid chunk length %d") % l)
51 return ""
51 return ""
52 return readexactly(stream, l - 4)
52 return readexactly(stream, l - 4)
53
53
54 def chunkheader(length):
54 def chunkheader(length):
55 """return a changegroup chunk header (string)"""
55 """return a changegroup chunk header (string)"""
56 return struct.pack(">l", length + 4)
56 return struct.pack(">l", length + 4)
57
57
58 def closechunk():
58 def closechunk():
59 """return a changegroup chunk header (string) for a zero-length chunk"""
59 """return a changegroup chunk header (string) for a zero-length chunk"""
60 return struct.pack(">l", 0)
60 return struct.pack(">l", 0)
61
61
62 def writechunks(ui, chunks, filename, vfs=None):
62 def writechunks(ui, chunks, filename, vfs=None):
63 """Write chunks to a file and return its filename.
63 """Write chunks to a file and return its filename.
64
64
65 The stream is assumed to be a bundle file.
65 The stream is assumed to be a bundle file.
66 Existing files will not be overwritten.
66 Existing files will not be overwritten.
67 If no filename is specified, a temporary file is created.
67 If no filename is specified, a temporary file is created.
68 """
68 """
69 fh = None
69 fh = None
70 cleanup = None
70 cleanup = None
71 try:
71 try:
72 if filename:
72 if filename:
73 if vfs:
73 if vfs:
74 fh = vfs.open(filename, "wb")
74 fh = vfs.open(filename, "wb")
75 else:
75 else:
76 # Increase default buffer size because default is usually
76 # Increase default buffer size because default is usually
77 # small (4k is common on Linux).
77 # small (4k is common on Linux).
78 fh = open(filename, "wb", 131072)
78 fh = open(filename, "wb", 131072)
79 else:
79 else:
80 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
80 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
81 fh = os.fdopen(fd, pycompat.sysstr("wb"))
81 fh = os.fdopen(fd, pycompat.sysstr("wb"))
82 cleanup = filename
82 cleanup = filename
83 for c in chunks:
83 for c in chunks:
84 fh.write(c)
84 fh.write(c)
85 cleanup = None
85 cleanup = None
86 return filename
86 return filename
87 finally:
87 finally:
88 if fh is not None:
88 if fh is not None:
89 fh.close()
89 fh.close()
90 if cleanup is not None:
90 if cleanup is not None:
91 if filename and vfs:
91 if filename and vfs:
92 vfs.unlink(cleanup)
92 vfs.unlink(cleanup)
93 else:
93 else:
94 os.unlink(cleanup)
94 os.unlink(cleanup)
95
95
96 class cg1unpacker(object):
96 class cg1unpacker(object):
97 """Unpacker for cg1 changegroup streams.
97 """Unpacker for cg1 changegroup streams.
98
98
99 A changegroup unpacker handles the framing of the revision data in
99 A changegroup unpacker handles the framing of the revision data in
100 the wire format. Most consumers will want to use the apply()
100 the wire format. Most consumers will want to use the apply()
101 method to add the changes from the changegroup to a repository.
101 method to add the changes from the changegroup to a repository.
102
102
103 If you're forwarding a changegroup unmodified to another consumer,
103 If you're forwarding a changegroup unmodified to another consumer,
104 use getchunks(), which returns an iterator of changegroup
104 use getchunks(), which returns an iterator of changegroup
105 chunks. This is mostly useful for cases where you need to know the
105 chunks. This is mostly useful for cases where you need to know the
106 data stream has ended by observing the end of the changegroup.
106 data stream has ended by observing the end of the changegroup.
107
107
108 deltachunk() is useful only if you're applying delta data. Most
108 deltachunk() is useful only if you're applying delta data. Most
109 consumers should prefer apply() instead.
109 consumers should prefer apply() instead.
110
110
111 A few other public methods exist. Those are used only for
111 A few other public methods exist. Those are used only for
112 bundlerepo and some debug commands - their use is discouraged.
112 bundlerepo and some debug commands - their use is discouraged.
113 """
113 """
114 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
114 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
115 deltaheadersize = struct.calcsize(deltaheader)
115 deltaheadersize = struct.calcsize(deltaheader)
116 version = '01'
116 version = '01'
117 _grouplistcount = 1 # One list of files after the manifests
117 _grouplistcount = 1 # One list of files after the manifests
118
118
119 def __init__(self, fh, alg, extras=None):
119 def __init__(self, fh, alg, extras=None):
120 if alg is None:
120 if alg is None:
121 alg = 'UN'
121 alg = 'UN'
122 if alg not in util.compengines.supportedbundletypes:
122 if alg not in util.compengines.supportedbundletypes:
123 raise error.Abort(_('unknown stream compression type: %s')
123 raise error.Abort(_('unknown stream compression type: %s')
124 % alg)
124 % alg)
125 if alg == 'BZ':
125 if alg == 'BZ':
126 alg = '_truncatedBZ'
126 alg = '_truncatedBZ'
127
127
128 compengine = util.compengines.forbundletype(alg)
128 compengine = util.compengines.forbundletype(alg)
129 self._stream = compengine.decompressorreader(fh)
129 self._stream = compengine.decompressorreader(fh)
130 self._type = alg
130 self._type = alg
131 self.extras = extras or {}
131 self.extras = extras or {}
132 self.callback = None
132 self.callback = None
133
133
134 # These methods (compressed, read, seek, tell) all appear to only
134 # These methods (compressed, read, seek, tell) all appear to only
135 # be used by bundlerepo, but it's a little hard to tell.
135 # be used by bundlerepo, but it's a little hard to tell.
136 def compressed(self):
136 def compressed(self):
137 return self._type is not None and self._type != 'UN'
137 return self._type is not None and self._type != 'UN'
138 def read(self, l):
138 def read(self, l):
139 return self._stream.read(l)
139 return self._stream.read(l)
140 def seek(self, pos):
140 def seek(self, pos):
141 return self._stream.seek(pos)
141 return self._stream.seek(pos)
142 def tell(self):
142 def tell(self):
143 return self._stream.tell()
143 return self._stream.tell()
144 def close(self):
144 def close(self):
145 return self._stream.close()
145 return self._stream.close()
146
146
147 def _chunklength(self):
147 def _chunklength(self):
148 d = readexactly(self._stream, 4)
148 d = readexactly(self._stream, 4)
149 l = struct.unpack(">l", d)[0]
149 l = struct.unpack(">l", d)[0]
150 if l <= 4:
150 if l <= 4:
151 if l:
151 if l:
152 raise error.Abort(_("invalid chunk length %d") % l)
152 raise error.Abort(_("invalid chunk length %d") % l)
153 return 0
153 return 0
154 if self.callback:
154 if self.callback:
155 self.callback()
155 self.callback()
156 return l - 4
156 return l - 4
157
157
158 def changelogheader(self):
158 def changelogheader(self):
159 """v10 does not have a changelog header chunk"""
159 """v10 does not have a changelog header chunk"""
160 return {}
160 return {}
161
161
162 def manifestheader(self):
162 def manifestheader(self):
163 """v10 does not have a manifest header chunk"""
163 """v10 does not have a manifest header chunk"""
164 return {}
164 return {}
165
165
166 def filelogheader(self):
166 def filelogheader(self):
167 """return the header of the filelogs chunk, v10 only has the filename"""
167 """return the header of the filelogs chunk, v10 only has the filename"""
168 l = self._chunklength()
168 l = self._chunklength()
169 if not l:
169 if not l:
170 return {}
170 return {}
171 fname = readexactly(self._stream, l)
171 fname = readexactly(self._stream, l)
172 return {'filename': fname}
172 return {'filename': fname}
173
173
174 def _deltaheader(self, headertuple, prevnode):
174 def _deltaheader(self, headertuple, prevnode):
175 node, p1, p2, cs = headertuple
175 node, p1, p2, cs = headertuple
176 if prevnode is None:
176 if prevnode is None:
177 deltabase = p1
177 deltabase = p1
178 else:
178 else:
179 deltabase = prevnode
179 deltabase = prevnode
180 flags = 0
180 flags = 0
181 return node, p1, p2, deltabase, cs, flags
181 return node, p1, p2, deltabase, cs, flags
182
182
183 def deltachunk(self, prevnode):
183 def deltachunk(self, prevnode):
184 l = self._chunklength()
184 l = self._chunklength()
185 if not l:
185 if not l:
186 return {}
186 return {}
187 headerdata = readexactly(self._stream, self.deltaheadersize)
187 headerdata = readexactly(self._stream, self.deltaheadersize)
188 header = struct.unpack(self.deltaheader, headerdata)
188 header = struct.unpack(self.deltaheader, headerdata)
189 delta = readexactly(self._stream, l - self.deltaheadersize)
189 delta = readexactly(self._stream, l - self.deltaheadersize)
190 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
190 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
191 return (node, p1, p2, cs, deltabase, delta, flags)
191 return (node, p1, p2, cs, deltabase, delta, flags)
192
192
193 def getchunks(self):
193 def getchunks(self):
194 """returns all the chunks contains in the bundle
194 """returns all the chunks contains in the bundle
195
195
196 Used when you need to forward the binary stream to a file or another
196 Used when you need to forward the binary stream to a file or another
197 network API. To do so, it parse the changegroup data, otherwise it will
197 network API. To do so, it parse the changegroup data, otherwise it will
198 block in case of sshrepo because it don't know the end of the stream.
198 block in case of sshrepo because it don't know the end of the stream.
199 """
199 """
200 # For changegroup 1 and 2, we expect 3 parts: changelog, manifestlog,
200 # For changegroup 1 and 2, we expect 3 parts: changelog, manifestlog,
201 # and a list of filelogs. For changegroup 3, we expect 4 parts:
201 # and a list of filelogs. For changegroup 3, we expect 4 parts:
202 # changelog, manifestlog, a list of tree manifestlogs, and a list of
202 # changelog, manifestlog, a list of tree manifestlogs, and a list of
203 # filelogs.
203 # filelogs.
204 #
204 #
205 # Changelog and manifestlog parts are terminated with empty chunks. The
205 # Changelog and manifestlog parts are terminated with empty chunks. The
206 # tree and file parts are a list of entry sections. Each entry section
206 # tree and file parts are a list of entry sections. Each entry section
207 # is a series of chunks terminating in an empty chunk. The list of these
207 # is a series of chunks terminating in an empty chunk. The list of these
208 # entry sections is terminated in yet another empty chunk, so we know
208 # entry sections is terminated in yet another empty chunk, so we know
209 # we've reached the end of the tree/file list when we reach an empty
209 # we've reached the end of the tree/file list when we reach an empty
210 # chunk that was proceeded by no non-empty chunks.
210 # chunk that was proceeded by no non-empty chunks.
211
211
212 parts = 0
212 parts = 0
213 while parts < 2 + self._grouplistcount:
213 while parts < 2 + self._grouplistcount:
214 noentries = True
214 noentries = True
215 while True:
215 while True:
216 chunk = getchunk(self)
216 chunk = getchunk(self)
217 if not chunk:
217 if not chunk:
218 # The first two empty chunks represent the end of the
218 # The first two empty chunks represent the end of the
219 # changelog and the manifestlog portions. The remaining
219 # changelog and the manifestlog portions. The remaining
220 # empty chunks represent either A) the end of individual
220 # empty chunks represent either A) the end of individual
221 # tree or file entries in the file list, or B) the end of
221 # tree or file entries in the file list, or B) the end of
222 # the entire list. It's the end of the entire list if there
222 # the entire list. It's the end of the entire list if there
223 # were no entries (i.e. noentries is True).
223 # were no entries (i.e. noentries is True).
224 if parts < 2:
224 if parts < 2:
225 parts += 1
225 parts += 1
226 elif noentries:
226 elif noentries:
227 parts += 1
227 parts += 1
228 break
228 break
229 noentries = False
229 noentries = False
230 yield chunkheader(len(chunk))
230 yield chunkheader(len(chunk))
231 pos = 0
231 pos = 0
232 while pos < len(chunk):
232 while pos < len(chunk):
233 next = pos + 2**20
233 next = pos + 2**20
234 yield chunk[pos:next]
234 yield chunk[pos:next]
235 pos = next
235 pos = next
236 yield closechunk()
236 yield closechunk()
237
237
238 def _unpackmanifests(self, repo, revmap, trp, prog, numchanges):
238 def _unpackmanifests(self, repo, revmap, trp, prog, numchanges):
239 # We know that we'll never have more manifests than we had
239 # We know that we'll never have more manifests than we had
240 # changesets.
240 # changesets.
241 self.callback = prog(_('manifests'), numchanges)
241 self.callback = prog(_('manifests'), numchanges)
242 # no need to check for empty manifest group here:
242 # no need to check for empty manifest group here:
243 # if the result of the merge of 1 and 2 is the same in 3 and 4,
243 # if the result of the merge of 1 and 2 is the same in 3 and 4,
244 # no new manifest will be created and the manifest group will
244 # no new manifest will be created and the manifest group will
245 # be empty during the pull
245 # be empty during the pull
246 self.manifestheader()
246 self.manifestheader()
247 deltas = self.deltaiter()
247 deltas = self.deltaiter()
248 repo.manifestlog._revlog.addgroup(deltas, revmap, trp)
248 repo.manifestlog._revlog.addgroup(deltas, revmap, trp)
249 repo.ui.progress(_('manifests'), None)
249 repo.ui.progress(_('manifests'), None)
250 self.callback = None
250 self.callback = None
251
251
252 def apply(self, repo, tr, srctype, url, targetphase=phases.draft,
252 def apply(self, repo, tr, srctype, url, targetphase=phases.draft,
253 expectedtotal=None):
253 expectedtotal=None):
254 """Add the changegroup returned by source.read() to this repo.
254 """Add the changegroup returned by source.read() to this repo.
255 srctype is a string like 'push', 'pull', or 'unbundle'. url is
255 srctype is a string like 'push', 'pull', or 'unbundle'. url is
256 the URL of the repo where this changegroup is coming from.
256 the URL of the repo where this changegroup is coming from.
257
257
258 Return an integer summarizing the change to this repo:
258 Return an integer summarizing the change to this repo:
259 - nothing changed or no source: 0
259 - nothing changed or no source: 0
260 - more heads than before: 1+added heads (2..n)
260 - more heads than before: 1+added heads (2..n)
261 - fewer heads than before: -1-removed heads (-2..-n)
261 - fewer heads than before: -1-removed heads (-2..-n)
262 - number of heads stays the same: 1
262 - number of heads stays the same: 1
263 """
263 """
264 repo = repo.unfiltered()
264 repo = repo.unfiltered()
265 def csmap(x):
265 def csmap(x):
266 repo.ui.debug("add changeset %s\n" % short(x))
266 repo.ui.debug("add changeset %s\n" % short(x))
267 return len(cl)
267 return len(cl)
268
268
269 def revmap(x):
269 def revmap(x):
270 return cl.rev(x)
270 return cl.rev(x)
271
271
272 changesets = files = revisions = 0
272 changesets = files = revisions = 0
273
273
274 try:
274 try:
275 # The transaction may already carry source information. In this
275 # The transaction may already carry source information. In this
276 # case we use the top level data. We overwrite the argument
276 # case we use the top level data. We overwrite the argument
277 # because we need to use the top level value (if they exist)
277 # because we need to use the top level value (if they exist)
278 # in this function.
278 # in this function.
279 srctype = tr.hookargs.setdefault('source', srctype)
279 srctype = tr.hookargs.setdefault('source', srctype)
280 url = tr.hookargs.setdefault('url', url)
280 url = tr.hookargs.setdefault('url', url)
281 repo.hook('prechangegroup',
281 repo.hook('prechangegroup',
282 throw=True, **pycompat.strkwargs(tr.hookargs))
282 throw=True, **pycompat.strkwargs(tr.hookargs))
283
283
284 # write changelog data to temp files so concurrent readers
284 # write changelog data to temp files so concurrent readers
285 # will not see an inconsistent view
285 # will not see an inconsistent view
286 cl = repo.changelog
286 cl = repo.changelog
287 cl.delayupdate(tr)
287 cl.delayupdate(tr)
288 oldheads = set(cl.heads())
288 oldheads = set(cl.heads())
289
289
290 trp = weakref.proxy(tr)
290 trp = weakref.proxy(tr)
291 # pull off the changeset group
291 # pull off the changeset group
292 repo.ui.status(_("adding changesets\n"))
292 repo.ui.status(_("adding changesets\n"))
293 clstart = len(cl)
293 clstart = len(cl)
294 class prog(object):
294 class prog(object):
295 def __init__(self, step, total):
295 def __init__(self, step, total):
296 self._step = step
296 self._step = step
297 self._total = total
297 self._total = total
298 self._count = 1
298 self._count = 1
299 def __call__(self):
299 def __call__(self):
300 repo.ui.progress(self._step, self._count, unit=_('chunks'),
300 repo.ui.progress(self._step, self._count, unit=_('chunks'),
301 total=self._total)
301 total=self._total)
302 self._count += 1
302 self._count += 1
303 self.callback = prog(_('changesets'), expectedtotal)
303 self.callback = prog(_('changesets'), expectedtotal)
304
304
305 efiles = set()
305 efiles = set()
306 def onchangelog(cl, node):
306 def onchangelog(cl, node):
307 efiles.update(cl.readfiles(node))
307 efiles.update(cl.readfiles(node))
308
308
309 self.changelogheader()
309 self.changelogheader()
310 deltas = self.deltaiter()
310 deltas = self.deltaiter()
311 cgnodes = cl.addgroup(deltas, csmap, trp, addrevisioncb=onchangelog)
311 cgnodes = cl.addgroup(deltas, csmap, trp, addrevisioncb=onchangelog)
312 efiles = len(efiles)
312 efiles = len(efiles)
313
313
314 if not cgnodes:
314 if not cgnodes:
315 repo.ui.develwarn('applied empty changegroup',
315 repo.ui.develwarn('applied empty changegroup',
316 config='empty-changegroup')
316 config='warn-empty-changegroup')
317 clend = len(cl)
317 clend = len(cl)
318 changesets = clend - clstart
318 changesets = clend - clstart
319 repo.ui.progress(_('changesets'), None)
319 repo.ui.progress(_('changesets'), None)
320 self.callback = None
320 self.callback = None
321
321
322 # pull off the manifest group
322 # pull off the manifest group
323 repo.ui.status(_("adding manifests\n"))
323 repo.ui.status(_("adding manifests\n"))
324 self._unpackmanifests(repo, revmap, trp, prog, changesets)
324 self._unpackmanifests(repo, revmap, trp, prog, changesets)
325
325
326 needfiles = {}
326 needfiles = {}
327 if repo.ui.configbool('server', 'validate'):
327 if repo.ui.configbool('server', 'validate'):
328 cl = repo.changelog
328 cl = repo.changelog
329 ml = repo.manifestlog
329 ml = repo.manifestlog
330 # validate incoming csets have their manifests
330 # validate incoming csets have their manifests
331 for cset in xrange(clstart, clend):
331 for cset in xrange(clstart, clend):
332 mfnode = cl.changelogrevision(cset).manifest
332 mfnode = cl.changelogrevision(cset).manifest
333 mfest = ml[mfnode].readdelta()
333 mfest = ml[mfnode].readdelta()
334 # store file cgnodes we must see
334 # store file cgnodes we must see
335 for f, n in mfest.iteritems():
335 for f, n in mfest.iteritems():
336 needfiles.setdefault(f, set()).add(n)
336 needfiles.setdefault(f, set()).add(n)
337
337
338 # process the files
338 # process the files
339 repo.ui.status(_("adding file changes\n"))
339 repo.ui.status(_("adding file changes\n"))
340 newrevs, newfiles = _addchangegroupfiles(
340 newrevs, newfiles = _addchangegroupfiles(
341 repo, self, revmap, trp, efiles, needfiles)
341 repo, self, revmap, trp, efiles, needfiles)
342 revisions += newrevs
342 revisions += newrevs
343 files += newfiles
343 files += newfiles
344
344
345 deltaheads = 0
345 deltaheads = 0
346 if oldheads:
346 if oldheads:
347 heads = cl.heads()
347 heads = cl.heads()
348 deltaheads = len(heads) - len(oldheads)
348 deltaheads = len(heads) - len(oldheads)
349 for h in heads:
349 for h in heads:
350 if h not in oldheads and repo[h].closesbranch():
350 if h not in oldheads and repo[h].closesbranch():
351 deltaheads -= 1
351 deltaheads -= 1
352 htext = ""
352 htext = ""
353 if deltaheads:
353 if deltaheads:
354 htext = _(" (%+d heads)") % deltaheads
354 htext = _(" (%+d heads)") % deltaheads
355
355
356 repo.ui.status(_("added %d changesets"
356 repo.ui.status(_("added %d changesets"
357 " with %d changes to %d files%s\n")
357 " with %d changes to %d files%s\n")
358 % (changesets, revisions, files, htext))
358 % (changesets, revisions, files, htext))
359 repo.invalidatevolatilesets()
359 repo.invalidatevolatilesets()
360
360
361 if changesets > 0:
361 if changesets > 0:
362 if 'node' not in tr.hookargs:
362 if 'node' not in tr.hookargs:
363 tr.hookargs['node'] = hex(cl.node(clstart))
363 tr.hookargs['node'] = hex(cl.node(clstart))
364 tr.hookargs['node_last'] = hex(cl.node(clend - 1))
364 tr.hookargs['node_last'] = hex(cl.node(clend - 1))
365 hookargs = dict(tr.hookargs)
365 hookargs = dict(tr.hookargs)
366 else:
366 else:
367 hookargs = dict(tr.hookargs)
367 hookargs = dict(tr.hookargs)
368 hookargs['node'] = hex(cl.node(clstart))
368 hookargs['node'] = hex(cl.node(clstart))
369 hookargs['node_last'] = hex(cl.node(clend - 1))
369 hookargs['node_last'] = hex(cl.node(clend - 1))
370 repo.hook('pretxnchangegroup',
370 repo.hook('pretxnchangegroup',
371 throw=True, **pycompat.strkwargs(hookargs))
371 throw=True, **pycompat.strkwargs(hookargs))
372
372
373 added = [cl.node(r) for r in xrange(clstart, clend)]
373 added = [cl.node(r) for r in xrange(clstart, clend)]
374 phaseall = None
374 phaseall = None
375 if srctype in ('push', 'serve'):
375 if srctype in ('push', 'serve'):
376 # Old servers can not push the boundary themselves.
376 # Old servers can not push the boundary themselves.
377 # New servers won't push the boundary if changeset already
377 # New servers won't push the boundary if changeset already
378 # exists locally as secret
378 # exists locally as secret
379 #
379 #
380 # We should not use added here but the list of all change in
380 # We should not use added here but the list of all change in
381 # the bundle
381 # the bundle
382 if repo.publishing():
382 if repo.publishing():
383 targetphase = phaseall = phases.public
383 targetphase = phaseall = phases.public
384 else:
384 else:
385 # closer target phase computation
385 # closer target phase computation
386
386
387 # Those changesets have been pushed from the
387 # Those changesets have been pushed from the
388 # outside, their phases are going to be pushed
388 # outside, their phases are going to be pushed
389 # alongside. Therefor `targetphase` is
389 # alongside. Therefor `targetphase` is
390 # ignored.
390 # ignored.
391 targetphase = phaseall = phases.draft
391 targetphase = phaseall = phases.draft
392 if added:
392 if added:
393 phases.registernew(repo, tr, targetphase, added)
393 phases.registernew(repo, tr, targetphase, added)
394 if phaseall is not None:
394 if phaseall is not None:
395 phases.advanceboundary(repo, tr, phaseall, cgnodes)
395 phases.advanceboundary(repo, tr, phaseall, cgnodes)
396
396
397 if changesets > 0:
397 if changesets > 0:
398
398
399 def runhooks():
399 def runhooks():
400 # These hooks run when the lock releases, not when the
400 # These hooks run when the lock releases, not when the
401 # transaction closes. So it's possible for the changelog
401 # transaction closes. So it's possible for the changelog
402 # to have changed since we last saw it.
402 # to have changed since we last saw it.
403 if clstart >= len(repo):
403 if clstart >= len(repo):
404 return
404 return
405
405
406 repo.hook("changegroup", **pycompat.strkwargs(hookargs))
406 repo.hook("changegroup", **pycompat.strkwargs(hookargs))
407
407
408 for n in added:
408 for n in added:
409 args = hookargs.copy()
409 args = hookargs.copy()
410 args['node'] = hex(n)
410 args['node'] = hex(n)
411 del args['node_last']
411 del args['node_last']
412 repo.hook("incoming", **pycompat.strkwargs(args))
412 repo.hook("incoming", **pycompat.strkwargs(args))
413
413
414 newheads = [h for h in repo.heads()
414 newheads = [h for h in repo.heads()
415 if h not in oldheads]
415 if h not in oldheads]
416 repo.ui.log("incoming",
416 repo.ui.log("incoming",
417 "%s incoming changes - new heads: %s\n",
417 "%s incoming changes - new heads: %s\n",
418 len(added),
418 len(added),
419 ', '.join([hex(c[:6]) for c in newheads]))
419 ', '.join([hex(c[:6]) for c in newheads]))
420
420
421 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
421 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
422 lambda tr: repo._afterlock(runhooks))
422 lambda tr: repo._afterlock(runhooks))
423 finally:
423 finally:
424 repo.ui.flush()
424 repo.ui.flush()
425 # never return 0 here:
425 # never return 0 here:
426 if deltaheads < 0:
426 if deltaheads < 0:
427 ret = deltaheads - 1
427 ret = deltaheads - 1
428 else:
428 else:
429 ret = deltaheads + 1
429 ret = deltaheads + 1
430 return ret
430 return ret
431
431
432 def deltaiter(self):
432 def deltaiter(self):
433 """
433 """
434 returns an iterator of the deltas in this changegroup
434 returns an iterator of the deltas in this changegroup
435
435
436 Useful for passing to the underlying storage system to be stored.
436 Useful for passing to the underlying storage system to be stored.
437 """
437 """
438 chain = None
438 chain = None
439 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
439 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
440 # Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
440 # Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
441 yield chunkdata
441 yield chunkdata
442 chain = chunkdata[0]
442 chain = chunkdata[0]
443
443
444 class cg2unpacker(cg1unpacker):
444 class cg2unpacker(cg1unpacker):
445 """Unpacker for cg2 streams.
445 """Unpacker for cg2 streams.
446
446
447 cg2 streams add support for generaldelta, so the delta header
447 cg2 streams add support for generaldelta, so the delta header
448 format is slightly different. All other features about the data
448 format is slightly different. All other features about the data
449 remain the same.
449 remain the same.
450 """
450 """
451 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
451 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
452 deltaheadersize = struct.calcsize(deltaheader)
452 deltaheadersize = struct.calcsize(deltaheader)
453 version = '02'
453 version = '02'
454
454
455 def _deltaheader(self, headertuple, prevnode):
455 def _deltaheader(self, headertuple, prevnode):
456 node, p1, p2, deltabase, cs = headertuple
456 node, p1, p2, deltabase, cs = headertuple
457 flags = 0
457 flags = 0
458 return node, p1, p2, deltabase, cs, flags
458 return node, p1, p2, deltabase, cs, flags
459
459
460 class cg3unpacker(cg2unpacker):
460 class cg3unpacker(cg2unpacker):
461 """Unpacker for cg3 streams.
461 """Unpacker for cg3 streams.
462
462
463 cg3 streams add support for exchanging treemanifests and revlog
463 cg3 streams add support for exchanging treemanifests and revlog
464 flags. It adds the revlog flags to the delta header and an empty chunk
464 flags. It adds the revlog flags to the delta header and an empty chunk
465 separating manifests and files.
465 separating manifests and files.
466 """
466 """
467 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
467 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
468 deltaheadersize = struct.calcsize(deltaheader)
468 deltaheadersize = struct.calcsize(deltaheader)
469 version = '03'
469 version = '03'
470 _grouplistcount = 2 # One list of manifests and one list of files
470 _grouplistcount = 2 # One list of manifests and one list of files
471
471
472 def _deltaheader(self, headertuple, prevnode):
472 def _deltaheader(self, headertuple, prevnode):
473 node, p1, p2, deltabase, cs, flags = headertuple
473 node, p1, p2, deltabase, cs, flags = headertuple
474 return node, p1, p2, deltabase, cs, flags
474 return node, p1, p2, deltabase, cs, flags
475
475
476 def _unpackmanifests(self, repo, revmap, trp, prog, numchanges):
476 def _unpackmanifests(self, repo, revmap, trp, prog, numchanges):
477 super(cg3unpacker, self)._unpackmanifests(repo, revmap, trp, prog,
477 super(cg3unpacker, self)._unpackmanifests(repo, revmap, trp, prog,
478 numchanges)
478 numchanges)
479 for chunkdata in iter(self.filelogheader, {}):
479 for chunkdata in iter(self.filelogheader, {}):
480 # If we get here, there are directory manifests in the changegroup
480 # If we get here, there are directory manifests in the changegroup
481 d = chunkdata["filename"]
481 d = chunkdata["filename"]
482 repo.ui.debug("adding %s revisions\n" % d)
482 repo.ui.debug("adding %s revisions\n" % d)
483 dirlog = repo.manifestlog._revlog.dirlog(d)
483 dirlog = repo.manifestlog._revlog.dirlog(d)
484 deltas = self.deltaiter()
484 deltas = self.deltaiter()
485 if not dirlog.addgroup(deltas, revmap, trp):
485 if not dirlog.addgroup(deltas, revmap, trp):
486 raise error.Abort(_("received dir revlog group is empty"))
486 raise error.Abort(_("received dir revlog group is empty"))
487
487
488 class headerlessfixup(object):
488 class headerlessfixup(object):
489 def __init__(self, fh, h):
489 def __init__(self, fh, h):
490 self._h = h
490 self._h = h
491 self._fh = fh
491 self._fh = fh
492 def read(self, n):
492 def read(self, n):
493 if self._h:
493 if self._h:
494 d, self._h = self._h[:n], self._h[n:]
494 d, self._h = self._h[:n], self._h[n:]
495 if len(d) < n:
495 if len(d) < n:
496 d += readexactly(self._fh, n - len(d))
496 d += readexactly(self._fh, n - len(d))
497 return d
497 return d
498 return readexactly(self._fh, n)
498 return readexactly(self._fh, n)
499
499
500 class cg1packer(object):
500 class cg1packer(object):
501 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
501 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
502 version = '01'
502 version = '01'
503 def __init__(self, repo, bundlecaps=None):
503 def __init__(self, repo, bundlecaps=None):
504 """Given a source repo, construct a bundler.
504 """Given a source repo, construct a bundler.
505
505
506 bundlecaps is optional and can be used to specify the set of
506 bundlecaps is optional and can be used to specify the set of
507 capabilities which can be used to build the bundle. While bundlecaps is
507 capabilities which can be used to build the bundle. While bundlecaps is
508 unused in core Mercurial, extensions rely on this feature to communicate
508 unused in core Mercurial, extensions rely on this feature to communicate
509 capabilities to customize the changegroup packer.
509 capabilities to customize the changegroup packer.
510 """
510 """
511 # Set of capabilities we can use to build the bundle.
511 # Set of capabilities we can use to build the bundle.
512 if bundlecaps is None:
512 if bundlecaps is None:
513 bundlecaps = set()
513 bundlecaps = set()
514 self._bundlecaps = bundlecaps
514 self._bundlecaps = bundlecaps
515 # experimental config: bundle.reorder
515 # experimental config: bundle.reorder
516 reorder = repo.ui.config('bundle', 'reorder')
516 reorder = repo.ui.config('bundle', 'reorder')
517 if reorder == 'auto':
517 if reorder == 'auto':
518 reorder = None
518 reorder = None
519 else:
519 else:
520 reorder = util.parsebool(reorder)
520 reorder = util.parsebool(reorder)
521 self._repo = repo
521 self._repo = repo
522 self._reorder = reorder
522 self._reorder = reorder
523 self._progress = repo.ui.progress
523 self._progress = repo.ui.progress
524 if self._repo.ui.verbose and not self._repo.ui.debugflag:
524 if self._repo.ui.verbose and not self._repo.ui.debugflag:
525 self._verbosenote = self._repo.ui.note
525 self._verbosenote = self._repo.ui.note
526 else:
526 else:
527 self._verbosenote = lambda s: None
527 self._verbosenote = lambda s: None
528
528
529 def close(self):
529 def close(self):
530 return closechunk()
530 return closechunk()
531
531
532 def fileheader(self, fname):
532 def fileheader(self, fname):
533 return chunkheader(len(fname)) + fname
533 return chunkheader(len(fname)) + fname
534
534
535 # Extracted both for clarity and for overriding in extensions.
535 # Extracted both for clarity and for overriding in extensions.
536 def _sortgroup(self, revlog, nodelist, lookup):
536 def _sortgroup(self, revlog, nodelist, lookup):
537 """Sort nodes for change group and turn them into revnums."""
537 """Sort nodes for change group and turn them into revnums."""
538 # for generaldelta revlogs, we linearize the revs; this will both be
538 # for generaldelta revlogs, we linearize the revs; this will both be
539 # much quicker and generate a much smaller bundle
539 # much quicker and generate a much smaller bundle
540 if (revlog._generaldelta and self._reorder is None) or self._reorder:
540 if (revlog._generaldelta and self._reorder is None) or self._reorder:
541 dag = dagutil.revlogdag(revlog)
541 dag = dagutil.revlogdag(revlog)
542 return dag.linearize(set(revlog.rev(n) for n in nodelist))
542 return dag.linearize(set(revlog.rev(n) for n in nodelist))
543 else:
543 else:
544 return sorted([revlog.rev(n) for n in nodelist])
544 return sorted([revlog.rev(n) for n in nodelist])
545
545
546 def group(self, nodelist, revlog, lookup, units=None):
546 def group(self, nodelist, revlog, lookup, units=None):
547 """Calculate a delta group, yielding a sequence of changegroup chunks
547 """Calculate a delta group, yielding a sequence of changegroup chunks
548 (strings).
548 (strings).
549
549
550 Given a list of changeset revs, return a set of deltas and
550 Given a list of changeset revs, return a set of deltas and
551 metadata corresponding to nodes. The first delta is
551 metadata corresponding to nodes. The first delta is
552 first parent(nodelist[0]) -> nodelist[0], the receiver is
552 first parent(nodelist[0]) -> nodelist[0], the receiver is
553 guaranteed to have this parent as it has all history before
553 guaranteed to have this parent as it has all history before
554 these changesets. In the case firstparent is nullrev the
554 these changesets. In the case firstparent is nullrev the
555 changegroup starts with a full revision.
555 changegroup starts with a full revision.
556
556
557 If units is not None, progress detail will be generated, units specifies
557 If units is not None, progress detail will be generated, units specifies
558 the type of revlog that is touched (changelog, manifest, etc.).
558 the type of revlog that is touched (changelog, manifest, etc.).
559 """
559 """
560 # if we don't have any revisions touched by these changesets, bail
560 # if we don't have any revisions touched by these changesets, bail
561 if len(nodelist) == 0:
561 if len(nodelist) == 0:
562 yield self.close()
562 yield self.close()
563 return
563 return
564
564
565 revs = self._sortgroup(revlog, nodelist, lookup)
565 revs = self._sortgroup(revlog, nodelist, lookup)
566
566
567 # add the parent of the first rev
567 # add the parent of the first rev
568 p = revlog.parentrevs(revs[0])[0]
568 p = revlog.parentrevs(revs[0])[0]
569 revs.insert(0, p)
569 revs.insert(0, p)
570
570
571 # build deltas
571 # build deltas
572 total = len(revs) - 1
572 total = len(revs) - 1
573 msgbundling = _('bundling')
573 msgbundling = _('bundling')
574 for r in xrange(len(revs) - 1):
574 for r in xrange(len(revs) - 1):
575 if units is not None:
575 if units is not None:
576 self._progress(msgbundling, r + 1, unit=units, total=total)
576 self._progress(msgbundling, r + 1, unit=units, total=total)
577 prev, curr = revs[r], revs[r + 1]
577 prev, curr = revs[r], revs[r + 1]
578 linknode = lookup(revlog.node(curr))
578 linknode = lookup(revlog.node(curr))
579 for c in self.revchunk(revlog, curr, prev, linknode):
579 for c in self.revchunk(revlog, curr, prev, linknode):
580 yield c
580 yield c
581
581
582 if units is not None:
582 if units is not None:
583 self._progress(msgbundling, None)
583 self._progress(msgbundling, None)
584 yield self.close()
584 yield self.close()
585
585
586 # filter any nodes that claim to be part of the known set
586 # filter any nodes that claim to be part of the known set
587 def prune(self, revlog, missing, commonrevs):
587 def prune(self, revlog, missing, commonrevs):
588 rr, rl = revlog.rev, revlog.linkrev
588 rr, rl = revlog.rev, revlog.linkrev
589 return [n for n in missing if rl(rr(n)) not in commonrevs]
589 return [n for n in missing if rl(rr(n)) not in commonrevs]
590
590
591 def _packmanifests(self, dir, mfnodes, lookuplinknode):
591 def _packmanifests(self, dir, mfnodes, lookuplinknode):
592 """Pack flat manifests into a changegroup stream."""
592 """Pack flat manifests into a changegroup stream."""
593 assert not dir
593 assert not dir
594 for chunk in self.group(mfnodes, self._repo.manifestlog._revlog,
594 for chunk in self.group(mfnodes, self._repo.manifestlog._revlog,
595 lookuplinknode, units=_('manifests')):
595 lookuplinknode, units=_('manifests')):
596 yield chunk
596 yield chunk
597
597
598 def _manifestsdone(self):
598 def _manifestsdone(self):
599 return ''
599 return ''
600
600
601 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
601 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
602 '''yield a sequence of changegroup chunks (strings)'''
602 '''yield a sequence of changegroup chunks (strings)'''
603 repo = self._repo
603 repo = self._repo
604 cl = repo.changelog
604 cl = repo.changelog
605
605
606 clrevorder = {}
606 clrevorder = {}
607 mfs = {} # needed manifests
607 mfs = {} # needed manifests
608 fnodes = {} # needed file nodes
608 fnodes = {} # needed file nodes
609 changedfiles = set()
609 changedfiles = set()
610
610
611 # Callback for the changelog, used to collect changed files and manifest
611 # Callback for the changelog, used to collect changed files and manifest
612 # nodes.
612 # nodes.
613 # Returns the linkrev node (identity in the changelog case).
613 # Returns the linkrev node (identity in the changelog case).
614 def lookupcl(x):
614 def lookupcl(x):
615 c = cl.read(x)
615 c = cl.read(x)
616 clrevorder[x] = len(clrevorder)
616 clrevorder[x] = len(clrevorder)
617 n = c[0]
617 n = c[0]
618 # record the first changeset introducing this manifest version
618 # record the first changeset introducing this manifest version
619 mfs.setdefault(n, x)
619 mfs.setdefault(n, x)
620 # Record a complete list of potentially-changed files in
620 # Record a complete list of potentially-changed files in
621 # this manifest.
621 # this manifest.
622 changedfiles.update(c[3])
622 changedfiles.update(c[3])
623 return x
623 return x
624
624
625 self._verbosenote(_('uncompressed size of bundle content:\n'))
625 self._verbosenote(_('uncompressed size of bundle content:\n'))
626 size = 0
626 size = 0
627 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
627 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
628 size += len(chunk)
628 size += len(chunk)
629 yield chunk
629 yield chunk
630 self._verbosenote(_('%8.i (changelog)\n') % size)
630 self._verbosenote(_('%8.i (changelog)\n') % size)
631
631
632 # We need to make sure that the linkrev in the changegroup refers to
632 # We need to make sure that the linkrev in the changegroup refers to
633 # the first changeset that introduced the manifest or file revision.
633 # the first changeset that introduced the manifest or file revision.
634 # The fastpath is usually safer than the slowpath, because the filelogs
634 # The fastpath is usually safer than the slowpath, because the filelogs
635 # are walked in revlog order.
635 # are walked in revlog order.
636 #
636 #
637 # When taking the slowpath with reorder=None and the manifest revlog
637 # When taking the slowpath with reorder=None and the manifest revlog
638 # uses generaldelta, the manifest may be walked in the "wrong" order.
638 # uses generaldelta, the manifest may be walked in the "wrong" order.
639 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
639 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
640 # cc0ff93d0c0c).
640 # cc0ff93d0c0c).
641 #
641 #
642 # When taking the fastpath, we are only vulnerable to reordering
642 # When taking the fastpath, we are only vulnerable to reordering
643 # of the changelog itself. The changelog never uses generaldelta, so
643 # of the changelog itself. The changelog never uses generaldelta, so
644 # it is only reordered when reorder=True. To handle this case, we
644 # it is only reordered when reorder=True. To handle this case, we
645 # simply take the slowpath, which already has the 'clrevorder' logic.
645 # simply take the slowpath, which already has the 'clrevorder' logic.
646 # This was also fixed in cc0ff93d0c0c.
646 # This was also fixed in cc0ff93d0c0c.
647 fastpathlinkrev = fastpathlinkrev and not self._reorder
647 fastpathlinkrev = fastpathlinkrev and not self._reorder
648 # Treemanifests don't work correctly with fastpathlinkrev
648 # Treemanifests don't work correctly with fastpathlinkrev
649 # either, because we don't discover which directory nodes to
649 # either, because we don't discover which directory nodes to
650 # send along with files. This could probably be fixed.
650 # send along with files. This could probably be fixed.
651 fastpathlinkrev = fastpathlinkrev and (
651 fastpathlinkrev = fastpathlinkrev and (
652 'treemanifest' not in repo.requirements)
652 'treemanifest' not in repo.requirements)
653
653
654 for chunk in self.generatemanifests(commonrevs, clrevorder,
654 for chunk in self.generatemanifests(commonrevs, clrevorder,
655 fastpathlinkrev, mfs, fnodes, source):
655 fastpathlinkrev, mfs, fnodes, source):
656 yield chunk
656 yield chunk
657 mfs.clear()
657 mfs.clear()
658 clrevs = set(cl.rev(x) for x in clnodes)
658 clrevs = set(cl.rev(x) for x in clnodes)
659
659
660 if not fastpathlinkrev:
660 if not fastpathlinkrev:
661 def linknodes(unused, fname):
661 def linknodes(unused, fname):
662 return fnodes.get(fname, {})
662 return fnodes.get(fname, {})
663 else:
663 else:
664 cln = cl.node
664 cln = cl.node
665 def linknodes(filerevlog, fname):
665 def linknodes(filerevlog, fname):
666 llr = filerevlog.linkrev
666 llr = filerevlog.linkrev
667 fln = filerevlog.node
667 fln = filerevlog.node
668 revs = ((r, llr(r)) for r in filerevlog)
668 revs = ((r, llr(r)) for r in filerevlog)
669 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
669 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
670
670
671 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
671 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
672 source):
672 source):
673 yield chunk
673 yield chunk
674
674
675 yield self.close()
675 yield self.close()
676
676
677 if clnodes:
677 if clnodes:
678 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
678 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
679
679
680 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
680 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
681 fnodes, source):
681 fnodes, source):
682 """Returns an iterator of changegroup chunks containing manifests.
682 """Returns an iterator of changegroup chunks containing manifests.
683
683
684 `source` is unused here, but is used by extensions like remotefilelog to
684 `source` is unused here, but is used by extensions like remotefilelog to
685 change what is sent based in pulls vs pushes, etc.
685 change what is sent based in pulls vs pushes, etc.
686 """
686 """
687 repo = self._repo
687 repo = self._repo
688 mfl = repo.manifestlog
688 mfl = repo.manifestlog
689 dirlog = mfl._revlog.dirlog
689 dirlog = mfl._revlog.dirlog
690 tmfnodes = {'': mfs}
690 tmfnodes = {'': mfs}
691
691
692 # Callback for the manifest, used to collect linkrevs for filelog
692 # Callback for the manifest, used to collect linkrevs for filelog
693 # revisions.
693 # revisions.
694 # Returns the linkrev node (collected in lookupcl).
694 # Returns the linkrev node (collected in lookupcl).
695 def makelookupmflinknode(dir):
695 def makelookupmflinknode(dir):
696 if fastpathlinkrev:
696 if fastpathlinkrev:
697 assert not dir
697 assert not dir
698 return mfs.__getitem__
698 return mfs.__getitem__
699
699
700 def lookupmflinknode(x):
700 def lookupmflinknode(x):
701 """Callback for looking up the linknode for manifests.
701 """Callback for looking up the linknode for manifests.
702
702
703 Returns the linkrev node for the specified manifest.
703 Returns the linkrev node for the specified manifest.
704
704
705 SIDE EFFECT:
705 SIDE EFFECT:
706
706
707 1) fclnodes gets populated with the list of relevant
707 1) fclnodes gets populated with the list of relevant
708 file nodes if we're not using fastpathlinkrev
708 file nodes if we're not using fastpathlinkrev
709 2) When treemanifests are in use, collects treemanifest nodes
709 2) When treemanifests are in use, collects treemanifest nodes
710 to send
710 to send
711
711
712 Note that this means manifests must be completely sent to
712 Note that this means manifests must be completely sent to
713 the client before you can trust the list of files and
713 the client before you can trust the list of files and
714 treemanifests to send.
714 treemanifests to send.
715 """
715 """
716 clnode = tmfnodes[dir][x]
716 clnode = tmfnodes[dir][x]
717 mdata = mfl.get(dir, x).readfast(shallow=True)
717 mdata = mfl.get(dir, x).readfast(shallow=True)
718 for p, n, fl in mdata.iterentries():
718 for p, n, fl in mdata.iterentries():
719 if fl == 't': # subdirectory manifest
719 if fl == 't': # subdirectory manifest
720 subdir = dir + p + '/'
720 subdir = dir + p + '/'
721 tmfclnodes = tmfnodes.setdefault(subdir, {})
721 tmfclnodes = tmfnodes.setdefault(subdir, {})
722 tmfclnode = tmfclnodes.setdefault(n, clnode)
722 tmfclnode = tmfclnodes.setdefault(n, clnode)
723 if clrevorder[clnode] < clrevorder[tmfclnode]:
723 if clrevorder[clnode] < clrevorder[tmfclnode]:
724 tmfclnodes[n] = clnode
724 tmfclnodes[n] = clnode
725 else:
725 else:
726 f = dir + p
726 f = dir + p
727 fclnodes = fnodes.setdefault(f, {})
727 fclnodes = fnodes.setdefault(f, {})
728 fclnode = fclnodes.setdefault(n, clnode)
728 fclnode = fclnodes.setdefault(n, clnode)
729 if clrevorder[clnode] < clrevorder[fclnode]:
729 if clrevorder[clnode] < clrevorder[fclnode]:
730 fclnodes[n] = clnode
730 fclnodes[n] = clnode
731 return clnode
731 return clnode
732 return lookupmflinknode
732 return lookupmflinknode
733
733
734 size = 0
734 size = 0
735 while tmfnodes:
735 while tmfnodes:
736 dir = min(tmfnodes)
736 dir = min(tmfnodes)
737 nodes = tmfnodes[dir]
737 nodes = tmfnodes[dir]
738 prunednodes = self.prune(dirlog(dir), nodes, commonrevs)
738 prunednodes = self.prune(dirlog(dir), nodes, commonrevs)
739 if not dir or prunednodes:
739 if not dir or prunednodes:
740 for x in self._packmanifests(dir, prunednodes,
740 for x in self._packmanifests(dir, prunednodes,
741 makelookupmflinknode(dir)):
741 makelookupmflinknode(dir)):
742 size += len(x)
742 size += len(x)
743 yield x
743 yield x
744 del tmfnodes[dir]
744 del tmfnodes[dir]
745 self._verbosenote(_('%8.i (manifests)\n') % size)
745 self._verbosenote(_('%8.i (manifests)\n') % size)
746 yield self._manifestsdone()
746 yield self._manifestsdone()
747
747
748 # The 'source' parameter is useful for extensions
748 # The 'source' parameter is useful for extensions
749 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
749 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
750 repo = self._repo
750 repo = self._repo
751 progress = self._progress
751 progress = self._progress
752 msgbundling = _('bundling')
752 msgbundling = _('bundling')
753
753
754 total = len(changedfiles)
754 total = len(changedfiles)
755 # for progress output
755 # for progress output
756 msgfiles = _('files')
756 msgfiles = _('files')
757 for i, fname in enumerate(sorted(changedfiles)):
757 for i, fname in enumerate(sorted(changedfiles)):
758 filerevlog = repo.file(fname)
758 filerevlog = repo.file(fname)
759 if not filerevlog:
759 if not filerevlog:
760 raise error.Abort(_("empty or missing revlog for %s") % fname)
760 raise error.Abort(_("empty or missing revlog for %s") % fname)
761
761
762 linkrevnodes = linknodes(filerevlog, fname)
762 linkrevnodes = linknodes(filerevlog, fname)
763 # Lookup for filenodes, we collected the linkrev nodes above in the
763 # Lookup for filenodes, we collected the linkrev nodes above in the
764 # fastpath case and with lookupmf in the slowpath case.
764 # fastpath case and with lookupmf in the slowpath case.
765 def lookupfilelog(x):
765 def lookupfilelog(x):
766 return linkrevnodes[x]
766 return linkrevnodes[x]
767
767
768 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs)
768 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs)
769 if filenodes:
769 if filenodes:
770 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
770 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
771 total=total)
771 total=total)
772 h = self.fileheader(fname)
772 h = self.fileheader(fname)
773 size = len(h)
773 size = len(h)
774 yield h
774 yield h
775 for chunk in self.group(filenodes, filerevlog, lookupfilelog):
775 for chunk in self.group(filenodes, filerevlog, lookupfilelog):
776 size += len(chunk)
776 size += len(chunk)
777 yield chunk
777 yield chunk
778 self._verbosenote(_('%8.i %s\n') % (size, fname))
778 self._verbosenote(_('%8.i %s\n') % (size, fname))
779 progress(msgbundling, None)
779 progress(msgbundling, None)
780
780
781 def deltaparent(self, revlog, rev, p1, p2, prev):
781 def deltaparent(self, revlog, rev, p1, p2, prev):
782 return prev
782 return prev
783
783
784 def revchunk(self, revlog, rev, prev, linknode):
784 def revchunk(self, revlog, rev, prev, linknode):
785 node = revlog.node(rev)
785 node = revlog.node(rev)
786 p1, p2 = revlog.parentrevs(rev)
786 p1, p2 = revlog.parentrevs(rev)
787 base = self.deltaparent(revlog, rev, p1, p2, prev)
787 base = self.deltaparent(revlog, rev, p1, p2, prev)
788
788
789 prefix = ''
789 prefix = ''
790 if revlog.iscensored(base) or revlog.iscensored(rev):
790 if revlog.iscensored(base) or revlog.iscensored(rev):
791 try:
791 try:
792 delta = revlog.revision(node, raw=True)
792 delta = revlog.revision(node, raw=True)
793 except error.CensoredNodeError as e:
793 except error.CensoredNodeError as e:
794 delta = e.tombstone
794 delta = e.tombstone
795 if base == nullrev:
795 if base == nullrev:
796 prefix = mdiff.trivialdiffheader(len(delta))
796 prefix = mdiff.trivialdiffheader(len(delta))
797 else:
797 else:
798 baselen = revlog.rawsize(base)
798 baselen = revlog.rawsize(base)
799 prefix = mdiff.replacediffheader(baselen, len(delta))
799 prefix = mdiff.replacediffheader(baselen, len(delta))
800 elif base == nullrev:
800 elif base == nullrev:
801 delta = revlog.revision(node, raw=True)
801 delta = revlog.revision(node, raw=True)
802 prefix = mdiff.trivialdiffheader(len(delta))
802 prefix = mdiff.trivialdiffheader(len(delta))
803 else:
803 else:
804 delta = revlog.revdiff(base, rev)
804 delta = revlog.revdiff(base, rev)
805 p1n, p2n = revlog.parents(node)
805 p1n, p2n = revlog.parents(node)
806 basenode = revlog.node(base)
806 basenode = revlog.node(base)
807 flags = revlog.flags(rev)
807 flags = revlog.flags(rev)
808 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode, flags)
808 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode, flags)
809 meta += prefix
809 meta += prefix
810 l = len(meta) + len(delta)
810 l = len(meta) + len(delta)
811 yield chunkheader(l)
811 yield chunkheader(l)
812 yield meta
812 yield meta
813 yield delta
813 yield delta
814 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
814 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
815 # do nothing with basenode, it is implicitly the previous one in HG10
815 # do nothing with basenode, it is implicitly the previous one in HG10
816 # do nothing with flags, it is implicitly 0 for cg1 and cg2
816 # do nothing with flags, it is implicitly 0 for cg1 and cg2
817 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
817 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
818
818
819 class cg2packer(cg1packer):
819 class cg2packer(cg1packer):
820 version = '02'
820 version = '02'
821 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
821 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
822
822
823 def __init__(self, repo, bundlecaps=None):
823 def __init__(self, repo, bundlecaps=None):
824 super(cg2packer, self).__init__(repo, bundlecaps)
824 super(cg2packer, self).__init__(repo, bundlecaps)
825 if self._reorder is None:
825 if self._reorder is None:
826 # Since generaldelta is directly supported by cg2, reordering
826 # Since generaldelta is directly supported by cg2, reordering
827 # generally doesn't help, so we disable it by default (treating
827 # generally doesn't help, so we disable it by default (treating
828 # bundle.reorder=auto just like bundle.reorder=False).
828 # bundle.reorder=auto just like bundle.reorder=False).
829 self._reorder = False
829 self._reorder = False
830
830
831 def deltaparent(self, revlog, rev, p1, p2, prev):
831 def deltaparent(self, revlog, rev, p1, p2, prev):
832 dp = revlog.deltaparent(rev)
832 dp = revlog.deltaparent(rev)
833 if dp == nullrev and revlog.storedeltachains:
833 if dp == nullrev and revlog.storedeltachains:
834 # Avoid sending full revisions when delta parent is null. Pick prev
834 # Avoid sending full revisions when delta parent is null. Pick prev
835 # in that case. It's tempting to pick p1 in this case, as p1 will
835 # in that case. It's tempting to pick p1 in this case, as p1 will
836 # be smaller in the common case. However, computing a delta against
836 # be smaller in the common case. However, computing a delta against
837 # p1 may require resolving the raw text of p1, which could be
837 # p1 may require resolving the raw text of p1, which could be
838 # expensive. The revlog caches should have prev cached, meaning
838 # expensive. The revlog caches should have prev cached, meaning
839 # less CPU for changegroup generation. There is likely room to add
839 # less CPU for changegroup generation. There is likely room to add
840 # a flag and/or config option to control this behavior.
840 # a flag and/or config option to control this behavior.
841 return prev
841 return prev
842 elif dp == nullrev:
842 elif dp == nullrev:
843 # revlog is configured to use full snapshot for a reason,
843 # revlog is configured to use full snapshot for a reason,
844 # stick to full snapshot.
844 # stick to full snapshot.
845 return nullrev
845 return nullrev
846 elif dp not in (p1, p2, prev):
846 elif dp not in (p1, p2, prev):
847 # Pick prev when we can't be sure remote has the base revision.
847 # Pick prev when we can't be sure remote has the base revision.
848 return prev
848 return prev
849 else:
849 else:
850 return dp
850 return dp
851
851
852 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
852 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
853 # Do nothing with flags, it is implicitly 0 in cg1 and cg2
853 # Do nothing with flags, it is implicitly 0 in cg1 and cg2
854 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
854 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
855
855
856 class cg3packer(cg2packer):
856 class cg3packer(cg2packer):
857 version = '03'
857 version = '03'
858 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
858 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
859
859
860 def _packmanifests(self, dir, mfnodes, lookuplinknode):
860 def _packmanifests(self, dir, mfnodes, lookuplinknode):
861 if dir:
861 if dir:
862 yield self.fileheader(dir)
862 yield self.fileheader(dir)
863
863
864 dirlog = self._repo.manifestlog._revlog.dirlog(dir)
864 dirlog = self._repo.manifestlog._revlog.dirlog(dir)
865 for chunk in self.group(mfnodes, dirlog, lookuplinknode,
865 for chunk in self.group(mfnodes, dirlog, lookuplinknode,
866 units=_('manifests')):
866 units=_('manifests')):
867 yield chunk
867 yield chunk
868
868
869 def _manifestsdone(self):
869 def _manifestsdone(self):
870 return self.close()
870 return self.close()
871
871
872 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
872 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
873 return struct.pack(
873 return struct.pack(
874 self.deltaheader, node, p1n, p2n, basenode, linknode, flags)
874 self.deltaheader, node, p1n, p2n, basenode, linknode, flags)
875
875
876 _packermap = {'01': (cg1packer, cg1unpacker),
876 _packermap = {'01': (cg1packer, cg1unpacker),
877 # cg2 adds support for exchanging generaldelta
877 # cg2 adds support for exchanging generaldelta
878 '02': (cg2packer, cg2unpacker),
878 '02': (cg2packer, cg2unpacker),
879 # cg3 adds support for exchanging revlog flags and treemanifests
879 # cg3 adds support for exchanging revlog flags and treemanifests
880 '03': (cg3packer, cg3unpacker),
880 '03': (cg3packer, cg3unpacker),
881 }
881 }
882
882
883 def allsupportedversions(repo):
883 def allsupportedversions(repo):
884 versions = set(_packermap.keys())
884 versions = set(_packermap.keys())
885 if not (repo.ui.configbool('experimental', 'changegroup3') or
885 if not (repo.ui.configbool('experimental', 'changegroup3') or
886 repo.ui.configbool('experimental', 'treemanifest') or
886 repo.ui.configbool('experimental', 'treemanifest') or
887 'treemanifest' in repo.requirements):
887 'treemanifest' in repo.requirements):
888 versions.discard('03')
888 versions.discard('03')
889 return versions
889 return versions
890
890
891 # Changegroup versions that can be applied to the repo
891 # Changegroup versions that can be applied to the repo
892 def supportedincomingversions(repo):
892 def supportedincomingversions(repo):
893 return allsupportedversions(repo)
893 return allsupportedversions(repo)
894
894
895 # Changegroup versions that can be created from the repo
895 # Changegroup versions that can be created from the repo
896 def supportedoutgoingversions(repo):
896 def supportedoutgoingversions(repo):
897 versions = allsupportedversions(repo)
897 versions = allsupportedversions(repo)
898 if 'treemanifest' in repo.requirements:
898 if 'treemanifest' in repo.requirements:
899 # Versions 01 and 02 support only flat manifests and it's just too
899 # Versions 01 and 02 support only flat manifests and it's just too
900 # expensive to convert between the flat manifest and tree manifest on
900 # expensive to convert between the flat manifest and tree manifest on
901 # the fly. Since tree manifests are hashed differently, all of history
901 # the fly. Since tree manifests are hashed differently, all of history
902 # would have to be converted. Instead, we simply don't even pretend to
902 # would have to be converted. Instead, we simply don't even pretend to
903 # support versions 01 and 02.
903 # support versions 01 and 02.
904 versions.discard('01')
904 versions.discard('01')
905 versions.discard('02')
905 versions.discard('02')
906 return versions
906 return versions
907
907
908 def localversion(repo):
908 def localversion(repo):
909 # Finds the best version to use for bundles that are meant to be used
909 # Finds the best version to use for bundles that are meant to be used
910 # locally, such as those from strip and shelve, and temporary bundles.
910 # locally, such as those from strip and shelve, and temporary bundles.
911 return max(supportedoutgoingversions(repo))
911 return max(supportedoutgoingversions(repo))
912
912
913 def safeversion(repo):
913 def safeversion(repo):
914 # Finds the smallest version that it's safe to assume clients of the repo
914 # Finds the smallest version that it's safe to assume clients of the repo
915 # will support. For example, all hg versions that support generaldelta also
915 # will support. For example, all hg versions that support generaldelta also
916 # support changegroup 02.
916 # support changegroup 02.
917 versions = supportedoutgoingversions(repo)
917 versions = supportedoutgoingversions(repo)
918 if 'generaldelta' in repo.requirements:
918 if 'generaldelta' in repo.requirements:
919 versions.discard('01')
919 versions.discard('01')
920 assert versions
920 assert versions
921 return min(versions)
921 return min(versions)
922
922
923 def getbundler(version, repo, bundlecaps=None):
923 def getbundler(version, repo, bundlecaps=None):
924 assert version in supportedoutgoingversions(repo)
924 assert version in supportedoutgoingversions(repo)
925 return _packermap[version][0](repo, bundlecaps)
925 return _packermap[version][0](repo, bundlecaps)
926
926
927 def getunbundler(version, fh, alg, extras=None):
927 def getunbundler(version, fh, alg, extras=None):
928 return _packermap[version][1](fh, alg, extras=extras)
928 return _packermap[version][1](fh, alg, extras=extras)
929
929
930 def _changegroupinfo(repo, nodes, source):
930 def _changegroupinfo(repo, nodes, source):
931 if repo.ui.verbose or source == 'bundle':
931 if repo.ui.verbose or source == 'bundle':
932 repo.ui.status(_("%d changesets found\n") % len(nodes))
932 repo.ui.status(_("%d changesets found\n") % len(nodes))
933 if repo.ui.debugflag:
933 if repo.ui.debugflag:
934 repo.ui.debug("list of changesets:\n")
934 repo.ui.debug("list of changesets:\n")
935 for node in nodes:
935 for node in nodes:
936 repo.ui.debug("%s\n" % hex(node))
936 repo.ui.debug("%s\n" % hex(node))
937
937
938 def makechangegroup(repo, outgoing, version, source, fastpath=False,
938 def makechangegroup(repo, outgoing, version, source, fastpath=False,
939 bundlecaps=None):
939 bundlecaps=None):
940 cgstream = makestream(repo, outgoing, version, source,
940 cgstream = makestream(repo, outgoing, version, source,
941 fastpath=fastpath, bundlecaps=bundlecaps)
941 fastpath=fastpath, bundlecaps=bundlecaps)
942 return getunbundler(version, util.chunkbuffer(cgstream), None,
942 return getunbundler(version, util.chunkbuffer(cgstream), None,
943 {'clcount': len(outgoing.missing) })
943 {'clcount': len(outgoing.missing) })
944
944
945 def makestream(repo, outgoing, version, source, fastpath=False,
945 def makestream(repo, outgoing, version, source, fastpath=False,
946 bundlecaps=None):
946 bundlecaps=None):
947 bundler = getbundler(version, repo, bundlecaps=bundlecaps)
947 bundler = getbundler(version, repo, bundlecaps=bundlecaps)
948
948
949 repo = repo.unfiltered()
949 repo = repo.unfiltered()
950 commonrevs = outgoing.common
950 commonrevs = outgoing.common
951 csets = outgoing.missing
951 csets = outgoing.missing
952 heads = outgoing.missingheads
952 heads = outgoing.missingheads
953 # We go through the fast path if we get told to, or if all (unfiltered
953 # We go through the fast path if we get told to, or if all (unfiltered
954 # heads have been requested (since we then know there all linkrevs will
954 # heads have been requested (since we then know there all linkrevs will
955 # be pulled by the client).
955 # be pulled by the client).
956 heads.sort()
956 heads.sort()
957 fastpathlinkrev = fastpath or (
957 fastpathlinkrev = fastpath or (
958 repo.filtername is None and heads == sorted(repo.heads()))
958 repo.filtername is None and heads == sorted(repo.heads()))
959
959
960 repo.hook('preoutgoing', throw=True, source=source)
960 repo.hook('preoutgoing', throw=True, source=source)
961 _changegroupinfo(repo, csets, source)
961 _changegroupinfo(repo, csets, source)
962 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
962 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
963
963
964 def _addchangegroupfiles(repo, source, revmap, trp, expectedfiles, needfiles):
964 def _addchangegroupfiles(repo, source, revmap, trp, expectedfiles, needfiles):
965 revisions = 0
965 revisions = 0
966 files = 0
966 files = 0
967 for chunkdata in iter(source.filelogheader, {}):
967 for chunkdata in iter(source.filelogheader, {}):
968 files += 1
968 files += 1
969 f = chunkdata["filename"]
969 f = chunkdata["filename"]
970 repo.ui.debug("adding %s revisions\n" % f)
970 repo.ui.debug("adding %s revisions\n" % f)
971 repo.ui.progress(_('files'), files, unit=_('files'),
971 repo.ui.progress(_('files'), files, unit=_('files'),
972 total=expectedfiles)
972 total=expectedfiles)
973 fl = repo.file(f)
973 fl = repo.file(f)
974 o = len(fl)
974 o = len(fl)
975 try:
975 try:
976 deltas = source.deltaiter()
976 deltas = source.deltaiter()
977 if not fl.addgroup(deltas, revmap, trp):
977 if not fl.addgroup(deltas, revmap, trp):
978 raise error.Abort(_("received file revlog group is empty"))
978 raise error.Abort(_("received file revlog group is empty"))
979 except error.CensoredBaseError as e:
979 except error.CensoredBaseError as e:
980 raise error.Abort(_("received delta base is censored: %s") % e)
980 raise error.Abort(_("received delta base is censored: %s") % e)
981 revisions += len(fl) - o
981 revisions += len(fl) - o
982 if f in needfiles:
982 if f in needfiles:
983 needs = needfiles[f]
983 needs = needfiles[f]
984 for new in xrange(o, len(fl)):
984 for new in xrange(o, len(fl)):
985 n = fl.node(new)
985 n = fl.node(new)
986 if n in needs:
986 if n in needs:
987 needs.remove(n)
987 needs.remove(n)
988 else:
988 else:
989 raise error.Abort(
989 raise error.Abort(
990 _("received spurious file revlog entry"))
990 _("received spurious file revlog entry"))
991 if not needs:
991 if not needs:
992 del needfiles[f]
992 del needfiles[f]
993 repo.ui.progress(_('files'), None)
993 repo.ui.progress(_('files'), None)
994
994
995 for f, needs in needfiles.iteritems():
995 for f, needs in needfiles.iteritems():
996 fl = repo.file(f)
996 fl = repo.file(f)
997 for n in needs:
997 for n in needs:
998 try:
998 try:
999 fl.rev(n)
999 fl.rev(n)
1000 except error.LookupError:
1000 except error.LookupError:
1001 raise error.Abort(
1001 raise error.Abort(
1002 _('missing file data for %s:%s - run hg verify') %
1002 _('missing file data for %s:%s - run hg verify') %
1003 (f, hex(n)))
1003 (f, hex(n)))
1004
1004
1005 return revisions, files
1005 return revisions, files
@@ -1,979 +1,979 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 configtable.items():
20 for section, items in configtable.items():
21 knownitems = ui._knownconfig.setdefault(section, {})
21 knownitems = ui._knownconfig.setdefault(section, {})
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 if key in self:
70 if key in self:
71 return self[key]
71 return self[key]
72
72
73 # search for a matching generic item
73 # search for a matching generic item
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 for item in generics:
75 for item in generics:
76 if item._re.match(key):
76 if item._re.match(key):
77 return item
77 return item
78
78
79 # fallback to dict get
79 # fallback to dict get
80 return super(itemregister, self).get(key)
80 return super(itemregister, self).get(key)
81
81
82 coreitems = {}
82 coreitems = {}
83
83
84 def _register(configtable, *args, **kwargs):
84 def _register(configtable, *args, **kwargs):
85 item = configitem(*args, **kwargs)
85 item = configitem(*args, **kwargs)
86 section = configtable.setdefault(item.section, itemregister())
86 section = configtable.setdefault(item.section, itemregister())
87 if item.name in section:
87 if item.name in section:
88 msg = "duplicated config item registration for '%s.%s'"
88 msg = "duplicated config item registration for '%s.%s'"
89 raise error.ProgrammingError(msg % (item.section, item.name))
89 raise error.ProgrammingError(msg % (item.section, item.name))
90 section[item.name] = item
90 section[item.name] = item
91
91
92 # special value for case where the default is derived from other values
92 # special value for case where the default is derived from other values
93 dynamicdefault = object()
93 dynamicdefault = object()
94
94
95 # Registering actual config items
95 # Registering actual config items
96
96
97 def getitemregister(configtable):
97 def getitemregister(configtable):
98 return functools.partial(_register, configtable)
98 return functools.partial(_register, configtable)
99
99
100 coreconfigitem = getitemregister(coreitems)
100 coreconfigitem = getitemregister(coreitems)
101
101
102 coreconfigitem('alias', '.*',
102 coreconfigitem('alias', '.*',
103 default=None,
103 default=None,
104 generic=True,
104 generic=True,
105 )
105 )
106 coreconfigitem('annotate', 'nodates',
106 coreconfigitem('annotate', 'nodates',
107 default=None,
107 default=None,
108 )
108 )
109 coreconfigitem('annotate', 'showfunc',
109 coreconfigitem('annotate', 'showfunc',
110 default=None,
110 default=None,
111 )
111 )
112 coreconfigitem('annotate', 'unified',
112 coreconfigitem('annotate', 'unified',
113 default=None,
113 default=None,
114 )
114 )
115 coreconfigitem('annotate', 'git',
115 coreconfigitem('annotate', 'git',
116 default=None,
116 default=None,
117 )
117 )
118 coreconfigitem('annotate', 'ignorews',
118 coreconfigitem('annotate', 'ignorews',
119 default=None,
119 default=None,
120 )
120 )
121 coreconfigitem('annotate', 'ignorewsamount',
121 coreconfigitem('annotate', 'ignorewsamount',
122 default=None,
122 default=None,
123 )
123 )
124 coreconfigitem('annotate', 'ignoreblanklines',
124 coreconfigitem('annotate', 'ignoreblanklines',
125 default=None,
125 default=None,
126 )
126 )
127 coreconfigitem('annotate', 'ignorewseol',
127 coreconfigitem('annotate', 'ignorewseol',
128 default=None,
128 default=None,
129 )
129 )
130 coreconfigitem('annotate', 'nobinary',
130 coreconfigitem('annotate', 'nobinary',
131 default=None,
131 default=None,
132 )
132 )
133 coreconfigitem('annotate', 'noprefix',
133 coreconfigitem('annotate', 'noprefix',
134 default=None,
134 default=None,
135 )
135 )
136 coreconfigitem('auth', 'cookiefile',
136 coreconfigitem('auth', 'cookiefile',
137 default=None,
137 default=None,
138 )
138 )
139 # bookmarks.pushing: internal hack for discovery
139 # bookmarks.pushing: internal hack for discovery
140 coreconfigitem('bookmarks', 'pushing',
140 coreconfigitem('bookmarks', 'pushing',
141 default=list,
141 default=list,
142 )
142 )
143 # bundle.mainreporoot: internal hack for bundlerepo
143 # bundle.mainreporoot: internal hack for bundlerepo
144 coreconfigitem('bundle', 'mainreporoot',
144 coreconfigitem('bundle', 'mainreporoot',
145 default='',
145 default='',
146 )
146 )
147 # bundle.reorder: experimental config
147 # bundle.reorder: experimental config
148 coreconfigitem('bundle', 'reorder',
148 coreconfigitem('bundle', 'reorder',
149 default='auto',
149 default='auto',
150 )
150 )
151 coreconfigitem('censor', 'policy',
151 coreconfigitem('censor', 'policy',
152 default='abort',
152 default='abort',
153 )
153 )
154 coreconfigitem('chgserver', 'idletimeout',
154 coreconfigitem('chgserver', 'idletimeout',
155 default=3600,
155 default=3600,
156 )
156 )
157 coreconfigitem('chgserver', 'skiphash',
157 coreconfigitem('chgserver', 'skiphash',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem('cmdserver', 'log',
160 coreconfigitem('cmdserver', 'log',
161 default=None,
161 default=None,
162 )
162 )
163 coreconfigitem('color', '.*',
163 coreconfigitem('color', '.*',
164 default=None,
164 default=None,
165 generic=True,
165 generic=True,
166 )
166 )
167 coreconfigitem('color', 'mode',
167 coreconfigitem('color', 'mode',
168 default='auto',
168 default='auto',
169 )
169 )
170 coreconfigitem('color', 'pagermode',
170 coreconfigitem('color', 'pagermode',
171 default=dynamicdefault,
171 default=dynamicdefault,
172 )
172 )
173 coreconfigitem('commands', 'status.relative',
173 coreconfigitem('commands', 'status.relative',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('commands', 'status.skipstates',
176 coreconfigitem('commands', 'status.skipstates',
177 default=[],
177 default=[],
178 )
178 )
179 coreconfigitem('commands', 'status.verbose',
179 coreconfigitem('commands', 'status.verbose',
180 default=False,
180 default=False,
181 )
181 )
182 coreconfigitem('commands', 'update.check',
182 coreconfigitem('commands', 'update.check',
183 default=None,
183 default=None,
184 )
184 )
185 coreconfigitem('commands', 'update.requiredest',
185 coreconfigitem('commands', 'update.requiredest',
186 default=False,
186 default=False,
187 )
187 )
188 coreconfigitem('committemplate', '.*',
188 coreconfigitem('committemplate', '.*',
189 default=None,
189 default=None,
190 generic=True,
190 generic=True,
191 )
191 )
192 coreconfigitem('debug', 'dirstate.delaywrite',
192 coreconfigitem('debug', 'dirstate.delaywrite',
193 default=0,
193 default=0,
194 )
194 )
195 coreconfigitem('defaults', '.*',
195 coreconfigitem('defaults', '.*',
196 default=None,
196 default=None,
197 generic=True,
197 generic=True,
198 )
198 )
199 coreconfigitem('devel', 'all-warnings',
199 coreconfigitem('devel', 'all-warnings',
200 default=False,
200 default=False,
201 )
201 )
202 coreconfigitem('devel', 'bundle2.debug',
202 coreconfigitem('devel', 'bundle2.debug',
203 default=False,
203 default=False,
204 )
204 )
205 coreconfigitem('devel', 'cache-vfs',
205 coreconfigitem('devel', 'cache-vfs',
206 default=None,
206 default=None,
207 )
207 )
208 coreconfigitem('devel', 'check-locks',
208 coreconfigitem('devel', 'check-locks',
209 default=False,
209 default=False,
210 )
210 )
211 coreconfigitem('devel', 'check-relroot',
211 coreconfigitem('devel', 'check-relroot',
212 default=False,
212 default=False,
213 )
213 )
214 coreconfigitem('devel', 'default-date',
214 coreconfigitem('devel', 'default-date',
215 default=None,
215 default=None,
216 )
216 )
217 coreconfigitem('devel', 'deprec-warn',
217 coreconfigitem('devel', 'deprec-warn',
218 default=False,
218 default=False,
219 )
219 )
220 coreconfigitem('devel', 'disableloaddefaultcerts',
220 coreconfigitem('devel', 'disableloaddefaultcerts',
221 default=False,
221 default=False,
222 )
222 )
223 coreconfigitem('devel', 'empty-changegroup',
223 coreconfigitem('devel', 'warn-empty-changegroup',
224 default=False,
224 default=False,
225 )
225 )
226 coreconfigitem('devel', 'legacy.exchange',
226 coreconfigitem('devel', 'legacy.exchange',
227 default=list,
227 default=list,
228 )
228 )
229 coreconfigitem('devel', 'servercafile',
229 coreconfigitem('devel', 'servercafile',
230 default='',
230 default='',
231 )
231 )
232 coreconfigitem('devel', 'serverexactprotocol',
232 coreconfigitem('devel', 'serverexactprotocol',
233 default='',
233 default='',
234 )
234 )
235 coreconfigitem('devel', 'serverrequirecert',
235 coreconfigitem('devel', 'serverrequirecert',
236 default=False,
236 default=False,
237 )
237 )
238 coreconfigitem('devel', 'strip-obsmarkers',
238 coreconfigitem('devel', 'strip-obsmarkers',
239 default=True,
239 default=True,
240 )
240 )
241 coreconfigitem('devel', 'warn-config',
241 coreconfigitem('devel', 'warn-config',
242 default=None,
242 default=None,
243 )
243 )
244 coreconfigitem('devel', 'warn-config-default',
244 coreconfigitem('devel', 'warn-config-default',
245 default=None,
245 default=None,
246 )
246 )
247 coreconfigitem('devel', 'user.obsmarker',
247 coreconfigitem('devel', 'user.obsmarker',
248 default=None,
248 default=None,
249 )
249 )
250 coreconfigitem('diff', 'nodates',
250 coreconfigitem('diff', 'nodates',
251 default=None,
251 default=None,
252 )
252 )
253 coreconfigitem('diff', 'showfunc',
253 coreconfigitem('diff', 'showfunc',
254 default=None,
254 default=None,
255 )
255 )
256 coreconfigitem('diff', 'unified',
256 coreconfigitem('diff', 'unified',
257 default=None,
257 default=None,
258 )
258 )
259 coreconfigitem('diff', 'git',
259 coreconfigitem('diff', 'git',
260 default=None,
260 default=None,
261 )
261 )
262 coreconfigitem('diff', 'ignorews',
262 coreconfigitem('diff', 'ignorews',
263 default=None,
263 default=None,
264 )
264 )
265 coreconfigitem('diff', 'ignorewsamount',
265 coreconfigitem('diff', 'ignorewsamount',
266 default=None,
266 default=None,
267 )
267 )
268 coreconfigitem('diff', 'ignoreblanklines',
268 coreconfigitem('diff', 'ignoreblanklines',
269 default=None,
269 default=None,
270 )
270 )
271 coreconfigitem('diff', 'ignorewseol',
271 coreconfigitem('diff', 'ignorewseol',
272 default=None,
272 default=None,
273 )
273 )
274 coreconfigitem('diff', 'nobinary',
274 coreconfigitem('diff', 'nobinary',
275 default=None,
275 default=None,
276 )
276 )
277 coreconfigitem('diff', 'noprefix',
277 coreconfigitem('diff', 'noprefix',
278 default=None,
278 default=None,
279 )
279 )
280 coreconfigitem('email', 'bcc',
280 coreconfigitem('email', 'bcc',
281 default=None,
281 default=None,
282 )
282 )
283 coreconfigitem('email', 'cc',
283 coreconfigitem('email', 'cc',
284 default=None,
284 default=None,
285 )
285 )
286 coreconfigitem('email', 'charsets',
286 coreconfigitem('email', 'charsets',
287 default=list,
287 default=list,
288 )
288 )
289 coreconfigitem('email', 'from',
289 coreconfigitem('email', 'from',
290 default=None,
290 default=None,
291 )
291 )
292 coreconfigitem('email', 'method',
292 coreconfigitem('email', 'method',
293 default='smtp',
293 default='smtp',
294 )
294 )
295 coreconfigitem('email', 'reply-to',
295 coreconfigitem('email', 'reply-to',
296 default=None,
296 default=None,
297 )
297 )
298 coreconfigitem('experimental', 'allowdivergence',
298 coreconfigitem('experimental', 'allowdivergence',
299 default=False,
299 default=False,
300 )
300 )
301 coreconfigitem('experimental', 'archivemetatemplate',
301 coreconfigitem('experimental', 'archivemetatemplate',
302 default=dynamicdefault,
302 default=dynamicdefault,
303 )
303 )
304 coreconfigitem('experimental', 'bundle-phases',
304 coreconfigitem('experimental', 'bundle-phases',
305 default=False,
305 default=False,
306 )
306 )
307 coreconfigitem('experimental', 'bundle2-advertise',
307 coreconfigitem('experimental', 'bundle2-advertise',
308 default=True,
308 default=True,
309 )
309 )
310 coreconfigitem('experimental', 'bundle2-output-capture',
310 coreconfigitem('experimental', 'bundle2-output-capture',
311 default=False,
311 default=False,
312 )
312 )
313 coreconfigitem('experimental', 'bundle2.pushback',
313 coreconfigitem('experimental', 'bundle2.pushback',
314 default=False,
314 default=False,
315 )
315 )
316 coreconfigitem('experimental', 'bundle2lazylocking',
316 coreconfigitem('experimental', 'bundle2lazylocking',
317 default=False,
317 default=False,
318 )
318 )
319 coreconfigitem('experimental', 'bundlecomplevel',
319 coreconfigitem('experimental', 'bundlecomplevel',
320 default=None,
320 default=None,
321 )
321 )
322 coreconfigitem('experimental', 'changegroup3',
322 coreconfigitem('experimental', 'changegroup3',
323 default=False,
323 default=False,
324 )
324 )
325 coreconfigitem('experimental', 'clientcompressionengines',
325 coreconfigitem('experimental', 'clientcompressionengines',
326 default=list,
326 default=list,
327 )
327 )
328 coreconfigitem('experimental', 'copytrace',
328 coreconfigitem('experimental', 'copytrace',
329 default='on',
329 default='on',
330 )
330 )
331 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
331 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
332 default=100,
332 default=100,
333 )
333 )
334 coreconfigitem('experimental', 'crecordtest',
334 coreconfigitem('experimental', 'crecordtest',
335 default=None,
335 default=None,
336 )
336 )
337 coreconfigitem('experimental', 'editortmpinhg',
337 coreconfigitem('experimental', 'editortmpinhg',
338 default=False,
338 default=False,
339 )
339 )
340 coreconfigitem('experimental', 'maxdeltachainspan',
340 coreconfigitem('experimental', 'maxdeltachainspan',
341 default=-1,
341 default=-1,
342 )
342 )
343 coreconfigitem('experimental', 'mmapindexthreshold',
343 coreconfigitem('experimental', 'mmapindexthreshold',
344 default=None,
344 default=None,
345 )
345 )
346 coreconfigitem('experimental', 'nonnormalparanoidcheck',
346 coreconfigitem('experimental', 'nonnormalparanoidcheck',
347 default=False,
347 default=False,
348 )
348 )
349 coreconfigitem('experimental', 'stabilization',
349 coreconfigitem('experimental', 'stabilization',
350 default=list,
350 default=list,
351 alias=[('experimental', 'evolution')],
351 alias=[('experimental', 'evolution')],
352 )
352 )
353 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
353 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
354 default=False,
354 default=False,
355 alias=[('experimental', 'evolution.bundle-obsmarker')],
355 alias=[('experimental', 'evolution.bundle-obsmarker')],
356 )
356 )
357 coreconfigitem('experimental', 'stabilization.track-operation',
357 coreconfigitem('experimental', 'stabilization.track-operation',
358 default=True,
358 default=True,
359 alias=[('experimental', 'evolution.track-operation')]
359 alias=[('experimental', 'evolution.track-operation')]
360 )
360 )
361 coreconfigitem('experimental', 'exportableenviron',
361 coreconfigitem('experimental', 'exportableenviron',
362 default=list,
362 default=list,
363 )
363 )
364 coreconfigitem('experimental', 'extendedheader.index',
364 coreconfigitem('experimental', 'extendedheader.index',
365 default=None,
365 default=None,
366 )
366 )
367 coreconfigitem('experimental', 'extendedheader.similarity',
367 coreconfigitem('experimental', 'extendedheader.similarity',
368 default=False,
368 default=False,
369 )
369 )
370 coreconfigitem('experimental', 'format.compression',
370 coreconfigitem('experimental', 'format.compression',
371 default='zlib',
371 default='zlib',
372 )
372 )
373 coreconfigitem('experimental', 'graphshorten',
373 coreconfigitem('experimental', 'graphshorten',
374 default=False,
374 default=False,
375 )
375 )
376 coreconfigitem('experimental', 'graphstyle.parent',
376 coreconfigitem('experimental', 'graphstyle.parent',
377 default=dynamicdefault,
377 default=dynamicdefault,
378 )
378 )
379 coreconfigitem('experimental', 'graphstyle.missing',
379 coreconfigitem('experimental', 'graphstyle.missing',
380 default=dynamicdefault,
380 default=dynamicdefault,
381 )
381 )
382 coreconfigitem('experimental', 'graphstyle.grandparent',
382 coreconfigitem('experimental', 'graphstyle.grandparent',
383 default=dynamicdefault,
383 default=dynamicdefault,
384 )
384 )
385 coreconfigitem('experimental', 'hook-track-tags',
385 coreconfigitem('experimental', 'hook-track-tags',
386 default=False,
386 default=False,
387 )
387 )
388 coreconfigitem('experimental', 'httppostargs',
388 coreconfigitem('experimental', 'httppostargs',
389 default=False,
389 default=False,
390 )
390 )
391 coreconfigitem('experimental', 'manifestv2',
391 coreconfigitem('experimental', 'manifestv2',
392 default=False,
392 default=False,
393 )
393 )
394 coreconfigitem('experimental', 'mergedriver',
394 coreconfigitem('experimental', 'mergedriver',
395 default=None,
395 default=None,
396 )
396 )
397 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
397 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
398 default=False,
398 default=False,
399 )
399 )
400 coreconfigitem('experimental', 'rebase.multidest',
400 coreconfigitem('experimental', 'rebase.multidest',
401 default=False,
401 default=False,
402 )
402 )
403 coreconfigitem('experimental', 'revertalternateinteractivemode',
403 coreconfigitem('experimental', 'revertalternateinteractivemode',
404 default=True,
404 default=True,
405 )
405 )
406 coreconfigitem('experimental', 'revlogv2',
406 coreconfigitem('experimental', 'revlogv2',
407 default=None,
407 default=None,
408 )
408 )
409 coreconfigitem('experimental', 'spacemovesdown',
409 coreconfigitem('experimental', 'spacemovesdown',
410 default=False,
410 default=False,
411 )
411 )
412 coreconfigitem('experimental', 'treemanifest',
412 coreconfigitem('experimental', 'treemanifest',
413 default=False,
413 default=False,
414 )
414 )
415 # Deprecated, remove after 4.4 release
415 # Deprecated, remove after 4.4 release
416 coreconfigitem('experimental', 'updatecheck',
416 coreconfigitem('experimental', 'updatecheck',
417 default=None,
417 default=None,
418 )
418 )
419 coreconfigitem('extensions', '.*',
419 coreconfigitem('extensions', '.*',
420 default=None,
420 default=None,
421 generic=True,
421 generic=True,
422 )
422 )
423 coreconfigitem('format', 'aggressivemergedeltas',
423 coreconfigitem('format', 'aggressivemergedeltas',
424 default=False,
424 default=False,
425 )
425 )
426 coreconfigitem('format', 'chunkcachesize',
426 coreconfigitem('format', 'chunkcachesize',
427 default=None,
427 default=None,
428 )
428 )
429 coreconfigitem('format', 'dotencode',
429 coreconfigitem('format', 'dotencode',
430 default=True,
430 default=True,
431 )
431 )
432 coreconfigitem('format', 'generaldelta',
432 coreconfigitem('format', 'generaldelta',
433 default=False,
433 default=False,
434 )
434 )
435 coreconfigitem('format', 'manifestcachesize',
435 coreconfigitem('format', 'manifestcachesize',
436 default=None,
436 default=None,
437 )
437 )
438 coreconfigitem('format', 'maxchainlen',
438 coreconfigitem('format', 'maxchainlen',
439 default=None,
439 default=None,
440 )
440 )
441 coreconfigitem('format', 'obsstore-version',
441 coreconfigitem('format', 'obsstore-version',
442 default=None,
442 default=None,
443 )
443 )
444 coreconfigitem('format', 'usefncache',
444 coreconfigitem('format', 'usefncache',
445 default=True,
445 default=True,
446 )
446 )
447 coreconfigitem('format', 'usegeneraldelta',
447 coreconfigitem('format', 'usegeneraldelta',
448 default=True,
448 default=True,
449 )
449 )
450 coreconfigitem('format', 'usestore',
450 coreconfigitem('format', 'usestore',
451 default=True,
451 default=True,
452 )
452 )
453 coreconfigitem('hooks', '.*',
453 coreconfigitem('hooks', '.*',
454 default=dynamicdefault,
454 default=dynamicdefault,
455 generic=True,
455 generic=True,
456 )
456 )
457 coreconfigitem('hostsecurity', 'ciphers',
457 coreconfigitem('hostsecurity', 'ciphers',
458 default=None,
458 default=None,
459 )
459 )
460 coreconfigitem('hostsecurity', 'disabletls10warning',
460 coreconfigitem('hostsecurity', 'disabletls10warning',
461 default=False,
461 default=False,
462 )
462 )
463 coreconfigitem('http_proxy', 'always',
463 coreconfigitem('http_proxy', 'always',
464 default=False,
464 default=False,
465 )
465 )
466 coreconfigitem('http_proxy', 'host',
466 coreconfigitem('http_proxy', 'host',
467 default=None,
467 default=None,
468 )
468 )
469 coreconfigitem('http_proxy', 'no',
469 coreconfigitem('http_proxy', 'no',
470 default=list,
470 default=list,
471 )
471 )
472 coreconfigitem('http_proxy', 'passwd',
472 coreconfigitem('http_proxy', 'passwd',
473 default=None,
473 default=None,
474 )
474 )
475 coreconfigitem('http_proxy', 'user',
475 coreconfigitem('http_proxy', 'user',
476 default=None,
476 default=None,
477 )
477 )
478 coreconfigitem('logtoprocess', 'commandexception',
478 coreconfigitem('logtoprocess', 'commandexception',
479 default=None,
479 default=None,
480 )
480 )
481 coreconfigitem('logtoprocess', 'commandfinish',
481 coreconfigitem('logtoprocess', 'commandfinish',
482 default=None,
482 default=None,
483 )
483 )
484 coreconfigitem('logtoprocess', 'command',
484 coreconfigitem('logtoprocess', 'command',
485 default=None,
485 default=None,
486 )
486 )
487 coreconfigitem('logtoprocess', 'develwarn',
487 coreconfigitem('logtoprocess', 'develwarn',
488 default=None,
488 default=None,
489 )
489 )
490 coreconfigitem('logtoprocess', 'uiblocked',
490 coreconfigitem('logtoprocess', 'uiblocked',
491 default=None,
491 default=None,
492 )
492 )
493 coreconfigitem('merge', 'checkunknown',
493 coreconfigitem('merge', 'checkunknown',
494 default='abort',
494 default='abort',
495 )
495 )
496 coreconfigitem('merge', 'checkignored',
496 coreconfigitem('merge', 'checkignored',
497 default='abort',
497 default='abort',
498 )
498 )
499 coreconfigitem('merge', 'followcopies',
499 coreconfigitem('merge', 'followcopies',
500 default=True,
500 default=True,
501 )
501 )
502 coreconfigitem('merge', 'preferancestor',
502 coreconfigitem('merge', 'preferancestor',
503 default=lambda: ['*'],
503 default=lambda: ['*'],
504 )
504 )
505 coreconfigitem('pager', 'attend-.*',
505 coreconfigitem('pager', 'attend-.*',
506 default=dynamicdefault,
506 default=dynamicdefault,
507 generic=True,
507 generic=True,
508 )
508 )
509 coreconfigitem('pager', 'ignore',
509 coreconfigitem('pager', 'ignore',
510 default=list,
510 default=list,
511 )
511 )
512 coreconfigitem('pager', 'pager',
512 coreconfigitem('pager', 'pager',
513 default=dynamicdefault,
513 default=dynamicdefault,
514 )
514 )
515 coreconfigitem('patch', 'eol',
515 coreconfigitem('patch', 'eol',
516 default='strict',
516 default='strict',
517 )
517 )
518 coreconfigitem('patch', 'fuzz',
518 coreconfigitem('patch', 'fuzz',
519 default=2,
519 default=2,
520 )
520 )
521 coreconfigitem('paths', 'default',
521 coreconfigitem('paths', 'default',
522 default=None,
522 default=None,
523 )
523 )
524 coreconfigitem('paths', 'default-push',
524 coreconfigitem('paths', 'default-push',
525 default=None,
525 default=None,
526 )
526 )
527 coreconfigitem('paths', '.*',
527 coreconfigitem('paths', '.*',
528 default=None,
528 default=None,
529 generic=True,
529 generic=True,
530 )
530 )
531 coreconfigitem('phases', 'checksubrepos',
531 coreconfigitem('phases', 'checksubrepos',
532 default='follow',
532 default='follow',
533 )
533 )
534 coreconfigitem('phases', 'new-commit',
534 coreconfigitem('phases', 'new-commit',
535 default='draft',
535 default='draft',
536 )
536 )
537 coreconfigitem('phases', 'publish',
537 coreconfigitem('phases', 'publish',
538 default=True,
538 default=True,
539 )
539 )
540 coreconfigitem('profiling', 'enabled',
540 coreconfigitem('profiling', 'enabled',
541 default=False,
541 default=False,
542 )
542 )
543 coreconfigitem('profiling', 'format',
543 coreconfigitem('profiling', 'format',
544 default='text',
544 default='text',
545 )
545 )
546 coreconfigitem('profiling', 'freq',
546 coreconfigitem('profiling', 'freq',
547 default=1000,
547 default=1000,
548 )
548 )
549 coreconfigitem('profiling', 'limit',
549 coreconfigitem('profiling', 'limit',
550 default=30,
550 default=30,
551 )
551 )
552 coreconfigitem('profiling', 'nested',
552 coreconfigitem('profiling', 'nested',
553 default=0,
553 default=0,
554 )
554 )
555 coreconfigitem('profiling', 'output',
555 coreconfigitem('profiling', 'output',
556 default=None,
556 default=None,
557 )
557 )
558 coreconfigitem('profiling', 'showmax',
558 coreconfigitem('profiling', 'showmax',
559 default=0.999,
559 default=0.999,
560 )
560 )
561 coreconfigitem('profiling', 'showmin',
561 coreconfigitem('profiling', 'showmin',
562 default=dynamicdefault,
562 default=dynamicdefault,
563 )
563 )
564 coreconfigitem('profiling', 'sort',
564 coreconfigitem('profiling', 'sort',
565 default='inlinetime',
565 default='inlinetime',
566 )
566 )
567 coreconfigitem('profiling', 'statformat',
567 coreconfigitem('profiling', 'statformat',
568 default='hotpath',
568 default='hotpath',
569 )
569 )
570 coreconfigitem('profiling', 'type',
570 coreconfigitem('profiling', 'type',
571 default='stat',
571 default='stat',
572 )
572 )
573 coreconfigitem('progress', 'assume-tty',
573 coreconfigitem('progress', 'assume-tty',
574 default=False,
574 default=False,
575 )
575 )
576 coreconfigitem('progress', 'changedelay',
576 coreconfigitem('progress', 'changedelay',
577 default=1,
577 default=1,
578 )
578 )
579 coreconfigitem('progress', 'clear-complete',
579 coreconfigitem('progress', 'clear-complete',
580 default=True,
580 default=True,
581 )
581 )
582 coreconfigitem('progress', 'debug',
582 coreconfigitem('progress', 'debug',
583 default=False,
583 default=False,
584 )
584 )
585 coreconfigitem('progress', 'delay',
585 coreconfigitem('progress', 'delay',
586 default=3,
586 default=3,
587 )
587 )
588 coreconfigitem('progress', 'disable',
588 coreconfigitem('progress', 'disable',
589 default=False,
589 default=False,
590 )
590 )
591 coreconfigitem('progress', 'estimateinterval',
591 coreconfigitem('progress', 'estimateinterval',
592 default=60.0,
592 default=60.0,
593 )
593 )
594 coreconfigitem('progress', 'refresh',
594 coreconfigitem('progress', 'refresh',
595 default=0.1,
595 default=0.1,
596 )
596 )
597 coreconfigitem('progress', 'width',
597 coreconfigitem('progress', 'width',
598 default=dynamicdefault,
598 default=dynamicdefault,
599 )
599 )
600 coreconfigitem('push', 'pushvars.server',
600 coreconfigitem('push', 'pushvars.server',
601 default=False,
601 default=False,
602 )
602 )
603 coreconfigitem('server', 'bundle1',
603 coreconfigitem('server', 'bundle1',
604 default=True,
604 default=True,
605 )
605 )
606 coreconfigitem('server', 'bundle1gd',
606 coreconfigitem('server', 'bundle1gd',
607 default=None,
607 default=None,
608 )
608 )
609 coreconfigitem('server', 'bundle1.pull',
609 coreconfigitem('server', 'bundle1.pull',
610 default=None,
610 default=None,
611 )
611 )
612 coreconfigitem('server', 'bundle1gd.pull',
612 coreconfigitem('server', 'bundle1gd.pull',
613 default=None,
613 default=None,
614 )
614 )
615 coreconfigitem('server', 'bundle1.push',
615 coreconfigitem('server', 'bundle1.push',
616 default=None,
616 default=None,
617 )
617 )
618 coreconfigitem('server', 'bundle1gd.push',
618 coreconfigitem('server', 'bundle1gd.push',
619 default=None,
619 default=None,
620 )
620 )
621 coreconfigitem('server', 'compressionengines',
621 coreconfigitem('server', 'compressionengines',
622 default=list,
622 default=list,
623 )
623 )
624 coreconfigitem('server', 'concurrent-push-mode',
624 coreconfigitem('server', 'concurrent-push-mode',
625 default='strict',
625 default='strict',
626 )
626 )
627 coreconfigitem('server', 'disablefullbundle',
627 coreconfigitem('server', 'disablefullbundle',
628 default=False,
628 default=False,
629 )
629 )
630 coreconfigitem('server', 'maxhttpheaderlen',
630 coreconfigitem('server', 'maxhttpheaderlen',
631 default=1024,
631 default=1024,
632 )
632 )
633 coreconfigitem('server', 'preferuncompressed',
633 coreconfigitem('server', 'preferuncompressed',
634 default=False,
634 default=False,
635 )
635 )
636 coreconfigitem('server', 'uncompressed',
636 coreconfigitem('server', 'uncompressed',
637 default=True,
637 default=True,
638 )
638 )
639 coreconfigitem('server', 'uncompressedallowsecret',
639 coreconfigitem('server', 'uncompressedallowsecret',
640 default=False,
640 default=False,
641 )
641 )
642 coreconfigitem('server', 'validate',
642 coreconfigitem('server', 'validate',
643 default=False,
643 default=False,
644 )
644 )
645 coreconfigitem('server', 'zliblevel',
645 coreconfigitem('server', 'zliblevel',
646 default=-1,
646 default=-1,
647 )
647 )
648 coreconfigitem('smtp', 'host',
648 coreconfigitem('smtp', 'host',
649 default=None,
649 default=None,
650 )
650 )
651 coreconfigitem('smtp', 'local_hostname',
651 coreconfigitem('smtp', 'local_hostname',
652 default=None,
652 default=None,
653 )
653 )
654 coreconfigitem('smtp', 'password',
654 coreconfigitem('smtp', 'password',
655 default=None,
655 default=None,
656 )
656 )
657 coreconfigitem('smtp', 'port',
657 coreconfigitem('smtp', 'port',
658 default=dynamicdefault,
658 default=dynamicdefault,
659 )
659 )
660 coreconfigitem('smtp', 'tls',
660 coreconfigitem('smtp', 'tls',
661 default='none',
661 default='none',
662 )
662 )
663 coreconfigitem('smtp', 'username',
663 coreconfigitem('smtp', 'username',
664 default=None,
664 default=None,
665 )
665 )
666 coreconfigitem('sparse', 'missingwarning',
666 coreconfigitem('sparse', 'missingwarning',
667 default=True,
667 default=True,
668 )
668 )
669 coreconfigitem('templates', '.*',
669 coreconfigitem('templates', '.*',
670 default=None,
670 default=None,
671 generic=True,
671 generic=True,
672 )
672 )
673 coreconfigitem('trusted', 'groups',
673 coreconfigitem('trusted', 'groups',
674 default=list,
674 default=list,
675 )
675 )
676 coreconfigitem('trusted', 'users',
676 coreconfigitem('trusted', 'users',
677 default=list,
677 default=list,
678 )
678 )
679 coreconfigitem('ui', '_usedassubrepo',
679 coreconfigitem('ui', '_usedassubrepo',
680 default=False,
680 default=False,
681 )
681 )
682 coreconfigitem('ui', 'allowemptycommit',
682 coreconfigitem('ui', 'allowemptycommit',
683 default=False,
683 default=False,
684 )
684 )
685 coreconfigitem('ui', 'archivemeta',
685 coreconfigitem('ui', 'archivemeta',
686 default=True,
686 default=True,
687 )
687 )
688 coreconfigitem('ui', 'askusername',
688 coreconfigitem('ui', 'askusername',
689 default=False,
689 default=False,
690 )
690 )
691 coreconfigitem('ui', 'clonebundlefallback',
691 coreconfigitem('ui', 'clonebundlefallback',
692 default=False,
692 default=False,
693 )
693 )
694 coreconfigitem('ui', 'clonebundleprefers',
694 coreconfigitem('ui', 'clonebundleprefers',
695 default=list,
695 default=list,
696 )
696 )
697 coreconfigitem('ui', 'clonebundles',
697 coreconfigitem('ui', 'clonebundles',
698 default=True,
698 default=True,
699 )
699 )
700 coreconfigitem('ui', 'color',
700 coreconfigitem('ui', 'color',
701 default='auto',
701 default='auto',
702 )
702 )
703 coreconfigitem('ui', 'commitsubrepos',
703 coreconfigitem('ui', 'commitsubrepos',
704 default=False,
704 default=False,
705 )
705 )
706 coreconfigitem('ui', 'debug',
706 coreconfigitem('ui', 'debug',
707 default=False,
707 default=False,
708 )
708 )
709 coreconfigitem('ui', 'debugger',
709 coreconfigitem('ui', 'debugger',
710 default=None,
710 default=None,
711 )
711 )
712 coreconfigitem('ui', 'fallbackencoding',
712 coreconfigitem('ui', 'fallbackencoding',
713 default=None,
713 default=None,
714 )
714 )
715 coreconfigitem('ui', 'forcecwd',
715 coreconfigitem('ui', 'forcecwd',
716 default=None,
716 default=None,
717 )
717 )
718 coreconfigitem('ui', 'forcemerge',
718 coreconfigitem('ui', 'forcemerge',
719 default=None,
719 default=None,
720 )
720 )
721 coreconfigitem('ui', 'formatdebug',
721 coreconfigitem('ui', 'formatdebug',
722 default=False,
722 default=False,
723 )
723 )
724 coreconfigitem('ui', 'formatjson',
724 coreconfigitem('ui', 'formatjson',
725 default=False,
725 default=False,
726 )
726 )
727 coreconfigitem('ui', 'formatted',
727 coreconfigitem('ui', 'formatted',
728 default=None,
728 default=None,
729 )
729 )
730 coreconfigitem('ui', 'graphnodetemplate',
730 coreconfigitem('ui', 'graphnodetemplate',
731 default=None,
731 default=None,
732 )
732 )
733 coreconfigitem('ui', 'http2debuglevel',
733 coreconfigitem('ui', 'http2debuglevel',
734 default=None,
734 default=None,
735 )
735 )
736 coreconfigitem('ui', 'interactive',
736 coreconfigitem('ui', 'interactive',
737 default=None,
737 default=None,
738 )
738 )
739 coreconfigitem('ui', 'interface',
739 coreconfigitem('ui', 'interface',
740 default=None,
740 default=None,
741 )
741 )
742 coreconfigitem('ui', 'interface.chunkselector',
742 coreconfigitem('ui', 'interface.chunkselector',
743 default=None,
743 default=None,
744 )
744 )
745 coreconfigitem('ui', 'logblockedtimes',
745 coreconfigitem('ui', 'logblockedtimes',
746 default=False,
746 default=False,
747 )
747 )
748 coreconfigitem('ui', 'logtemplate',
748 coreconfigitem('ui', 'logtemplate',
749 default=None,
749 default=None,
750 )
750 )
751 coreconfigitem('ui', 'merge',
751 coreconfigitem('ui', 'merge',
752 default=None,
752 default=None,
753 )
753 )
754 coreconfigitem('ui', 'mergemarkers',
754 coreconfigitem('ui', 'mergemarkers',
755 default='basic',
755 default='basic',
756 )
756 )
757 coreconfigitem('ui', 'mergemarkertemplate',
757 coreconfigitem('ui', 'mergemarkertemplate',
758 default=('{node|short} '
758 default=('{node|short} '
759 '{ifeq(tags, "tip", "", '
759 '{ifeq(tags, "tip", "", '
760 'ifeq(tags, "", "", "{tags} "))}'
760 'ifeq(tags, "", "", "{tags} "))}'
761 '{if(bookmarks, "{bookmarks} ")}'
761 '{if(bookmarks, "{bookmarks} ")}'
762 '{ifeq(branch, "default", "", "{branch} ")}'
762 '{ifeq(branch, "default", "", "{branch} ")}'
763 '- {author|user}: {desc|firstline}')
763 '- {author|user}: {desc|firstline}')
764 )
764 )
765 coreconfigitem('ui', 'nontty',
765 coreconfigitem('ui', 'nontty',
766 default=False,
766 default=False,
767 )
767 )
768 coreconfigitem('ui', 'origbackuppath',
768 coreconfigitem('ui', 'origbackuppath',
769 default=None,
769 default=None,
770 )
770 )
771 coreconfigitem('ui', 'paginate',
771 coreconfigitem('ui', 'paginate',
772 default=True,
772 default=True,
773 )
773 )
774 coreconfigitem('ui', 'patch',
774 coreconfigitem('ui', 'patch',
775 default=None,
775 default=None,
776 )
776 )
777 coreconfigitem('ui', 'portablefilenames',
777 coreconfigitem('ui', 'portablefilenames',
778 default='warn',
778 default='warn',
779 )
779 )
780 coreconfigitem('ui', 'promptecho',
780 coreconfigitem('ui', 'promptecho',
781 default=False,
781 default=False,
782 )
782 )
783 coreconfigitem('ui', 'quiet',
783 coreconfigitem('ui', 'quiet',
784 default=False,
784 default=False,
785 )
785 )
786 coreconfigitem('ui', 'quietbookmarkmove',
786 coreconfigitem('ui', 'quietbookmarkmove',
787 default=False,
787 default=False,
788 )
788 )
789 coreconfigitem('ui', 'remotecmd',
789 coreconfigitem('ui', 'remotecmd',
790 default='hg',
790 default='hg',
791 )
791 )
792 coreconfigitem('ui', 'report_untrusted',
792 coreconfigitem('ui', 'report_untrusted',
793 default=True,
793 default=True,
794 )
794 )
795 coreconfigitem('ui', 'rollback',
795 coreconfigitem('ui', 'rollback',
796 default=True,
796 default=True,
797 )
797 )
798 coreconfigitem('ui', 'slash',
798 coreconfigitem('ui', 'slash',
799 default=False,
799 default=False,
800 )
800 )
801 coreconfigitem('ui', 'ssh',
801 coreconfigitem('ui', 'ssh',
802 default='ssh',
802 default='ssh',
803 )
803 )
804 coreconfigitem('ui', 'statuscopies',
804 coreconfigitem('ui', 'statuscopies',
805 default=False,
805 default=False,
806 )
806 )
807 coreconfigitem('ui', 'strict',
807 coreconfigitem('ui', 'strict',
808 default=False,
808 default=False,
809 )
809 )
810 coreconfigitem('ui', 'style',
810 coreconfigitem('ui', 'style',
811 default='',
811 default='',
812 )
812 )
813 coreconfigitem('ui', 'supportcontact',
813 coreconfigitem('ui', 'supportcontact',
814 default=None,
814 default=None,
815 )
815 )
816 coreconfigitem('ui', 'textwidth',
816 coreconfigitem('ui', 'textwidth',
817 default=78,
817 default=78,
818 )
818 )
819 coreconfigitem('ui', 'timeout',
819 coreconfigitem('ui', 'timeout',
820 default='600',
820 default='600',
821 )
821 )
822 coreconfigitem('ui', 'traceback',
822 coreconfigitem('ui', 'traceback',
823 default=False,
823 default=False,
824 )
824 )
825 coreconfigitem('ui', 'tweakdefaults',
825 coreconfigitem('ui', 'tweakdefaults',
826 default=False,
826 default=False,
827 )
827 )
828 coreconfigitem('ui', 'usehttp2',
828 coreconfigitem('ui', 'usehttp2',
829 default=False,
829 default=False,
830 )
830 )
831 coreconfigitem('ui', 'username',
831 coreconfigitem('ui', 'username',
832 alias=[('ui', 'user')]
832 alias=[('ui', 'user')]
833 )
833 )
834 coreconfigitem('ui', 'verbose',
834 coreconfigitem('ui', 'verbose',
835 default=False,
835 default=False,
836 )
836 )
837 coreconfigitem('verify', 'skipflags',
837 coreconfigitem('verify', 'skipflags',
838 default=None,
838 default=None,
839 )
839 )
840 coreconfigitem('web', 'allowbz2',
840 coreconfigitem('web', 'allowbz2',
841 default=False,
841 default=False,
842 )
842 )
843 coreconfigitem('web', 'allowgz',
843 coreconfigitem('web', 'allowgz',
844 default=False,
844 default=False,
845 )
845 )
846 coreconfigitem('web', 'allowpull',
846 coreconfigitem('web', 'allowpull',
847 default=True,
847 default=True,
848 )
848 )
849 coreconfigitem('web', 'allow_push',
849 coreconfigitem('web', 'allow_push',
850 default=list,
850 default=list,
851 )
851 )
852 coreconfigitem('web', 'allowzip',
852 coreconfigitem('web', 'allowzip',
853 default=False,
853 default=False,
854 )
854 )
855 coreconfigitem('web', 'cache',
855 coreconfigitem('web', 'cache',
856 default=True,
856 default=True,
857 )
857 )
858 coreconfigitem('web', 'contact',
858 coreconfigitem('web', 'contact',
859 default=None,
859 default=None,
860 )
860 )
861 coreconfigitem('web', 'deny_push',
861 coreconfigitem('web', 'deny_push',
862 default=list,
862 default=list,
863 )
863 )
864 coreconfigitem('web', 'guessmime',
864 coreconfigitem('web', 'guessmime',
865 default=False,
865 default=False,
866 )
866 )
867 coreconfigitem('web', 'hidden',
867 coreconfigitem('web', 'hidden',
868 default=False,
868 default=False,
869 )
869 )
870 coreconfigitem('web', 'labels',
870 coreconfigitem('web', 'labels',
871 default=list,
871 default=list,
872 )
872 )
873 coreconfigitem('web', 'logoimg',
873 coreconfigitem('web', 'logoimg',
874 default='hglogo.png',
874 default='hglogo.png',
875 )
875 )
876 coreconfigitem('web', 'logourl',
876 coreconfigitem('web', 'logourl',
877 default='https://mercurial-scm.org/',
877 default='https://mercurial-scm.org/',
878 )
878 )
879 coreconfigitem('web', 'accesslog',
879 coreconfigitem('web', 'accesslog',
880 default='-',
880 default='-',
881 )
881 )
882 coreconfigitem('web', 'address',
882 coreconfigitem('web', 'address',
883 default='',
883 default='',
884 )
884 )
885 coreconfigitem('web', 'allow_archive',
885 coreconfigitem('web', 'allow_archive',
886 default=list,
886 default=list,
887 )
887 )
888 coreconfigitem('web', 'allow_read',
888 coreconfigitem('web', 'allow_read',
889 default=list,
889 default=list,
890 )
890 )
891 coreconfigitem('web', 'baseurl',
891 coreconfigitem('web', 'baseurl',
892 default=None,
892 default=None,
893 )
893 )
894 coreconfigitem('web', 'cacerts',
894 coreconfigitem('web', 'cacerts',
895 default=None,
895 default=None,
896 )
896 )
897 coreconfigitem('web', 'certificate',
897 coreconfigitem('web', 'certificate',
898 default=None,
898 default=None,
899 )
899 )
900 coreconfigitem('web', 'collapse',
900 coreconfigitem('web', 'collapse',
901 default=False,
901 default=False,
902 )
902 )
903 coreconfigitem('web', 'csp',
903 coreconfigitem('web', 'csp',
904 default=None,
904 default=None,
905 )
905 )
906 coreconfigitem('web', 'deny_read',
906 coreconfigitem('web', 'deny_read',
907 default=list,
907 default=list,
908 )
908 )
909 coreconfigitem('web', 'descend',
909 coreconfigitem('web', 'descend',
910 default=True,
910 default=True,
911 )
911 )
912 coreconfigitem('web', 'description',
912 coreconfigitem('web', 'description',
913 default="",
913 default="",
914 )
914 )
915 coreconfigitem('web', 'encoding',
915 coreconfigitem('web', 'encoding',
916 default=lambda: encoding.encoding,
916 default=lambda: encoding.encoding,
917 )
917 )
918 coreconfigitem('web', 'errorlog',
918 coreconfigitem('web', 'errorlog',
919 default='-',
919 default='-',
920 )
920 )
921 coreconfigitem('web', 'ipv6',
921 coreconfigitem('web', 'ipv6',
922 default=False,
922 default=False,
923 )
923 )
924 coreconfigitem('web', 'maxchanges',
924 coreconfigitem('web', 'maxchanges',
925 default=10,
925 default=10,
926 )
926 )
927 coreconfigitem('web', 'maxfiles',
927 coreconfigitem('web', 'maxfiles',
928 default=10,
928 default=10,
929 )
929 )
930 coreconfigitem('web', 'maxshortchanges',
930 coreconfigitem('web', 'maxshortchanges',
931 default=60,
931 default=60,
932 )
932 )
933 coreconfigitem('web', 'motd',
933 coreconfigitem('web', 'motd',
934 default='',
934 default='',
935 )
935 )
936 coreconfigitem('web', 'name',
936 coreconfigitem('web', 'name',
937 default=dynamicdefault,
937 default=dynamicdefault,
938 )
938 )
939 coreconfigitem('web', 'port',
939 coreconfigitem('web', 'port',
940 default=8000,
940 default=8000,
941 )
941 )
942 coreconfigitem('web', 'prefix',
942 coreconfigitem('web', 'prefix',
943 default='',
943 default='',
944 )
944 )
945 coreconfigitem('web', 'push_ssl',
945 coreconfigitem('web', 'push_ssl',
946 default=True,
946 default=True,
947 )
947 )
948 coreconfigitem('web', 'refreshinterval',
948 coreconfigitem('web', 'refreshinterval',
949 default=20,
949 default=20,
950 )
950 )
951 coreconfigitem('web', 'stripes',
951 coreconfigitem('web', 'stripes',
952 default=1,
952 default=1,
953 )
953 )
954 coreconfigitem('web', 'style',
954 coreconfigitem('web', 'style',
955 default='paper',
955 default='paper',
956 )
956 )
957 coreconfigitem('web', 'templates',
957 coreconfigitem('web', 'templates',
958 default=None,
958 default=None,
959 )
959 )
960 coreconfigitem('web', 'view',
960 coreconfigitem('web', 'view',
961 default='served',
961 default='served',
962 )
962 )
963 coreconfigitem('worker', 'backgroundclose',
963 coreconfigitem('worker', 'backgroundclose',
964 default=dynamicdefault,
964 default=dynamicdefault,
965 )
965 )
966 # Windows defaults to a limit of 512 open files. A buffer of 128
966 # Windows defaults to a limit of 512 open files. A buffer of 128
967 # should give us enough headway.
967 # should give us enough headway.
968 coreconfigitem('worker', 'backgroundclosemaxqueue',
968 coreconfigitem('worker', 'backgroundclosemaxqueue',
969 default=384,
969 default=384,
970 )
970 )
971 coreconfigitem('worker', 'backgroundcloseminfilecount',
971 coreconfigitem('worker', 'backgroundcloseminfilecount',
972 default=2048,
972 default=2048,
973 )
973 )
974 coreconfigitem('worker', 'backgroundclosethreadcount',
974 coreconfigitem('worker', 'backgroundclosethreadcount',
975 default=4,
975 default=4,
976 )
976 )
977 coreconfigitem('worker', 'numcpus',
977 coreconfigitem('worker', 'numcpus',
978 default=None,
978 default=None,
979 )
979 )
General Comments 0
You need to be logged in to leave comments. Login now