##// END OF EJS Templates
configitems: register 'email.to' and 'patchbomb.to'
Yuya Nishihara -
r34912:645b6684 stable
parent child Browse files
Show More
@@ -1,795 +1,798 b''
1 # patchbomb.py - sending Mercurial changesets as patch emails
1 # patchbomb.py - sending Mercurial changesets as patch emails
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 '''command to send changesets as (a series of) patch emails
8 '''command to send changesets as (a series of) patch emails
9
9
10 The series is started off with a "[PATCH 0 of N]" introduction, which
10 The series is started off with a "[PATCH 0 of N]" introduction, which
11 describes the series as a whole.
11 describes the series as a whole.
12
12
13 Each patch email has a Subject line of "[PATCH M of N] ...", using the
13 Each patch email has a Subject line of "[PATCH M of N] ...", using the
14 first line of the changeset description as the subject text. The
14 first line of the changeset description as the subject text. The
15 message contains two or three body parts:
15 message contains two or three body parts:
16
16
17 - The changeset description.
17 - The changeset description.
18 - [Optional] The result of running diffstat on the patch.
18 - [Optional] The result of running diffstat on the patch.
19 - The patch itself, as generated by :hg:`export`.
19 - The patch itself, as generated by :hg:`export`.
20
20
21 Each message refers to the first in the series using the In-Reply-To
21 Each message refers to the first in the series using the In-Reply-To
22 and References headers, so they will show up as a sequence in threaded
22 and References headers, so they will show up as a sequence in threaded
23 mail and news readers, and in mail archives.
23 mail and news readers, and in mail archives.
24
24
25 To configure other defaults, add a section like this to your
25 To configure other defaults, add a section like this to your
26 configuration file::
26 configuration file::
27
27
28 [email]
28 [email]
29 from = My Name <my@email>
29 from = My Name <my@email>
30 to = recipient1, recipient2, ...
30 to = recipient1, recipient2, ...
31 cc = cc1, cc2, ...
31 cc = cc1, cc2, ...
32 bcc = bcc1, bcc2, ...
32 bcc = bcc1, bcc2, ...
33 reply-to = address1, address2, ...
33 reply-to = address1, address2, ...
34
34
35 Use ``[patchbomb]`` as configuration section name if you need to
35 Use ``[patchbomb]`` as configuration section name if you need to
36 override global ``[email]`` address settings.
36 override global ``[email]`` address settings.
37
37
38 Then you can use the :hg:`email` command to mail a series of
38 Then you can use the :hg:`email` command to mail a series of
39 changesets as a patchbomb.
39 changesets as a patchbomb.
40
40
41 You can also either configure the method option in the email section
41 You can also either configure the method option in the email section
42 to be a sendmail compatible mailer or fill out the [smtp] section so
42 to be a sendmail compatible mailer or fill out the [smtp] section so
43 that the patchbomb extension can automatically send patchbombs
43 that the patchbomb extension can automatically send patchbombs
44 directly from the commandline. See the [email] and [smtp] sections in
44 directly from the commandline. See the [email] and [smtp] sections in
45 hgrc(5) for details.
45 hgrc(5) for details.
46
46
47 By default, :hg:`email` will prompt for a ``To`` or ``CC`` header if
47 By default, :hg:`email` will prompt for a ``To`` or ``CC`` header if
48 you do not supply one via configuration or the command line. You can
48 you do not supply one via configuration or the command line. You can
49 override this to never prompt by configuring an empty value::
49 override this to never prompt by configuring an empty value::
50
50
51 [email]
51 [email]
52 cc =
52 cc =
53
53
54 You can control the default inclusion of an introduction message with the
54 You can control the default inclusion of an introduction message with the
55 ``patchbomb.intro`` configuration option. The configuration is always
55 ``patchbomb.intro`` configuration option. The configuration is always
56 overwritten by command line flags like --intro and --desc::
56 overwritten by command line flags like --intro and --desc::
57
57
58 [patchbomb]
58 [patchbomb]
59 intro=auto # include introduction message if more than 1 patch (default)
59 intro=auto # include introduction message if more than 1 patch (default)
60 intro=never # never include an introduction message
60 intro=never # never include an introduction message
61 intro=always # always include an introduction message
61 intro=always # always include an introduction message
62
62
63 You can specify a template for flags to be added in subject prefixes. Flags
63 You can specify a template for flags to be added in subject prefixes. Flags
64 specified by --flag option are exported as ``{flags}`` keyword::
64 specified by --flag option are exported as ``{flags}`` keyword::
65
65
66 [patchbomb]
66 [patchbomb]
67 flagtemplate = "{separate(' ',
67 flagtemplate = "{separate(' ',
68 ifeq(branch, 'default', '', branch|upper),
68 ifeq(branch, 'default', '', branch|upper),
69 flags)}"
69 flags)}"
70
70
71 You can set patchbomb to always ask for confirmation by setting
71 You can set patchbomb to always ask for confirmation by setting
72 ``patchbomb.confirm`` to true.
72 ``patchbomb.confirm`` to true.
73 '''
73 '''
74 from __future__ import absolute_import
74 from __future__ import absolute_import
75
75
76 import email as emailmod
76 import email as emailmod
77 import errno
77 import errno
78 import os
78 import os
79 import socket
79 import socket
80 import tempfile
80 import tempfile
81
81
82 from mercurial.i18n import _
82 from mercurial.i18n import _
83 from mercurial import (
83 from mercurial import (
84 cmdutil,
84 cmdutil,
85 commands,
85 commands,
86 error,
86 error,
87 formatter,
87 formatter,
88 hg,
88 hg,
89 mail,
89 mail,
90 node as nodemod,
90 node as nodemod,
91 patch,
91 patch,
92 registrar,
92 registrar,
93 repair,
93 repair,
94 scmutil,
94 scmutil,
95 templater,
95 templater,
96 util,
96 util,
97 )
97 )
98 stringio = util.stringio
98 stringio = util.stringio
99
99
100 cmdtable = {}
100 cmdtable = {}
101 command = registrar.command(cmdtable)
101 command = registrar.command(cmdtable)
102
102
103 configtable = {}
103 configtable = {}
104 configitem = registrar.configitem(configtable)
104 configitem = registrar.configitem(configtable)
105
105
106 configitem('patchbomb', 'bundletype',
106 configitem('patchbomb', 'bundletype',
107 default=None,
107 default=None,
108 )
108 )
109 configitem('patchbomb', 'bcc',
109 configitem('patchbomb', 'bcc',
110 default=None,
110 default=None,
111 )
111 )
112 configitem('patchbomb', 'cc',
112 configitem('patchbomb', 'cc',
113 default=None,
113 default=None,
114 )
114 )
115 configitem('patchbomb', 'confirm',
115 configitem('patchbomb', 'confirm',
116 default=False,
116 default=False,
117 )
117 )
118 configitem('patchbomb', 'flagtemplate',
118 configitem('patchbomb', 'flagtemplate',
119 default=None,
119 default=None,
120 )
120 )
121 configitem('patchbomb', 'from',
121 configitem('patchbomb', 'from',
122 default=None,
122 default=None,
123 )
123 )
124 configitem('patchbomb', 'intro',
124 configitem('patchbomb', 'intro',
125 default='auto',
125 default='auto',
126 )
126 )
127 configitem('patchbomb', 'publicurl',
127 configitem('patchbomb', 'publicurl',
128 default=None,
128 default=None,
129 )
129 )
130 configitem('patchbomb', 'reply-to',
130 configitem('patchbomb', 'reply-to',
131 default=None,
131 default=None,
132 )
132 )
133 configitem('patchbomb', 'to',
134 default=None,
135 )
133
136
134 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
137 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
135 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
138 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
136 # be specifying the version(s) of Mercurial they are tested with, or
139 # be specifying the version(s) of Mercurial they are tested with, or
137 # leave the attribute unspecified.
140 # leave the attribute unspecified.
138 testedwith = 'ships-with-hg-core'
141 testedwith = 'ships-with-hg-core'
139
142
140 def _addpullheader(seq, ctx):
143 def _addpullheader(seq, ctx):
141 """Add a header pointing to a public URL where the changeset is available
144 """Add a header pointing to a public URL where the changeset is available
142 """
145 """
143 repo = ctx.repo()
146 repo = ctx.repo()
144 # experimental config: patchbomb.publicurl
147 # experimental config: patchbomb.publicurl
145 # waiting for some logic that check that the changeset are available on the
148 # waiting for some logic that check that the changeset are available on the
146 # destination before patchbombing anything.
149 # destination before patchbombing anything.
147 publicurl = repo.ui.config('patchbomb', 'publicurl')
150 publicurl = repo.ui.config('patchbomb', 'publicurl')
148 if publicurl:
151 if publicurl:
149 return ('Available At %s\n'
152 return ('Available At %s\n'
150 '# hg pull %s -r %s' % (publicurl, publicurl, ctx))
153 '# hg pull %s -r %s' % (publicurl, publicurl, ctx))
151 return None
154 return None
152
155
153 def uisetup(ui):
156 def uisetup(ui):
154 cmdutil.extraexport.append('pullurl')
157 cmdutil.extraexport.append('pullurl')
155 cmdutil.extraexportmap['pullurl'] = _addpullheader
158 cmdutil.extraexportmap['pullurl'] = _addpullheader
156
159
157 def reposetup(ui, repo):
160 def reposetup(ui, repo):
158 if not repo.local():
161 if not repo.local():
159 return
162 return
160 repo._wlockfreeprefix.add('last-email.txt')
163 repo._wlockfreeprefix.add('last-email.txt')
161
164
162 def prompt(ui, prompt, default=None, rest=':'):
165 def prompt(ui, prompt, default=None, rest=':'):
163 if default:
166 if default:
164 prompt += ' [%s]' % default
167 prompt += ' [%s]' % default
165 return ui.prompt(prompt + rest, default)
168 return ui.prompt(prompt + rest, default)
166
169
167 def introwanted(ui, opts, number):
170 def introwanted(ui, opts, number):
168 '''is an introductory message apparently wanted?'''
171 '''is an introductory message apparently wanted?'''
169 introconfig = ui.config('patchbomb', 'intro')
172 introconfig = ui.config('patchbomb', 'intro')
170 if opts.get('intro') or opts.get('desc'):
173 if opts.get('intro') or opts.get('desc'):
171 intro = True
174 intro = True
172 elif introconfig == 'always':
175 elif introconfig == 'always':
173 intro = True
176 intro = True
174 elif introconfig == 'never':
177 elif introconfig == 'never':
175 intro = False
178 intro = False
176 elif introconfig == 'auto':
179 elif introconfig == 'auto':
177 intro = 1 < number
180 intro = 1 < number
178 else:
181 else:
179 ui.write_err(_('warning: invalid patchbomb.intro value "%s"\n')
182 ui.write_err(_('warning: invalid patchbomb.intro value "%s"\n')
180 % introconfig)
183 % introconfig)
181 ui.write_err(_('(should be one of always, never, auto)\n'))
184 ui.write_err(_('(should be one of always, never, auto)\n'))
182 intro = 1 < number
185 intro = 1 < number
183 return intro
186 return intro
184
187
185 def _formatflags(ui, repo, rev, flags):
188 def _formatflags(ui, repo, rev, flags):
186 """build flag string optionally by template"""
189 """build flag string optionally by template"""
187 tmpl = ui.config('patchbomb', 'flagtemplate')
190 tmpl = ui.config('patchbomb', 'flagtemplate')
188 if not tmpl:
191 if not tmpl:
189 return ' '.join(flags)
192 return ' '.join(flags)
190 out = util.stringio()
193 out = util.stringio()
191 opts = {'template': templater.unquotestring(tmpl)}
194 opts = {'template': templater.unquotestring(tmpl)}
192 with formatter.templateformatter(ui, out, 'patchbombflag', opts) as fm:
195 with formatter.templateformatter(ui, out, 'patchbombflag', opts) as fm:
193 fm.startitem()
196 fm.startitem()
194 fm.context(ctx=repo[rev])
197 fm.context(ctx=repo[rev])
195 fm.write('flags', '%s', fm.formatlist(flags, name='flag'))
198 fm.write('flags', '%s', fm.formatlist(flags, name='flag'))
196 return out.getvalue()
199 return out.getvalue()
197
200
198 def _formatprefix(ui, repo, rev, flags, idx, total, numbered):
201 def _formatprefix(ui, repo, rev, flags, idx, total, numbered):
199 """build prefix to patch subject"""
202 """build prefix to patch subject"""
200 flag = _formatflags(ui, repo, rev, flags)
203 flag = _formatflags(ui, repo, rev, flags)
201 if flag:
204 if flag:
202 flag = ' ' + flag
205 flag = ' ' + flag
203
206
204 if not numbered:
207 if not numbered:
205 return '[PATCH%s]' % flag
208 return '[PATCH%s]' % flag
206 else:
209 else:
207 tlen = len(str(total))
210 tlen = len(str(total))
208 return '[PATCH %0*d of %d%s]' % (tlen, idx, total, flag)
211 return '[PATCH %0*d of %d%s]' % (tlen, idx, total, flag)
209
212
210 def makepatch(ui, repo, rev, patchlines, opts, _charsets, idx, total, numbered,
213 def makepatch(ui, repo, rev, patchlines, opts, _charsets, idx, total, numbered,
211 patchname=None):
214 patchname=None):
212
215
213 desc = []
216 desc = []
214 node = None
217 node = None
215 body = ''
218 body = ''
216
219
217 for line in patchlines:
220 for line in patchlines:
218 if line.startswith('#'):
221 if line.startswith('#'):
219 if line.startswith('# Node ID'):
222 if line.startswith('# Node ID'):
220 node = line.split()[-1]
223 node = line.split()[-1]
221 continue
224 continue
222 if line.startswith('diff -r') or line.startswith('diff --git'):
225 if line.startswith('diff -r') or line.startswith('diff --git'):
223 break
226 break
224 desc.append(line)
227 desc.append(line)
225
228
226 if not patchname and not node:
229 if not patchname and not node:
227 raise ValueError
230 raise ValueError
228
231
229 if opts.get('attach') and not opts.get('body'):
232 if opts.get('attach') and not opts.get('body'):
230 body = ('\n'.join(desc[1:]).strip() or
233 body = ('\n'.join(desc[1:]).strip() or
231 'Patch subject is complete summary.')
234 'Patch subject is complete summary.')
232 body += '\n\n\n'
235 body += '\n\n\n'
233
236
234 if opts.get('plain'):
237 if opts.get('plain'):
235 while patchlines and patchlines[0].startswith('# '):
238 while patchlines and patchlines[0].startswith('# '):
236 patchlines.pop(0)
239 patchlines.pop(0)
237 if patchlines:
240 if patchlines:
238 patchlines.pop(0)
241 patchlines.pop(0)
239 while patchlines and not patchlines[0].strip():
242 while patchlines and not patchlines[0].strip():
240 patchlines.pop(0)
243 patchlines.pop(0)
241
244
242 ds = patch.diffstat(patchlines)
245 ds = patch.diffstat(patchlines)
243 if opts.get('diffstat'):
246 if opts.get('diffstat'):
244 body += ds + '\n\n'
247 body += ds + '\n\n'
245
248
246 addattachment = opts.get('attach') or opts.get('inline')
249 addattachment = opts.get('attach') or opts.get('inline')
247 if not addattachment or opts.get('body'):
250 if not addattachment or opts.get('body'):
248 body += '\n'.join(patchlines)
251 body += '\n'.join(patchlines)
249
252
250 if addattachment:
253 if addattachment:
251 msg = emailmod.MIMEMultipart.MIMEMultipart()
254 msg = emailmod.MIMEMultipart.MIMEMultipart()
252 if body:
255 if body:
253 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
256 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
254 p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch',
257 p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch',
255 opts.get('test'))
258 opts.get('test'))
256 binnode = nodemod.bin(node)
259 binnode = nodemod.bin(node)
257 # if node is mq patch, it will have the patch file's name as a tag
260 # if node is mq patch, it will have the patch file's name as a tag
258 if not patchname:
261 if not patchname:
259 patchtags = [t for t in repo.nodetags(binnode)
262 patchtags = [t for t in repo.nodetags(binnode)
260 if t.endswith('.patch') or t.endswith('.diff')]
263 if t.endswith('.patch') or t.endswith('.diff')]
261 if patchtags:
264 if patchtags:
262 patchname = patchtags[0]
265 patchname = patchtags[0]
263 elif total > 1:
266 elif total > 1:
264 patchname = cmdutil.makefilename(repo, '%b-%n.patch',
267 patchname = cmdutil.makefilename(repo, '%b-%n.patch',
265 binnode, seqno=idx,
268 binnode, seqno=idx,
266 total=total)
269 total=total)
267 else:
270 else:
268 patchname = cmdutil.makefilename(repo, '%b.patch', binnode)
271 patchname = cmdutil.makefilename(repo, '%b.patch', binnode)
269 disposition = 'inline'
272 disposition = 'inline'
270 if opts.get('attach'):
273 if opts.get('attach'):
271 disposition = 'attachment'
274 disposition = 'attachment'
272 p['Content-Disposition'] = disposition + '; filename=' + patchname
275 p['Content-Disposition'] = disposition + '; filename=' + patchname
273 msg.attach(p)
276 msg.attach(p)
274 else:
277 else:
275 msg = mail.mimetextpatch(body, display=opts.get('test'))
278 msg = mail.mimetextpatch(body, display=opts.get('test'))
276
279
277 prefix = _formatprefix(ui, repo, rev, opts.get('flag'), idx, total,
280 prefix = _formatprefix(ui, repo, rev, opts.get('flag'), idx, total,
278 numbered)
281 numbered)
279 subj = desc[0].strip().rstrip('. ')
282 subj = desc[0].strip().rstrip('. ')
280 if not numbered:
283 if not numbered:
281 subj = ' '.join([prefix, opts.get('subject') or subj])
284 subj = ' '.join([prefix, opts.get('subject') or subj])
282 else:
285 else:
283 subj = ' '.join([prefix, subj])
286 subj = ' '.join([prefix, subj])
284 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
287 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
285 msg['X-Mercurial-Node'] = node
288 msg['X-Mercurial-Node'] = node
286 msg['X-Mercurial-Series-Index'] = '%i' % idx
289 msg['X-Mercurial-Series-Index'] = '%i' % idx
287 msg['X-Mercurial-Series-Total'] = '%i' % total
290 msg['X-Mercurial-Series-Total'] = '%i' % total
288 return msg, subj, ds
291 return msg, subj, ds
289
292
290 def _getpatches(repo, revs, **opts):
293 def _getpatches(repo, revs, **opts):
291 """return a list of patches for a list of revisions
294 """return a list of patches for a list of revisions
292
295
293 Each patch in the list is itself a list of lines.
296 Each patch in the list is itself a list of lines.
294 """
297 """
295 ui = repo.ui
298 ui = repo.ui
296 prev = repo['.'].rev()
299 prev = repo['.'].rev()
297 for r in revs:
300 for r in revs:
298 if r == prev and (repo[None].files() or repo[None].deleted()):
301 if r == prev and (repo[None].files() or repo[None].deleted()):
299 ui.warn(_('warning: working directory has '
302 ui.warn(_('warning: working directory has '
300 'uncommitted changes\n'))
303 'uncommitted changes\n'))
301 output = stringio()
304 output = stringio()
302 cmdutil.export(repo, [r], fp=output,
305 cmdutil.export(repo, [r], fp=output,
303 opts=patch.difffeatureopts(ui, opts, git=True))
306 opts=patch.difffeatureopts(ui, opts, git=True))
304 yield output.getvalue().split('\n')
307 yield output.getvalue().split('\n')
305 def _getbundle(repo, dest, **opts):
308 def _getbundle(repo, dest, **opts):
306 """return a bundle containing changesets missing in "dest"
309 """return a bundle containing changesets missing in "dest"
307
310
308 The `opts` keyword-arguments are the same as the one accepted by the
311 The `opts` keyword-arguments are the same as the one accepted by the
309 `bundle` command.
312 `bundle` command.
310
313
311 The bundle is a returned as a single in-memory binary blob.
314 The bundle is a returned as a single in-memory binary blob.
312 """
315 """
313 ui = repo.ui
316 ui = repo.ui
314 tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-')
317 tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-')
315 tmpfn = os.path.join(tmpdir, 'bundle')
318 tmpfn = os.path.join(tmpdir, 'bundle')
316 btype = ui.config('patchbomb', 'bundletype')
319 btype = ui.config('patchbomb', 'bundletype')
317 if btype:
320 if btype:
318 opts['type'] = btype
321 opts['type'] = btype
319 try:
322 try:
320 commands.bundle(ui, repo, tmpfn, dest, **opts)
323 commands.bundle(ui, repo, tmpfn, dest, **opts)
321 return util.readfile(tmpfn)
324 return util.readfile(tmpfn)
322 finally:
325 finally:
323 try:
326 try:
324 os.unlink(tmpfn)
327 os.unlink(tmpfn)
325 except OSError:
328 except OSError:
326 pass
329 pass
327 os.rmdir(tmpdir)
330 os.rmdir(tmpdir)
328
331
329 def _getdescription(repo, defaultbody, sender, **opts):
332 def _getdescription(repo, defaultbody, sender, **opts):
330 """obtain the body of the introduction message and return it
333 """obtain the body of the introduction message and return it
331
334
332 This is also used for the body of email with an attached bundle.
335 This is also used for the body of email with an attached bundle.
333
336
334 The body can be obtained either from the command line option or entered by
337 The body can be obtained either from the command line option or entered by
335 the user through the editor.
338 the user through the editor.
336 """
339 """
337 ui = repo.ui
340 ui = repo.ui
338 if opts.get('desc'):
341 if opts.get('desc'):
339 body = open(opts.get('desc')).read()
342 body = open(opts.get('desc')).read()
340 else:
343 else:
341 ui.write(_('\nWrite the introductory message for the '
344 ui.write(_('\nWrite the introductory message for the '
342 'patch series.\n\n'))
345 'patch series.\n\n'))
343 body = ui.edit(defaultbody, sender, repopath=repo.path,
346 body = ui.edit(defaultbody, sender, repopath=repo.path,
344 action='patchbombbody')
347 action='patchbombbody')
345 # Save series description in case sendmail fails
348 # Save series description in case sendmail fails
346 msgfile = repo.vfs('last-email.txt', 'wb')
349 msgfile = repo.vfs('last-email.txt', 'wb')
347 msgfile.write(body)
350 msgfile.write(body)
348 msgfile.close()
351 msgfile.close()
349 return body
352 return body
350
353
351 def _getbundlemsgs(repo, sender, bundle, **opts):
354 def _getbundlemsgs(repo, sender, bundle, **opts):
352 """Get the full email for sending a given bundle
355 """Get the full email for sending a given bundle
353
356
354 This function returns a list of "email" tuples (subject, content, None).
357 This function returns a list of "email" tuples (subject, content, None).
355 The list is always one message long in that case.
358 The list is always one message long in that case.
356 """
359 """
357 ui = repo.ui
360 ui = repo.ui
358 _charsets = mail._charsets(ui)
361 _charsets = mail._charsets(ui)
359 subj = (opts.get('subject')
362 subj = (opts.get('subject')
360 or prompt(ui, 'Subject:', 'A bundle for your repository'))
363 or prompt(ui, 'Subject:', 'A bundle for your repository'))
361
364
362 body = _getdescription(repo, '', sender, **opts)
365 body = _getdescription(repo, '', sender, **opts)
363 msg = emailmod.MIMEMultipart.MIMEMultipart()
366 msg = emailmod.MIMEMultipart.MIMEMultipart()
364 if body:
367 if body:
365 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
368 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
366 datapart = emailmod.MIMEBase.MIMEBase('application', 'x-mercurial-bundle')
369 datapart = emailmod.MIMEBase.MIMEBase('application', 'x-mercurial-bundle')
367 datapart.set_payload(bundle)
370 datapart.set_payload(bundle)
368 bundlename = '%s.hg' % opts.get('bundlename', 'bundle')
371 bundlename = '%s.hg' % opts.get('bundlename', 'bundle')
369 datapart.add_header('Content-Disposition', 'attachment',
372 datapart.add_header('Content-Disposition', 'attachment',
370 filename=bundlename)
373 filename=bundlename)
371 emailmod.Encoders.encode_base64(datapart)
374 emailmod.Encoders.encode_base64(datapart)
372 msg.attach(datapart)
375 msg.attach(datapart)
373 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
376 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
374 return [(msg, subj, None)]
377 return [(msg, subj, None)]
375
378
376 def _makeintro(repo, sender, revs, patches, **opts):
379 def _makeintro(repo, sender, revs, patches, **opts):
377 """make an introduction email, asking the user for content if needed
380 """make an introduction email, asking the user for content if needed
378
381
379 email is returned as (subject, body, cumulative-diffstat)"""
382 email is returned as (subject, body, cumulative-diffstat)"""
380 ui = repo.ui
383 ui = repo.ui
381 _charsets = mail._charsets(ui)
384 _charsets = mail._charsets(ui)
382
385
383 # use the last revision which is likely to be a bookmarked head
386 # use the last revision which is likely to be a bookmarked head
384 prefix = _formatprefix(ui, repo, revs.last(), opts.get('flag'),
387 prefix = _formatprefix(ui, repo, revs.last(), opts.get('flag'),
385 0, len(patches), numbered=True)
388 0, len(patches), numbered=True)
386 subj = (opts.get('subject') or
389 subj = (opts.get('subject') or
387 prompt(ui, '(optional) Subject: ', rest=prefix, default=''))
390 prompt(ui, '(optional) Subject: ', rest=prefix, default=''))
388 if not subj:
391 if not subj:
389 return None # skip intro if the user doesn't bother
392 return None # skip intro if the user doesn't bother
390
393
391 subj = prefix + ' ' + subj
394 subj = prefix + ' ' + subj
392
395
393 body = ''
396 body = ''
394 if opts.get('diffstat'):
397 if opts.get('diffstat'):
395 # generate a cumulative diffstat of the whole patch series
398 # generate a cumulative diffstat of the whole patch series
396 diffstat = patch.diffstat(sum(patches, []))
399 diffstat = patch.diffstat(sum(patches, []))
397 body = '\n' + diffstat
400 body = '\n' + diffstat
398 else:
401 else:
399 diffstat = None
402 diffstat = None
400
403
401 body = _getdescription(repo, body, sender, **opts)
404 body = _getdescription(repo, body, sender, **opts)
402 msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
405 msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
403 msg['Subject'] = mail.headencode(ui, subj, _charsets,
406 msg['Subject'] = mail.headencode(ui, subj, _charsets,
404 opts.get('test'))
407 opts.get('test'))
405 return (msg, subj, diffstat)
408 return (msg, subj, diffstat)
406
409
407 def _getpatchmsgs(repo, sender, revs, patchnames=None, **opts):
410 def _getpatchmsgs(repo, sender, revs, patchnames=None, **opts):
408 """return a list of emails from a list of patches
411 """return a list of emails from a list of patches
409
412
410 This involves introduction message creation if necessary.
413 This involves introduction message creation if necessary.
411
414
412 This function returns a list of "email" tuples (subject, content, None).
415 This function returns a list of "email" tuples (subject, content, None).
413 """
416 """
414 ui = repo.ui
417 ui = repo.ui
415 _charsets = mail._charsets(ui)
418 _charsets = mail._charsets(ui)
416 patches = list(_getpatches(repo, revs, **opts))
419 patches = list(_getpatches(repo, revs, **opts))
417 msgs = []
420 msgs = []
418
421
419 ui.write(_('this patch series consists of %d patches.\n\n')
422 ui.write(_('this patch series consists of %d patches.\n\n')
420 % len(patches))
423 % len(patches))
421
424
422 # build the intro message, or skip it if the user declines
425 # build the intro message, or skip it if the user declines
423 if introwanted(ui, opts, len(patches)):
426 if introwanted(ui, opts, len(patches)):
424 msg = _makeintro(repo, sender, revs, patches, **opts)
427 msg = _makeintro(repo, sender, revs, patches, **opts)
425 if msg:
428 if msg:
426 msgs.append(msg)
429 msgs.append(msg)
427
430
428 # are we going to send more than one message?
431 # are we going to send more than one message?
429 numbered = len(msgs) + len(patches) > 1
432 numbered = len(msgs) + len(patches) > 1
430
433
431 # now generate the actual patch messages
434 # now generate the actual patch messages
432 name = None
435 name = None
433 assert len(revs) == len(patches)
436 assert len(revs) == len(patches)
434 for i, (r, p) in enumerate(zip(revs, patches)):
437 for i, (r, p) in enumerate(zip(revs, patches)):
435 if patchnames:
438 if patchnames:
436 name = patchnames[i]
439 name = patchnames[i]
437 msg = makepatch(ui, repo, r, p, opts, _charsets, i + 1,
440 msg = makepatch(ui, repo, r, p, opts, _charsets, i + 1,
438 len(patches), numbered, name)
441 len(patches), numbered, name)
439 msgs.append(msg)
442 msgs.append(msg)
440
443
441 return msgs
444 return msgs
442
445
443 def _getoutgoing(repo, dest, revs):
446 def _getoutgoing(repo, dest, revs):
444 '''Return the revisions present locally but not in dest'''
447 '''Return the revisions present locally but not in dest'''
445 ui = repo.ui
448 ui = repo.ui
446 url = ui.expandpath(dest or 'default-push', dest or 'default')
449 url = ui.expandpath(dest or 'default-push', dest or 'default')
447 url = hg.parseurl(url)[0]
450 url = hg.parseurl(url)[0]
448 ui.status(_('comparing with %s\n') % util.hidepassword(url))
451 ui.status(_('comparing with %s\n') % util.hidepassword(url))
449
452
450 revs = [r for r in revs if r >= 0]
453 revs = [r for r in revs if r >= 0]
451 if not revs:
454 if not revs:
452 revs = [len(repo) - 1]
455 revs = [len(repo) - 1]
453 revs = repo.revs('outgoing(%s) and ::%ld', dest or '', revs)
456 revs = repo.revs('outgoing(%s) and ::%ld', dest or '', revs)
454 if not revs:
457 if not revs:
455 ui.status(_("no changes found\n"))
458 ui.status(_("no changes found\n"))
456 return revs
459 return revs
457
460
458 emailopts = [
461 emailopts = [
459 ('', 'body', None, _('send patches as inline message text (default)')),
462 ('', 'body', None, _('send patches as inline message text (default)')),
460 ('a', 'attach', None, _('send patches as attachments')),
463 ('a', 'attach', None, _('send patches as attachments')),
461 ('i', 'inline', None, _('send patches as inline attachments')),
464 ('i', 'inline', None, _('send patches as inline attachments')),
462 ('', 'bcc', [], _('email addresses of blind carbon copy recipients')),
465 ('', 'bcc', [], _('email addresses of blind carbon copy recipients')),
463 ('c', 'cc', [], _('email addresses of copy recipients')),
466 ('c', 'cc', [], _('email addresses of copy recipients')),
464 ('', 'confirm', None, _('ask for confirmation before sending')),
467 ('', 'confirm', None, _('ask for confirmation before sending')),
465 ('d', 'diffstat', None, _('add diffstat output to messages')),
468 ('d', 'diffstat', None, _('add diffstat output to messages')),
466 ('', 'date', '', _('use the given date as the sending date')),
469 ('', 'date', '', _('use the given date as the sending date')),
467 ('', 'desc', '', _('use the given file as the series description')),
470 ('', 'desc', '', _('use the given file as the series description')),
468 ('f', 'from', '', _('email address of sender')),
471 ('f', 'from', '', _('email address of sender')),
469 ('n', 'test', None, _('print messages that would be sent')),
472 ('n', 'test', None, _('print messages that would be sent')),
470 ('m', 'mbox', '', _('write messages to mbox file instead of sending them')),
473 ('m', 'mbox', '', _('write messages to mbox file instead of sending them')),
471 ('', 'reply-to', [], _('email addresses replies should be sent to')),
474 ('', 'reply-to', [], _('email addresses replies should be sent to')),
472 ('s', 'subject', '', _('subject of first message (intro or single patch)')),
475 ('s', 'subject', '', _('subject of first message (intro or single patch)')),
473 ('', 'in-reply-to', '', _('message identifier to reply to')),
476 ('', 'in-reply-to', '', _('message identifier to reply to')),
474 ('', 'flag', [], _('flags to add in subject prefixes')),
477 ('', 'flag', [], _('flags to add in subject prefixes')),
475 ('t', 'to', [], _('email addresses of recipients'))]
478 ('t', 'to', [], _('email addresses of recipients'))]
476
479
477 @command('email',
480 @command('email',
478 [('g', 'git', None, _('use git extended diff format')),
481 [('g', 'git', None, _('use git extended diff format')),
479 ('', 'plain', None, _('omit hg patch header')),
482 ('', 'plain', None, _('omit hg patch header')),
480 ('o', 'outgoing', None,
483 ('o', 'outgoing', None,
481 _('send changes not found in the target repository')),
484 _('send changes not found in the target repository')),
482 ('b', 'bundle', None, _('send changes not in target as a binary bundle')),
485 ('b', 'bundle', None, _('send changes not in target as a binary bundle')),
483 ('B', 'bookmark', '', _('send changes only reachable by given bookmark')),
486 ('B', 'bookmark', '', _('send changes only reachable by given bookmark')),
484 ('', 'bundlename', 'bundle',
487 ('', 'bundlename', 'bundle',
485 _('name of the bundle attachment file'), _('NAME')),
488 _('name of the bundle attachment file'), _('NAME')),
486 ('r', 'rev', [], _('a revision to send'), _('REV')),
489 ('r', 'rev', [], _('a revision to send'), _('REV')),
487 ('', 'force', None, _('run even when remote repository is unrelated '
490 ('', 'force', None, _('run even when remote repository is unrelated '
488 '(with -b/--bundle)')),
491 '(with -b/--bundle)')),
489 ('', 'base', [], _('a base changeset to specify instead of a destination '
492 ('', 'base', [], _('a base changeset to specify instead of a destination '
490 '(with -b/--bundle)'), _('REV')),
493 '(with -b/--bundle)'), _('REV')),
491 ('', 'intro', None, _('send an introduction email for a single patch')),
494 ('', 'intro', None, _('send an introduction email for a single patch')),
492 ] + emailopts + cmdutil.remoteopts,
495 ] + emailopts + cmdutil.remoteopts,
493 _('hg email [OPTION]... [DEST]...'))
496 _('hg email [OPTION]... [DEST]...'))
494 def email(ui, repo, *revs, **opts):
497 def email(ui, repo, *revs, **opts):
495 '''send changesets by email
498 '''send changesets by email
496
499
497 By default, diffs are sent in the format generated by
500 By default, diffs are sent in the format generated by
498 :hg:`export`, one per message. The series starts with a "[PATCH 0
501 :hg:`export`, one per message. The series starts with a "[PATCH 0
499 of N]" introduction, which describes the series as a whole.
502 of N]" introduction, which describes the series as a whole.
500
503
501 Each patch email has a Subject line of "[PATCH M of N] ...", using
504 Each patch email has a Subject line of "[PATCH M of N] ...", using
502 the first line of the changeset description as the subject text.
505 the first line of the changeset description as the subject text.
503 The message contains two or three parts. First, the changeset
506 The message contains two or three parts. First, the changeset
504 description.
507 description.
505
508
506 With the -d/--diffstat option, if the diffstat program is
509 With the -d/--diffstat option, if the diffstat program is
507 installed, the result of running diffstat on the patch is inserted.
510 installed, the result of running diffstat on the patch is inserted.
508
511
509 Finally, the patch itself, as generated by :hg:`export`.
512 Finally, the patch itself, as generated by :hg:`export`.
510
513
511 With the -d/--diffstat or --confirm options, you will be presented
514 With the -d/--diffstat or --confirm options, you will be presented
512 with a final summary of all messages and asked for confirmation before
515 with a final summary of all messages and asked for confirmation before
513 the messages are sent.
516 the messages are sent.
514
517
515 By default the patch is included as text in the email body for
518 By default the patch is included as text in the email body for
516 easy reviewing. Using the -a/--attach option will instead create
519 easy reviewing. Using the -a/--attach option will instead create
517 an attachment for the patch. With -i/--inline an inline attachment
520 an attachment for the patch. With -i/--inline an inline attachment
518 will be created. You can include a patch both as text in the email
521 will be created. You can include a patch both as text in the email
519 body and as a regular or an inline attachment by combining the
522 body and as a regular or an inline attachment by combining the
520 -a/--attach or -i/--inline with the --body option.
523 -a/--attach or -i/--inline with the --body option.
521
524
522 With -B/--bookmark changesets reachable by the given bookmark are
525 With -B/--bookmark changesets reachable by the given bookmark are
523 selected.
526 selected.
524
527
525 With -o/--outgoing, emails will be generated for patches not found
528 With -o/--outgoing, emails will be generated for patches not found
526 in the destination repository (or only those which are ancestors
529 in the destination repository (or only those which are ancestors
527 of the specified revisions if any are provided)
530 of the specified revisions if any are provided)
528
531
529 With -b/--bundle, changesets are selected as for --outgoing, but a
532 With -b/--bundle, changesets are selected as for --outgoing, but a
530 single email containing a binary Mercurial bundle as an attachment
533 single email containing a binary Mercurial bundle as an attachment
531 will be sent. Use the ``patchbomb.bundletype`` config option to
534 will be sent. Use the ``patchbomb.bundletype`` config option to
532 control the bundle type as with :hg:`bundle --type`.
535 control the bundle type as with :hg:`bundle --type`.
533
536
534 With -m/--mbox, instead of previewing each patchbomb message in a
537 With -m/--mbox, instead of previewing each patchbomb message in a
535 pager or sending the messages directly, it will create a UNIX
538 pager or sending the messages directly, it will create a UNIX
536 mailbox file with the patch emails. This mailbox file can be
539 mailbox file with the patch emails. This mailbox file can be
537 previewed with any mail user agent which supports UNIX mbox
540 previewed with any mail user agent which supports UNIX mbox
538 files.
541 files.
539
542
540 With -n/--test, all steps will run, but mail will not be sent.
543 With -n/--test, all steps will run, but mail will not be sent.
541 You will be prompted for an email recipient address, a subject and
544 You will be prompted for an email recipient address, a subject and
542 an introductory message describing the patches of your patchbomb.
545 an introductory message describing the patches of your patchbomb.
543 Then when all is done, patchbomb messages are displayed.
546 Then when all is done, patchbomb messages are displayed.
544
547
545 In case email sending fails, you will find a backup of your series
548 In case email sending fails, you will find a backup of your series
546 introductory message in ``.hg/last-email.txt``.
549 introductory message in ``.hg/last-email.txt``.
547
550
548 The default behavior of this command can be customized through
551 The default behavior of this command can be customized through
549 configuration. (See :hg:`help patchbomb` for details)
552 configuration. (See :hg:`help patchbomb` for details)
550
553
551 Examples::
554 Examples::
552
555
553 hg email -r 3000 # send patch 3000 only
556 hg email -r 3000 # send patch 3000 only
554 hg email -r 3000 -r 3001 # send patches 3000 and 3001
557 hg email -r 3000 -r 3001 # send patches 3000 and 3001
555 hg email -r 3000:3005 # send patches 3000 through 3005
558 hg email -r 3000:3005 # send patches 3000 through 3005
556 hg email 3000 # send patch 3000 (deprecated)
559 hg email 3000 # send patch 3000 (deprecated)
557
560
558 hg email -o # send all patches not in default
561 hg email -o # send all patches not in default
559 hg email -o DEST # send all patches not in DEST
562 hg email -o DEST # send all patches not in DEST
560 hg email -o -r 3000 # send all ancestors of 3000 not in default
563 hg email -o -r 3000 # send all ancestors of 3000 not in default
561 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
564 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
562
565
563 hg email -B feature # send all ancestors of feature bookmark
566 hg email -B feature # send all ancestors of feature bookmark
564
567
565 hg email -b # send bundle of all patches not in default
568 hg email -b # send bundle of all patches not in default
566 hg email -b DEST # send bundle of all patches not in DEST
569 hg email -b DEST # send bundle of all patches not in DEST
567 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
570 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
568 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
571 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
569
572
570 hg email -o -m mbox && # generate an mbox file...
573 hg email -o -m mbox && # generate an mbox file...
571 mutt -R -f mbox # ... and view it with mutt
574 mutt -R -f mbox # ... and view it with mutt
572 hg email -o -m mbox && # generate an mbox file ...
575 hg email -o -m mbox && # generate an mbox file ...
573 formail -s sendmail \\ # ... and use formail to send from the mbox
576 formail -s sendmail \\ # ... and use formail to send from the mbox
574 -bm -t < mbox # ... using sendmail
577 -bm -t < mbox # ... using sendmail
575
578
576 Before using this command, you will need to enable email in your
579 Before using this command, you will need to enable email in your
577 hgrc. See the [email] section in hgrc(5) for details.
580 hgrc. See the [email] section in hgrc(5) for details.
578 '''
581 '''
579
582
580 _charsets = mail._charsets(ui)
583 _charsets = mail._charsets(ui)
581
584
582 bundle = opts.get('bundle')
585 bundle = opts.get('bundle')
583 date = opts.get('date')
586 date = opts.get('date')
584 mbox = opts.get('mbox')
587 mbox = opts.get('mbox')
585 outgoing = opts.get('outgoing')
588 outgoing = opts.get('outgoing')
586 rev = opts.get('rev')
589 rev = opts.get('rev')
587 bookmark = opts.get('bookmark')
590 bookmark = opts.get('bookmark')
588
591
589 if not (opts.get('test') or mbox):
592 if not (opts.get('test') or mbox):
590 # really sending
593 # really sending
591 mail.validateconfig(ui)
594 mail.validateconfig(ui)
592
595
593 if not (revs or rev or outgoing or bundle or bookmark):
596 if not (revs or rev or outgoing or bundle or bookmark):
594 raise error.Abort(_('specify at least one changeset with -B, -r or -o'))
597 raise error.Abort(_('specify at least one changeset with -B, -r or -o'))
595
598
596 if outgoing and bundle:
599 if outgoing and bundle:
597 raise error.Abort(_("--outgoing mode always on with --bundle;"
600 raise error.Abort(_("--outgoing mode always on with --bundle;"
598 " do not re-specify --outgoing"))
601 " do not re-specify --outgoing"))
599 if rev and bookmark:
602 if rev and bookmark:
600 raise error.Abort(_("-r and -B are mutually exclusive"))
603 raise error.Abort(_("-r and -B are mutually exclusive"))
601
604
602 if outgoing or bundle:
605 if outgoing or bundle:
603 if len(revs) > 1:
606 if len(revs) > 1:
604 raise error.Abort(_("too many destinations"))
607 raise error.Abort(_("too many destinations"))
605 if revs:
608 if revs:
606 dest = revs[0]
609 dest = revs[0]
607 else:
610 else:
608 dest = None
611 dest = None
609 revs = []
612 revs = []
610
613
611 if rev:
614 if rev:
612 if revs:
615 if revs:
613 raise error.Abort(_('use only one form to specify the revision'))
616 raise error.Abort(_('use only one form to specify the revision'))
614 revs = rev
617 revs = rev
615 elif bookmark:
618 elif bookmark:
616 if bookmark not in repo._bookmarks:
619 if bookmark not in repo._bookmarks:
617 raise error.Abort(_("bookmark '%s' not found") % bookmark)
620 raise error.Abort(_("bookmark '%s' not found") % bookmark)
618 revs = repair.stripbmrevset(repo, bookmark)
621 revs = repair.stripbmrevset(repo, bookmark)
619
622
620 revs = scmutil.revrange(repo, revs)
623 revs = scmutil.revrange(repo, revs)
621 if outgoing:
624 if outgoing:
622 revs = _getoutgoing(repo, dest, revs)
625 revs = _getoutgoing(repo, dest, revs)
623 if bundle:
626 if bundle:
624 opts['revs'] = [str(r) for r in revs]
627 opts['revs'] = [str(r) for r in revs]
625
628
626 # check if revision exist on the public destination
629 # check if revision exist on the public destination
627 publicurl = repo.ui.config('patchbomb', 'publicurl')
630 publicurl = repo.ui.config('patchbomb', 'publicurl')
628 if publicurl:
631 if publicurl:
629 repo.ui.debug('checking that revision exist in the public repo')
632 repo.ui.debug('checking that revision exist in the public repo')
630 try:
633 try:
631 publicpeer = hg.peer(repo, {}, publicurl)
634 publicpeer = hg.peer(repo, {}, publicurl)
632 except error.RepoError:
635 except error.RepoError:
633 repo.ui.write_err(_('unable to access public repo: %s\n')
636 repo.ui.write_err(_('unable to access public repo: %s\n')
634 % publicurl)
637 % publicurl)
635 raise
638 raise
636 if not publicpeer.capable('known'):
639 if not publicpeer.capable('known'):
637 repo.ui.debug('skipping existence checks: public repo too old')
640 repo.ui.debug('skipping existence checks: public repo too old')
638 else:
641 else:
639 out = [repo[r] for r in revs]
642 out = [repo[r] for r in revs]
640 known = publicpeer.known(h.node() for h in out)
643 known = publicpeer.known(h.node() for h in out)
641 missing = []
644 missing = []
642 for idx, h in enumerate(out):
645 for idx, h in enumerate(out):
643 if not known[idx]:
646 if not known[idx]:
644 missing.append(h)
647 missing.append(h)
645 if missing:
648 if missing:
646 if 1 < len(missing):
649 if 1 < len(missing):
647 msg = _('public "%s" is missing %s and %i others')
650 msg = _('public "%s" is missing %s and %i others')
648 msg %= (publicurl, missing[0], len(missing) - 1)
651 msg %= (publicurl, missing[0], len(missing) - 1)
649 else:
652 else:
650 msg = _('public url %s is missing %s')
653 msg = _('public url %s is missing %s')
651 msg %= (publicurl, missing[0])
654 msg %= (publicurl, missing[0])
652 revhint = ' '.join('-r %s' % h
655 revhint = ' '.join('-r %s' % h
653 for h in repo.set('heads(%ld)', missing))
656 for h in repo.set('heads(%ld)', missing))
654 hint = _("use 'hg push %s %s'") % (publicurl, revhint)
657 hint = _("use 'hg push %s %s'") % (publicurl, revhint)
655 raise error.Abort(msg, hint=hint)
658 raise error.Abort(msg, hint=hint)
656
659
657 # start
660 # start
658 if date:
661 if date:
659 start_time = util.parsedate(date)
662 start_time = util.parsedate(date)
660 else:
663 else:
661 start_time = util.makedate()
664 start_time = util.makedate()
662
665
663 def genmsgid(id):
666 def genmsgid(id):
664 return '<%s.%s@%s>' % (id[:20], int(start_time[0]), socket.getfqdn())
667 return '<%s.%s@%s>' % (id[:20], int(start_time[0]), socket.getfqdn())
665
668
666 # deprecated config: patchbomb.from
669 # deprecated config: patchbomb.from
667 sender = (opts.get('from') or ui.config('email', 'from') or
670 sender = (opts.get('from') or ui.config('email', 'from') or
668 ui.config('patchbomb', 'from') or
671 ui.config('patchbomb', 'from') or
669 prompt(ui, 'From', ui.username()))
672 prompt(ui, 'From', ui.username()))
670
673
671 if bundle:
674 if bundle:
672 bundledata = _getbundle(repo, dest, **opts)
675 bundledata = _getbundle(repo, dest, **opts)
673 bundleopts = opts.copy()
676 bundleopts = opts.copy()
674 bundleopts.pop('bundle', None) # already processed
677 bundleopts.pop('bundle', None) # already processed
675 msgs = _getbundlemsgs(repo, sender, bundledata, **bundleopts)
678 msgs = _getbundlemsgs(repo, sender, bundledata, **bundleopts)
676 else:
679 else:
677 msgs = _getpatchmsgs(repo, sender, revs, **opts)
680 msgs = _getpatchmsgs(repo, sender, revs, **opts)
678
681
679 showaddrs = []
682 showaddrs = []
680
683
681 def getaddrs(header, ask=False, default=None):
684 def getaddrs(header, ask=False, default=None):
682 configkey = header.lower()
685 configkey = header.lower()
683 opt = header.replace('-', '_').lower()
686 opt = header.replace('-', '_').lower()
684 addrs = opts.get(opt)
687 addrs = opts.get(opt)
685 if addrs:
688 if addrs:
686 showaddrs.append('%s: %s' % (header, ', '.join(addrs)))
689 showaddrs.append('%s: %s' % (header, ', '.join(addrs)))
687 return mail.addrlistencode(ui, addrs, _charsets, opts.get('test'))
690 return mail.addrlistencode(ui, addrs, _charsets, opts.get('test'))
688
691
689 # not on the command line: fallback to config and then maybe ask
692 # not on the command line: fallback to config and then maybe ask
690 addr = (ui.config('email', configkey) or
693 addr = (ui.config('email', configkey) or
691 ui.config('patchbomb', configkey))
694 ui.config('patchbomb', configkey))
692 if not addr:
695 if not addr:
693 specified = (ui.hasconfig('email', configkey) or
696 specified = (ui.hasconfig('email', configkey) or
694 ui.hasconfig('patchbomb', configkey))
697 ui.hasconfig('patchbomb', configkey))
695 if not specified and ask:
698 if not specified and ask:
696 addr = prompt(ui, header, default=default)
699 addr = prompt(ui, header, default=default)
697 if addr:
700 if addr:
698 showaddrs.append('%s: %s' % (header, addr))
701 showaddrs.append('%s: %s' % (header, addr))
699 return mail.addrlistencode(ui, [addr], _charsets, opts.get('test'))
702 return mail.addrlistencode(ui, [addr], _charsets, opts.get('test'))
700 elif default:
703 elif default:
701 return mail.addrlistencode(
704 return mail.addrlistencode(
702 ui, [default], _charsets, opts.get('test'))
705 ui, [default], _charsets, opts.get('test'))
703 return []
706 return []
704
707
705 to = getaddrs('To', ask=True)
708 to = getaddrs('To', ask=True)
706 if not to:
709 if not to:
707 # we can get here in non-interactive mode
710 # we can get here in non-interactive mode
708 raise error.Abort(_('no recipient addresses provided'))
711 raise error.Abort(_('no recipient addresses provided'))
709 cc = getaddrs('Cc', ask=True, default='')
712 cc = getaddrs('Cc', ask=True, default='')
710 bcc = getaddrs('Bcc')
713 bcc = getaddrs('Bcc')
711 replyto = getaddrs('Reply-To')
714 replyto = getaddrs('Reply-To')
712
715
713 confirm = ui.configbool('patchbomb', 'confirm')
716 confirm = ui.configbool('patchbomb', 'confirm')
714 confirm |= bool(opts.get('diffstat') or opts.get('confirm'))
717 confirm |= bool(opts.get('diffstat') or opts.get('confirm'))
715
718
716 if confirm:
719 if confirm:
717 ui.write(_('\nFinal summary:\n\n'), label='patchbomb.finalsummary')
720 ui.write(_('\nFinal summary:\n\n'), label='patchbomb.finalsummary')
718 ui.write(('From: %s\n' % sender), label='patchbomb.from')
721 ui.write(('From: %s\n' % sender), label='patchbomb.from')
719 for addr in showaddrs:
722 for addr in showaddrs:
720 ui.write('%s\n' % addr, label='patchbomb.to')
723 ui.write('%s\n' % addr, label='patchbomb.to')
721 for m, subj, ds in msgs:
724 for m, subj, ds in msgs:
722 ui.write(('Subject: %s\n' % subj), label='patchbomb.subject')
725 ui.write(('Subject: %s\n' % subj), label='patchbomb.subject')
723 if ds:
726 if ds:
724 ui.write(ds, label='patchbomb.diffstats')
727 ui.write(ds, label='patchbomb.diffstats')
725 ui.write('\n')
728 ui.write('\n')
726 if ui.promptchoice(_('are you sure you want to send (yn)?'
729 if ui.promptchoice(_('are you sure you want to send (yn)?'
727 '$$ &Yes $$ &No')):
730 '$$ &Yes $$ &No')):
728 raise error.Abort(_('patchbomb canceled'))
731 raise error.Abort(_('patchbomb canceled'))
729
732
730 ui.write('\n')
733 ui.write('\n')
731
734
732 parent = opts.get('in_reply_to') or None
735 parent = opts.get('in_reply_to') or None
733 # angle brackets may be omitted, they're not semantically part of the msg-id
736 # angle brackets may be omitted, they're not semantically part of the msg-id
734 if parent is not None:
737 if parent is not None:
735 if not parent.startswith('<'):
738 if not parent.startswith('<'):
736 parent = '<' + parent
739 parent = '<' + parent
737 if not parent.endswith('>'):
740 if not parent.endswith('>'):
738 parent += '>'
741 parent += '>'
739
742
740 sender_addr = emailmod.Utils.parseaddr(sender)[1]
743 sender_addr = emailmod.Utils.parseaddr(sender)[1]
741 sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
744 sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
742 sendmail = None
745 sendmail = None
743 firstpatch = None
746 firstpatch = None
744 for i, (m, subj, ds) in enumerate(msgs):
747 for i, (m, subj, ds) in enumerate(msgs):
745 try:
748 try:
746 m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
749 m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
747 if not firstpatch:
750 if not firstpatch:
748 firstpatch = m['Message-Id']
751 firstpatch = m['Message-Id']
749 m['X-Mercurial-Series-Id'] = firstpatch
752 m['X-Mercurial-Series-Id'] = firstpatch
750 except TypeError:
753 except TypeError:
751 m['Message-Id'] = genmsgid('patchbomb')
754 m['Message-Id'] = genmsgid('patchbomb')
752 if parent:
755 if parent:
753 m['In-Reply-To'] = parent
756 m['In-Reply-To'] = parent
754 m['References'] = parent
757 m['References'] = parent
755 if not parent or 'X-Mercurial-Node' not in m:
758 if not parent or 'X-Mercurial-Node' not in m:
756 parent = m['Message-Id']
759 parent = m['Message-Id']
757
760
758 m['User-Agent'] = 'Mercurial-patchbomb/%s' % util.version()
761 m['User-Agent'] = 'Mercurial-patchbomb/%s' % util.version()
759 m['Date'] = emailmod.Utils.formatdate(start_time[0], localtime=True)
762 m['Date'] = emailmod.Utils.formatdate(start_time[0], localtime=True)
760
763
761 start_time = (start_time[0] + 1, start_time[1])
764 start_time = (start_time[0] + 1, start_time[1])
762 m['From'] = sender
765 m['From'] = sender
763 m['To'] = ', '.join(to)
766 m['To'] = ', '.join(to)
764 if cc:
767 if cc:
765 m['Cc'] = ', '.join(cc)
768 m['Cc'] = ', '.join(cc)
766 if bcc:
769 if bcc:
767 m['Bcc'] = ', '.join(bcc)
770 m['Bcc'] = ', '.join(bcc)
768 if replyto:
771 if replyto:
769 m['Reply-To'] = ', '.join(replyto)
772 m['Reply-To'] = ', '.join(replyto)
770 if opts.get('test'):
773 if opts.get('test'):
771 ui.status(_('displaying '), subj, ' ...\n')
774 ui.status(_('displaying '), subj, ' ...\n')
772 ui.pager('email')
775 ui.pager('email')
773 generator = emailmod.Generator.Generator(ui, mangle_from_=False)
776 generator = emailmod.Generator.Generator(ui, mangle_from_=False)
774 try:
777 try:
775 generator.flatten(m, 0)
778 generator.flatten(m, 0)
776 ui.write('\n')
779 ui.write('\n')
777 except IOError as inst:
780 except IOError as inst:
778 if inst.errno != errno.EPIPE:
781 if inst.errno != errno.EPIPE:
779 raise
782 raise
780 else:
783 else:
781 if not sendmail:
784 if not sendmail:
782 sendmail = mail.connect(ui, mbox=mbox)
785 sendmail = mail.connect(ui, mbox=mbox)
783 ui.status(_('sending '), subj, ' ...\n')
786 ui.status(_('sending '), subj, ' ...\n')
784 ui.progress(_('sending'), i, item=subj, total=len(msgs),
787 ui.progress(_('sending'), i, item=subj, total=len(msgs),
785 unit=_('emails'))
788 unit=_('emails'))
786 if not mbox:
789 if not mbox:
787 # Exim does not remove the Bcc field
790 # Exim does not remove the Bcc field
788 del m['Bcc']
791 del m['Bcc']
789 fp = stringio()
792 fp = stringio()
790 generator = emailmod.Generator.Generator(fp, mangle_from_=False)
793 generator = emailmod.Generator.Generator(fp, mangle_from_=False)
791 generator.flatten(m, 0)
794 generator.flatten(m, 0)
792 sendmail(sender_addr, to + bcc + cc, fp.getvalue())
795 sendmail(sender_addr, to + bcc + cc, fp.getvalue())
793
796
794 ui.progress(_('writing'), None)
797 ui.progress(_('writing'), None)
795 ui.progress(_('sending'), None)
798 ui.progress(_('sending'), None)
@@ -1,1134 +1,1137 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, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 return functools.partial(_register, configtable)
109 return functools.partial(_register, configtable)
110
110
111 coreconfigitem = getitemregister(coreitems)
111 coreconfigitem = getitemregister(coreitems)
112
112
113 coreconfigitem('alias', '.*',
113 coreconfigitem('alias', '.*',
114 default=None,
114 default=None,
115 generic=True,
115 generic=True,
116 )
116 )
117 coreconfigitem('annotate', 'nodates',
117 coreconfigitem('annotate', 'nodates',
118 default=False,
118 default=False,
119 )
119 )
120 coreconfigitem('annotate', 'showfunc',
120 coreconfigitem('annotate', 'showfunc',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem('annotate', 'unified',
123 coreconfigitem('annotate', 'unified',
124 default=None,
124 default=None,
125 )
125 )
126 coreconfigitem('annotate', 'git',
126 coreconfigitem('annotate', 'git',
127 default=False,
127 default=False,
128 )
128 )
129 coreconfigitem('annotate', 'ignorews',
129 coreconfigitem('annotate', 'ignorews',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem('annotate', 'ignorewsamount',
132 coreconfigitem('annotate', 'ignorewsamount',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem('annotate', 'ignoreblanklines',
135 coreconfigitem('annotate', 'ignoreblanklines',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem('annotate', 'ignorewseol',
138 coreconfigitem('annotate', 'ignorewseol',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem('annotate', 'nobinary',
141 coreconfigitem('annotate', 'nobinary',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem('annotate', 'noprefix',
144 coreconfigitem('annotate', 'noprefix',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem('auth', 'cookiefile',
147 coreconfigitem('auth', 'cookiefile',
148 default=None,
148 default=None,
149 )
149 )
150 # bookmarks.pushing: internal hack for discovery
150 # bookmarks.pushing: internal hack for discovery
151 coreconfigitem('bookmarks', 'pushing',
151 coreconfigitem('bookmarks', 'pushing',
152 default=list,
152 default=list,
153 )
153 )
154 # bundle.mainreporoot: internal hack for bundlerepo
154 # bundle.mainreporoot: internal hack for bundlerepo
155 coreconfigitem('bundle', 'mainreporoot',
155 coreconfigitem('bundle', 'mainreporoot',
156 default='',
156 default='',
157 )
157 )
158 # bundle.reorder: experimental config
158 # bundle.reorder: experimental config
159 coreconfigitem('bundle', 'reorder',
159 coreconfigitem('bundle', 'reorder',
160 default='auto',
160 default='auto',
161 )
161 )
162 coreconfigitem('censor', 'policy',
162 coreconfigitem('censor', 'policy',
163 default='abort',
163 default='abort',
164 )
164 )
165 coreconfigitem('chgserver', 'idletimeout',
165 coreconfigitem('chgserver', 'idletimeout',
166 default=3600,
166 default=3600,
167 )
167 )
168 coreconfigitem('chgserver', 'skiphash',
168 coreconfigitem('chgserver', 'skiphash',
169 default=False,
169 default=False,
170 )
170 )
171 coreconfigitem('cmdserver', 'log',
171 coreconfigitem('cmdserver', 'log',
172 default=None,
172 default=None,
173 )
173 )
174 coreconfigitem('color', '.*',
174 coreconfigitem('color', '.*',
175 default=None,
175 default=None,
176 generic=True,
176 generic=True,
177 )
177 )
178 coreconfigitem('color', 'mode',
178 coreconfigitem('color', 'mode',
179 default='auto',
179 default='auto',
180 )
180 )
181 coreconfigitem('color', 'pagermode',
181 coreconfigitem('color', 'pagermode',
182 default=dynamicdefault,
182 default=dynamicdefault,
183 )
183 )
184 coreconfigitem('commands', 'show.aliasprefix',
184 coreconfigitem('commands', 'show.aliasprefix',
185 default=list,
185 default=list,
186 )
186 )
187 coreconfigitem('commands', 'status.relative',
187 coreconfigitem('commands', 'status.relative',
188 default=False,
188 default=False,
189 )
189 )
190 coreconfigitem('commands', 'status.skipstates',
190 coreconfigitem('commands', 'status.skipstates',
191 default=[],
191 default=[],
192 )
192 )
193 coreconfigitem('commands', 'status.verbose',
193 coreconfigitem('commands', 'status.verbose',
194 default=False,
194 default=False,
195 )
195 )
196 coreconfigitem('commands', 'update.check',
196 coreconfigitem('commands', 'update.check',
197 default=None,
197 default=None,
198 # Deprecated, remove after 4.4 release
198 # Deprecated, remove after 4.4 release
199 alias=[('experimental', 'updatecheck')]
199 alias=[('experimental', 'updatecheck')]
200 )
200 )
201 coreconfigitem('commands', 'update.requiredest',
201 coreconfigitem('commands', 'update.requiredest',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('committemplate', '.*',
204 coreconfigitem('committemplate', '.*',
205 default=None,
205 default=None,
206 generic=True,
206 generic=True,
207 )
207 )
208 coreconfigitem('debug', 'dirstate.delaywrite',
208 coreconfigitem('debug', 'dirstate.delaywrite',
209 default=0,
209 default=0,
210 )
210 )
211 coreconfigitem('defaults', '.*',
211 coreconfigitem('defaults', '.*',
212 default=None,
212 default=None,
213 generic=True,
213 generic=True,
214 )
214 )
215 coreconfigitem('devel', 'all-warnings',
215 coreconfigitem('devel', 'all-warnings',
216 default=False,
216 default=False,
217 )
217 )
218 coreconfigitem('devel', 'bundle2.debug',
218 coreconfigitem('devel', 'bundle2.debug',
219 default=False,
219 default=False,
220 )
220 )
221 coreconfigitem('devel', 'cache-vfs',
221 coreconfigitem('devel', 'cache-vfs',
222 default=None,
222 default=None,
223 )
223 )
224 coreconfigitem('devel', 'check-locks',
224 coreconfigitem('devel', 'check-locks',
225 default=False,
225 default=False,
226 )
226 )
227 coreconfigitem('devel', 'check-relroot',
227 coreconfigitem('devel', 'check-relroot',
228 default=False,
228 default=False,
229 )
229 )
230 coreconfigitem('devel', 'default-date',
230 coreconfigitem('devel', 'default-date',
231 default=None,
231 default=None,
232 )
232 )
233 coreconfigitem('devel', 'deprec-warn',
233 coreconfigitem('devel', 'deprec-warn',
234 default=False,
234 default=False,
235 )
235 )
236 coreconfigitem('devel', 'disableloaddefaultcerts',
236 coreconfigitem('devel', 'disableloaddefaultcerts',
237 default=False,
237 default=False,
238 )
238 )
239 coreconfigitem('devel', 'warn-empty-changegroup',
239 coreconfigitem('devel', 'warn-empty-changegroup',
240 default=False,
240 default=False,
241 )
241 )
242 coreconfigitem('devel', 'legacy.exchange',
242 coreconfigitem('devel', 'legacy.exchange',
243 default=list,
243 default=list,
244 )
244 )
245 coreconfigitem('devel', 'servercafile',
245 coreconfigitem('devel', 'servercafile',
246 default='',
246 default='',
247 )
247 )
248 coreconfigitem('devel', 'serverexactprotocol',
248 coreconfigitem('devel', 'serverexactprotocol',
249 default='',
249 default='',
250 )
250 )
251 coreconfigitem('devel', 'serverrequirecert',
251 coreconfigitem('devel', 'serverrequirecert',
252 default=False,
252 default=False,
253 )
253 )
254 coreconfigitem('devel', 'strip-obsmarkers',
254 coreconfigitem('devel', 'strip-obsmarkers',
255 default=True,
255 default=True,
256 )
256 )
257 coreconfigitem('devel', 'warn-config',
257 coreconfigitem('devel', 'warn-config',
258 default=None,
258 default=None,
259 )
259 )
260 coreconfigitem('devel', 'warn-config-default',
260 coreconfigitem('devel', 'warn-config-default',
261 default=None,
261 default=None,
262 )
262 )
263 coreconfigitem('devel', 'user.obsmarker',
263 coreconfigitem('devel', 'user.obsmarker',
264 default=None,
264 default=None,
265 )
265 )
266 coreconfigitem('devel', 'warn-config-unknown',
266 coreconfigitem('devel', 'warn-config-unknown',
267 default=None,
267 default=None,
268 )
268 )
269 coreconfigitem('diff', 'nodates',
269 coreconfigitem('diff', 'nodates',
270 default=False,
270 default=False,
271 )
271 )
272 coreconfigitem('diff', 'showfunc',
272 coreconfigitem('diff', 'showfunc',
273 default=False,
273 default=False,
274 )
274 )
275 coreconfigitem('diff', 'unified',
275 coreconfigitem('diff', 'unified',
276 default=None,
276 default=None,
277 )
277 )
278 coreconfigitem('diff', 'git',
278 coreconfigitem('diff', 'git',
279 default=False,
279 default=False,
280 )
280 )
281 coreconfigitem('diff', 'ignorews',
281 coreconfigitem('diff', 'ignorews',
282 default=False,
282 default=False,
283 )
283 )
284 coreconfigitem('diff', 'ignorewsamount',
284 coreconfigitem('diff', 'ignorewsamount',
285 default=False,
285 default=False,
286 )
286 )
287 coreconfigitem('diff', 'ignoreblanklines',
287 coreconfigitem('diff', 'ignoreblanklines',
288 default=False,
288 default=False,
289 )
289 )
290 coreconfigitem('diff', 'ignorewseol',
290 coreconfigitem('diff', 'ignorewseol',
291 default=False,
291 default=False,
292 )
292 )
293 coreconfigitem('diff', 'nobinary',
293 coreconfigitem('diff', 'nobinary',
294 default=False,
294 default=False,
295 )
295 )
296 coreconfigitem('diff', 'noprefix',
296 coreconfigitem('diff', 'noprefix',
297 default=False,
297 default=False,
298 )
298 )
299 coreconfigitem('email', 'bcc',
299 coreconfigitem('email', 'bcc',
300 default=None,
300 default=None,
301 )
301 )
302 coreconfigitem('email', 'cc',
302 coreconfigitem('email', 'cc',
303 default=None,
303 default=None,
304 )
304 )
305 coreconfigitem('email', 'charsets',
305 coreconfigitem('email', 'charsets',
306 default=list,
306 default=list,
307 )
307 )
308 coreconfigitem('email', 'from',
308 coreconfigitem('email', 'from',
309 default=None,
309 default=None,
310 )
310 )
311 coreconfigitem('email', 'method',
311 coreconfigitem('email', 'method',
312 default='smtp',
312 default='smtp',
313 )
313 )
314 coreconfigitem('email', 'reply-to',
314 coreconfigitem('email', 'reply-to',
315 default=None,
315 default=None,
316 )
316 )
317 coreconfigitem('email', 'to',
318 default=None,
319 )
317 coreconfigitem('experimental', 'archivemetatemplate',
320 coreconfigitem('experimental', 'archivemetatemplate',
318 default=dynamicdefault,
321 default=dynamicdefault,
319 )
322 )
320 coreconfigitem('experimental', 'bundle-phases',
323 coreconfigitem('experimental', 'bundle-phases',
321 default=False,
324 default=False,
322 )
325 )
323 coreconfigitem('experimental', 'bundle2-advertise',
326 coreconfigitem('experimental', 'bundle2-advertise',
324 default=True,
327 default=True,
325 )
328 )
326 coreconfigitem('experimental', 'bundle2-output-capture',
329 coreconfigitem('experimental', 'bundle2-output-capture',
327 default=False,
330 default=False,
328 )
331 )
329 coreconfigitem('experimental', 'bundle2.pushback',
332 coreconfigitem('experimental', 'bundle2.pushback',
330 default=False,
333 default=False,
331 )
334 )
332 coreconfigitem('experimental', 'bundle2lazylocking',
335 coreconfigitem('experimental', 'bundle2lazylocking',
333 default=False,
336 default=False,
334 )
337 )
335 coreconfigitem('experimental', 'bundlecomplevel',
338 coreconfigitem('experimental', 'bundlecomplevel',
336 default=None,
339 default=None,
337 )
340 )
338 coreconfigitem('experimental', 'changegroup3',
341 coreconfigitem('experimental', 'changegroup3',
339 default=False,
342 default=False,
340 )
343 )
341 coreconfigitem('experimental', 'clientcompressionengines',
344 coreconfigitem('experimental', 'clientcompressionengines',
342 default=list,
345 default=list,
343 )
346 )
344 coreconfigitem('experimental', 'copytrace',
347 coreconfigitem('experimental', 'copytrace',
345 default='on',
348 default='on',
346 )
349 )
347 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
350 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
348 default=100,
351 default=100,
349 )
352 )
350 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
353 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
351 default=100,
354 default=100,
352 )
355 )
353 coreconfigitem('experimental', 'crecordtest',
356 coreconfigitem('experimental', 'crecordtest',
354 default=None,
357 default=None,
355 )
358 )
356 coreconfigitem('experimental', 'editortmpinhg',
359 coreconfigitem('experimental', 'editortmpinhg',
357 default=False,
360 default=False,
358 )
361 )
359 coreconfigitem('experimental', 'evolution',
362 coreconfigitem('experimental', 'evolution',
360 default=list,
363 default=list,
361 )
364 )
362 coreconfigitem('experimental', 'evolution.allowdivergence',
365 coreconfigitem('experimental', 'evolution.allowdivergence',
363 default=False,
366 default=False,
364 alias=[('experimental', 'allowdivergence')]
367 alias=[('experimental', 'allowdivergence')]
365 )
368 )
366 coreconfigitem('experimental', 'evolution.allowunstable',
369 coreconfigitem('experimental', 'evolution.allowunstable',
367 default=None,
370 default=None,
368 )
371 )
369 coreconfigitem('experimental', 'evolution.createmarkers',
372 coreconfigitem('experimental', 'evolution.createmarkers',
370 default=None,
373 default=None,
371 )
374 )
372 coreconfigitem('experimental', 'evolution.effect-flags',
375 coreconfigitem('experimental', 'evolution.effect-flags',
373 default=False,
376 default=False,
374 alias=[('experimental', 'effect-flags')]
377 alias=[('experimental', 'effect-flags')]
375 )
378 )
376 coreconfigitem('experimental', 'evolution.exchange',
379 coreconfigitem('experimental', 'evolution.exchange',
377 default=None,
380 default=None,
378 )
381 )
379 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
382 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
380 default=False,
383 default=False,
381 )
384 )
382 coreconfigitem('experimental', 'evolution.track-operation',
385 coreconfigitem('experimental', 'evolution.track-operation',
383 default=True,
386 default=True,
384 )
387 )
385 coreconfigitem('experimental', 'maxdeltachainspan',
388 coreconfigitem('experimental', 'maxdeltachainspan',
386 default=-1,
389 default=-1,
387 )
390 )
388 coreconfigitem('experimental', 'mmapindexthreshold',
391 coreconfigitem('experimental', 'mmapindexthreshold',
389 default=None,
392 default=None,
390 )
393 )
391 coreconfigitem('experimental', 'nonnormalparanoidcheck',
394 coreconfigitem('experimental', 'nonnormalparanoidcheck',
392 default=False,
395 default=False,
393 )
396 )
394 coreconfigitem('experimental', 'exportableenviron',
397 coreconfigitem('experimental', 'exportableenviron',
395 default=list,
398 default=list,
396 )
399 )
397 coreconfigitem('experimental', 'extendedheader.index',
400 coreconfigitem('experimental', 'extendedheader.index',
398 default=None,
401 default=None,
399 )
402 )
400 coreconfigitem('experimental', 'extendedheader.similarity',
403 coreconfigitem('experimental', 'extendedheader.similarity',
401 default=False,
404 default=False,
402 )
405 )
403 coreconfigitem('experimental', 'format.compression',
406 coreconfigitem('experimental', 'format.compression',
404 default='zlib',
407 default='zlib',
405 )
408 )
406 coreconfigitem('experimental', 'graphshorten',
409 coreconfigitem('experimental', 'graphshorten',
407 default=False,
410 default=False,
408 )
411 )
409 coreconfigitem('experimental', 'graphstyle.parent',
412 coreconfigitem('experimental', 'graphstyle.parent',
410 default=dynamicdefault,
413 default=dynamicdefault,
411 )
414 )
412 coreconfigitem('experimental', 'graphstyle.missing',
415 coreconfigitem('experimental', 'graphstyle.missing',
413 default=dynamicdefault,
416 default=dynamicdefault,
414 )
417 )
415 coreconfigitem('experimental', 'graphstyle.grandparent',
418 coreconfigitem('experimental', 'graphstyle.grandparent',
416 default=dynamicdefault,
419 default=dynamicdefault,
417 )
420 )
418 coreconfigitem('experimental', 'hook-track-tags',
421 coreconfigitem('experimental', 'hook-track-tags',
419 default=False,
422 default=False,
420 )
423 )
421 coreconfigitem('experimental', 'httppostargs',
424 coreconfigitem('experimental', 'httppostargs',
422 default=False,
425 default=False,
423 )
426 )
424 coreconfigitem('experimental', 'manifestv2',
427 coreconfigitem('experimental', 'manifestv2',
425 default=False,
428 default=False,
426 )
429 )
427 coreconfigitem('experimental', 'mergedriver',
430 coreconfigitem('experimental', 'mergedriver',
428 default=None,
431 default=None,
429 )
432 )
430 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
433 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
431 default=False,
434 default=False,
432 )
435 )
433 coreconfigitem('experimental', 'rebase.multidest',
436 coreconfigitem('experimental', 'rebase.multidest',
434 default=False,
437 default=False,
435 )
438 )
436 coreconfigitem('experimental', 'revertalternateinteractivemode',
439 coreconfigitem('experimental', 'revertalternateinteractivemode',
437 default=True,
440 default=True,
438 )
441 )
439 coreconfigitem('experimental', 'revlogv2',
442 coreconfigitem('experimental', 'revlogv2',
440 default=None,
443 default=None,
441 )
444 )
442 coreconfigitem('experimental', 'spacemovesdown',
445 coreconfigitem('experimental', 'spacemovesdown',
443 default=False,
446 default=False,
444 )
447 )
445 coreconfigitem('experimental', 'sparse-read',
448 coreconfigitem('experimental', 'sparse-read',
446 default=False,
449 default=False,
447 )
450 )
448 coreconfigitem('experimental', 'sparse-read.density-threshold',
451 coreconfigitem('experimental', 'sparse-read.density-threshold',
449 default=0.25,
452 default=0.25,
450 )
453 )
451 coreconfigitem('experimental', 'sparse-read.min-gap-size',
454 coreconfigitem('experimental', 'sparse-read.min-gap-size',
452 default='256K',
455 default='256K',
453 )
456 )
454 coreconfigitem('experimental', 'treemanifest',
457 coreconfigitem('experimental', 'treemanifest',
455 default=False,
458 default=False,
456 )
459 )
457 coreconfigitem('extensions', '.*',
460 coreconfigitem('extensions', '.*',
458 default=None,
461 default=None,
459 generic=True,
462 generic=True,
460 )
463 )
461 coreconfigitem('extdata', '.*',
464 coreconfigitem('extdata', '.*',
462 default=None,
465 default=None,
463 generic=True,
466 generic=True,
464 )
467 )
465 coreconfigitem('format', 'aggressivemergedeltas',
468 coreconfigitem('format', 'aggressivemergedeltas',
466 default=False,
469 default=False,
467 )
470 )
468 coreconfigitem('format', 'chunkcachesize',
471 coreconfigitem('format', 'chunkcachesize',
469 default=None,
472 default=None,
470 )
473 )
471 coreconfigitem('format', 'dotencode',
474 coreconfigitem('format', 'dotencode',
472 default=True,
475 default=True,
473 )
476 )
474 coreconfigitem('format', 'generaldelta',
477 coreconfigitem('format', 'generaldelta',
475 default=False,
478 default=False,
476 )
479 )
477 coreconfigitem('format', 'manifestcachesize',
480 coreconfigitem('format', 'manifestcachesize',
478 default=None,
481 default=None,
479 )
482 )
480 coreconfigitem('format', 'maxchainlen',
483 coreconfigitem('format', 'maxchainlen',
481 default=None,
484 default=None,
482 )
485 )
483 coreconfigitem('format', 'obsstore-version',
486 coreconfigitem('format', 'obsstore-version',
484 default=None,
487 default=None,
485 )
488 )
486 coreconfigitem('format', 'usefncache',
489 coreconfigitem('format', 'usefncache',
487 default=True,
490 default=True,
488 )
491 )
489 coreconfigitem('format', 'usegeneraldelta',
492 coreconfigitem('format', 'usegeneraldelta',
490 default=True,
493 default=True,
491 )
494 )
492 coreconfigitem('format', 'usestore',
495 coreconfigitem('format', 'usestore',
493 default=True,
496 default=True,
494 )
497 )
495 coreconfigitem('fsmonitor', 'warn_when_unused',
498 coreconfigitem('fsmonitor', 'warn_when_unused',
496 default=True,
499 default=True,
497 )
500 )
498 coreconfigitem('fsmonitor', 'warn_update_file_count',
501 coreconfigitem('fsmonitor', 'warn_update_file_count',
499 default=50000,
502 default=50000,
500 )
503 )
501 coreconfigitem('hooks', '.*',
504 coreconfigitem('hooks', '.*',
502 default=dynamicdefault,
505 default=dynamicdefault,
503 generic=True,
506 generic=True,
504 )
507 )
505 coreconfigitem('hgweb-paths', '.*',
508 coreconfigitem('hgweb-paths', '.*',
506 default=list,
509 default=list,
507 generic=True,
510 generic=True,
508 )
511 )
509 coreconfigitem('hostfingerprints', '.*',
512 coreconfigitem('hostfingerprints', '.*',
510 default=list,
513 default=list,
511 generic=True,
514 generic=True,
512 )
515 )
513 coreconfigitem('hostsecurity', 'ciphers',
516 coreconfigitem('hostsecurity', 'ciphers',
514 default=None,
517 default=None,
515 )
518 )
516 coreconfigitem('hostsecurity', 'disabletls10warning',
519 coreconfigitem('hostsecurity', 'disabletls10warning',
517 default=False,
520 default=False,
518 )
521 )
519 coreconfigitem('hostsecurity', 'minimumprotocol',
522 coreconfigitem('hostsecurity', 'minimumprotocol',
520 default=dynamicdefault,
523 default=dynamicdefault,
521 )
524 )
522 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
525 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
523 default=dynamicdefault,
526 default=dynamicdefault,
524 generic=True,
527 generic=True,
525 )
528 )
526 coreconfigitem('hostsecurity', '.*:ciphers$',
529 coreconfigitem('hostsecurity', '.*:ciphers$',
527 default=dynamicdefault,
530 default=dynamicdefault,
528 generic=True,
531 generic=True,
529 )
532 )
530 coreconfigitem('hostsecurity', '.*:fingerprints$',
533 coreconfigitem('hostsecurity', '.*:fingerprints$',
531 default=list,
534 default=list,
532 generic=True,
535 generic=True,
533 )
536 )
534 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
537 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
535 default=None,
538 default=None,
536 generic=True,
539 generic=True,
537 )
540 )
538
541
539 coreconfigitem('http_proxy', 'always',
542 coreconfigitem('http_proxy', 'always',
540 default=False,
543 default=False,
541 )
544 )
542 coreconfigitem('http_proxy', 'host',
545 coreconfigitem('http_proxy', 'host',
543 default=None,
546 default=None,
544 )
547 )
545 coreconfigitem('http_proxy', 'no',
548 coreconfigitem('http_proxy', 'no',
546 default=list,
549 default=list,
547 )
550 )
548 coreconfigitem('http_proxy', 'passwd',
551 coreconfigitem('http_proxy', 'passwd',
549 default=None,
552 default=None,
550 )
553 )
551 coreconfigitem('http_proxy', 'user',
554 coreconfigitem('http_proxy', 'user',
552 default=None,
555 default=None,
553 )
556 )
554 coreconfigitem('logtoprocess', 'commandexception',
557 coreconfigitem('logtoprocess', 'commandexception',
555 default=None,
558 default=None,
556 )
559 )
557 coreconfigitem('logtoprocess', 'commandfinish',
560 coreconfigitem('logtoprocess', 'commandfinish',
558 default=None,
561 default=None,
559 )
562 )
560 coreconfigitem('logtoprocess', 'command',
563 coreconfigitem('logtoprocess', 'command',
561 default=None,
564 default=None,
562 )
565 )
563 coreconfigitem('logtoprocess', 'develwarn',
566 coreconfigitem('logtoprocess', 'develwarn',
564 default=None,
567 default=None,
565 )
568 )
566 coreconfigitem('logtoprocess', 'uiblocked',
569 coreconfigitem('logtoprocess', 'uiblocked',
567 default=None,
570 default=None,
568 )
571 )
569 coreconfigitem('merge', 'checkunknown',
572 coreconfigitem('merge', 'checkunknown',
570 default='abort',
573 default='abort',
571 )
574 )
572 coreconfigitem('merge', 'checkignored',
575 coreconfigitem('merge', 'checkignored',
573 default='abort',
576 default='abort',
574 )
577 )
575 coreconfigitem('merge', 'followcopies',
578 coreconfigitem('merge', 'followcopies',
576 default=True,
579 default=True,
577 )
580 )
578 coreconfigitem('merge', 'on-failure',
581 coreconfigitem('merge', 'on-failure',
579 default='continue',
582 default='continue',
580 )
583 )
581 coreconfigitem('merge', 'preferancestor',
584 coreconfigitem('merge', 'preferancestor',
582 default=lambda: ['*'],
585 default=lambda: ['*'],
583 )
586 )
584 coreconfigitem('merge-tools', '.*',
587 coreconfigitem('merge-tools', '.*',
585 default=None,
588 default=None,
586 generic=True,
589 generic=True,
587 )
590 )
588 coreconfigitem('merge-tools', br'.*\.args$',
591 coreconfigitem('merge-tools', br'.*\.args$',
589 default="$local $base $other",
592 default="$local $base $other",
590 generic=True,
593 generic=True,
591 priority=-1,
594 priority=-1,
592 )
595 )
593 coreconfigitem('merge-tools', br'.*\.binary$',
596 coreconfigitem('merge-tools', br'.*\.binary$',
594 default=False,
597 default=False,
595 generic=True,
598 generic=True,
596 priority=-1,
599 priority=-1,
597 )
600 )
598 coreconfigitem('merge-tools', br'.*\.check$',
601 coreconfigitem('merge-tools', br'.*\.check$',
599 default=list,
602 default=list,
600 generic=True,
603 generic=True,
601 priority=-1,
604 priority=-1,
602 )
605 )
603 coreconfigitem('merge-tools', br'.*\.checkchanged$',
606 coreconfigitem('merge-tools', br'.*\.checkchanged$',
604 default=False,
607 default=False,
605 generic=True,
608 generic=True,
606 priority=-1,
609 priority=-1,
607 )
610 )
608 coreconfigitem('merge-tools', br'.*\.executable$',
611 coreconfigitem('merge-tools', br'.*\.executable$',
609 default=dynamicdefault,
612 default=dynamicdefault,
610 generic=True,
613 generic=True,
611 priority=-1,
614 priority=-1,
612 )
615 )
613 coreconfigitem('merge-tools', br'.*\.fixeol$',
616 coreconfigitem('merge-tools', br'.*\.fixeol$',
614 default=False,
617 default=False,
615 generic=True,
618 generic=True,
616 priority=-1,
619 priority=-1,
617 )
620 )
618 coreconfigitem('merge-tools', br'.*\.gui$',
621 coreconfigitem('merge-tools', br'.*\.gui$',
619 default=False,
622 default=False,
620 generic=True,
623 generic=True,
621 priority=-1,
624 priority=-1,
622 )
625 )
623 coreconfigitem('merge-tools', br'.*\.priority$',
626 coreconfigitem('merge-tools', br'.*\.priority$',
624 default=0,
627 default=0,
625 generic=True,
628 generic=True,
626 priority=-1,
629 priority=-1,
627 )
630 )
628 coreconfigitem('merge-tools', br'.*\.premerge$',
631 coreconfigitem('merge-tools', br'.*\.premerge$',
629 default=dynamicdefault,
632 default=dynamicdefault,
630 generic=True,
633 generic=True,
631 priority=-1,
634 priority=-1,
632 )
635 )
633 coreconfigitem('merge-tools', br'.*\.symlink$',
636 coreconfigitem('merge-tools', br'.*\.symlink$',
634 default=False,
637 default=False,
635 generic=True,
638 generic=True,
636 priority=-1,
639 priority=-1,
637 )
640 )
638 coreconfigitem('pager', 'attend-.*',
641 coreconfigitem('pager', 'attend-.*',
639 default=dynamicdefault,
642 default=dynamicdefault,
640 generic=True,
643 generic=True,
641 )
644 )
642 coreconfigitem('pager', 'ignore',
645 coreconfigitem('pager', 'ignore',
643 default=list,
646 default=list,
644 )
647 )
645 coreconfigitem('pager', 'pager',
648 coreconfigitem('pager', 'pager',
646 default=dynamicdefault,
649 default=dynamicdefault,
647 )
650 )
648 coreconfigitem('patch', 'eol',
651 coreconfigitem('patch', 'eol',
649 default='strict',
652 default='strict',
650 )
653 )
651 coreconfigitem('patch', 'fuzz',
654 coreconfigitem('patch', 'fuzz',
652 default=2,
655 default=2,
653 )
656 )
654 coreconfigitem('paths', 'default',
657 coreconfigitem('paths', 'default',
655 default=None,
658 default=None,
656 )
659 )
657 coreconfigitem('paths', 'default-push',
660 coreconfigitem('paths', 'default-push',
658 default=None,
661 default=None,
659 )
662 )
660 coreconfigitem('paths', '.*',
663 coreconfigitem('paths', '.*',
661 default=None,
664 default=None,
662 generic=True,
665 generic=True,
663 )
666 )
664 coreconfigitem('phases', 'checksubrepos',
667 coreconfigitem('phases', 'checksubrepos',
665 default='follow',
668 default='follow',
666 )
669 )
667 coreconfigitem('phases', 'new-commit',
670 coreconfigitem('phases', 'new-commit',
668 default='draft',
671 default='draft',
669 )
672 )
670 coreconfigitem('phases', 'publish',
673 coreconfigitem('phases', 'publish',
671 default=True,
674 default=True,
672 )
675 )
673 coreconfigitem('profiling', 'enabled',
676 coreconfigitem('profiling', 'enabled',
674 default=False,
677 default=False,
675 )
678 )
676 coreconfigitem('profiling', 'format',
679 coreconfigitem('profiling', 'format',
677 default='text',
680 default='text',
678 )
681 )
679 coreconfigitem('profiling', 'freq',
682 coreconfigitem('profiling', 'freq',
680 default=1000,
683 default=1000,
681 )
684 )
682 coreconfigitem('profiling', 'limit',
685 coreconfigitem('profiling', 'limit',
683 default=30,
686 default=30,
684 )
687 )
685 coreconfigitem('profiling', 'nested',
688 coreconfigitem('profiling', 'nested',
686 default=0,
689 default=0,
687 )
690 )
688 coreconfigitem('profiling', 'output',
691 coreconfigitem('profiling', 'output',
689 default=None,
692 default=None,
690 )
693 )
691 coreconfigitem('profiling', 'showmax',
694 coreconfigitem('profiling', 'showmax',
692 default=0.999,
695 default=0.999,
693 )
696 )
694 coreconfigitem('profiling', 'showmin',
697 coreconfigitem('profiling', 'showmin',
695 default=dynamicdefault,
698 default=dynamicdefault,
696 )
699 )
697 coreconfigitem('profiling', 'sort',
700 coreconfigitem('profiling', 'sort',
698 default='inlinetime',
701 default='inlinetime',
699 )
702 )
700 coreconfigitem('profiling', 'statformat',
703 coreconfigitem('profiling', 'statformat',
701 default='hotpath',
704 default='hotpath',
702 )
705 )
703 coreconfigitem('profiling', 'type',
706 coreconfigitem('profiling', 'type',
704 default='stat',
707 default='stat',
705 )
708 )
706 coreconfigitem('progress', 'assume-tty',
709 coreconfigitem('progress', 'assume-tty',
707 default=False,
710 default=False,
708 )
711 )
709 coreconfigitem('progress', 'changedelay',
712 coreconfigitem('progress', 'changedelay',
710 default=1,
713 default=1,
711 )
714 )
712 coreconfigitem('progress', 'clear-complete',
715 coreconfigitem('progress', 'clear-complete',
713 default=True,
716 default=True,
714 )
717 )
715 coreconfigitem('progress', 'debug',
718 coreconfigitem('progress', 'debug',
716 default=False,
719 default=False,
717 )
720 )
718 coreconfigitem('progress', 'delay',
721 coreconfigitem('progress', 'delay',
719 default=3,
722 default=3,
720 )
723 )
721 coreconfigitem('progress', 'disable',
724 coreconfigitem('progress', 'disable',
722 default=False,
725 default=False,
723 )
726 )
724 coreconfigitem('progress', 'estimateinterval',
727 coreconfigitem('progress', 'estimateinterval',
725 default=60.0,
728 default=60.0,
726 )
729 )
727 coreconfigitem('progress', 'format',
730 coreconfigitem('progress', 'format',
728 default=lambda: ['topic', 'bar', 'number', 'estimate'],
731 default=lambda: ['topic', 'bar', 'number', 'estimate'],
729 )
732 )
730 coreconfigitem('progress', 'refresh',
733 coreconfigitem('progress', 'refresh',
731 default=0.1,
734 default=0.1,
732 )
735 )
733 coreconfigitem('progress', 'width',
736 coreconfigitem('progress', 'width',
734 default=dynamicdefault,
737 default=dynamicdefault,
735 )
738 )
736 coreconfigitem('push', 'pushvars.server',
739 coreconfigitem('push', 'pushvars.server',
737 default=False,
740 default=False,
738 )
741 )
739 coreconfigitem('server', 'bundle1',
742 coreconfigitem('server', 'bundle1',
740 default=True,
743 default=True,
741 )
744 )
742 coreconfigitem('server', 'bundle1gd',
745 coreconfigitem('server', 'bundle1gd',
743 default=None,
746 default=None,
744 )
747 )
745 coreconfigitem('server', 'bundle1.pull',
748 coreconfigitem('server', 'bundle1.pull',
746 default=None,
749 default=None,
747 )
750 )
748 coreconfigitem('server', 'bundle1gd.pull',
751 coreconfigitem('server', 'bundle1gd.pull',
749 default=None,
752 default=None,
750 )
753 )
751 coreconfigitem('server', 'bundle1.push',
754 coreconfigitem('server', 'bundle1.push',
752 default=None,
755 default=None,
753 )
756 )
754 coreconfigitem('server', 'bundle1gd.push',
757 coreconfigitem('server', 'bundle1gd.push',
755 default=None,
758 default=None,
756 )
759 )
757 coreconfigitem('server', 'compressionengines',
760 coreconfigitem('server', 'compressionengines',
758 default=list,
761 default=list,
759 )
762 )
760 coreconfigitem('server', 'concurrent-push-mode',
763 coreconfigitem('server', 'concurrent-push-mode',
761 default='strict',
764 default='strict',
762 )
765 )
763 coreconfigitem('server', 'disablefullbundle',
766 coreconfigitem('server', 'disablefullbundle',
764 default=False,
767 default=False,
765 )
768 )
766 coreconfigitem('server', 'maxhttpheaderlen',
769 coreconfigitem('server', 'maxhttpheaderlen',
767 default=1024,
770 default=1024,
768 )
771 )
769 coreconfigitem('server', 'preferuncompressed',
772 coreconfigitem('server', 'preferuncompressed',
770 default=False,
773 default=False,
771 )
774 )
772 coreconfigitem('server', 'uncompressed',
775 coreconfigitem('server', 'uncompressed',
773 default=True,
776 default=True,
774 )
777 )
775 coreconfigitem('server', 'uncompressedallowsecret',
778 coreconfigitem('server', 'uncompressedallowsecret',
776 default=False,
779 default=False,
777 )
780 )
778 coreconfigitem('server', 'validate',
781 coreconfigitem('server', 'validate',
779 default=False,
782 default=False,
780 )
783 )
781 coreconfigitem('server', 'zliblevel',
784 coreconfigitem('server', 'zliblevel',
782 default=-1,
785 default=-1,
783 )
786 )
784 coreconfigitem('smtp', 'host',
787 coreconfigitem('smtp', 'host',
785 default=None,
788 default=None,
786 )
789 )
787 coreconfigitem('smtp', 'local_hostname',
790 coreconfigitem('smtp', 'local_hostname',
788 default=None,
791 default=None,
789 )
792 )
790 coreconfigitem('smtp', 'password',
793 coreconfigitem('smtp', 'password',
791 default=None,
794 default=None,
792 )
795 )
793 coreconfigitem('smtp', 'port',
796 coreconfigitem('smtp', 'port',
794 default=dynamicdefault,
797 default=dynamicdefault,
795 )
798 )
796 coreconfigitem('smtp', 'tls',
799 coreconfigitem('smtp', 'tls',
797 default='none',
800 default='none',
798 )
801 )
799 coreconfigitem('smtp', 'username',
802 coreconfigitem('smtp', 'username',
800 default=None,
803 default=None,
801 )
804 )
802 coreconfigitem('sparse', 'missingwarning',
805 coreconfigitem('sparse', 'missingwarning',
803 default=True,
806 default=True,
804 )
807 )
805 coreconfigitem('templates', '.*',
808 coreconfigitem('templates', '.*',
806 default=None,
809 default=None,
807 generic=True,
810 generic=True,
808 )
811 )
809 coreconfigitem('trusted', 'groups',
812 coreconfigitem('trusted', 'groups',
810 default=list,
813 default=list,
811 )
814 )
812 coreconfigitem('trusted', 'users',
815 coreconfigitem('trusted', 'users',
813 default=list,
816 default=list,
814 )
817 )
815 coreconfigitem('ui', '_usedassubrepo',
818 coreconfigitem('ui', '_usedassubrepo',
816 default=False,
819 default=False,
817 )
820 )
818 coreconfigitem('ui', 'allowemptycommit',
821 coreconfigitem('ui', 'allowemptycommit',
819 default=False,
822 default=False,
820 )
823 )
821 coreconfigitem('ui', 'archivemeta',
824 coreconfigitem('ui', 'archivemeta',
822 default=True,
825 default=True,
823 )
826 )
824 coreconfigitem('ui', 'askusername',
827 coreconfigitem('ui', 'askusername',
825 default=False,
828 default=False,
826 )
829 )
827 coreconfigitem('ui', 'clonebundlefallback',
830 coreconfigitem('ui', 'clonebundlefallback',
828 default=False,
831 default=False,
829 )
832 )
830 coreconfigitem('ui', 'clonebundleprefers',
833 coreconfigitem('ui', 'clonebundleprefers',
831 default=list,
834 default=list,
832 )
835 )
833 coreconfigitem('ui', 'clonebundles',
836 coreconfigitem('ui', 'clonebundles',
834 default=True,
837 default=True,
835 )
838 )
836 coreconfigitem('ui', 'color',
839 coreconfigitem('ui', 'color',
837 default='auto',
840 default='auto',
838 )
841 )
839 coreconfigitem('ui', 'commitsubrepos',
842 coreconfigitem('ui', 'commitsubrepos',
840 default=False,
843 default=False,
841 )
844 )
842 coreconfigitem('ui', 'debug',
845 coreconfigitem('ui', 'debug',
843 default=False,
846 default=False,
844 )
847 )
845 coreconfigitem('ui', 'debugger',
848 coreconfigitem('ui', 'debugger',
846 default=None,
849 default=None,
847 )
850 )
848 coreconfigitem('ui', 'fallbackencoding',
851 coreconfigitem('ui', 'fallbackencoding',
849 default=None,
852 default=None,
850 )
853 )
851 coreconfigitem('ui', 'forcecwd',
854 coreconfigitem('ui', 'forcecwd',
852 default=None,
855 default=None,
853 )
856 )
854 coreconfigitem('ui', 'forcemerge',
857 coreconfigitem('ui', 'forcemerge',
855 default=None,
858 default=None,
856 )
859 )
857 coreconfigitem('ui', 'formatdebug',
860 coreconfigitem('ui', 'formatdebug',
858 default=False,
861 default=False,
859 )
862 )
860 coreconfigitem('ui', 'formatjson',
863 coreconfigitem('ui', 'formatjson',
861 default=False,
864 default=False,
862 )
865 )
863 coreconfigitem('ui', 'formatted',
866 coreconfigitem('ui', 'formatted',
864 default=None,
867 default=None,
865 )
868 )
866 coreconfigitem('ui', 'graphnodetemplate',
869 coreconfigitem('ui', 'graphnodetemplate',
867 default=None,
870 default=None,
868 )
871 )
869 coreconfigitem('ui', 'http2debuglevel',
872 coreconfigitem('ui', 'http2debuglevel',
870 default=None,
873 default=None,
871 )
874 )
872 coreconfigitem('ui', 'interactive',
875 coreconfigitem('ui', 'interactive',
873 default=None,
876 default=None,
874 )
877 )
875 coreconfigitem('ui', 'interface',
878 coreconfigitem('ui', 'interface',
876 default=None,
879 default=None,
877 )
880 )
878 coreconfigitem('ui', 'interface.chunkselector',
881 coreconfigitem('ui', 'interface.chunkselector',
879 default=None,
882 default=None,
880 )
883 )
881 coreconfigitem('ui', 'logblockedtimes',
884 coreconfigitem('ui', 'logblockedtimes',
882 default=False,
885 default=False,
883 )
886 )
884 coreconfigitem('ui', 'logtemplate',
887 coreconfigitem('ui', 'logtemplate',
885 default=None,
888 default=None,
886 )
889 )
887 coreconfigitem('ui', 'merge',
890 coreconfigitem('ui', 'merge',
888 default=None,
891 default=None,
889 )
892 )
890 coreconfigitem('ui', 'mergemarkers',
893 coreconfigitem('ui', 'mergemarkers',
891 default='basic',
894 default='basic',
892 )
895 )
893 coreconfigitem('ui', 'mergemarkertemplate',
896 coreconfigitem('ui', 'mergemarkertemplate',
894 default=('{node|short} '
897 default=('{node|short} '
895 '{ifeq(tags, "tip", "", '
898 '{ifeq(tags, "tip", "", '
896 'ifeq(tags, "", "", "{tags} "))}'
899 'ifeq(tags, "", "", "{tags} "))}'
897 '{if(bookmarks, "{bookmarks} ")}'
900 '{if(bookmarks, "{bookmarks} ")}'
898 '{ifeq(branch, "default", "", "{branch} ")}'
901 '{ifeq(branch, "default", "", "{branch} ")}'
899 '- {author|user}: {desc|firstline}')
902 '- {author|user}: {desc|firstline}')
900 )
903 )
901 coreconfigitem('ui', 'nontty',
904 coreconfigitem('ui', 'nontty',
902 default=False,
905 default=False,
903 )
906 )
904 coreconfigitem('ui', 'origbackuppath',
907 coreconfigitem('ui', 'origbackuppath',
905 default=None,
908 default=None,
906 )
909 )
907 coreconfigitem('ui', 'paginate',
910 coreconfigitem('ui', 'paginate',
908 default=True,
911 default=True,
909 )
912 )
910 coreconfigitem('ui', 'patch',
913 coreconfigitem('ui', 'patch',
911 default=None,
914 default=None,
912 )
915 )
913 coreconfigitem('ui', 'portablefilenames',
916 coreconfigitem('ui', 'portablefilenames',
914 default='warn',
917 default='warn',
915 )
918 )
916 coreconfigitem('ui', 'promptecho',
919 coreconfigitem('ui', 'promptecho',
917 default=False,
920 default=False,
918 )
921 )
919 coreconfigitem('ui', 'quiet',
922 coreconfigitem('ui', 'quiet',
920 default=False,
923 default=False,
921 )
924 )
922 coreconfigitem('ui', 'quietbookmarkmove',
925 coreconfigitem('ui', 'quietbookmarkmove',
923 default=False,
926 default=False,
924 )
927 )
925 coreconfigitem('ui', 'remotecmd',
928 coreconfigitem('ui', 'remotecmd',
926 default='hg',
929 default='hg',
927 )
930 )
928 coreconfigitem('ui', 'report_untrusted',
931 coreconfigitem('ui', 'report_untrusted',
929 default=True,
932 default=True,
930 )
933 )
931 coreconfigitem('ui', 'rollback',
934 coreconfigitem('ui', 'rollback',
932 default=True,
935 default=True,
933 )
936 )
934 coreconfigitem('ui', 'slash',
937 coreconfigitem('ui', 'slash',
935 default=False,
938 default=False,
936 )
939 )
937 coreconfigitem('ui', 'ssh',
940 coreconfigitem('ui', 'ssh',
938 default='ssh',
941 default='ssh',
939 )
942 )
940 coreconfigitem('ui', 'statuscopies',
943 coreconfigitem('ui', 'statuscopies',
941 default=False,
944 default=False,
942 )
945 )
943 coreconfigitem('ui', 'strict',
946 coreconfigitem('ui', 'strict',
944 default=False,
947 default=False,
945 )
948 )
946 coreconfigitem('ui', 'style',
949 coreconfigitem('ui', 'style',
947 default='',
950 default='',
948 )
951 )
949 coreconfigitem('ui', 'supportcontact',
952 coreconfigitem('ui', 'supportcontact',
950 default=None,
953 default=None,
951 )
954 )
952 coreconfigitem('ui', 'textwidth',
955 coreconfigitem('ui', 'textwidth',
953 default=78,
956 default=78,
954 )
957 )
955 coreconfigitem('ui', 'timeout',
958 coreconfigitem('ui', 'timeout',
956 default='600',
959 default='600',
957 )
960 )
958 coreconfigitem('ui', 'traceback',
961 coreconfigitem('ui', 'traceback',
959 default=False,
962 default=False,
960 )
963 )
961 coreconfigitem('ui', 'tweakdefaults',
964 coreconfigitem('ui', 'tweakdefaults',
962 default=False,
965 default=False,
963 )
966 )
964 coreconfigitem('ui', 'usehttp2',
967 coreconfigitem('ui', 'usehttp2',
965 default=False,
968 default=False,
966 )
969 )
967 coreconfigitem('ui', 'username',
970 coreconfigitem('ui', 'username',
968 alias=[('ui', 'user')]
971 alias=[('ui', 'user')]
969 )
972 )
970 coreconfigitem('ui', 'verbose',
973 coreconfigitem('ui', 'verbose',
971 default=False,
974 default=False,
972 )
975 )
973 coreconfigitem('verify', 'skipflags',
976 coreconfigitem('verify', 'skipflags',
974 default=None,
977 default=None,
975 )
978 )
976 coreconfigitem('web', 'allowbz2',
979 coreconfigitem('web', 'allowbz2',
977 default=False,
980 default=False,
978 )
981 )
979 coreconfigitem('web', 'allowgz',
982 coreconfigitem('web', 'allowgz',
980 default=False,
983 default=False,
981 )
984 )
982 coreconfigitem('web', 'allowpull',
985 coreconfigitem('web', 'allowpull',
983 default=True,
986 default=True,
984 )
987 )
985 coreconfigitem('web', 'allow_push',
988 coreconfigitem('web', 'allow_push',
986 default=list,
989 default=list,
987 )
990 )
988 coreconfigitem('web', 'allowzip',
991 coreconfigitem('web', 'allowzip',
989 default=False,
992 default=False,
990 )
993 )
991 coreconfigitem('web', 'archivesubrepos',
994 coreconfigitem('web', 'archivesubrepos',
992 default=False,
995 default=False,
993 )
996 )
994 coreconfigitem('web', 'cache',
997 coreconfigitem('web', 'cache',
995 default=True,
998 default=True,
996 )
999 )
997 coreconfigitem('web', 'contact',
1000 coreconfigitem('web', 'contact',
998 default=None,
1001 default=None,
999 )
1002 )
1000 coreconfigitem('web', 'deny_push',
1003 coreconfigitem('web', 'deny_push',
1001 default=list,
1004 default=list,
1002 )
1005 )
1003 coreconfigitem('web', 'guessmime',
1006 coreconfigitem('web', 'guessmime',
1004 default=False,
1007 default=False,
1005 )
1008 )
1006 coreconfigitem('web', 'hidden',
1009 coreconfigitem('web', 'hidden',
1007 default=False,
1010 default=False,
1008 )
1011 )
1009 coreconfigitem('web', 'labels',
1012 coreconfigitem('web', 'labels',
1010 default=list,
1013 default=list,
1011 )
1014 )
1012 coreconfigitem('web', 'logoimg',
1015 coreconfigitem('web', 'logoimg',
1013 default='hglogo.png',
1016 default='hglogo.png',
1014 )
1017 )
1015 coreconfigitem('web', 'logourl',
1018 coreconfigitem('web', 'logourl',
1016 default='https://mercurial-scm.org/',
1019 default='https://mercurial-scm.org/',
1017 )
1020 )
1018 coreconfigitem('web', 'accesslog',
1021 coreconfigitem('web', 'accesslog',
1019 default='-',
1022 default='-',
1020 )
1023 )
1021 coreconfigitem('web', 'address',
1024 coreconfigitem('web', 'address',
1022 default='',
1025 default='',
1023 )
1026 )
1024 coreconfigitem('web', 'allow_archive',
1027 coreconfigitem('web', 'allow_archive',
1025 default=list,
1028 default=list,
1026 )
1029 )
1027 coreconfigitem('web', 'allow_read',
1030 coreconfigitem('web', 'allow_read',
1028 default=list,
1031 default=list,
1029 )
1032 )
1030 coreconfigitem('web', 'baseurl',
1033 coreconfigitem('web', 'baseurl',
1031 default=None,
1034 default=None,
1032 )
1035 )
1033 coreconfigitem('web', 'cacerts',
1036 coreconfigitem('web', 'cacerts',
1034 default=None,
1037 default=None,
1035 )
1038 )
1036 coreconfigitem('web', 'certificate',
1039 coreconfigitem('web', 'certificate',
1037 default=None,
1040 default=None,
1038 )
1041 )
1039 coreconfigitem('web', 'collapse',
1042 coreconfigitem('web', 'collapse',
1040 default=False,
1043 default=False,
1041 )
1044 )
1042 coreconfigitem('web', 'csp',
1045 coreconfigitem('web', 'csp',
1043 default=None,
1046 default=None,
1044 )
1047 )
1045 coreconfigitem('web', 'deny_read',
1048 coreconfigitem('web', 'deny_read',
1046 default=list,
1049 default=list,
1047 )
1050 )
1048 coreconfigitem('web', 'descend',
1051 coreconfigitem('web', 'descend',
1049 default=True,
1052 default=True,
1050 )
1053 )
1051 coreconfigitem('web', 'description',
1054 coreconfigitem('web', 'description',
1052 default="",
1055 default="",
1053 )
1056 )
1054 coreconfigitem('web', 'encoding',
1057 coreconfigitem('web', 'encoding',
1055 default=lambda: encoding.encoding,
1058 default=lambda: encoding.encoding,
1056 )
1059 )
1057 coreconfigitem('web', 'errorlog',
1060 coreconfigitem('web', 'errorlog',
1058 default='-',
1061 default='-',
1059 )
1062 )
1060 coreconfigitem('web', 'ipv6',
1063 coreconfigitem('web', 'ipv6',
1061 default=False,
1064 default=False,
1062 )
1065 )
1063 coreconfigitem('web', 'maxchanges',
1066 coreconfigitem('web', 'maxchanges',
1064 default=10,
1067 default=10,
1065 )
1068 )
1066 coreconfigitem('web', 'maxfiles',
1069 coreconfigitem('web', 'maxfiles',
1067 default=10,
1070 default=10,
1068 )
1071 )
1069 coreconfigitem('web', 'maxshortchanges',
1072 coreconfigitem('web', 'maxshortchanges',
1070 default=60,
1073 default=60,
1071 )
1074 )
1072 coreconfigitem('web', 'motd',
1075 coreconfigitem('web', 'motd',
1073 default='',
1076 default='',
1074 )
1077 )
1075 coreconfigitem('web', 'name',
1078 coreconfigitem('web', 'name',
1076 default=dynamicdefault,
1079 default=dynamicdefault,
1077 )
1080 )
1078 coreconfigitem('web', 'port',
1081 coreconfigitem('web', 'port',
1079 default=8000,
1082 default=8000,
1080 )
1083 )
1081 coreconfigitem('web', 'prefix',
1084 coreconfigitem('web', 'prefix',
1082 default='',
1085 default='',
1083 )
1086 )
1084 coreconfigitem('web', 'push_ssl',
1087 coreconfigitem('web', 'push_ssl',
1085 default=True,
1088 default=True,
1086 )
1089 )
1087 coreconfigitem('web', 'refreshinterval',
1090 coreconfigitem('web', 'refreshinterval',
1088 default=20,
1091 default=20,
1089 )
1092 )
1090 coreconfigitem('web', 'staticurl',
1093 coreconfigitem('web', 'staticurl',
1091 default=None,
1094 default=None,
1092 )
1095 )
1093 coreconfigitem('web', 'stripes',
1096 coreconfigitem('web', 'stripes',
1094 default=1,
1097 default=1,
1095 )
1098 )
1096 coreconfigitem('web', 'style',
1099 coreconfigitem('web', 'style',
1097 default='paper',
1100 default='paper',
1098 )
1101 )
1099 coreconfigitem('web', 'templates',
1102 coreconfigitem('web', 'templates',
1100 default=None,
1103 default=None,
1101 )
1104 )
1102 coreconfigitem('web', 'view',
1105 coreconfigitem('web', 'view',
1103 default='served',
1106 default='served',
1104 )
1107 )
1105 coreconfigitem('worker', 'backgroundclose',
1108 coreconfigitem('worker', 'backgroundclose',
1106 default=dynamicdefault,
1109 default=dynamicdefault,
1107 )
1110 )
1108 # Windows defaults to a limit of 512 open files. A buffer of 128
1111 # Windows defaults to a limit of 512 open files. A buffer of 128
1109 # should give us enough headway.
1112 # should give us enough headway.
1110 coreconfigitem('worker', 'backgroundclosemaxqueue',
1113 coreconfigitem('worker', 'backgroundclosemaxqueue',
1111 default=384,
1114 default=384,
1112 )
1115 )
1113 coreconfigitem('worker', 'backgroundcloseminfilecount',
1116 coreconfigitem('worker', 'backgroundcloseminfilecount',
1114 default=2048,
1117 default=2048,
1115 )
1118 )
1116 coreconfigitem('worker', 'backgroundclosethreadcount',
1119 coreconfigitem('worker', 'backgroundclosethreadcount',
1117 default=4,
1120 default=4,
1118 )
1121 )
1119 coreconfigitem('worker', 'numcpus',
1122 coreconfigitem('worker', 'numcpus',
1120 default=None,
1123 default=None,
1121 )
1124 )
1122
1125
1123 # Rebase related configuration moved to core because other extension are doing
1126 # Rebase related configuration moved to core because other extension are doing
1124 # strange things. For example, shelve import the extensions to reuse some bit
1127 # strange things. For example, shelve import the extensions to reuse some bit
1125 # without formally loading it.
1128 # without formally loading it.
1126 coreconfigitem('commands', 'rebase.requiredest',
1129 coreconfigitem('commands', 'rebase.requiredest',
1127 default=False,
1130 default=False,
1128 )
1131 )
1129 coreconfigitem('experimental', 'rebaseskipobsolete',
1132 coreconfigitem('experimental', 'rebaseskipobsolete',
1130 default=True,
1133 default=True,
1131 )
1134 )
1132 coreconfigitem('rebase', 'singletransaction',
1135 coreconfigitem('rebase', 'singletransaction',
1133 default=False,
1136 default=False,
1134 )
1137 )
General Comments 0
You need to be logged in to leave comments. Login now