##// END OF EJS Templates
filemerge: use 'basic' as the default of '[ui] mergemarkers' for safety...
FUJIWARA Katsunori -
r21918:10abc3a5 default
parent child Browse files
Show More
@@ -1,436 +1,436 b''
1 # filemerge.py - file-level merge handling for Mercurial
1 # filemerge.py - file-level merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import short
8 from node import short
9 from i18n import _
9 from i18n import _
10 import util, simplemerge, match, error, templater, templatekw
10 import util, simplemerge, match, error, templater, templatekw
11 import os, tempfile, re, filecmp
11 import os, tempfile, re, filecmp
12
12
13 def _toolstr(ui, tool, part, default=""):
13 def _toolstr(ui, tool, part, default=""):
14 return ui.config("merge-tools", tool + "." + part, default)
14 return ui.config("merge-tools", tool + "." + part, default)
15
15
16 def _toolbool(ui, tool, part, default=False):
16 def _toolbool(ui, tool, part, default=False):
17 return ui.configbool("merge-tools", tool + "." + part, default)
17 return ui.configbool("merge-tools", tool + "." + part, default)
18
18
19 def _toollist(ui, tool, part, default=[]):
19 def _toollist(ui, tool, part, default=[]):
20 return ui.configlist("merge-tools", tool + "." + part, default)
20 return ui.configlist("merge-tools", tool + "." + part, default)
21
21
22 internals = {}
22 internals = {}
23
23
24 def internaltool(name, trymerge, onfailure=None):
24 def internaltool(name, trymerge, onfailure=None):
25 '''return a decorator for populating internal merge tool table'''
25 '''return a decorator for populating internal merge tool table'''
26 def decorator(func):
26 def decorator(func):
27 fullname = 'internal:' + name
27 fullname = 'internal:' + name
28 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
28 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
29 internals[fullname] = func
29 internals[fullname] = func
30 func.trymerge = trymerge
30 func.trymerge = trymerge
31 func.onfailure = onfailure
31 func.onfailure = onfailure
32 return func
32 return func
33 return decorator
33 return decorator
34
34
35 def _findtool(ui, tool):
35 def _findtool(ui, tool):
36 if tool in internals:
36 if tool in internals:
37 return tool
37 return tool
38 for kn in ("regkey", "regkeyalt"):
38 for kn in ("regkey", "regkeyalt"):
39 k = _toolstr(ui, tool, kn)
39 k = _toolstr(ui, tool, kn)
40 if not k:
40 if not k:
41 continue
41 continue
42 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
42 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
43 if p:
43 if p:
44 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
44 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
45 if p:
45 if p:
46 return p
46 return p
47 exe = _toolstr(ui, tool, "executable", tool)
47 exe = _toolstr(ui, tool, "executable", tool)
48 return util.findexe(util.expandpath(exe))
48 return util.findexe(util.expandpath(exe))
49
49
50 def _picktool(repo, ui, path, binary, symlink):
50 def _picktool(repo, ui, path, binary, symlink):
51 def check(tool, pat, symlink, binary):
51 def check(tool, pat, symlink, binary):
52 tmsg = tool
52 tmsg = tool
53 if pat:
53 if pat:
54 tmsg += " specified for " + pat
54 tmsg += " specified for " + pat
55 if not _findtool(ui, tool):
55 if not _findtool(ui, tool):
56 if pat: # explicitly requested tool deserves a warning
56 if pat: # explicitly requested tool deserves a warning
57 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
57 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
58 else: # configured but non-existing tools are more silent
58 else: # configured but non-existing tools are more silent
59 ui.note(_("couldn't find merge tool %s\n") % tmsg)
59 ui.note(_("couldn't find merge tool %s\n") % tmsg)
60 elif symlink and not _toolbool(ui, tool, "symlink"):
60 elif symlink and not _toolbool(ui, tool, "symlink"):
61 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
61 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
62 elif binary and not _toolbool(ui, tool, "binary"):
62 elif binary and not _toolbool(ui, tool, "binary"):
63 ui.warn(_("tool %s can't handle binary\n") % tmsg)
63 ui.warn(_("tool %s can't handle binary\n") % tmsg)
64 elif not util.gui() and _toolbool(ui, tool, "gui"):
64 elif not util.gui() and _toolbool(ui, tool, "gui"):
65 ui.warn(_("tool %s requires a GUI\n") % tmsg)
65 ui.warn(_("tool %s requires a GUI\n") % tmsg)
66 else:
66 else:
67 return True
67 return True
68 return False
68 return False
69
69
70 # forcemerge comes from command line arguments, highest priority
70 # forcemerge comes from command line arguments, highest priority
71 force = ui.config('ui', 'forcemerge')
71 force = ui.config('ui', 'forcemerge')
72 if force:
72 if force:
73 toolpath = _findtool(ui, force)
73 toolpath = _findtool(ui, force)
74 if toolpath:
74 if toolpath:
75 return (force, util.shellquote(toolpath))
75 return (force, util.shellquote(toolpath))
76 else:
76 else:
77 # mimic HGMERGE if given tool not found
77 # mimic HGMERGE if given tool not found
78 return (force, force)
78 return (force, force)
79
79
80 # HGMERGE takes next precedence
80 # HGMERGE takes next precedence
81 hgmerge = os.environ.get("HGMERGE")
81 hgmerge = os.environ.get("HGMERGE")
82 if hgmerge:
82 if hgmerge:
83 return (hgmerge, hgmerge)
83 return (hgmerge, hgmerge)
84
84
85 # then patterns
85 # then patterns
86 for pat, tool in ui.configitems("merge-patterns"):
86 for pat, tool in ui.configitems("merge-patterns"):
87 mf = match.match(repo.root, '', [pat])
87 mf = match.match(repo.root, '', [pat])
88 if mf(path) and check(tool, pat, symlink, False):
88 if mf(path) and check(tool, pat, symlink, False):
89 toolpath = _findtool(ui, tool)
89 toolpath = _findtool(ui, tool)
90 return (tool, util.shellquote(toolpath))
90 return (tool, util.shellquote(toolpath))
91
91
92 # then merge tools
92 # then merge tools
93 tools = {}
93 tools = {}
94 for k, v in ui.configitems("merge-tools"):
94 for k, v in ui.configitems("merge-tools"):
95 t = k.split('.')[0]
95 t = k.split('.')[0]
96 if t not in tools:
96 if t not in tools:
97 tools[t] = int(_toolstr(ui, t, "priority", "0"))
97 tools[t] = int(_toolstr(ui, t, "priority", "0"))
98 names = tools.keys()
98 names = tools.keys()
99 tools = sorted([(-p, t) for t, p in tools.items()])
99 tools = sorted([(-p, t) for t, p in tools.items()])
100 uimerge = ui.config("ui", "merge")
100 uimerge = ui.config("ui", "merge")
101 if uimerge:
101 if uimerge:
102 if uimerge not in names:
102 if uimerge not in names:
103 return (uimerge, uimerge)
103 return (uimerge, uimerge)
104 tools.insert(0, (None, uimerge)) # highest priority
104 tools.insert(0, (None, uimerge)) # highest priority
105 tools.append((None, "hgmerge")) # the old default, if found
105 tools.append((None, "hgmerge")) # the old default, if found
106 for p, t in tools:
106 for p, t in tools:
107 if check(t, None, symlink, binary):
107 if check(t, None, symlink, binary):
108 toolpath = _findtool(ui, t)
108 toolpath = _findtool(ui, t)
109 return (t, util.shellquote(toolpath))
109 return (t, util.shellquote(toolpath))
110
110
111 # internal merge or prompt as last resort
111 # internal merge or prompt as last resort
112 if symlink or binary:
112 if symlink or binary:
113 return "internal:prompt", None
113 return "internal:prompt", None
114 return "internal:merge", None
114 return "internal:merge", None
115
115
116 def _eoltype(data):
116 def _eoltype(data):
117 "Guess the EOL type of a file"
117 "Guess the EOL type of a file"
118 if '\0' in data: # binary
118 if '\0' in data: # binary
119 return None
119 return None
120 if '\r\n' in data: # Windows
120 if '\r\n' in data: # Windows
121 return '\r\n'
121 return '\r\n'
122 if '\r' in data: # Old Mac
122 if '\r' in data: # Old Mac
123 return '\r'
123 return '\r'
124 if '\n' in data: # UNIX
124 if '\n' in data: # UNIX
125 return '\n'
125 return '\n'
126 return None # unknown
126 return None # unknown
127
127
128 def _matcheol(file, origfile):
128 def _matcheol(file, origfile):
129 "Convert EOL markers in a file to match origfile"
129 "Convert EOL markers in a file to match origfile"
130 tostyle = _eoltype(util.readfile(origfile))
130 tostyle = _eoltype(util.readfile(origfile))
131 if tostyle:
131 if tostyle:
132 data = util.readfile(file)
132 data = util.readfile(file)
133 style = _eoltype(data)
133 style = _eoltype(data)
134 if style:
134 if style:
135 newdata = data.replace(style, tostyle)
135 newdata = data.replace(style, tostyle)
136 if newdata != data:
136 if newdata != data:
137 util.writefile(file, newdata)
137 util.writefile(file, newdata)
138
138
139 @internaltool('prompt', False)
139 @internaltool('prompt', False)
140 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
140 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
141 """Asks the user which of the local or the other version to keep as
141 """Asks the user which of the local or the other version to keep as
142 the merged version."""
142 the merged version."""
143 ui = repo.ui
143 ui = repo.ui
144 fd = fcd.path()
144 fd = fcd.path()
145
145
146 if ui.promptchoice(_(" no tool found to merge %s\n"
146 if ui.promptchoice(_(" no tool found to merge %s\n"
147 "keep (l)ocal or take (o)ther?"
147 "keep (l)ocal or take (o)ther?"
148 "$$ &Local $$ &Other") % fd, 0):
148 "$$ &Local $$ &Other") % fd, 0):
149 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
149 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
150 else:
150 else:
151 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
151 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
152
152
153 @internaltool('local', False)
153 @internaltool('local', False)
154 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
154 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
155 """Uses the local version of files as the merged version."""
155 """Uses the local version of files as the merged version."""
156 return 0
156 return 0
157
157
158 @internaltool('other', False)
158 @internaltool('other', False)
159 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
159 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
160 """Uses the other version of files as the merged version."""
160 """Uses the other version of files as the merged version."""
161 repo.wwrite(fcd.path(), fco.data(), fco.flags())
161 repo.wwrite(fcd.path(), fco.data(), fco.flags())
162 return 0
162 return 0
163
163
164 @internaltool('fail', False)
164 @internaltool('fail', False)
165 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
165 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
166 """
166 """
167 Rather than attempting to merge files that were modified on both
167 Rather than attempting to merge files that were modified on both
168 branches, it marks them as unresolved. The resolve command must be
168 branches, it marks them as unresolved. The resolve command must be
169 used to resolve these conflicts."""
169 used to resolve these conflicts."""
170 return 1
170 return 1
171
171
172 def _premerge(repo, toolconf, files, labels=None):
172 def _premerge(repo, toolconf, files, labels=None):
173 tool, toolpath, binary, symlink = toolconf
173 tool, toolpath, binary, symlink = toolconf
174 if symlink:
174 if symlink:
175 return 1
175 return 1
176 a, b, c, back = files
176 a, b, c, back = files
177
177
178 ui = repo.ui
178 ui = repo.ui
179
179
180 # do we attempt to simplemerge first?
180 # do we attempt to simplemerge first?
181 try:
181 try:
182 premerge = _toolbool(ui, tool, "premerge", not binary)
182 premerge = _toolbool(ui, tool, "premerge", not binary)
183 except error.ConfigError:
183 except error.ConfigError:
184 premerge = _toolstr(ui, tool, "premerge").lower()
184 premerge = _toolstr(ui, tool, "premerge").lower()
185 valid = 'keep'.split()
185 valid = 'keep'.split()
186 if premerge not in valid:
186 if premerge not in valid:
187 _valid = ', '.join(["'" + v + "'" for v in valid])
187 _valid = ', '.join(["'" + v + "'" for v in valid])
188 raise error.ConfigError(_("%s.premerge not valid "
188 raise error.ConfigError(_("%s.premerge not valid "
189 "('%s' is neither boolean nor %s)") %
189 "('%s' is neither boolean nor %s)") %
190 (tool, premerge, _valid))
190 (tool, premerge, _valid))
191
191
192 if premerge:
192 if premerge:
193 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
193 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
194 if not r:
194 if not r:
195 ui.debug(" premerge successful\n")
195 ui.debug(" premerge successful\n")
196 return 0
196 return 0
197 if premerge != 'keep':
197 if premerge != 'keep':
198 util.copyfile(back, a) # restore from backup and try again
198 util.copyfile(back, a) # restore from backup and try again
199 return 1 # continue merging
199 return 1 # continue merging
200
200
201 @internaltool('merge', True,
201 @internaltool('merge', True,
202 _("merging %s incomplete! "
202 _("merging %s incomplete! "
203 "(edit conflicts, then use 'hg resolve --mark')\n"))
203 "(edit conflicts, then use 'hg resolve --mark')\n"))
204 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
204 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
205 """
205 """
206 Uses the internal non-interactive simple merge algorithm for merging
206 Uses the internal non-interactive simple merge algorithm for merging
207 files. It will fail if there are any conflicts and leave markers in
207 files. It will fail if there are any conflicts and leave markers in
208 the partially merged file."""
208 the partially merged file."""
209 tool, toolpath, binary, symlink = toolconf
209 tool, toolpath, binary, symlink = toolconf
210 if symlink:
210 if symlink:
211 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
211 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
212 'for %s\n') % fcd.path())
212 'for %s\n') % fcd.path())
213 return False, 1
213 return False, 1
214 r = _premerge(repo, toolconf, files, labels=labels)
214 r = _premerge(repo, toolconf, files, labels=labels)
215 if r:
215 if r:
216 a, b, c, back = files
216 a, b, c, back = files
217
217
218 ui = repo.ui
218 ui = repo.ui
219
219
220 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
220 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
221 return True, r
221 return True, r
222 return False, 0
222 return False, 0
223
223
224 @internaltool('dump', True)
224 @internaltool('dump', True)
225 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
225 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
226 """
226 """
227 Creates three versions of the files to merge, containing the
227 Creates three versions of the files to merge, containing the
228 contents of local, other and base. These files can then be used to
228 contents of local, other and base. These files can then be used to
229 perform a merge manually. If the file to be merged is named
229 perform a merge manually. If the file to be merged is named
230 ``a.txt``, these files will accordingly be named ``a.txt.local``,
230 ``a.txt``, these files will accordingly be named ``a.txt.local``,
231 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
231 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
232 same directory as ``a.txt``."""
232 same directory as ``a.txt``."""
233 r = _premerge(repo, toolconf, files, labels=labels)
233 r = _premerge(repo, toolconf, files, labels=labels)
234 if r:
234 if r:
235 a, b, c, back = files
235 a, b, c, back = files
236
236
237 fd = fcd.path()
237 fd = fcd.path()
238
238
239 util.copyfile(a, a + ".local")
239 util.copyfile(a, a + ".local")
240 repo.wwrite(fd + ".other", fco.data(), fco.flags())
240 repo.wwrite(fd + ".other", fco.data(), fco.flags())
241 repo.wwrite(fd + ".base", fca.data(), fca.flags())
241 repo.wwrite(fd + ".base", fca.data(), fca.flags())
242 return False, r
242 return False, r
243
243
244 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
244 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
245 r = _premerge(repo, toolconf, files, labels=labels)
245 r = _premerge(repo, toolconf, files, labels=labels)
246 if r:
246 if r:
247 tool, toolpath, binary, symlink = toolconf
247 tool, toolpath, binary, symlink = toolconf
248 a, b, c, back = files
248 a, b, c, back = files
249 out = ""
249 out = ""
250 env = {'HG_FILE': fcd.path(),
250 env = {'HG_FILE': fcd.path(),
251 'HG_MY_NODE': short(mynode),
251 'HG_MY_NODE': short(mynode),
252 'HG_OTHER_NODE': str(fco.changectx()),
252 'HG_OTHER_NODE': str(fco.changectx()),
253 'HG_BASE_NODE': str(fca.changectx()),
253 'HG_BASE_NODE': str(fca.changectx()),
254 'HG_MY_ISLINK': 'l' in fcd.flags(),
254 'HG_MY_ISLINK': 'l' in fcd.flags(),
255 'HG_OTHER_ISLINK': 'l' in fco.flags(),
255 'HG_OTHER_ISLINK': 'l' in fco.flags(),
256 'HG_BASE_ISLINK': 'l' in fca.flags(),
256 'HG_BASE_ISLINK': 'l' in fca.flags(),
257 }
257 }
258
258
259 ui = repo.ui
259 ui = repo.ui
260
260
261 args = _toolstr(ui, tool, "args", '$local $base $other')
261 args = _toolstr(ui, tool, "args", '$local $base $other')
262 if "$output" in args:
262 if "$output" in args:
263 out, a = a, back # read input from backup, write to original
263 out, a = a, back # read input from backup, write to original
264 replace = {'local': a, 'base': b, 'other': c, 'output': out}
264 replace = {'local': a, 'base': b, 'other': c, 'output': out}
265 args = util.interpolate(r'\$', replace, args,
265 args = util.interpolate(r'\$', replace, args,
266 lambda s: util.shellquote(util.localpath(s)))
266 lambda s: util.shellquote(util.localpath(s)))
267 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
267 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
268 out=ui.fout)
268 out=ui.fout)
269 return True, r
269 return True, r
270 return False, 0
270 return False, 0
271
271
272 def _formatconflictmarker(repo, ctx, template, label, pad):
272 def _formatconflictmarker(repo, ctx, template, label, pad):
273 """Applies the given template to the ctx, prefixed by the label.
273 """Applies the given template to the ctx, prefixed by the label.
274
274
275 Pad is the minimum width of the label prefix, so that multiple markers
275 Pad is the minimum width of the label prefix, so that multiple markers
276 can have aligned templated parts.
276 can have aligned templated parts.
277 """
277 """
278 if ctx.node() is None:
278 if ctx.node() is None:
279 ctx = ctx.p1()
279 ctx = ctx.p1()
280
280
281 props = templatekw.keywords.copy()
281 props = templatekw.keywords.copy()
282 props['templ'] = template
282 props['templ'] = template
283 props['ctx'] = ctx
283 props['ctx'] = ctx
284 props['repo'] = repo
284 props['repo'] = repo
285 templateresult = template('conflictmarker', **props)
285 templateresult = template('conflictmarker', **props)
286
286
287 label = ('%s:' % label).ljust(pad + 1)
287 label = ('%s:' % label).ljust(pad + 1)
288 mark = '%s %s' % (label, templater.stringify(templateresult))
288 mark = '%s %s' % (label, templater.stringify(templateresult))
289
289
290 if mark:
290 if mark:
291 mark = mark.splitlines()[0] # split for safety
291 mark = mark.splitlines()[0] # split for safety
292
292
293 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
293 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
294 return util.ellipsis(mark, 80 - 8)
294 return util.ellipsis(mark, 80 - 8)
295
295
296 _defaultconflictmarker = ('{node|short} ' +
296 _defaultconflictmarker = ('{node|short} ' +
297 '{ifeq(tags, "tip", "", "{tags} ")}' +
297 '{ifeq(tags, "tip", "", "{tags} ")}' +
298 '{if(bookmarks, "{bookmarks} ")}' +
298 '{if(bookmarks, "{bookmarks} ")}' +
299 '{ifeq(branch, "default", "", "{branch} ")}' +
299 '{ifeq(branch, "default", "", "{branch} ")}' +
300 '- {author|user}: {desc|firstline}')
300 '- {author|user}: {desc|firstline}')
301
301
302 _defaultconflictlabels = ['local', 'other']
302 _defaultconflictlabels = ['local', 'other']
303
303
304 def _formatlabels(repo, fcd, fco, labels):
304 def _formatlabels(repo, fcd, fco, labels):
305 """Formats the given labels using the conflict marker template.
305 """Formats the given labels using the conflict marker template.
306
306
307 Returns a list of formatted labels.
307 Returns a list of formatted labels.
308 """
308 """
309 cd = fcd.changectx()
309 cd = fcd.changectx()
310 co = fco.changectx()
310 co = fco.changectx()
311
311
312 ui = repo.ui
312 ui = repo.ui
313 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
313 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
314 template = templater.parsestring(template, quoted=False)
314 template = templater.parsestring(template, quoted=False)
315 tmpl = templater.templater(None, cache={ 'conflictmarker' : template })
315 tmpl = templater.templater(None, cache={ 'conflictmarker' : template })
316
316
317 pad = max(len(labels[0]), len(labels[1]))
317 pad = max(len(labels[0]), len(labels[1]))
318
318
319 return [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
319 return [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
320 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
320 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
321
321
322 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
322 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
323 """perform a 3-way merge in the working directory
323 """perform a 3-way merge in the working directory
324
324
325 mynode = parent node before merge
325 mynode = parent node before merge
326 orig = original local filename before merge
326 orig = original local filename before merge
327 fco = other file context
327 fco = other file context
328 fca = ancestor file context
328 fca = ancestor file context
329 fcd = local file context for current/destination file
329 fcd = local file context for current/destination file
330 """
330 """
331
331
332 def temp(prefix, ctx):
332 def temp(prefix, ctx):
333 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
333 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
334 (fd, name) = tempfile.mkstemp(prefix=pre)
334 (fd, name) = tempfile.mkstemp(prefix=pre)
335 data = repo.wwritedata(ctx.path(), ctx.data())
335 data = repo.wwritedata(ctx.path(), ctx.data())
336 f = os.fdopen(fd, "wb")
336 f = os.fdopen(fd, "wb")
337 f.write(data)
337 f.write(data)
338 f.close()
338 f.close()
339 return name
339 return name
340
340
341 if not fco.cmp(fcd): # files identical?
341 if not fco.cmp(fcd): # files identical?
342 return None
342 return None
343
343
344 ui = repo.ui
344 ui = repo.ui
345 fd = fcd.path()
345 fd = fcd.path()
346 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
346 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
347 symlink = 'l' in fcd.flags() + fco.flags()
347 symlink = 'l' in fcd.flags() + fco.flags()
348 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
348 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
349 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
349 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
350 (tool, fd, binary, symlink))
350 (tool, fd, binary, symlink))
351
351
352 if tool in internals:
352 if tool in internals:
353 func = internals[tool]
353 func = internals[tool]
354 trymerge = func.trymerge
354 trymerge = func.trymerge
355 onfailure = func.onfailure
355 onfailure = func.onfailure
356 else:
356 else:
357 func = _xmerge
357 func = _xmerge
358 trymerge = True
358 trymerge = True
359 onfailure = _("merging %s failed!\n")
359 onfailure = _("merging %s failed!\n")
360
360
361 toolconf = tool, toolpath, binary, symlink
361 toolconf = tool, toolpath, binary, symlink
362
362
363 if not trymerge:
363 if not trymerge:
364 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
364 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
365
365
366 a = repo.wjoin(fd)
366 a = repo.wjoin(fd)
367 b = temp("base", fca)
367 b = temp("base", fca)
368 c = temp("other", fco)
368 c = temp("other", fco)
369 back = a + ".orig"
369 back = a + ".orig"
370 util.copyfile(a, back)
370 util.copyfile(a, back)
371
371
372 if orig != fco.path():
372 if orig != fco.path():
373 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
373 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
374 else:
374 else:
375 ui.status(_("merging %s\n") % fd)
375 ui.status(_("merging %s\n") % fd)
376
376
377 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
377 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
378
378
379 markerstyle = ui.config('ui', 'mergemarkers', 'detailed')
379 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
380 if markerstyle == 'basic':
380 if markerstyle == 'basic':
381 formattedlabels = _defaultconflictlabels
381 formattedlabels = _defaultconflictlabels
382 else:
382 else:
383 if not labels:
383 if not labels:
384 labels = _defaultconflictlabels
384 labels = _defaultconflictlabels
385
385
386 formattedlabels = _formatlabels(repo, fcd, fco, labels)
386 formattedlabels = _formatlabels(repo, fcd, fco, labels)
387
387
388 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
388 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
389 (a, b, c, back), labels=formattedlabels)
389 (a, b, c, back), labels=formattedlabels)
390 if not needcheck:
390 if not needcheck:
391 if r:
391 if r:
392 if onfailure:
392 if onfailure:
393 ui.warn(onfailure % fd)
393 ui.warn(onfailure % fd)
394 else:
394 else:
395 util.unlink(back)
395 util.unlink(back)
396
396
397 util.unlink(b)
397 util.unlink(b)
398 util.unlink(c)
398 util.unlink(c)
399 return r
399 return r
400
400
401 if not r and (_toolbool(ui, tool, "checkconflicts") or
401 if not r and (_toolbool(ui, tool, "checkconflicts") or
402 'conflicts' in _toollist(ui, tool, "check")):
402 'conflicts' in _toollist(ui, tool, "check")):
403 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
403 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
404 re.MULTILINE):
404 re.MULTILINE):
405 r = 1
405 r = 1
406
406
407 checked = False
407 checked = False
408 if 'prompt' in _toollist(ui, tool, "check"):
408 if 'prompt' in _toollist(ui, tool, "check"):
409 checked = True
409 checked = True
410 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
410 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
411 "$$ &Yes $$ &No") % fd, 1):
411 "$$ &Yes $$ &No") % fd, 1):
412 r = 1
412 r = 1
413
413
414 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
414 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
415 'changed' in _toollist(ui, tool, "check")):
415 'changed' in _toollist(ui, tool, "check")):
416 if filecmp.cmp(a, back):
416 if filecmp.cmp(a, back):
417 if ui.promptchoice(_(" output file %s appears unchanged\n"
417 if ui.promptchoice(_(" output file %s appears unchanged\n"
418 "was merge successful (yn)?"
418 "was merge successful (yn)?"
419 "$$ &Yes $$ &No") % fd, 1):
419 "$$ &Yes $$ &No") % fd, 1):
420 r = 1
420 r = 1
421
421
422 if _toolbool(ui, tool, "fixeol"):
422 if _toolbool(ui, tool, "fixeol"):
423 _matcheol(a, back)
423 _matcheol(a, back)
424
424
425 if r:
425 if r:
426 if onfailure:
426 if onfailure:
427 ui.warn(onfailure % fd)
427 ui.warn(onfailure % fd)
428 else:
428 else:
429 util.unlink(back)
429 util.unlink(back)
430
430
431 util.unlink(b)
431 util.unlink(b)
432 util.unlink(c)
432 util.unlink(c)
433 return r
433 return r
434
434
435 # tell hggettext to extract docstrings from these functions:
435 # tell hggettext to extract docstrings from these functions:
436 i18nfunctions = internals.values()
436 i18nfunctions = internals.values()
@@ -1,1572 +1,1579 b''
1 The Mercurial system uses a set of configuration files to control
1 The Mercurial system uses a set of configuration files to control
2 aspects of its behavior.
2 aspects of its behavior.
3
3
4 The configuration files use a simple ini-file format. A configuration
4 The configuration files use a simple ini-file format. A configuration
5 file consists of sections, led by a ``[section]`` header and followed
5 file consists of sections, led by a ``[section]`` header and followed
6 by ``name = value`` entries::
6 by ``name = value`` entries::
7
7
8 [ui]
8 [ui]
9 username = Firstname Lastname <firstname.lastname@example.net>
9 username = Firstname Lastname <firstname.lastname@example.net>
10 verbose = True
10 verbose = True
11
11
12 The above entries will be referred to as ``ui.username`` and
12 The above entries will be referred to as ``ui.username`` and
13 ``ui.verbose``, respectively. See the Syntax section below.
13 ``ui.verbose``, respectively. See the Syntax section below.
14
14
15 Files
15 Files
16 =====
16 =====
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 These files do not exist by default and you will have to create the
19 These files do not exist by default and you will have to create the
20 appropriate configuration files yourself: global configuration like
20 appropriate configuration files yourself: global configuration like
21 the username setting is typically put into
21 the username setting is typically put into
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24
24
25 The names of these files depend on the system on which Mercurial is
25 The names of these files depend on the system on which Mercurial is
26 installed. ``*.rc`` files from a single directory are read in
26 installed. ``*.rc`` files from a single directory are read in
27 alphabetical order, later ones overriding earlier ones. Where multiple
27 alphabetical order, later ones overriding earlier ones. Where multiple
28 paths are given below, settings from earlier paths override later
28 paths are given below, settings from earlier paths override later
29 ones.
29 ones.
30
30
31 | (All) ``<repo>/.hg/hgrc``
31 | (All) ``<repo>/.hg/hgrc``
32
32
33 Per-repository configuration options that only apply in a
33 Per-repository configuration options that only apply in a
34 particular repository. This file is not version-controlled, and
34 particular repository. This file is not version-controlled, and
35 will not get transferred during a "clone" operation. Options in
35 will not get transferred during a "clone" operation. Options in
36 this file override options in all other configuration files. On
36 this file override options in all other configuration files. On
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
38 belong to a trusted user or to a trusted group. See the documentation
38 belong to a trusted user or to a trusted group. See the documentation
39 for the ``[trusted]`` section below for more details.
39 for the ``[trusted]`` section below for more details.
40
40
41 | (Plan 9) ``$home/lib/hgrc``
41 | (Plan 9) ``$home/lib/hgrc``
42 | (Unix) ``$HOME/.hgrc``
42 | (Unix) ``$HOME/.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
45 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\.hgrc``
46 | (Windows) ``%HOME%\Mercurial.ini``
46 | (Windows) ``%HOME%\Mercurial.ini``
47
47
48 Per-user configuration file(s), for the user running Mercurial. On
48 Per-user configuration file(s), for the user running Mercurial. On
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
50 files apply to all Mercurial commands executed by this user in any
50 files apply to all Mercurial commands executed by this user in any
51 directory. Options in these files override per-system and per-installation
51 directory. Options in these files override per-system and per-installation
52 options.
52 options.
53
53
54 | (Plan 9) ``/lib/mercurial/hgrc``
54 | (Plan 9) ``/lib/mercurial/hgrc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
56 | (Unix) ``/etc/mercurial/hgrc``
56 | (Unix) ``/etc/mercurial/hgrc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
58
58
59 Per-system configuration files, for the system on which Mercurial
59 Per-system configuration files, for the system on which Mercurial
60 is running. Options in these files apply to all Mercurial commands
60 is running. Options in these files apply to all Mercurial commands
61 executed by any user in any directory. Options in these files
61 executed by any user in any directory. Options in these files
62 override per-installation options.
62 override per-installation options.
63
63
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
68
68
69 Per-installation configuration files, searched for in the
69 Per-installation configuration files, searched for in the
70 directory where Mercurial is installed. ``<install-root>`` is the
70 directory where Mercurial is installed. ``<install-root>`` is the
71 parent directory of the **hg** executable (or symlink) being run. For
71 parent directory of the **hg** executable (or symlink) being run. For
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
74 to all Mercurial commands executed by any user in any directory.
74 to all Mercurial commands executed by any user in any directory.
75
75
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
79
79
80 Per-installation/system configuration files, for the system on
80 Per-installation/system configuration files, for the system on
81 which Mercurial is running. Options in these files apply to all
81 which Mercurial is running. Options in these files apply to all
82 Mercurial commands executed by any user in any directory. Registry
82 Mercurial commands executed by any user in any directory. Registry
83 keys contain PATH-like strings, every part of which must reference
83 keys contain PATH-like strings, every part of which must reference
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
85 be read. Mercurial checks each of these locations in the specified
85 be read. Mercurial checks each of these locations in the specified
86 order until one or more configuration files are detected.
86 order until one or more configuration files are detected.
87
87
88 .. note::
88 .. note::
89
89
90 The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
90 The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
91 is used when running 32-bit Python on 64-bit Windows.
91 is used when running 32-bit Python on 64-bit Windows.
92
92
93 Syntax
93 Syntax
94 ======
94 ======
95
95
96 A configuration file consists of sections, led by a ``[section]`` header
96 A configuration file consists of sections, led by a ``[section]`` header
97 and followed by ``name = value`` entries (sometimes called
97 and followed by ``name = value`` entries (sometimes called
98 ``configuration keys``)::
98 ``configuration keys``)::
99
99
100 [spam]
100 [spam]
101 eggs=ham
101 eggs=ham
102 green=
102 green=
103 eggs
103 eggs
104
104
105 Each line contains one entry. If the lines that follow are indented,
105 Each line contains one entry. If the lines that follow are indented,
106 they are treated as continuations of that entry. Leading whitespace is
106 they are treated as continuations of that entry. Leading whitespace is
107 removed from values. Empty lines are skipped. Lines beginning with
107 removed from values. Empty lines are skipped. Lines beginning with
108 ``#`` or ``;`` are ignored and may be used to provide comments.
108 ``#`` or ``;`` are ignored and may be used to provide comments.
109
109
110 Configuration keys can be set multiple times, in which case Mercurial
110 Configuration keys can be set multiple times, in which case Mercurial
111 will use the value that was configured last. As an example::
111 will use the value that was configured last. As an example::
112
112
113 [spam]
113 [spam]
114 eggs=large
114 eggs=large
115 ham=serrano
115 ham=serrano
116 eggs=small
116 eggs=small
117
117
118 This would set the configuration key named ``eggs`` to ``small``.
118 This would set the configuration key named ``eggs`` to ``small``.
119
119
120 It is also possible to define a section multiple times. A section can
120 It is also possible to define a section multiple times. A section can
121 be redefined on the same and/or on different configuration files. For
121 be redefined on the same and/or on different configuration files. For
122 example::
122 example::
123
123
124 [foo]
124 [foo]
125 eggs=large
125 eggs=large
126 ham=serrano
126 ham=serrano
127 eggs=small
127 eggs=small
128
128
129 [bar]
129 [bar]
130 eggs=ham
130 eggs=ham
131 green=
131 green=
132 eggs
132 eggs
133
133
134 [foo]
134 [foo]
135 ham=prosciutto
135 ham=prosciutto
136 eggs=medium
136 eggs=medium
137 bread=toasted
137 bread=toasted
138
138
139 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
139 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
140 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
140 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
141 respectively. As you can see there only thing that matters is the last
141 respectively. As you can see there only thing that matters is the last
142 value that was set for each of the configuration keys.
142 value that was set for each of the configuration keys.
143
143
144 If a configuration key is set multiple times in different
144 If a configuration key is set multiple times in different
145 configuration files the final value will depend on the order in which
145 configuration files the final value will depend on the order in which
146 the different configuration files are read, with settings from earlier
146 the different configuration files are read, with settings from earlier
147 paths overriding later ones as described on the ``Files`` section
147 paths overriding later ones as described on the ``Files`` section
148 above.
148 above.
149
149
150 A line of the form ``%include file`` will include ``file`` into the
150 A line of the form ``%include file`` will include ``file`` into the
151 current configuration file. The inclusion is recursive, which means
151 current configuration file. The inclusion is recursive, which means
152 that included files can include other files. Filenames are relative to
152 that included files can include other files. Filenames are relative to
153 the configuration file in which the ``%include`` directive is found.
153 the configuration file in which the ``%include`` directive is found.
154 Environment variables and ``~user`` constructs are expanded in
154 Environment variables and ``~user`` constructs are expanded in
155 ``file``. This lets you do something like::
155 ``file``. This lets you do something like::
156
156
157 %include ~/.hgrc.d/$HOST.rc
157 %include ~/.hgrc.d/$HOST.rc
158
158
159 to include a different configuration file on each computer you use.
159 to include a different configuration file on each computer you use.
160
160
161 A line with ``%unset name`` will remove ``name`` from the current
161 A line with ``%unset name`` will remove ``name`` from the current
162 section, if it has been set previously.
162 section, if it has been set previously.
163
163
164 The values are either free-form text strings, lists of text strings,
164 The values are either free-form text strings, lists of text strings,
165 or Boolean values. Boolean values can be set to true using any of "1",
165 or Boolean values. Boolean values can be set to true using any of "1",
166 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
166 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
167 (all case insensitive).
167 (all case insensitive).
168
168
169 List values are separated by whitespace or comma, except when values are
169 List values are separated by whitespace or comma, except when values are
170 placed in double quotation marks::
170 placed in double quotation marks::
171
171
172 allow_read = "John Doe, PhD", brian, betty
172 allow_read = "John Doe, PhD", brian, betty
173
173
174 Quotation marks can be escaped by prefixing them with a backslash. Only
174 Quotation marks can be escaped by prefixing them with a backslash. Only
175 quotation marks at the beginning of a word is counted as a quotation
175 quotation marks at the beginning of a word is counted as a quotation
176 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
176 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
177
177
178 Sections
178 Sections
179 ========
179 ========
180
180
181 This section describes the different sections that may appear in a
181 This section describes the different sections that may appear in a
182 Mercurial configuration file, the purpose of each section, its possible
182 Mercurial configuration file, the purpose of each section, its possible
183 keys, and their possible values.
183 keys, and their possible values.
184
184
185 ``alias``
185 ``alias``
186 ---------
186 ---------
187
187
188 Defines command aliases.
188 Defines command aliases.
189 Aliases allow you to define your own commands in terms of other
189 Aliases allow you to define your own commands in terms of other
190 commands (or aliases), optionally including arguments. Positional
190 commands (or aliases), optionally including arguments. Positional
191 arguments in the form of ``$1``, ``$2``, etc in the alias definition
191 arguments in the form of ``$1``, ``$2``, etc in the alias definition
192 are expanded by Mercurial before execution. Positional arguments not
192 are expanded by Mercurial before execution. Positional arguments not
193 already used by ``$N`` in the definition are put at the end of the
193 already used by ``$N`` in the definition are put at the end of the
194 command to be executed.
194 command to be executed.
195
195
196 Alias definitions consist of lines of the form::
196 Alias definitions consist of lines of the form::
197
197
198 <alias> = <command> [<argument>]...
198 <alias> = <command> [<argument>]...
199
199
200 For example, this definition::
200 For example, this definition::
201
201
202 latest = log --limit 5
202 latest = log --limit 5
203
203
204 creates a new command ``latest`` that shows only the five most recent
204 creates a new command ``latest`` that shows only the five most recent
205 changesets. You can define subsequent aliases using earlier ones::
205 changesets. You can define subsequent aliases using earlier ones::
206
206
207 stable5 = latest -b stable
207 stable5 = latest -b stable
208
208
209 .. note::
209 .. note::
210
210
211 It is possible to create aliases with the same names as
211 It is possible to create aliases with the same names as
212 existing commands, which will then override the original
212 existing commands, which will then override the original
213 definitions. This is almost always a bad idea!
213 definitions. This is almost always a bad idea!
214
214
215 An alias can start with an exclamation point (``!``) to make it a
215 An alias can start with an exclamation point (``!``) to make it a
216 shell alias. A shell alias is executed with the shell and will let you
216 shell alias. A shell alias is executed with the shell and will let you
217 run arbitrary commands. As an example, ::
217 run arbitrary commands. As an example, ::
218
218
219 echo = !echo $@
219 echo = !echo $@
220
220
221 will let you do ``hg echo foo`` to have ``foo`` printed in your
221 will let you do ``hg echo foo`` to have ``foo`` printed in your
222 terminal. A better example might be::
222 terminal. A better example might be::
223
223
224 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
224 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
225
225
226 which will make ``hg purge`` delete all unknown files in the
226 which will make ``hg purge`` delete all unknown files in the
227 repository in the same manner as the purge extension.
227 repository in the same manner as the purge extension.
228
228
229 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
229 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
230 expand to the command arguments. Unmatched arguments are
230 expand to the command arguments. Unmatched arguments are
231 removed. ``$0`` expands to the alias name and ``$@`` expands to all
231 removed. ``$0`` expands to the alias name and ``$@`` expands to all
232 arguments separated by a space. These expansions happen before the
232 arguments separated by a space. These expansions happen before the
233 command is passed to the shell.
233 command is passed to the shell.
234
234
235 Shell aliases are executed in an environment where ``$HG`` expands to
235 Shell aliases are executed in an environment where ``$HG`` expands to
236 the path of the Mercurial that was used to execute the alias. This is
236 the path of the Mercurial that was used to execute the alias. This is
237 useful when you want to call further Mercurial commands in a shell
237 useful when you want to call further Mercurial commands in a shell
238 alias, as was done above for the purge alias. In addition,
238 alias, as was done above for the purge alias. In addition,
239 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
239 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
240 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
240 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
241
241
242 .. note::
242 .. note::
243
243
244 Some global configuration options such as ``-R`` are
244 Some global configuration options such as ``-R`` are
245 processed before shell aliases and will thus not be passed to
245 processed before shell aliases and will thus not be passed to
246 aliases.
246 aliases.
247
247
248
248
249 ``annotate``
249 ``annotate``
250 ------------
250 ------------
251
251
252 Settings used when displaying file annotations. All values are
252 Settings used when displaying file annotations. All values are
253 Booleans and default to False. See ``diff`` section for related
253 Booleans and default to False. See ``diff`` section for related
254 options for the diff command.
254 options for the diff command.
255
255
256 ``ignorews``
256 ``ignorews``
257 Ignore white space when comparing lines.
257 Ignore white space when comparing lines.
258
258
259 ``ignorewsamount``
259 ``ignorewsamount``
260 Ignore changes in the amount of white space.
260 Ignore changes in the amount of white space.
261
261
262 ``ignoreblanklines``
262 ``ignoreblanklines``
263 Ignore changes whose lines are all blank.
263 Ignore changes whose lines are all blank.
264
264
265
265
266 ``auth``
266 ``auth``
267 --------
267 --------
268
268
269 Authentication credentials for HTTP authentication. This section
269 Authentication credentials for HTTP authentication. This section
270 allows you to store usernames and passwords for use when logging
270 allows you to store usernames and passwords for use when logging
271 *into* HTTP servers. See the ``[web]`` configuration section if
271 *into* HTTP servers. See the ``[web]`` configuration section if
272 you want to configure *who* can login to your HTTP server.
272 you want to configure *who* can login to your HTTP server.
273
273
274 Each line has the following format::
274 Each line has the following format::
275
275
276 <name>.<argument> = <value>
276 <name>.<argument> = <value>
277
277
278 where ``<name>`` is used to group arguments into authentication
278 where ``<name>`` is used to group arguments into authentication
279 entries. Example::
279 entries. Example::
280
280
281 foo.prefix = hg.intevation.org/mercurial
281 foo.prefix = hg.intevation.org/mercurial
282 foo.username = foo
282 foo.username = foo
283 foo.password = bar
283 foo.password = bar
284 foo.schemes = http https
284 foo.schemes = http https
285
285
286 bar.prefix = secure.example.org
286 bar.prefix = secure.example.org
287 bar.key = path/to/file.key
287 bar.key = path/to/file.key
288 bar.cert = path/to/file.cert
288 bar.cert = path/to/file.cert
289 bar.schemes = https
289 bar.schemes = https
290
290
291 Supported arguments:
291 Supported arguments:
292
292
293 ``prefix``
293 ``prefix``
294 Either ``*`` or a URI prefix with or without the scheme part.
294 Either ``*`` or a URI prefix with or without the scheme part.
295 The authentication entry with the longest matching prefix is used
295 The authentication entry with the longest matching prefix is used
296 (where ``*`` matches everything and counts as a match of length
296 (where ``*`` matches everything and counts as a match of length
297 1). If the prefix doesn't include a scheme, the match is performed
297 1). If the prefix doesn't include a scheme, the match is performed
298 against the URI with its scheme stripped as well, and the schemes
298 against the URI with its scheme stripped as well, and the schemes
299 argument, q.v., is then subsequently consulted.
299 argument, q.v., is then subsequently consulted.
300
300
301 ``username``
301 ``username``
302 Optional. Username to authenticate with. If not given, and the
302 Optional. Username to authenticate with. If not given, and the
303 remote site requires basic or digest authentication, the user will
303 remote site requires basic or digest authentication, the user will
304 be prompted for it. Environment variables are expanded in the
304 be prompted for it. Environment variables are expanded in the
305 username letting you do ``foo.username = $USER``. If the URI
305 username letting you do ``foo.username = $USER``. If the URI
306 includes a username, only ``[auth]`` entries with a matching
306 includes a username, only ``[auth]`` entries with a matching
307 username or without a username will be considered.
307 username or without a username will be considered.
308
308
309 ``password``
309 ``password``
310 Optional. Password to authenticate with. If not given, and the
310 Optional. Password to authenticate with. If not given, and the
311 remote site requires basic or digest authentication, the user
311 remote site requires basic or digest authentication, the user
312 will be prompted for it.
312 will be prompted for it.
313
313
314 ``key``
314 ``key``
315 Optional. PEM encoded client certificate key file. Environment
315 Optional. PEM encoded client certificate key file. Environment
316 variables are expanded in the filename.
316 variables are expanded in the filename.
317
317
318 ``cert``
318 ``cert``
319 Optional. PEM encoded client certificate chain file. Environment
319 Optional. PEM encoded client certificate chain file. Environment
320 variables are expanded in the filename.
320 variables are expanded in the filename.
321
321
322 ``schemes``
322 ``schemes``
323 Optional. Space separated list of URI schemes to use this
323 Optional. Space separated list of URI schemes to use this
324 authentication entry with. Only used if the prefix doesn't include
324 authentication entry with. Only used if the prefix doesn't include
325 a scheme. Supported schemes are http and https. They will match
325 a scheme. Supported schemes are http and https. They will match
326 static-http and static-https respectively, as well.
326 static-http and static-https respectively, as well.
327 Default: https.
327 Default: https.
328
328
329 If no suitable authentication entry is found, the user is prompted
329 If no suitable authentication entry is found, the user is prompted
330 for credentials as usual if required by the remote.
330 for credentials as usual if required by the remote.
331
331
332
332
333 ``decode/encode``
333 ``decode/encode``
334 -----------------
334 -----------------
335
335
336 Filters for transforming files on checkout/checkin. This would
336 Filters for transforming files on checkout/checkin. This would
337 typically be used for newline processing or other
337 typically be used for newline processing or other
338 localization/canonicalization of files.
338 localization/canonicalization of files.
339
339
340 Filters consist of a filter pattern followed by a filter command.
340 Filters consist of a filter pattern followed by a filter command.
341 Filter patterns are globs by default, rooted at the repository root.
341 Filter patterns are globs by default, rooted at the repository root.
342 For example, to match any file ending in ``.txt`` in the root
342 For example, to match any file ending in ``.txt`` in the root
343 directory only, use the pattern ``*.txt``. To match any file ending
343 directory only, use the pattern ``*.txt``. To match any file ending
344 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
344 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
345 For each file only the first matching filter applies.
345 For each file only the first matching filter applies.
346
346
347 The filter command can start with a specifier, either ``pipe:`` or
347 The filter command can start with a specifier, either ``pipe:`` or
348 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
348 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
349
349
350 A ``pipe:`` command must accept data on stdin and return the transformed
350 A ``pipe:`` command must accept data on stdin and return the transformed
351 data on stdout.
351 data on stdout.
352
352
353 Pipe example::
353 Pipe example::
354
354
355 [encode]
355 [encode]
356 # uncompress gzip files on checkin to improve delta compression
356 # uncompress gzip files on checkin to improve delta compression
357 # note: not necessarily a good idea, just an example
357 # note: not necessarily a good idea, just an example
358 *.gz = pipe: gunzip
358 *.gz = pipe: gunzip
359
359
360 [decode]
360 [decode]
361 # recompress gzip files when writing them to the working dir (we
361 # recompress gzip files when writing them to the working dir (we
362 # can safely omit "pipe:", because it's the default)
362 # can safely omit "pipe:", because it's the default)
363 *.gz = gzip
363 *.gz = gzip
364
364
365 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
365 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
366 with the name of a temporary file that contains the data to be
366 with the name of a temporary file that contains the data to be
367 filtered by the command. The string ``OUTFILE`` is replaced with the name
367 filtered by the command. The string ``OUTFILE`` is replaced with the name
368 of an empty temporary file, where the filtered data must be written by
368 of an empty temporary file, where the filtered data must be written by
369 the command.
369 the command.
370
370
371 .. note::
371 .. note::
372
372
373 The tempfile mechanism is recommended for Windows systems,
373 The tempfile mechanism is recommended for Windows systems,
374 where the standard shell I/O redirection operators often have
374 where the standard shell I/O redirection operators often have
375 strange effects and may corrupt the contents of your files.
375 strange effects and may corrupt the contents of your files.
376
376
377 This filter mechanism is used internally by the ``eol`` extension to
377 This filter mechanism is used internally by the ``eol`` extension to
378 translate line ending characters between Windows (CRLF) and Unix (LF)
378 translate line ending characters between Windows (CRLF) and Unix (LF)
379 format. We suggest you use the ``eol`` extension for convenience.
379 format. We suggest you use the ``eol`` extension for convenience.
380
380
381
381
382 ``defaults``
382 ``defaults``
383 ------------
383 ------------
384
384
385 (defaults are deprecated. Don't use them. Use aliases instead)
385 (defaults are deprecated. Don't use them. Use aliases instead)
386
386
387 Use the ``[defaults]`` section to define command defaults, i.e. the
387 Use the ``[defaults]`` section to define command defaults, i.e. the
388 default options/arguments to pass to the specified commands.
388 default options/arguments to pass to the specified commands.
389
389
390 The following example makes :hg:`log` run in verbose mode, and
390 The following example makes :hg:`log` run in verbose mode, and
391 :hg:`status` show only the modified files, by default::
391 :hg:`status` show only the modified files, by default::
392
392
393 [defaults]
393 [defaults]
394 log = -v
394 log = -v
395 status = -m
395 status = -m
396
396
397 The actual commands, instead of their aliases, must be used when
397 The actual commands, instead of their aliases, must be used when
398 defining command defaults. The command defaults will also be applied
398 defining command defaults. The command defaults will also be applied
399 to the aliases of the commands defined.
399 to the aliases of the commands defined.
400
400
401
401
402 ``diff``
402 ``diff``
403 --------
403 --------
404
404
405 Settings used when displaying diffs. Everything except for ``unified``
405 Settings used when displaying diffs. Everything except for ``unified``
406 is a Boolean and defaults to False. See ``annotate`` section for
406 is a Boolean and defaults to False. See ``annotate`` section for
407 related options for the annotate command.
407 related options for the annotate command.
408
408
409 ``git``
409 ``git``
410 Use git extended diff format.
410 Use git extended diff format.
411
411
412 ``nodates``
412 ``nodates``
413 Don't include dates in diff headers.
413 Don't include dates in diff headers.
414
414
415 ``showfunc``
415 ``showfunc``
416 Show which function each change is in.
416 Show which function each change is in.
417
417
418 ``ignorews``
418 ``ignorews``
419 Ignore white space when comparing lines.
419 Ignore white space when comparing lines.
420
420
421 ``ignorewsamount``
421 ``ignorewsamount``
422 Ignore changes in the amount of white space.
422 Ignore changes in the amount of white space.
423
423
424 ``ignoreblanklines``
424 ``ignoreblanklines``
425 Ignore changes whose lines are all blank.
425 Ignore changes whose lines are all blank.
426
426
427 ``unified``
427 ``unified``
428 Number of lines of context to show.
428 Number of lines of context to show.
429
429
430 ``email``
430 ``email``
431 ---------
431 ---------
432
432
433 Settings for extensions that send email messages.
433 Settings for extensions that send email messages.
434
434
435 ``from``
435 ``from``
436 Optional. Email address to use in "From" header and SMTP envelope
436 Optional. Email address to use in "From" header and SMTP envelope
437 of outgoing messages.
437 of outgoing messages.
438
438
439 ``to``
439 ``to``
440 Optional. Comma-separated list of recipients' email addresses.
440 Optional. Comma-separated list of recipients' email addresses.
441
441
442 ``cc``
442 ``cc``
443 Optional. Comma-separated list of carbon copy recipients'
443 Optional. Comma-separated list of carbon copy recipients'
444 email addresses.
444 email addresses.
445
445
446 ``bcc``
446 ``bcc``
447 Optional. Comma-separated list of blind carbon copy recipients'
447 Optional. Comma-separated list of blind carbon copy recipients'
448 email addresses.
448 email addresses.
449
449
450 ``method``
450 ``method``
451 Optional. Method to use to send email messages. If value is ``smtp``
451 Optional. Method to use to send email messages. If value is ``smtp``
452 (default), use SMTP (see the ``[smtp]`` section for configuration).
452 (default), use SMTP (see the ``[smtp]`` section for configuration).
453 Otherwise, use as name of program to run that acts like sendmail
453 Otherwise, use as name of program to run that acts like sendmail
454 (takes ``-f`` option for sender, list of recipients on command line,
454 (takes ``-f`` option for sender, list of recipients on command line,
455 message on stdin). Normally, setting this to ``sendmail`` or
455 message on stdin). Normally, setting this to ``sendmail`` or
456 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
456 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
457
457
458 ``charsets``
458 ``charsets``
459 Optional. Comma-separated list of character sets considered
459 Optional. Comma-separated list of character sets considered
460 convenient for recipients. Addresses, headers, and parts not
460 convenient for recipients. Addresses, headers, and parts not
461 containing patches of outgoing messages will be encoded in the
461 containing patches of outgoing messages will be encoded in the
462 first character set to which conversion from local encoding
462 first character set to which conversion from local encoding
463 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
463 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
464 conversion fails, the text in question is sent as is. Defaults to
464 conversion fails, the text in question is sent as is. Defaults to
465 empty (explicit) list.
465 empty (explicit) list.
466
466
467 Order of outgoing email character sets:
467 Order of outgoing email character sets:
468
468
469 1. ``us-ascii``: always first, regardless of settings
469 1. ``us-ascii``: always first, regardless of settings
470 2. ``email.charsets``: in order given by user
470 2. ``email.charsets``: in order given by user
471 3. ``ui.fallbackencoding``: if not in email.charsets
471 3. ``ui.fallbackencoding``: if not in email.charsets
472 4. ``$HGENCODING``: if not in email.charsets
472 4. ``$HGENCODING``: if not in email.charsets
473 5. ``utf-8``: always last, regardless of settings
473 5. ``utf-8``: always last, regardless of settings
474
474
475 Email example::
475 Email example::
476
476
477 [email]
477 [email]
478 from = Joseph User <joe.user@example.com>
478 from = Joseph User <joe.user@example.com>
479 method = /usr/sbin/sendmail
479 method = /usr/sbin/sendmail
480 # charsets for western Europeans
480 # charsets for western Europeans
481 # us-ascii, utf-8 omitted, as they are tried first and last
481 # us-ascii, utf-8 omitted, as they are tried first and last
482 charsets = iso-8859-1, iso-8859-15, windows-1252
482 charsets = iso-8859-1, iso-8859-15, windows-1252
483
483
484
484
485 ``extensions``
485 ``extensions``
486 --------------
486 --------------
487
487
488 Mercurial has an extension mechanism for adding new features. To
488 Mercurial has an extension mechanism for adding new features. To
489 enable an extension, create an entry for it in this section.
489 enable an extension, create an entry for it in this section.
490
490
491 If you know that the extension is already in Python's search path,
491 If you know that the extension is already in Python's search path,
492 you can give the name of the module, followed by ``=``, with nothing
492 you can give the name of the module, followed by ``=``, with nothing
493 after the ``=``.
493 after the ``=``.
494
494
495 Otherwise, give a name that you choose, followed by ``=``, followed by
495 Otherwise, give a name that you choose, followed by ``=``, followed by
496 the path to the ``.py`` file (including the file name extension) that
496 the path to the ``.py`` file (including the file name extension) that
497 defines the extension.
497 defines the extension.
498
498
499 To explicitly disable an extension that is enabled in an hgrc of
499 To explicitly disable an extension that is enabled in an hgrc of
500 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
500 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
501 or ``foo = !`` when path is not supplied.
501 or ``foo = !`` when path is not supplied.
502
502
503 Example for ``~/.hgrc``::
503 Example for ``~/.hgrc``::
504
504
505 [extensions]
505 [extensions]
506 # (the progress extension will get loaded from Mercurial's path)
506 # (the progress extension will get loaded from Mercurial's path)
507 progress =
507 progress =
508 # (this extension will get loaded from the file specified)
508 # (this extension will get loaded from the file specified)
509 myfeature = ~/.hgext/myfeature.py
509 myfeature = ~/.hgext/myfeature.py
510
510
511
511
512 ``format``
512 ``format``
513 ----------
513 ----------
514
514
515 ``usestore``
515 ``usestore``
516 Enable or disable the "store" repository format which improves
516 Enable or disable the "store" repository format which improves
517 compatibility with systems that fold case or otherwise mangle
517 compatibility with systems that fold case or otherwise mangle
518 filenames. Enabled by default. Disabling this option will allow
518 filenames. Enabled by default. Disabling this option will allow
519 you to store longer filenames in some situations at the expense of
519 you to store longer filenames in some situations at the expense of
520 compatibility and ensures that the on-disk format of newly created
520 compatibility and ensures that the on-disk format of newly created
521 repositories will be compatible with Mercurial before version 0.9.4.
521 repositories will be compatible with Mercurial before version 0.9.4.
522
522
523 ``usefncache``
523 ``usefncache``
524 Enable or disable the "fncache" repository format which enhances
524 Enable or disable the "fncache" repository format which enhances
525 the "store" repository format (which has to be enabled to use
525 the "store" repository format (which has to be enabled to use
526 fncache) to allow longer filenames and avoids using Windows
526 fncache) to allow longer filenames and avoids using Windows
527 reserved names, e.g. "nul". Enabled by default. Disabling this
527 reserved names, e.g. "nul". Enabled by default. Disabling this
528 option ensures that the on-disk format of newly created
528 option ensures that the on-disk format of newly created
529 repositories will be compatible with Mercurial before version 1.1.
529 repositories will be compatible with Mercurial before version 1.1.
530
530
531 ``dotencode``
531 ``dotencode``
532 Enable or disable the "dotencode" repository format which enhances
532 Enable or disable the "dotencode" repository format which enhances
533 the "fncache" repository format (which has to be enabled to use
533 the "fncache" repository format (which has to be enabled to use
534 dotencode) to avoid issues with filenames starting with ._ on
534 dotencode) to avoid issues with filenames starting with ._ on
535 Mac OS X and spaces on Windows. Enabled by default. Disabling this
535 Mac OS X and spaces on Windows. Enabled by default. Disabling this
536 option ensures that the on-disk format of newly created
536 option ensures that the on-disk format of newly created
537 repositories will be compatible with Mercurial before version 1.7.
537 repositories will be compatible with Mercurial before version 1.7.
538
538
539 ``graph``
539 ``graph``
540 ---------
540 ---------
541
541
542 Web graph view configuration. This section let you change graph
542 Web graph view configuration. This section let you change graph
543 elements display properties by branches, for instance to make the
543 elements display properties by branches, for instance to make the
544 ``default`` branch stand out.
544 ``default`` branch stand out.
545
545
546 Each line has the following format::
546 Each line has the following format::
547
547
548 <branch>.<argument> = <value>
548 <branch>.<argument> = <value>
549
549
550 where ``<branch>`` is the name of the branch being
550 where ``<branch>`` is the name of the branch being
551 customized. Example::
551 customized. Example::
552
552
553 [graph]
553 [graph]
554 # 2px width
554 # 2px width
555 default.width = 2
555 default.width = 2
556 # red color
556 # red color
557 default.color = FF0000
557 default.color = FF0000
558
558
559 Supported arguments:
559 Supported arguments:
560
560
561 ``width``
561 ``width``
562 Set branch edges width in pixels.
562 Set branch edges width in pixels.
563
563
564 ``color``
564 ``color``
565 Set branch edges color in hexadecimal RGB notation.
565 Set branch edges color in hexadecimal RGB notation.
566
566
567 ``hooks``
567 ``hooks``
568 ---------
568 ---------
569
569
570 Commands or Python functions that get automatically executed by
570 Commands or Python functions that get automatically executed by
571 various actions such as starting or finishing a commit. Multiple
571 various actions such as starting or finishing a commit. Multiple
572 hooks can be run for the same action by appending a suffix to the
572 hooks can be run for the same action by appending a suffix to the
573 action. Overriding a site-wide hook can be done by changing its
573 action. Overriding a site-wide hook can be done by changing its
574 value or setting it to an empty string. Hooks can be prioritized
574 value or setting it to an empty string. Hooks can be prioritized
575 by adding a prefix of ``priority`` to the hook name on a new line
575 by adding a prefix of ``priority`` to the hook name on a new line
576 and setting the priority. The default priority is 0 if
576 and setting the priority. The default priority is 0 if
577 not specified.
577 not specified.
578
578
579 Example ``.hg/hgrc``::
579 Example ``.hg/hgrc``::
580
580
581 [hooks]
581 [hooks]
582 # update working directory after adding changesets
582 # update working directory after adding changesets
583 changegroup.update = hg update
583 changegroup.update = hg update
584 # do not use the site-wide hook
584 # do not use the site-wide hook
585 incoming =
585 incoming =
586 incoming.email = /my/email/hook
586 incoming.email = /my/email/hook
587 incoming.autobuild = /my/build/hook
587 incoming.autobuild = /my/build/hook
588 # force autobuild hook to run before other incoming hooks
588 # force autobuild hook to run before other incoming hooks
589 priority.incoming.autobuild = 1
589 priority.incoming.autobuild = 1
590
590
591 Most hooks are run with environment variables set that give useful
591 Most hooks are run with environment variables set that give useful
592 additional information. For each hook below, the environment
592 additional information. For each hook below, the environment
593 variables it is passed are listed with names of the form ``$HG_foo``.
593 variables it is passed are listed with names of the form ``$HG_foo``.
594
594
595 ``changegroup``
595 ``changegroup``
596 Run after a changegroup has been added via push, pull or unbundle.
596 Run after a changegroup has been added via push, pull or unbundle.
597 ID of the first new changeset is in ``$HG_NODE``. URL from which
597 ID of the first new changeset is in ``$HG_NODE``. URL from which
598 changes came is in ``$HG_URL``.
598 changes came is in ``$HG_URL``.
599
599
600 ``commit``
600 ``commit``
601 Run after a changeset has been created in the local repository. ID
601 Run after a changeset has been created in the local repository. ID
602 of the newly created changeset is in ``$HG_NODE``. Parent changeset
602 of the newly created changeset is in ``$HG_NODE``. Parent changeset
603 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
603 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
604
604
605 ``incoming``
605 ``incoming``
606 Run after a changeset has been pulled, pushed, or unbundled into
606 Run after a changeset has been pulled, pushed, or unbundled into
607 the local repository. The ID of the newly arrived changeset is in
607 the local repository. The ID of the newly arrived changeset is in
608 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
608 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
609
609
610 ``outgoing``
610 ``outgoing``
611 Run after sending changes from local repository to another. ID of
611 Run after sending changes from local repository to another. ID of
612 first changeset sent is in ``$HG_NODE``. Source of operation is in
612 first changeset sent is in ``$HG_NODE``. Source of operation is in
613 ``$HG_SOURCE``; see "preoutgoing" hook for description.
613 ``$HG_SOURCE``; see "preoutgoing" hook for description.
614
614
615 ``post-<command>``
615 ``post-<command>``
616 Run after successful invocations of the associated command. The
616 Run after successful invocations of the associated command. The
617 contents of the command line are passed as ``$HG_ARGS`` and the result
617 contents of the command line are passed as ``$HG_ARGS`` and the result
618 code in ``$HG_RESULT``. Parsed command line arguments are passed as
618 code in ``$HG_RESULT``. Parsed command line arguments are passed as
619 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
619 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
620 the python data internally passed to <command>. ``$HG_OPTS`` is a
620 the python data internally passed to <command>. ``$HG_OPTS`` is a
621 dictionary of options (with unspecified options set to their defaults).
621 dictionary of options (with unspecified options set to their defaults).
622 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
622 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
623
623
624 ``pre-<command>``
624 ``pre-<command>``
625 Run before executing the associated command. The contents of the
625 Run before executing the associated command. The contents of the
626 command line are passed as ``$HG_ARGS``. Parsed command line arguments
626 command line are passed as ``$HG_ARGS``. Parsed command line arguments
627 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
627 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
628 representations of the data internally passed to <command>. ``$HG_OPTS``
628 representations of the data internally passed to <command>. ``$HG_OPTS``
629 is a dictionary of options (with unspecified options set to their
629 is a dictionary of options (with unspecified options set to their
630 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
630 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
631 failure, the command doesn't execute and Mercurial returns the failure
631 failure, the command doesn't execute and Mercurial returns the failure
632 code.
632 code.
633
633
634 ``prechangegroup``
634 ``prechangegroup``
635 Run before a changegroup is added via push, pull or unbundle. Exit
635 Run before a changegroup is added via push, pull or unbundle. Exit
636 status 0 allows the changegroup to proceed. Non-zero status will
636 status 0 allows the changegroup to proceed. Non-zero status will
637 cause the push, pull or unbundle to fail. URL from which changes
637 cause the push, pull or unbundle to fail. URL from which changes
638 will come is in ``$HG_URL``.
638 will come is in ``$HG_URL``.
639
639
640 ``precommit``
640 ``precommit``
641 Run before starting a local commit. Exit status 0 allows the
641 Run before starting a local commit. Exit status 0 allows the
642 commit to proceed. Non-zero status will cause the commit to fail.
642 commit to proceed. Non-zero status will cause the commit to fail.
643 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
643 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
644
644
645 ``prelistkeys``
645 ``prelistkeys``
646 Run before listing pushkeys (like bookmarks) in the
646 Run before listing pushkeys (like bookmarks) in the
647 repository. Non-zero status will cause failure. The key namespace is
647 repository. Non-zero status will cause failure. The key namespace is
648 in ``$HG_NAMESPACE``.
648 in ``$HG_NAMESPACE``.
649
649
650 ``preoutgoing``
650 ``preoutgoing``
651 Run before collecting changes to send from the local repository to
651 Run before collecting changes to send from the local repository to
652 another. Non-zero status will cause failure. This lets you prevent
652 another. Non-zero status will cause failure. This lets you prevent
653 pull over HTTP or SSH. Also prevents against local pull, push
653 pull over HTTP or SSH. Also prevents against local pull, push
654 (outbound) or bundle commands, but not effective, since you can
654 (outbound) or bundle commands, but not effective, since you can
655 just copy files instead then. Source of operation is in
655 just copy files instead then. Source of operation is in
656 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
656 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
657 SSH or HTTP repository. If "push", "pull" or "bundle", operation
657 SSH or HTTP repository. If "push", "pull" or "bundle", operation
658 is happening on behalf of repository on same system.
658 is happening on behalf of repository on same system.
659
659
660 ``prepushkey``
660 ``prepushkey``
661 Run before a pushkey (like a bookmark) is added to the
661 Run before a pushkey (like a bookmark) is added to the
662 repository. Non-zero status will cause the key to be rejected. The
662 repository. Non-zero status will cause the key to be rejected. The
663 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
663 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
664 the old value (if any) is in ``$HG_OLD``, and the new value is in
664 the old value (if any) is in ``$HG_OLD``, and the new value is in
665 ``$HG_NEW``.
665 ``$HG_NEW``.
666
666
667 ``pretag``
667 ``pretag``
668 Run before creating a tag. Exit status 0 allows the tag to be
668 Run before creating a tag. Exit status 0 allows the tag to be
669 created. Non-zero status will cause the tag to fail. ID of
669 created. Non-zero status will cause the tag to fail. ID of
670 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
670 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
671 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
671 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
672
672
673 ``pretxnchangegroup``
673 ``pretxnchangegroup``
674 Run after a changegroup has been added via push, pull or unbundle,
674 Run after a changegroup has been added via push, pull or unbundle,
675 but before the transaction has been committed. Changegroup is
675 but before the transaction has been committed. Changegroup is
676 visible to hook program. This lets you validate incoming changes
676 visible to hook program. This lets you validate incoming changes
677 before accepting them. Passed the ID of the first new changeset in
677 before accepting them. Passed the ID of the first new changeset in
678 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
678 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
679 status will cause the transaction to be rolled back and the push,
679 status will cause the transaction to be rolled back and the push,
680 pull or unbundle will fail. URL that was source of changes is in
680 pull or unbundle will fail. URL that was source of changes is in
681 ``$HG_URL``.
681 ``$HG_URL``.
682
682
683 ``pretxncommit``
683 ``pretxncommit``
684 Run after a changeset has been created but the transaction not yet
684 Run after a changeset has been created but the transaction not yet
685 committed. Changeset is visible to hook program. This lets you
685 committed. Changeset is visible to hook program. This lets you
686 validate commit message and changes. Exit status 0 allows the
686 validate commit message and changes. Exit status 0 allows the
687 commit to proceed. Non-zero status will cause the transaction to
687 commit to proceed. Non-zero status will cause the transaction to
688 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
688 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
689 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
689 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
690
690
691 ``preupdate``
691 ``preupdate``
692 Run before updating the working directory. Exit status 0 allows
692 Run before updating the working directory. Exit status 0 allows
693 the update to proceed. Non-zero status will prevent the update.
693 the update to proceed. Non-zero status will prevent the update.
694 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
694 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
695 of second new parent is in ``$HG_PARENT2``.
695 of second new parent is in ``$HG_PARENT2``.
696
696
697 ``listkeys``
697 ``listkeys``
698 Run after listing pushkeys (like bookmarks) in the repository. The
698 Run after listing pushkeys (like bookmarks) in the repository. The
699 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
699 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
700 dictionary containing the keys and values.
700 dictionary containing the keys and values.
701
701
702 ``pushkey``
702 ``pushkey``
703 Run after a pushkey (like a bookmark) is added to the
703 Run after a pushkey (like a bookmark) is added to the
704 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
704 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
705 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
705 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
706 value is in ``$HG_NEW``.
706 value is in ``$HG_NEW``.
707
707
708 ``tag``
708 ``tag``
709 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
709 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
710 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
710 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
711 repository if ``$HG_LOCAL=0``.
711 repository if ``$HG_LOCAL=0``.
712
712
713 ``update``
713 ``update``
714 Run after updating the working directory. Changeset ID of first
714 Run after updating the working directory. Changeset ID of first
715 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
715 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
716 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
716 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
717 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
717 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
718
718
719 .. note::
719 .. note::
720
720
721 It is generally better to use standard hooks rather than the
721 It is generally better to use standard hooks rather than the
722 generic pre- and post- command hooks as they are guaranteed to be
722 generic pre- and post- command hooks as they are guaranteed to be
723 called in the appropriate contexts for influencing transactions.
723 called in the appropriate contexts for influencing transactions.
724 Also, hooks like "commit" will be called in all contexts that
724 Also, hooks like "commit" will be called in all contexts that
725 generate a commit (e.g. tag) and not just the commit command.
725 generate a commit (e.g. tag) and not just the commit command.
726
726
727 .. note::
727 .. note::
728
728
729 Environment variables with empty values may not be passed to
729 Environment variables with empty values may not be passed to
730 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
730 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
731 will have an empty value under Unix-like platforms for non-merge
731 will have an empty value under Unix-like platforms for non-merge
732 changesets, while it will not be available at all under Windows.
732 changesets, while it will not be available at all under Windows.
733
733
734 The syntax for Python hooks is as follows::
734 The syntax for Python hooks is as follows::
735
735
736 hookname = python:modulename.submodule.callable
736 hookname = python:modulename.submodule.callable
737 hookname = python:/path/to/python/module.py:callable
737 hookname = python:/path/to/python/module.py:callable
738
738
739 Python hooks are run within the Mercurial process. Each hook is
739 Python hooks are run within the Mercurial process. Each hook is
740 called with at least three keyword arguments: a ui object (keyword
740 called with at least three keyword arguments: a ui object (keyword
741 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
741 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
742 keyword that tells what kind of hook is used. Arguments listed as
742 keyword that tells what kind of hook is used. Arguments listed as
743 environment variables above are passed as keyword arguments, with no
743 environment variables above are passed as keyword arguments, with no
744 ``HG_`` prefix, and names in lower case.
744 ``HG_`` prefix, and names in lower case.
745
745
746 If a Python hook returns a "true" value or raises an exception, this
746 If a Python hook returns a "true" value or raises an exception, this
747 is treated as a failure.
747 is treated as a failure.
748
748
749
749
750 ``hostfingerprints``
750 ``hostfingerprints``
751 --------------------
751 --------------------
752
752
753 Fingerprints of the certificates of known HTTPS servers.
753 Fingerprints of the certificates of known HTTPS servers.
754 A HTTPS connection to a server with a fingerprint configured here will
754 A HTTPS connection to a server with a fingerprint configured here will
755 only succeed if the servers certificate matches the fingerprint.
755 only succeed if the servers certificate matches the fingerprint.
756 This is very similar to how ssh known hosts works.
756 This is very similar to how ssh known hosts works.
757 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
757 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
758 The CA chain and web.cacerts is not used for servers with a fingerprint.
758 The CA chain and web.cacerts is not used for servers with a fingerprint.
759
759
760 For example::
760 For example::
761
761
762 [hostfingerprints]
762 [hostfingerprints]
763 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
763 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
764
764
765 This feature is only supported when using Python 2.6 or later.
765 This feature is only supported when using Python 2.6 or later.
766
766
767
767
768 ``http_proxy``
768 ``http_proxy``
769 --------------
769 --------------
770
770
771 Used to access web-based Mercurial repositories through a HTTP
771 Used to access web-based Mercurial repositories through a HTTP
772 proxy.
772 proxy.
773
773
774 ``host``
774 ``host``
775 Host name and (optional) port of the proxy server, for example
775 Host name and (optional) port of the proxy server, for example
776 "myproxy:8000".
776 "myproxy:8000".
777
777
778 ``no``
778 ``no``
779 Optional. Comma-separated list of host names that should bypass
779 Optional. Comma-separated list of host names that should bypass
780 the proxy.
780 the proxy.
781
781
782 ``passwd``
782 ``passwd``
783 Optional. Password to authenticate with at the proxy server.
783 Optional. Password to authenticate with at the proxy server.
784
784
785 ``user``
785 ``user``
786 Optional. User name to authenticate with at the proxy server.
786 Optional. User name to authenticate with at the proxy server.
787
787
788 ``always``
788 ``always``
789 Optional. Always use the proxy, even for localhost and any entries
789 Optional. Always use the proxy, even for localhost and any entries
790 in ``http_proxy.no``. True or False. Default: False.
790 in ``http_proxy.no``. True or False. Default: False.
791
791
792 ``merge-patterns``
792 ``merge-patterns``
793 ------------------
793 ------------------
794
794
795 This section specifies merge tools to associate with particular file
795 This section specifies merge tools to associate with particular file
796 patterns. Tools matched here will take precedence over the default
796 patterns. Tools matched here will take precedence over the default
797 merge tool. Patterns are globs by default, rooted at the repository
797 merge tool. Patterns are globs by default, rooted at the repository
798 root.
798 root.
799
799
800 Example::
800 Example::
801
801
802 [merge-patterns]
802 [merge-patterns]
803 **.c = kdiff3
803 **.c = kdiff3
804 **.jpg = myimgmerge
804 **.jpg = myimgmerge
805
805
806 ``merge-tools``
806 ``merge-tools``
807 ---------------
807 ---------------
808
808
809 This section configures external merge tools to use for file-level
809 This section configures external merge tools to use for file-level
810 merges. This section has likely been preconfigured at install time.
810 merges. This section has likely been preconfigured at install time.
811 Use :hg:`config merge-tools` to check the existing configuration.
811 Use :hg:`config merge-tools` to check the existing configuration.
812 Also see :hg:`help merge-tools` for more details.
812 Also see :hg:`help merge-tools` for more details.
813
813
814 Example ``~/.hgrc``::
814 Example ``~/.hgrc``::
815
815
816 [merge-tools]
816 [merge-tools]
817 # Override stock tool location
817 # Override stock tool location
818 kdiff3.executable = ~/bin/kdiff3
818 kdiff3.executable = ~/bin/kdiff3
819 # Specify command line
819 # Specify command line
820 kdiff3.args = $base $local $other -o $output
820 kdiff3.args = $base $local $other -o $output
821 # Give higher priority
821 # Give higher priority
822 kdiff3.priority = 1
822 kdiff3.priority = 1
823
823
824 # Changing the priority of preconfigured tool
824 # Changing the priority of preconfigured tool
825 vimdiff.priority = 0
825 vimdiff.priority = 0
826
826
827 # Define new tool
827 # Define new tool
828 myHtmlTool.args = -m $local $other $base $output
828 myHtmlTool.args = -m $local $other $base $output
829 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
829 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
830 myHtmlTool.priority = 1
830 myHtmlTool.priority = 1
831
831
832 Supported arguments:
832 Supported arguments:
833
833
834 ``priority``
834 ``priority``
835 The priority in which to evaluate this tool.
835 The priority in which to evaluate this tool.
836 Default: 0.
836 Default: 0.
837
837
838 ``executable``
838 ``executable``
839 Either just the name of the executable or its pathname. On Windows,
839 Either just the name of the executable or its pathname. On Windows,
840 the path can use environment variables with ${ProgramFiles} syntax.
840 the path can use environment variables with ${ProgramFiles} syntax.
841 Default: the tool name.
841 Default: the tool name.
842
842
843 ``args``
843 ``args``
844 The arguments to pass to the tool executable. You can refer to the
844 The arguments to pass to the tool executable. You can refer to the
845 files being merged as well as the output file through these
845 files being merged as well as the output file through these
846 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
846 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
847 of ``$local`` and ``$other`` can vary depending on which action is being
847 of ``$local`` and ``$other`` can vary depending on which action is being
848 performed. During and update or merge, ``$local`` represents the original
848 performed. During and update or merge, ``$local`` represents the original
849 state of the file, while ``$other`` represents the commit you are updating
849 state of the file, while ``$other`` represents the commit you are updating
850 to or the commit you are merging with. During a rebase ``$local``
850 to or the commit you are merging with. During a rebase ``$local``
851 represents the destination of the rebase, and ``$other`` represents the
851 represents the destination of the rebase, and ``$other`` represents the
852 commit being rebased.
852 commit being rebased.
853 Default: ``$local $base $other``
853 Default: ``$local $base $other``
854
854
855 ``premerge``
855 ``premerge``
856 Attempt to run internal non-interactive 3-way merge tool before
856 Attempt to run internal non-interactive 3-way merge tool before
857 launching external tool. Options are ``true``, ``false``, or ``keep``
857 launching external tool. Options are ``true``, ``false``, or ``keep``
858 to leave markers in the file if the premerge fails.
858 to leave markers in the file if the premerge fails.
859 Default: True
859 Default: True
860
860
861 ``binary``
861 ``binary``
862 This tool can merge binary files. Defaults to False, unless tool
862 This tool can merge binary files. Defaults to False, unless tool
863 was selected by file pattern match.
863 was selected by file pattern match.
864
864
865 ``symlink``
865 ``symlink``
866 This tool can merge symlinks. Defaults to False, even if tool was
866 This tool can merge symlinks. Defaults to False, even if tool was
867 selected by file pattern match.
867 selected by file pattern match.
868
868
869 ``check``
869 ``check``
870 A list of merge success-checking options:
870 A list of merge success-checking options:
871
871
872 ``changed``
872 ``changed``
873 Ask whether merge was successful when the merged file shows no changes.
873 Ask whether merge was successful when the merged file shows no changes.
874 ``conflicts``
874 ``conflicts``
875 Check whether there are conflicts even though the tool reported success.
875 Check whether there are conflicts even though the tool reported success.
876 ``prompt``
876 ``prompt``
877 Always prompt for merge success, regardless of success reported by tool.
877 Always prompt for merge success, regardless of success reported by tool.
878
878
879 ``fixeol``
879 ``fixeol``
880 Attempt to fix up EOL changes caused by the merge tool.
880 Attempt to fix up EOL changes caused by the merge tool.
881 Default: False
881 Default: False
882
882
883 ``gui``
883 ``gui``
884 This tool requires a graphical interface to run. Default: False
884 This tool requires a graphical interface to run. Default: False
885
885
886 ``regkey``
886 ``regkey``
887 Windows registry key which describes install location of this
887 Windows registry key which describes install location of this
888 tool. Mercurial will search for this key first under
888 tool. Mercurial will search for this key first under
889 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
889 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
890 Default: None
890 Default: None
891
891
892 ``regkeyalt``
892 ``regkeyalt``
893 An alternate Windows registry key to try if the first key is not
893 An alternate Windows registry key to try if the first key is not
894 found. The alternate key uses the same ``regname`` and ``regappend``
894 found. The alternate key uses the same ``regname`` and ``regappend``
895 semantics of the primary key. The most common use for this key
895 semantics of the primary key. The most common use for this key
896 is to search for 32bit applications on 64bit operating systems.
896 is to search for 32bit applications on 64bit operating systems.
897 Default: None
897 Default: None
898
898
899 ``regname``
899 ``regname``
900 Name of value to read from specified registry key. Defaults to the
900 Name of value to read from specified registry key. Defaults to the
901 unnamed (default) value.
901 unnamed (default) value.
902
902
903 ``regappend``
903 ``regappend``
904 String to append to the value read from the registry, typically
904 String to append to the value read from the registry, typically
905 the executable name of the tool.
905 the executable name of the tool.
906 Default: None
906 Default: None
907
907
908
908
909 ``patch``
909 ``patch``
910 ---------
910 ---------
911
911
912 Settings used when applying patches, for instance through the 'import'
912 Settings used when applying patches, for instance through the 'import'
913 command or with Mercurial Queues extension.
913 command or with Mercurial Queues extension.
914
914
915 ``eol``
915 ``eol``
916 When set to 'strict' patch content and patched files end of lines
916 When set to 'strict' patch content and patched files end of lines
917 are preserved. When set to ``lf`` or ``crlf``, both files end of
917 are preserved. When set to ``lf`` or ``crlf``, both files end of
918 lines are ignored when patching and the result line endings are
918 lines are ignored when patching and the result line endings are
919 normalized to either LF (Unix) or CRLF (Windows). When set to
919 normalized to either LF (Unix) or CRLF (Windows). When set to
920 ``auto``, end of lines are again ignored while patching but line
920 ``auto``, end of lines are again ignored while patching but line
921 endings in patched files are normalized to their original setting
921 endings in patched files are normalized to their original setting
922 on a per-file basis. If target file does not exist or has no end
922 on a per-file basis. If target file does not exist or has no end
923 of line, patch line endings are preserved.
923 of line, patch line endings are preserved.
924 Default: strict.
924 Default: strict.
925
925
926
926
927 ``paths``
927 ``paths``
928 ---------
928 ---------
929
929
930 Assigns symbolic names to repositories. The left side is the
930 Assigns symbolic names to repositories. The left side is the
931 symbolic name, and the right gives the directory or URL that is the
931 symbolic name, and the right gives the directory or URL that is the
932 location of the repository. Default paths can be declared by setting
932 location of the repository. Default paths can be declared by setting
933 the following entries.
933 the following entries.
934
934
935 ``default``
935 ``default``
936 Directory or URL to use when pulling if no source is specified.
936 Directory or URL to use when pulling if no source is specified.
937 Default is set to repository from which the current repository was
937 Default is set to repository from which the current repository was
938 cloned.
938 cloned.
939
939
940 ``default-push``
940 ``default-push``
941 Optional. Directory or URL to use when pushing if no destination
941 Optional. Directory or URL to use when pushing if no destination
942 is specified.
942 is specified.
943
943
944 Custom paths can be defined by assigning the path to a name that later can be
944 Custom paths can be defined by assigning the path to a name that later can be
945 used from the command line. Example::
945 used from the command line. Example::
946
946
947 [paths]
947 [paths]
948 my_path = http://example.com/path
948 my_path = http://example.com/path
949
949
950 To push to the path defined in ``my_path`` run the command::
950 To push to the path defined in ``my_path`` run the command::
951
951
952 hg push my_path
952 hg push my_path
953
953
954
954
955 ``phases``
955 ``phases``
956 ----------
956 ----------
957
957
958 Specifies default handling of phases. See :hg:`help phases` for more
958 Specifies default handling of phases. See :hg:`help phases` for more
959 information about working with phases.
959 information about working with phases.
960
960
961 ``publish``
961 ``publish``
962 Controls draft phase behavior when working as a server. When true,
962 Controls draft phase behavior when working as a server. When true,
963 pushed changesets are set to public in both client and server and
963 pushed changesets are set to public in both client and server and
964 pulled or cloned changesets are set to public in the client.
964 pulled or cloned changesets are set to public in the client.
965 Default: True
965 Default: True
966
966
967 ``new-commit``
967 ``new-commit``
968 Phase of newly-created commits.
968 Phase of newly-created commits.
969 Default: draft
969 Default: draft
970
970
971 ``checksubrepos``
971 ``checksubrepos``
972 Check the phase of the current revision of each subrepository. Allowed
972 Check the phase of the current revision of each subrepository. Allowed
973 values are "ignore", "follow" and "abort". For settings other than
973 values are "ignore", "follow" and "abort". For settings other than
974 "ignore", the phase of the current revision of each subrepository is
974 "ignore", the phase of the current revision of each subrepository is
975 checked before committing the parent repository. If any of those phases is
975 checked before committing the parent repository. If any of those phases is
976 greater than the phase of the parent repository (e.g. if a subrepo is in a
976 greater than the phase of the parent repository (e.g. if a subrepo is in a
977 "secret" phase while the parent repo is in "draft" phase), the commit is
977 "secret" phase while the parent repo is in "draft" phase), the commit is
978 either aborted (if checksubrepos is set to "abort") or the higher phase is
978 either aborted (if checksubrepos is set to "abort") or the higher phase is
979 used for the parent repository commit (if set to "follow").
979 used for the parent repository commit (if set to "follow").
980 Default: "follow"
980 Default: "follow"
981
981
982
982
983 ``profiling``
983 ``profiling``
984 -------------
984 -------------
985
985
986 Specifies profiling type, format, and file output. Two profilers are
986 Specifies profiling type, format, and file output. Two profilers are
987 supported: an instrumenting profiler (named ``ls``), and a sampling
987 supported: an instrumenting profiler (named ``ls``), and a sampling
988 profiler (named ``stat``).
988 profiler (named ``stat``).
989
989
990 In this section description, 'profiling data' stands for the raw data
990 In this section description, 'profiling data' stands for the raw data
991 collected during profiling, while 'profiling report' stands for a
991 collected during profiling, while 'profiling report' stands for a
992 statistical text report generated from the profiling data. The
992 statistical text report generated from the profiling data. The
993 profiling is done using lsprof.
993 profiling is done using lsprof.
994
994
995 ``type``
995 ``type``
996 The type of profiler to use.
996 The type of profiler to use.
997 Default: ls.
997 Default: ls.
998
998
999 ``ls``
999 ``ls``
1000 Use Python's built-in instrumenting profiler. This profiler
1000 Use Python's built-in instrumenting profiler. This profiler
1001 works on all platforms, but each line number it reports is the
1001 works on all platforms, but each line number it reports is the
1002 first line of a function. This restriction makes it difficult to
1002 first line of a function. This restriction makes it difficult to
1003 identify the expensive parts of a non-trivial function.
1003 identify the expensive parts of a non-trivial function.
1004 ``stat``
1004 ``stat``
1005 Use a third-party statistical profiler, statprof. This profiler
1005 Use a third-party statistical profiler, statprof. This profiler
1006 currently runs only on Unix systems, and is most useful for
1006 currently runs only on Unix systems, and is most useful for
1007 profiling commands that run for longer than about 0.1 seconds.
1007 profiling commands that run for longer than about 0.1 seconds.
1008
1008
1009 ``format``
1009 ``format``
1010 Profiling format. Specific to the ``ls`` instrumenting profiler.
1010 Profiling format. Specific to the ``ls`` instrumenting profiler.
1011 Default: text.
1011 Default: text.
1012
1012
1013 ``text``
1013 ``text``
1014 Generate a profiling report. When saving to a file, it should be
1014 Generate a profiling report. When saving to a file, it should be
1015 noted that only the report is saved, and the profiling data is
1015 noted that only the report is saved, and the profiling data is
1016 not kept.
1016 not kept.
1017 ``kcachegrind``
1017 ``kcachegrind``
1018 Format profiling data for kcachegrind use: when saving to a
1018 Format profiling data for kcachegrind use: when saving to a
1019 file, the generated file can directly be loaded into
1019 file, the generated file can directly be loaded into
1020 kcachegrind.
1020 kcachegrind.
1021
1021
1022 ``frequency``
1022 ``frequency``
1023 Sampling frequency. Specific to the ``stat`` sampling profiler.
1023 Sampling frequency. Specific to the ``stat`` sampling profiler.
1024 Default: 1000.
1024 Default: 1000.
1025
1025
1026 ``output``
1026 ``output``
1027 File path where profiling data or report should be saved. If the
1027 File path where profiling data or report should be saved. If the
1028 file exists, it is replaced. Default: None, data is printed on
1028 file exists, it is replaced. Default: None, data is printed on
1029 stderr
1029 stderr
1030
1030
1031 ``sort``
1031 ``sort``
1032 Sort field. Specific to the ``ls`` instrumenting profiler.
1032 Sort field. Specific to the ``ls`` instrumenting profiler.
1033 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1033 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1034 ``inlinetime``.
1034 ``inlinetime``.
1035 Default: inlinetime.
1035 Default: inlinetime.
1036
1036
1037 ``limit``
1037 ``limit``
1038 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1038 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1039 Default: 30.
1039 Default: 30.
1040
1040
1041 ``nested``
1041 ``nested``
1042 Show at most this number of lines of drill-down info after each main entry.
1042 Show at most this number of lines of drill-down info after each main entry.
1043 This can help explain the difference between Total and Inline.
1043 This can help explain the difference between Total and Inline.
1044 Specific to the ``ls`` instrumenting profiler.
1044 Specific to the ``ls`` instrumenting profiler.
1045 Default: 5.
1045 Default: 5.
1046
1046
1047 ``revsetalias``
1047 ``revsetalias``
1048 ---------------
1048 ---------------
1049
1049
1050 Alias definitions for revsets. See :hg:`help revsets` for details.
1050 Alias definitions for revsets. See :hg:`help revsets` for details.
1051
1051
1052 ``server``
1052 ``server``
1053 ----------
1053 ----------
1054
1054
1055 Controls generic server settings.
1055 Controls generic server settings.
1056
1056
1057 ``uncompressed``
1057 ``uncompressed``
1058 Whether to allow clients to clone a repository using the
1058 Whether to allow clients to clone a repository using the
1059 uncompressed streaming protocol. This transfers about 40% more
1059 uncompressed streaming protocol. This transfers about 40% more
1060 data than a regular clone, but uses less memory and CPU on both
1060 data than a regular clone, but uses less memory and CPU on both
1061 server and client. Over a LAN (100 Mbps or better) or a very fast
1061 server and client. Over a LAN (100 Mbps or better) or a very fast
1062 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1062 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1063 regular clone. Over most WAN connections (anything slower than
1063 regular clone. Over most WAN connections (anything slower than
1064 about 6 Mbps), uncompressed streaming is slower, because of the
1064 about 6 Mbps), uncompressed streaming is slower, because of the
1065 extra data transfer overhead. This mode will also temporarily hold
1065 extra data transfer overhead. This mode will also temporarily hold
1066 the write lock while determining what data to transfer.
1066 the write lock while determining what data to transfer.
1067 Default is True.
1067 Default is True.
1068
1068
1069 ``preferuncompressed``
1069 ``preferuncompressed``
1070 When set, clients will try to use the uncompressed streaming
1070 When set, clients will try to use the uncompressed streaming
1071 protocol. Default is False.
1071 protocol. Default is False.
1072
1072
1073 ``validate``
1073 ``validate``
1074 Whether to validate the completeness of pushed changesets by
1074 Whether to validate the completeness of pushed changesets by
1075 checking that all new file revisions specified in manifests are
1075 checking that all new file revisions specified in manifests are
1076 present. Default is False.
1076 present. Default is False.
1077
1077
1078 ``smtp``
1078 ``smtp``
1079 --------
1079 --------
1080
1080
1081 Configuration for extensions that need to send email messages.
1081 Configuration for extensions that need to send email messages.
1082
1082
1083 ``host``
1083 ``host``
1084 Host name of mail server, e.g. "mail.example.com".
1084 Host name of mail server, e.g. "mail.example.com".
1085
1085
1086 ``port``
1086 ``port``
1087 Optional. Port to connect to on mail server. Default: 465 (if
1087 Optional. Port to connect to on mail server. Default: 465 (if
1088 ``tls`` is smtps) or 25 (otherwise).
1088 ``tls`` is smtps) or 25 (otherwise).
1089
1089
1090 ``tls``
1090 ``tls``
1091 Optional. Method to enable TLS when connecting to mail server: starttls,
1091 Optional. Method to enable TLS when connecting to mail server: starttls,
1092 smtps or none. Default: none.
1092 smtps or none. Default: none.
1093
1093
1094 ``verifycert``
1094 ``verifycert``
1095 Optional. Verification for the certificate of mail server, when
1095 Optional. Verification for the certificate of mail server, when
1096 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1096 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1097 "strict" or "loose", the certificate is verified as same as the
1097 "strict" or "loose", the certificate is verified as same as the
1098 verification for HTTPS connections (see ``[hostfingerprints]`` and
1098 verification for HTTPS connections (see ``[hostfingerprints]`` and
1099 ``[web] cacerts`` also). For "strict", sending email is also
1099 ``[web] cacerts`` also). For "strict", sending email is also
1100 aborted, if there is no configuration for mail server in
1100 aborted, if there is no configuration for mail server in
1101 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1101 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1102 :hg:`email` overwrites this as "loose". Default: "strict".
1102 :hg:`email` overwrites this as "loose". Default: "strict".
1103
1103
1104 ``username``
1104 ``username``
1105 Optional. User name for authenticating with the SMTP server.
1105 Optional. User name for authenticating with the SMTP server.
1106 Default: none.
1106 Default: none.
1107
1107
1108 ``password``
1108 ``password``
1109 Optional. Password for authenticating with the SMTP server. If not
1109 Optional. Password for authenticating with the SMTP server. If not
1110 specified, interactive sessions will prompt the user for a
1110 specified, interactive sessions will prompt the user for a
1111 password; non-interactive sessions will fail. Default: none.
1111 password; non-interactive sessions will fail. Default: none.
1112
1112
1113 ``local_hostname``
1113 ``local_hostname``
1114 Optional. It's the hostname that the sender can use to identify
1114 Optional. It's the hostname that the sender can use to identify
1115 itself to the MTA.
1115 itself to the MTA.
1116
1116
1117
1117
1118 ``subpaths``
1118 ``subpaths``
1119 ------------
1119 ------------
1120
1120
1121 Subrepository source URLs can go stale if a remote server changes name
1121 Subrepository source URLs can go stale if a remote server changes name
1122 or becomes temporarily unavailable. This section lets you define
1122 or becomes temporarily unavailable. This section lets you define
1123 rewrite rules of the form::
1123 rewrite rules of the form::
1124
1124
1125 <pattern> = <replacement>
1125 <pattern> = <replacement>
1126
1126
1127 where ``pattern`` is a regular expression matching a subrepository
1127 where ``pattern`` is a regular expression matching a subrepository
1128 source URL and ``replacement`` is the replacement string used to
1128 source URL and ``replacement`` is the replacement string used to
1129 rewrite it. Groups can be matched in ``pattern`` and referenced in
1129 rewrite it. Groups can be matched in ``pattern`` and referenced in
1130 ``replacements``. For instance::
1130 ``replacements``. For instance::
1131
1131
1132 http://server/(.*)-hg/ = http://hg.server/\1/
1132 http://server/(.*)-hg/ = http://hg.server/\1/
1133
1133
1134 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1134 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1135
1135
1136 Relative subrepository paths are first made absolute, and the
1136 Relative subrepository paths are first made absolute, and the
1137 rewrite rules are then applied on the full (absolute) path. The rules
1137 rewrite rules are then applied on the full (absolute) path. The rules
1138 are applied in definition order.
1138 are applied in definition order.
1139
1139
1140 ``trusted``
1140 ``trusted``
1141 -----------
1141 -----------
1142
1142
1143 Mercurial will not use the settings in the
1143 Mercurial will not use the settings in the
1144 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1144 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1145 user or to a trusted group, as various hgrc features allow arbitrary
1145 user or to a trusted group, as various hgrc features allow arbitrary
1146 commands to be run. This issue is often encountered when configuring
1146 commands to be run. This issue is often encountered when configuring
1147 hooks or extensions for shared repositories or servers. However,
1147 hooks or extensions for shared repositories or servers. However,
1148 the web interface will use some safe settings from the ``[web]``
1148 the web interface will use some safe settings from the ``[web]``
1149 section.
1149 section.
1150
1150
1151 This section specifies what users and groups are trusted. The
1151 This section specifies what users and groups are trusted. The
1152 current user is always trusted. To trust everybody, list a user or a
1152 current user is always trusted. To trust everybody, list a user or a
1153 group with name ``*``. These settings must be placed in an
1153 group with name ``*``. These settings must be placed in an
1154 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1154 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1155 user or service running Mercurial.
1155 user or service running Mercurial.
1156
1156
1157 ``users``
1157 ``users``
1158 Comma-separated list of trusted users.
1158 Comma-separated list of trusted users.
1159
1159
1160 ``groups``
1160 ``groups``
1161 Comma-separated list of trusted groups.
1161 Comma-separated list of trusted groups.
1162
1162
1163
1163
1164 ``ui``
1164 ``ui``
1165 ------
1165 ------
1166
1166
1167 User interface controls.
1167 User interface controls.
1168
1168
1169 ``archivemeta``
1169 ``archivemeta``
1170 Whether to include the .hg_archival.txt file containing meta data
1170 Whether to include the .hg_archival.txt file containing meta data
1171 (hashes for the repository base and for tip) in archives created
1171 (hashes for the repository base and for tip) in archives created
1172 by the :hg:`archive` command or downloaded via hgweb.
1172 by the :hg:`archive` command or downloaded via hgweb.
1173 Default is True.
1173 Default is True.
1174
1174
1175 ``askusername``
1175 ``askusername``
1176 Whether to prompt for a username when committing. If True, and
1176 Whether to prompt for a username when committing. If True, and
1177 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1177 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1178 be prompted to enter a username. If no username is entered, the
1178 be prompted to enter a username. If no username is entered, the
1179 default ``USER@HOST`` is used instead.
1179 default ``USER@HOST`` is used instead.
1180 Default is False.
1180 Default is False.
1181
1181
1182 ``commitsubrepos``
1182 ``commitsubrepos``
1183 Whether to commit modified subrepositories when committing the
1183 Whether to commit modified subrepositories when committing the
1184 parent repository. If False and one subrepository has uncommitted
1184 parent repository. If False and one subrepository has uncommitted
1185 changes, abort the commit.
1185 changes, abort the commit.
1186 Default is False.
1186 Default is False.
1187
1187
1188 ``debug``
1188 ``debug``
1189 Print debugging information. True or False. Default is False.
1189 Print debugging information. True or False. Default is False.
1190
1190
1191 ``editor``
1191 ``editor``
1192 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1192 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1193
1193
1194 ``fallbackencoding``
1194 ``fallbackencoding``
1195 Encoding to try if it's not possible to decode the changelog using
1195 Encoding to try if it's not possible to decode the changelog using
1196 UTF-8. Default is ISO-8859-1.
1196 UTF-8. Default is ISO-8859-1.
1197
1197
1198 ``ignore``
1198 ``ignore``
1199 A file to read per-user ignore patterns from. This file should be
1199 A file to read per-user ignore patterns from. This file should be
1200 in the same format as a repository-wide .hgignore file. This
1200 in the same format as a repository-wide .hgignore file. This
1201 option supports hook syntax, so if you want to specify multiple
1201 option supports hook syntax, so if you want to specify multiple
1202 ignore files, you can do so by setting something like
1202 ignore files, you can do so by setting something like
1203 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1203 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1204 format, see the ``hgignore(5)`` man page.
1204 format, see the ``hgignore(5)`` man page.
1205
1205
1206 ``interactive``
1206 ``interactive``
1207 Allow to prompt the user. True or False. Default is True.
1207 Allow to prompt the user. True or False. Default is True.
1208
1208
1209 ``logtemplate``
1209 ``logtemplate``
1210 Template string for commands that print changesets.
1210 Template string for commands that print changesets.
1211
1211
1212 ``merge``
1212 ``merge``
1213 The conflict resolution program to use during a manual merge.
1213 The conflict resolution program to use during a manual merge.
1214 For more information on merge tools see :hg:`help merge-tools`.
1214 For more information on merge tools see :hg:`help merge-tools`.
1215 For configuring merge tools see the ``[merge-tools]`` section.
1215 For configuring merge tools see the ``[merge-tools]`` section.
1216
1216
1217 ``mergemarkers``
1217 ``mergemarkers``
1218 Sets the merge conflict marker label styling. The default ``detailed``
1218 Sets the merge conflict marker label styling. The ``detailed``
1219 style uses the ``mergemarkertemplate`` setting to style the labels.
1219 style uses the ``mergemarkertemplate`` setting to style the labels.
1220 The ``basic`` style just uses 'local' and 'other' as the marker label.
1220 The ``basic`` style just uses 'local' and 'other' as the marker label.
1221 One of ``basic`` or ``detailed``.
1221 One of ``basic`` or ``detailed``.
1222 Default is ``detailed``.
1222 Default is ``basic``.
1223
1223
1224 ``mergemarkertemplate``
1224 ``mergemarkertemplate``
1225 The template used to print the commit description next to each conflict
1225 The template used to print the commit description next to each conflict
1226 marker during merge conflicts. See :hg:`help templates` for the template
1226 marker during merge conflicts. See :hg:`help templates` for the template
1227 format.
1227 format.
1228 Defaults to showing the hash, tags, branches, bookmarks, author, and
1228 Defaults to showing the hash, tags, branches, bookmarks, author, and
1229 the first line of the commit description.
1229 the first line of the commit description.
1230 You have to pay attention to encodings of managed files, if you
1231 use non-ASCII characters in tags, branches, bookmarks, author
1232 and/or commit descriptions. At template expansion, non-ASCII
1233 characters use the encoding specified by ``--encoding`` global
1234 option, ``HGENCODING`` or other locale setting environment
1235 variables. The difference of encoding between merged file and
1236 conflict markers causes serious problem.
1230
1237
1231 ``portablefilenames``
1238 ``portablefilenames``
1232 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1239 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1233 Default is ``warn``.
1240 Default is ``warn``.
1234 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1241 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1235 platforms, if a file with a non-portable filename is added (e.g. a file
1242 platforms, if a file with a non-portable filename is added (e.g. a file
1236 with a name that can't be created on Windows because it contains reserved
1243 with a name that can't be created on Windows because it contains reserved
1237 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1244 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1238 collision with an existing file).
1245 collision with an existing file).
1239 If set to ``ignore`` (or ``false``), no warning is printed.
1246 If set to ``ignore`` (or ``false``), no warning is printed.
1240 If set to ``abort``, the command is aborted.
1247 If set to ``abort``, the command is aborted.
1241 On Windows, this configuration option is ignored and the command aborted.
1248 On Windows, this configuration option is ignored and the command aborted.
1242
1249
1243 ``quiet``
1250 ``quiet``
1244 Reduce the amount of output printed. True or False. Default is False.
1251 Reduce the amount of output printed. True or False. Default is False.
1245
1252
1246 ``remotecmd``
1253 ``remotecmd``
1247 remote command to use for clone/push/pull operations. Default is ``hg``.
1254 remote command to use for clone/push/pull operations. Default is ``hg``.
1248
1255
1249 ``reportoldssl``
1256 ``reportoldssl``
1250 Warn if an SSL certificate is unable to be due to using Python
1257 Warn if an SSL certificate is unable to be due to using Python
1251 2.5 or earlier. True or False. Default is True.
1258 2.5 or earlier. True or False. Default is True.
1252
1259
1253 ``report_untrusted``
1260 ``report_untrusted``
1254 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1261 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1255 trusted user or group. True or False. Default is True.
1262 trusted user or group. True or False. Default is True.
1256
1263
1257 ``slash``
1264 ``slash``
1258 Display paths using a slash (``/``) as the path separator. This
1265 Display paths using a slash (``/``) as the path separator. This
1259 only makes a difference on systems where the default path
1266 only makes a difference on systems where the default path
1260 separator is not the slash character (e.g. Windows uses the
1267 separator is not the slash character (e.g. Windows uses the
1261 backslash character (``\``)).
1268 backslash character (``\``)).
1262 Default is False.
1269 Default is False.
1263
1270
1264 ``ssh``
1271 ``ssh``
1265 command to use for SSH connections. Default is ``ssh``.
1272 command to use for SSH connections. Default is ``ssh``.
1266
1273
1267 ``strict``
1274 ``strict``
1268 Require exact command names, instead of allowing unambiguous
1275 Require exact command names, instead of allowing unambiguous
1269 abbreviations. True or False. Default is False.
1276 abbreviations. True or False. Default is False.
1270
1277
1271 ``style``
1278 ``style``
1272 Name of style to use for command output.
1279 Name of style to use for command output.
1273
1280
1274 ``timeout``
1281 ``timeout``
1275 The timeout used when a lock is held (in seconds), a negative value
1282 The timeout used when a lock is held (in seconds), a negative value
1276 means no timeout. Default is 600.
1283 means no timeout. Default is 600.
1277
1284
1278 ``traceback``
1285 ``traceback``
1279 Mercurial always prints a traceback when an unknown exception
1286 Mercurial always prints a traceback when an unknown exception
1280 occurs. Setting this to True will make Mercurial print a traceback
1287 occurs. Setting this to True will make Mercurial print a traceback
1281 on all exceptions, even those recognized by Mercurial (such as
1288 on all exceptions, even those recognized by Mercurial (such as
1282 IOError or MemoryError). Default is False.
1289 IOError or MemoryError). Default is False.
1283
1290
1284 ``username``
1291 ``username``
1285 The committer of a changeset created when running "commit".
1292 The committer of a changeset created when running "commit".
1286 Typically a person's name and email address, e.g. ``Fred Widget
1293 Typically a person's name and email address, e.g. ``Fred Widget
1287 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1294 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1288 the username in hgrc is empty, it has to be specified manually or
1295 the username in hgrc is empty, it has to be specified manually or
1289 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1296 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1290 ``username =`` in the system hgrc). Environment variables in the
1297 ``username =`` in the system hgrc). Environment variables in the
1291 username are expanded.
1298 username are expanded.
1292
1299
1293 ``verbose``
1300 ``verbose``
1294 Increase the amount of output printed. True or False. Default is False.
1301 Increase the amount of output printed. True or False. Default is False.
1295
1302
1296
1303
1297 ``web``
1304 ``web``
1298 -------
1305 -------
1299
1306
1300 Web interface configuration. The settings in this section apply to
1307 Web interface configuration. The settings in this section apply to
1301 both the builtin webserver (started by :hg:`serve`) and the script you
1308 both the builtin webserver (started by :hg:`serve`) and the script you
1302 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1309 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1303 and WSGI).
1310 and WSGI).
1304
1311
1305 The Mercurial webserver does no authentication (it does not prompt for
1312 The Mercurial webserver does no authentication (it does not prompt for
1306 usernames and passwords to validate *who* users are), but it does do
1313 usernames and passwords to validate *who* users are), but it does do
1307 authorization (it grants or denies access for *authenticated users*
1314 authorization (it grants or denies access for *authenticated users*
1308 based on settings in this section). You must either configure your
1315 based on settings in this section). You must either configure your
1309 webserver to do authentication for you, or disable the authorization
1316 webserver to do authentication for you, or disable the authorization
1310 checks.
1317 checks.
1311
1318
1312 For a quick setup in a trusted environment, e.g., a private LAN, where
1319 For a quick setup in a trusted environment, e.g., a private LAN, where
1313 you want it to accept pushes from anybody, you can use the following
1320 you want it to accept pushes from anybody, you can use the following
1314 command line::
1321 command line::
1315
1322
1316 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1323 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1317
1324
1318 Note that this will allow anybody to push anything to the server and
1325 Note that this will allow anybody to push anything to the server and
1319 that this should not be used for public servers.
1326 that this should not be used for public servers.
1320
1327
1321 The full set of options is:
1328 The full set of options is:
1322
1329
1323 ``accesslog``
1330 ``accesslog``
1324 Where to output the access log. Default is stdout.
1331 Where to output the access log. Default is stdout.
1325
1332
1326 ``address``
1333 ``address``
1327 Interface address to bind to. Default is all.
1334 Interface address to bind to. Default is all.
1328
1335
1329 ``allow_archive``
1336 ``allow_archive``
1330 List of archive format (bz2, gz, zip) allowed for downloading.
1337 List of archive format (bz2, gz, zip) allowed for downloading.
1331 Default is empty.
1338 Default is empty.
1332
1339
1333 ``allowbz2``
1340 ``allowbz2``
1334 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1341 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1335 revisions.
1342 revisions.
1336 Default is False.
1343 Default is False.
1337
1344
1338 ``allowgz``
1345 ``allowgz``
1339 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1346 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1340 revisions.
1347 revisions.
1341 Default is False.
1348 Default is False.
1342
1349
1343 ``allowpull``
1350 ``allowpull``
1344 Whether to allow pulling from the repository. Default is True.
1351 Whether to allow pulling from the repository. Default is True.
1345
1352
1346 ``allow_push``
1353 ``allow_push``
1347 Whether to allow pushing to the repository. If empty or not set,
1354 Whether to allow pushing to the repository. If empty or not set,
1348 push is not allowed. If the special value ``*``, any remote user can
1355 push is not allowed. If the special value ``*``, any remote user can
1349 push, including unauthenticated users. Otherwise, the remote user
1356 push, including unauthenticated users. Otherwise, the remote user
1350 must have been authenticated, and the authenticated user name must
1357 must have been authenticated, and the authenticated user name must
1351 be present in this list. The contents of the allow_push list are
1358 be present in this list. The contents of the allow_push list are
1352 examined after the deny_push list.
1359 examined after the deny_push list.
1353
1360
1354 ``allow_read``
1361 ``allow_read``
1355 If the user has not already been denied repository access due to
1362 If the user has not already been denied repository access due to
1356 the contents of deny_read, this list determines whether to grant
1363 the contents of deny_read, this list determines whether to grant
1357 repository access to the user. If this list is not empty, and the
1364 repository access to the user. If this list is not empty, and the
1358 user is unauthenticated or not present in the list, then access is
1365 user is unauthenticated or not present in the list, then access is
1359 denied for the user. If the list is empty or not set, then access
1366 denied for the user. If the list is empty or not set, then access
1360 is permitted to all users by default. Setting allow_read to the
1367 is permitted to all users by default. Setting allow_read to the
1361 special value ``*`` is equivalent to it not being set (i.e. access
1368 special value ``*`` is equivalent to it not being set (i.e. access
1362 is permitted to all users). The contents of the allow_read list are
1369 is permitted to all users). The contents of the allow_read list are
1363 examined after the deny_read list.
1370 examined after the deny_read list.
1364
1371
1365 ``allowzip``
1372 ``allowzip``
1366 (DEPRECATED) Whether to allow .zip downloading of repository
1373 (DEPRECATED) Whether to allow .zip downloading of repository
1367 revisions. Default is False. This feature creates temporary files.
1374 revisions. Default is False. This feature creates temporary files.
1368
1375
1369 ``archivesubrepos``
1376 ``archivesubrepos``
1370 Whether to recurse into subrepositories when archiving. Default is
1377 Whether to recurse into subrepositories when archiving. Default is
1371 False.
1378 False.
1372
1379
1373 ``baseurl``
1380 ``baseurl``
1374 Base URL to use when publishing URLs in other locations, so
1381 Base URL to use when publishing URLs in other locations, so
1375 third-party tools like email notification hooks can construct
1382 third-party tools like email notification hooks can construct
1376 URLs. Example: ``http://hgserver/repos/``.
1383 URLs. Example: ``http://hgserver/repos/``.
1377
1384
1378 ``cacerts``
1385 ``cacerts``
1379 Path to file containing a list of PEM encoded certificate
1386 Path to file containing a list of PEM encoded certificate
1380 authority certificates. Environment variables and ``~user``
1387 authority certificates. Environment variables and ``~user``
1381 constructs are expanded in the filename. If specified on the
1388 constructs are expanded in the filename. If specified on the
1382 client, then it will verify the identity of remote HTTPS servers
1389 client, then it will verify the identity of remote HTTPS servers
1383 with these certificates.
1390 with these certificates.
1384
1391
1385 This feature is only supported when using Python 2.6 or later. If you wish
1392 This feature is only supported when using Python 2.6 or later. If you wish
1386 to use it with earlier versions of Python, install the backported
1393 to use it with earlier versions of Python, install the backported
1387 version of the ssl library that is available from
1394 version of the ssl library that is available from
1388 ``http://pypi.python.org``.
1395 ``http://pypi.python.org``.
1389
1396
1390 To disable SSL verification temporarily, specify ``--insecure`` from
1397 To disable SSL verification temporarily, specify ``--insecure`` from
1391 command line.
1398 command line.
1392
1399
1393 You can use OpenSSL's CA certificate file if your platform has
1400 You can use OpenSSL's CA certificate file if your platform has
1394 one. On most Linux systems this will be
1401 one. On most Linux systems this will be
1395 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1402 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1396 generate this file manually. The form must be as follows::
1403 generate this file manually. The form must be as follows::
1397
1404
1398 -----BEGIN CERTIFICATE-----
1405 -----BEGIN CERTIFICATE-----
1399 ... (certificate in base64 PEM encoding) ...
1406 ... (certificate in base64 PEM encoding) ...
1400 -----END CERTIFICATE-----
1407 -----END CERTIFICATE-----
1401 -----BEGIN CERTIFICATE-----
1408 -----BEGIN CERTIFICATE-----
1402 ... (certificate in base64 PEM encoding) ...
1409 ... (certificate in base64 PEM encoding) ...
1403 -----END CERTIFICATE-----
1410 -----END CERTIFICATE-----
1404
1411
1405 ``cache``
1412 ``cache``
1406 Whether to support caching in hgweb. Defaults to True.
1413 Whether to support caching in hgweb. Defaults to True.
1407
1414
1408 ``collapse``
1415 ``collapse``
1409 With ``descend`` enabled, repositories in subdirectories are shown at
1416 With ``descend`` enabled, repositories in subdirectories are shown at
1410 a single level alongside repositories in the current path. With
1417 a single level alongside repositories in the current path. With
1411 ``collapse`` also enabled, repositories residing at a deeper level than
1418 ``collapse`` also enabled, repositories residing at a deeper level than
1412 the current path are grouped behind navigable directory entries that
1419 the current path are grouped behind navigable directory entries that
1413 lead to the locations of these repositories. In effect, this setting
1420 lead to the locations of these repositories. In effect, this setting
1414 collapses each collection of repositories found within a subdirectory
1421 collapses each collection of repositories found within a subdirectory
1415 into a single entry for that subdirectory. Default is False.
1422 into a single entry for that subdirectory. Default is False.
1416
1423
1417 ``comparisoncontext``
1424 ``comparisoncontext``
1418 Number of lines of context to show in side-by-side file comparison. If
1425 Number of lines of context to show in side-by-side file comparison. If
1419 negative or the value ``full``, whole files are shown. Default is 5.
1426 negative or the value ``full``, whole files are shown. Default is 5.
1420 This setting can be overridden by a ``context`` request parameter to the
1427 This setting can be overridden by a ``context`` request parameter to the
1421 ``comparison`` command, taking the same values.
1428 ``comparison`` command, taking the same values.
1422
1429
1423 ``contact``
1430 ``contact``
1424 Name or email address of the person in charge of the repository.
1431 Name or email address of the person in charge of the repository.
1425 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1432 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1426
1433
1427 ``deny_push``
1434 ``deny_push``
1428 Whether to deny pushing to the repository. If empty or not set,
1435 Whether to deny pushing to the repository. If empty or not set,
1429 push is not denied. If the special value ``*``, all remote users are
1436 push is not denied. If the special value ``*``, all remote users are
1430 denied push. Otherwise, unauthenticated users are all denied, and
1437 denied push. Otherwise, unauthenticated users are all denied, and
1431 any authenticated user name present in this list is also denied. The
1438 any authenticated user name present in this list is also denied. The
1432 contents of the deny_push list are examined before the allow_push list.
1439 contents of the deny_push list are examined before the allow_push list.
1433
1440
1434 ``deny_read``
1441 ``deny_read``
1435 Whether to deny reading/viewing of the repository. If this list is
1442 Whether to deny reading/viewing of the repository. If this list is
1436 not empty, unauthenticated users are all denied, and any
1443 not empty, unauthenticated users are all denied, and any
1437 authenticated user name present in this list is also denied access to
1444 authenticated user name present in this list is also denied access to
1438 the repository. If set to the special value ``*``, all remote users
1445 the repository. If set to the special value ``*``, all remote users
1439 are denied access (rarely needed ;). If deny_read is empty or not set,
1446 are denied access (rarely needed ;). If deny_read is empty or not set,
1440 the determination of repository access depends on the presence and
1447 the determination of repository access depends on the presence and
1441 content of the allow_read list (see description). If both
1448 content of the allow_read list (see description). If both
1442 deny_read and allow_read are empty or not set, then access is
1449 deny_read and allow_read are empty or not set, then access is
1443 permitted to all users by default. If the repository is being
1450 permitted to all users by default. If the repository is being
1444 served via hgwebdir, denied users will not be able to see it in
1451 served via hgwebdir, denied users will not be able to see it in
1445 the list of repositories. The contents of the deny_read list have
1452 the list of repositories. The contents of the deny_read list have
1446 priority over (are examined before) the contents of the allow_read
1453 priority over (are examined before) the contents of the allow_read
1447 list.
1454 list.
1448
1455
1449 ``descend``
1456 ``descend``
1450 hgwebdir indexes will not descend into subdirectories. Only repositories
1457 hgwebdir indexes will not descend into subdirectories. Only repositories
1451 directly in the current path will be shown (other repositories are still
1458 directly in the current path will be shown (other repositories are still
1452 available from the index corresponding to their containing path).
1459 available from the index corresponding to their containing path).
1453
1460
1454 ``description``
1461 ``description``
1455 Textual description of the repository's purpose or contents.
1462 Textual description of the repository's purpose or contents.
1456 Default is "unknown".
1463 Default is "unknown".
1457
1464
1458 ``encoding``
1465 ``encoding``
1459 Character encoding name. Default is the current locale charset.
1466 Character encoding name. Default is the current locale charset.
1460 Example: "UTF-8"
1467 Example: "UTF-8"
1461
1468
1462 ``errorlog``
1469 ``errorlog``
1463 Where to output the error log. Default is stderr.
1470 Where to output the error log. Default is stderr.
1464
1471
1465 ``guessmime``
1472 ``guessmime``
1466 Control MIME types for raw download of file content.
1473 Control MIME types for raw download of file content.
1467 Set to True to let hgweb guess the content type from the file
1474 Set to True to let hgweb guess the content type from the file
1468 extension. This will serve HTML files as ``text/html`` and might
1475 extension. This will serve HTML files as ``text/html`` and might
1469 allow cross-site scripting attacks when serving untrusted
1476 allow cross-site scripting attacks when serving untrusted
1470 repositories. Default is False.
1477 repositories. Default is False.
1471
1478
1472 ``hidden``
1479 ``hidden``
1473 Whether to hide the repository in the hgwebdir index.
1480 Whether to hide the repository in the hgwebdir index.
1474 Default is False.
1481 Default is False.
1475
1482
1476 ``ipv6``
1483 ``ipv6``
1477 Whether to use IPv6. Default is False.
1484 Whether to use IPv6. Default is False.
1478
1485
1479 ``logoimg``
1486 ``logoimg``
1480 File name of the logo image that some templates display on each page.
1487 File name of the logo image that some templates display on each page.
1481 The file name is relative to ``staticurl``. That is, the full path to
1488 The file name is relative to ``staticurl``. That is, the full path to
1482 the logo image is "staticurl/logoimg".
1489 the logo image is "staticurl/logoimg".
1483 If unset, ``hglogo.png`` will be used.
1490 If unset, ``hglogo.png`` will be used.
1484
1491
1485 ``logourl``
1492 ``logourl``
1486 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1493 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1487 will be used.
1494 will be used.
1488
1495
1489 ``maxchanges``
1496 ``maxchanges``
1490 Maximum number of changes to list on the changelog. Default is 10.
1497 Maximum number of changes to list on the changelog. Default is 10.
1491
1498
1492 ``maxfiles``
1499 ``maxfiles``
1493 Maximum number of files to list per changeset. Default is 10.
1500 Maximum number of files to list per changeset. Default is 10.
1494
1501
1495 ``maxshortchanges``
1502 ``maxshortchanges``
1496 Maximum number of changes to list on the shortlog, graph or filelog
1503 Maximum number of changes to list on the shortlog, graph or filelog
1497 pages. Default is 60.
1504 pages. Default is 60.
1498
1505
1499 ``name``
1506 ``name``
1500 Repository name to use in the web interface. Default is current
1507 Repository name to use in the web interface. Default is current
1501 working directory.
1508 working directory.
1502
1509
1503 ``port``
1510 ``port``
1504 Port to listen on. Default is 8000.
1511 Port to listen on. Default is 8000.
1505
1512
1506 ``prefix``
1513 ``prefix``
1507 Prefix path to serve from. Default is '' (server root).
1514 Prefix path to serve from. Default is '' (server root).
1508
1515
1509 ``push_ssl``
1516 ``push_ssl``
1510 Whether to require that inbound pushes be transported over SSL to
1517 Whether to require that inbound pushes be transported over SSL to
1511 prevent password sniffing. Default is True.
1518 prevent password sniffing. Default is True.
1512
1519
1513 ``staticurl``
1520 ``staticurl``
1514 Base URL to use for static files. If unset, static files (e.g. the
1521 Base URL to use for static files. If unset, static files (e.g. the
1515 hgicon.png favicon) will be served by the CGI script itself. Use
1522 hgicon.png favicon) will be served by the CGI script itself. Use
1516 this setting to serve them directly with the HTTP server.
1523 this setting to serve them directly with the HTTP server.
1517 Example: ``http://hgserver/static/``.
1524 Example: ``http://hgserver/static/``.
1518
1525
1519 ``stripes``
1526 ``stripes``
1520 How many lines a "zebra stripe" should span in multi-line output.
1527 How many lines a "zebra stripe" should span in multi-line output.
1521 Default is 1; set to 0 to disable.
1528 Default is 1; set to 0 to disable.
1522
1529
1523 ``style``
1530 ``style``
1524 Which template map style to use.
1531 Which template map style to use.
1525
1532
1526 ``templates``
1533 ``templates``
1527 Where to find the HTML templates. Default is install path.
1534 Where to find the HTML templates. Default is install path.
1528
1535
1529 ``websub``
1536 ``websub``
1530 ----------
1537 ----------
1531
1538
1532 Web substitution filter definition. You can use this section to
1539 Web substitution filter definition. You can use this section to
1533 define a set of regular expression substitution patterns which
1540 define a set of regular expression substitution patterns which
1534 let you automatically modify the hgweb server output.
1541 let you automatically modify the hgweb server output.
1535
1542
1536 The default hgweb templates only apply these substitution patterns
1543 The default hgweb templates only apply these substitution patterns
1537 on the revision description fields. You can apply them anywhere
1544 on the revision description fields. You can apply them anywhere
1538 you want when you create your own templates by adding calls to the
1545 you want when you create your own templates by adding calls to the
1539 "websub" filter (usually after calling the "escape" filter).
1546 "websub" filter (usually after calling the "escape" filter).
1540
1547
1541 This can be used, for example, to convert issue references to links
1548 This can be used, for example, to convert issue references to links
1542 to your issue tracker, or to convert "markdown-like" syntax into
1549 to your issue tracker, or to convert "markdown-like" syntax into
1543 HTML (see the examples below).
1550 HTML (see the examples below).
1544
1551
1545 Each entry in this section names a substitution filter.
1552 Each entry in this section names a substitution filter.
1546 The value of each entry defines the substitution expression itself.
1553 The value of each entry defines the substitution expression itself.
1547 The websub expressions follow the old interhg extension syntax,
1554 The websub expressions follow the old interhg extension syntax,
1548 which in turn imitates the Unix sed replacement syntax::
1555 which in turn imitates the Unix sed replacement syntax::
1549
1556
1550 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1557 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1551
1558
1552 You can use any separator other than "/". The final "i" is optional
1559 You can use any separator other than "/". The final "i" is optional
1553 and indicates that the search must be case insensitive.
1560 and indicates that the search must be case insensitive.
1554
1561
1555 Examples::
1562 Examples::
1556
1563
1557 [websub]
1564 [websub]
1558 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1565 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1559 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1566 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1560 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1567 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1561
1568
1562 ``worker``
1569 ``worker``
1563 ----------
1570 ----------
1564
1571
1565 Parallel master/worker configuration. We currently perform working
1572 Parallel master/worker configuration. We currently perform working
1566 directory updates in parallel on Unix-like systems, which greatly
1573 directory updates in parallel on Unix-like systems, which greatly
1567 helps performance.
1574 helps performance.
1568
1575
1569 ``numcpus``
1576 ``numcpus``
1570 Number of CPUs to use for parallel operations. Default is 4 or the
1577 Number of CPUs to use for parallel operations. Default is 4 or the
1571 number of CPUs on the system, whichever is larger. A zero or
1578 number of CPUs on the system, whichever is larger. A zero or
1572 negative value is treated as ``use the default``.
1579 negative value is treated as ``use the default``.
@@ -1,1821 +1,1822 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 # Modifying this script is tricky because it has many modes:
10 # Modifying this script is tricky because it has many modes:
11 # - serial (default) vs parallel (-jN, N > 1)
11 # - serial (default) vs parallel (-jN, N > 1)
12 # - no coverage (default) vs coverage (-c, -C, -s)
12 # - no coverage (default) vs coverage (-c, -C, -s)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
14 # - tests are a mix of shell scripts and Python scripts
14 # - tests are a mix of shell scripts and Python scripts
15 #
15 #
16 # If you change this script, it is recommended that you ensure you
16 # If you change this script, it is recommended that you ensure you
17 # haven't broken it by running it in various modes with a representative
17 # haven't broken it by running it in various modes with a representative
18 # sample of test scripts. For example:
18 # sample of test scripts. For example:
19 #
19 #
20 # 1) serial, no coverage, temp install:
20 # 1) serial, no coverage, temp install:
21 # ./run-tests.py test-s*
21 # ./run-tests.py test-s*
22 # 2) serial, no coverage, local hg:
22 # 2) serial, no coverage, local hg:
23 # ./run-tests.py --local test-s*
23 # ./run-tests.py --local test-s*
24 # 3) serial, coverage, temp install:
24 # 3) serial, coverage, temp install:
25 # ./run-tests.py -c test-s*
25 # ./run-tests.py -c test-s*
26 # 4) serial, coverage, local hg:
26 # 4) serial, coverage, local hg:
27 # ./run-tests.py -c --local test-s* # unsupported
27 # ./run-tests.py -c --local test-s* # unsupported
28 # 5) parallel, no coverage, temp install:
28 # 5) parallel, no coverage, temp install:
29 # ./run-tests.py -j2 test-s*
29 # ./run-tests.py -j2 test-s*
30 # 6) parallel, no coverage, local hg:
30 # 6) parallel, no coverage, local hg:
31 # ./run-tests.py -j2 --local test-s*
31 # ./run-tests.py -j2 --local test-s*
32 # 7) parallel, coverage, temp install:
32 # 7) parallel, coverage, temp install:
33 # ./run-tests.py -j2 -c test-s* # currently broken
33 # ./run-tests.py -j2 -c test-s* # currently broken
34 # 8) parallel, coverage, local install:
34 # 8) parallel, coverage, local install:
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
36 # 9) parallel, custom tmp dir:
36 # 9) parallel, custom tmp dir:
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
38 #
38 #
39 # (You could use any subset of the tests: test-s* happens to match
39 # (You could use any subset of the tests: test-s* happens to match
40 # enough that it's worth doing parallel runs, few enough that it
40 # enough that it's worth doing parallel runs, few enough that it
41 # completes fairly quickly, includes both shell and Python scripts, and
41 # completes fairly quickly, includes both shell and Python scripts, and
42 # includes some scripts that run daemon processes.)
42 # includes some scripts that run daemon processes.)
43
43
44 from distutils import version
44 from distutils import version
45 import difflib
45 import difflib
46 import errno
46 import errno
47 import optparse
47 import optparse
48 import os
48 import os
49 import shutil
49 import shutil
50 import subprocess
50 import subprocess
51 import signal
51 import signal
52 import sys
52 import sys
53 import tempfile
53 import tempfile
54 import time
54 import time
55 import random
55 import random
56 import re
56 import re
57 import threading
57 import threading
58 import killdaemons as killmod
58 import killdaemons as killmod
59 import Queue as queue
59 import Queue as queue
60 import unittest
60 import unittest
61
61
62 processlock = threading.Lock()
62 processlock = threading.Lock()
63
63
64 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
64 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
65 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing
65 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing
66 # zombies but it's pretty harmless even if we do.
66 # zombies but it's pretty harmless even if we do.
67 if sys.version_info < (2, 5):
67 if sys.version_info < (2, 5):
68 subprocess._cleanup = lambda: None
68 subprocess._cleanup = lambda: None
69
69
70 closefds = os.name == 'posix'
70 closefds = os.name == 'posix'
71 def Popen4(cmd, wd, timeout, env=None):
71 def Popen4(cmd, wd, timeout, env=None):
72 processlock.acquire()
72 processlock.acquire()
73 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
73 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
74 close_fds=closefds,
74 close_fds=closefds,
75 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
75 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
76 stderr=subprocess.STDOUT)
76 stderr=subprocess.STDOUT)
77 processlock.release()
77 processlock.release()
78
78
79 p.fromchild = p.stdout
79 p.fromchild = p.stdout
80 p.tochild = p.stdin
80 p.tochild = p.stdin
81 p.childerr = p.stderr
81 p.childerr = p.stderr
82
82
83 p.timeout = False
83 p.timeout = False
84 if timeout:
84 if timeout:
85 def t():
85 def t():
86 start = time.time()
86 start = time.time()
87 while time.time() - start < timeout and p.returncode is None:
87 while time.time() - start < timeout and p.returncode is None:
88 time.sleep(.1)
88 time.sleep(.1)
89 p.timeout = True
89 p.timeout = True
90 if p.returncode is None:
90 if p.returncode is None:
91 terminate(p)
91 terminate(p)
92 threading.Thread(target=t).start()
92 threading.Thread(target=t).start()
93
93
94 return p
94 return p
95
95
96 PYTHON = sys.executable.replace('\\', '/')
96 PYTHON = sys.executable.replace('\\', '/')
97 IMPL_PATH = 'PYTHONPATH'
97 IMPL_PATH = 'PYTHONPATH'
98 if 'java' in sys.platform:
98 if 'java' in sys.platform:
99 IMPL_PATH = 'JYTHONPATH'
99 IMPL_PATH = 'JYTHONPATH'
100
100
101 TESTDIR = HGTMP = INST = BINDIR = TMPBINDIR = PYTHONDIR = None
101 TESTDIR = HGTMP = INST = BINDIR = TMPBINDIR = PYTHONDIR = None
102
102
103 defaults = {
103 defaults = {
104 'jobs': ('HGTEST_JOBS', 1),
104 'jobs': ('HGTEST_JOBS', 1),
105 'timeout': ('HGTEST_TIMEOUT', 180),
105 'timeout': ('HGTEST_TIMEOUT', 180),
106 'port': ('HGTEST_PORT', 20059),
106 'port': ('HGTEST_PORT', 20059),
107 'shell': ('HGTEST_SHELL', 'sh'),
107 'shell': ('HGTEST_SHELL', 'sh'),
108 }
108 }
109
109
110 def parselistfiles(files, listtype, warn=True):
110 def parselistfiles(files, listtype, warn=True):
111 entries = dict()
111 entries = dict()
112 for filename in files:
112 for filename in files:
113 try:
113 try:
114 path = os.path.expanduser(os.path.expandvars(filename))
114 path = os.path.expanduser(os.path.expandvars(filename))
115 f = open(path, "rb")
115 f = open(path, "rb")
116 except IOError, err:
116 except IOError, err:
117 if err.errno != errno.ENOENT:
117 if err.errno != errno.ENOENT:
118 raise
118 raise
119 if warn:
119 if warn:
120 print "warning: no such %s file: %s" % (listtype, filename)
120 print "warning: no such %s file: %s" % (listtype, filename)
121 continue
121 continue
122
122
123 for line in f.readlines():
123 for line in f.readlines():
124 line = line.split('#', 1)[0].strip()
124 line = line.split('#', 1)[0].strip()
125 if line:
125 if line:
126 entries[line] = filename
126 entries[line] = filename
127
127
128 f.close()
128 f.close()
129 return entries
129 return entries
130
130
131 def getparser():
131 def getparser():
132 """Obtain the OptionParser used by the CLI."""
132 """Obtain the OptionParser used by the CLI."""
133 parser = optparse.OptionParser("%prog [options] [tests]")
133 parser = optparse.OptionParser("%prog [options] [tests]")
134
134
135 # keep these sorted
135 # keep these sorted
136 parser.add_option("--blacklist", action="append",
136 parser.add_option("--blacklist", action="append",
137 help="skip tests listed in the specified blacklist file")
137 help="skip tests listed in the specified blacklist file")
138 parser.add_option("--whitelist", action="append",
138 parser.add_option("--whitelist", action="append",
139 help="always run tests listed in the specified whitelist file")
139 help="always run tests listed in the specified whitelist file")
140 parser.add_option("--changed", type="string",
140 parser.add_option("--changed", type="string",
141 help="run tests that are changed in parent rev or working directory")
141 help="run tests that are changed in parent rev or working directory")
142 parser.add_option("-C", "--annotate", action="store_true",
142 parser.add_option("-C", "--annotate", action="store_true",
143 help="output files annotated with coverage")
143 help="output files annotated with coverage")
144 parser.add_option("-c", "--cover", action="store_true",
144 parser.add_option("-c", "--cover", action="store_true",
145 help="print a test coverage report")
145 help="print a test coverage report")
146 parser.add_option("-d", "--debug", action="store_true",
146 parser.add_option("-d", "--debug", action="store_true",
147 help="debug mode: write output of test scripts to console"
147 help="debug mode: write output of test scripts to console"
148 " rather than capturing and diffing it (disables timeout)")
148 " rather than capturing and diffing it (disables timeout)")
149 parser.add_option("-f", "--first", action="store_true",
149 parser.add_option("-f", "--first", action="store_true",
150 help="exit on the first test failure")
150 help="exit on the first test failure")
151 parser.add_option("-H", "--htmlcov", action="store_true",
151 parser.add_option("-H", "--htmlcov", action="store_true",
152 help="create an HTML report of the coverage of the files")
152 help="create an HTML report of the coverage of the files")
153 parser.add_option("-i", "--interactive", action="store_true",
153 parser.add_option("-i", "--interactive", action="store_true",
154 help="prompt to accept changed output")
154 help="prompt to accept changed output")
155 parser.add_option("-j", "--jobs", type="int",
155 parser.add_option("-j", "--jobs", type="int",
156 help="number of jobs to run in parallel"
156 help="number of jobs to run in parallel"
157 " (default: $%s or %d)" % defaults['jobs'])
157 " (default: $%s or %d)" % defaults['jobs'])
158 parser.add_option("--keep-tmpdir", action="store_true",
158 parser.add_option("--keep-tmpdir", action="store_true",
159 help="keep temporary directory after running tests")
159 help="keep temporary directory after running tests")
160 parser.add_option("-k", "--keywords",
160 parser.add_option("-k", "--keywords",
161 help="run tests matching keywords")
161 help="run tests matching keywords")
162 parser.add_option("-l", "--local", action="store_true",
162 parser.add_option("-l", "--local", action="store_true",
163 help="shortcut for --with-hg=<testdir>/../hg")
163 help="shortcut for --with-hg=<testdir>/../hg")
164 parser.add_option("--loop", action="store_true",
164 parser.add_option("--loop", action="store_true",
165 help="loop tests repeatedly")
165 help="loop tests repeatedly")
166 parser.add_option("-n", "--nodiff", action="store_true",
166 parser.add_option("-n", "--nodiff", action="store_true",
167 help="skip showing test changes")
167 help="skip showing test changes")
168 parser.add_option("-p", "--port", type="int",
168 parser.add_option("-p", "--port", type="int",
169 help="port on which servers should listen"
169 help="port on which servers should listen"
170 " (default: $%s or %d)" % defaults['port'])
170 " (default: $%s or %d)" % defaults['port'])
171 parser.add_option("--compiler", type="string",
171 parser.add_option("--compiler", type="string",
172 help="compiler to build with")
172 help="compiler to build with")
173 parser.add_option("--pure", action="store_true",
173 parser.add_option("--pure", action="store_true",
174 help="use pure Python code instead of C extensions")
174 help="use pure Python code instead of C extensions")
175 parser.add_option("-R", "--restart", action="store_true",
175 parser.add_option("-R", "--restart", action="store_true",
176 help="restart at last error")
176 help="restart at last error")
177 parser.add_option("-r", "--retest", action="store_true",
177 parser.add_option("-r", "--retest", action="store_true",
178 help="retest failed tests")
178 help="retest failed tests")
179 parser.add_option("-S", "--noskips", action="store_true",
179 parser.add_option("-S", "--noskips", action="store_true",
180 help="don't report skip tests verbosely")
180 help="don't report skip tests verbosely")
181 parser.add_option("--shell", type="string",
181 parser.add_option("--shell", type="string",
182 help="shell to use (default: $%s or %s)" % defaults['shell'])
182 help="shell to use (default: $%s or %s)" % defaults['shell'])
183 parser.add_option("-t", "--timeout", type="int",
183 parser.add_option("-t", "--timeout", type="int",
184 help="kill errant tests after TIMEOUT seconds"
184 help="kill errant tests after TIMEOUT seconds"
185 " (default: $%s or %d)" % defaults['timeout'])
185 " (default: $%s or %d)" % defaults['timeout'])
186 parser.add_option("--time", action="store_true",
186 parser.add_option("--time", action="store_true",
187 help="time how long each test takes")
187 help="time how long each test takes")
188 parser.add_option("--tmpdir", type="string",
188 parser.add_option("--tmpdir", type="string",
189 help="run tests in the given temporary directory"
189 help="run tests in the given temporary directory"
190 " (implies --keep-tmpdir)")
190 " (implies --keep-tmpdir)")
191 parser.add_option("-v", "--verbose", action="store_true",
191 parser.add_option("-v", "--verbose", action="store_true",
192 help="output verbose messages")
192 help="output verbose messages")
193 parser.add_option("--view", type="string",
193 parser.add_option("--view", type="string",
194 help="external diff viewer")
194 help="external diff viewer")
195 parser.add_option("--with-hg", type="string",
195 parser.add_option("--with-hg", type="string",
196 metavar="HG",
196 metavar="HG",
197 help="test using specified hg script rather than a "
197 help="test using specified hg script rather than a "
198 "temporary installation")
198 "temporary installation")
199 parser.add_option("-3", "--py3k-warnings", action="store_true",
199 parser.add_option("-3", "--py3k-warnings", action="store_true",
200 help="enable Py3k warnings on Python 2.6+")
200 help="enable Py3k warnings on Python 2.6+")
201 parser.add_option('--extra-config-opt', action="append",
201 parser.add_option('--extra-config-opt', action="append",
202 help='set the given config opt in the test hgrc')
202 help='set the given config opt in the test hgrc')
203 parser.add_option('--random', action="store_true",
203 parser.add_option('--random', action="store_true",
204 help='run tests in random order')
204 help='run tests in random order')
205
205
206 for option, (envvar, default) in defaults.items():
206 for option, (envvar, default) in defaults.items():
207 defaults[option] = type(default)(os.environ.get(envvar, default))
207 defaults[option] = type(default)(os.environ.get(envvar, default))
208 parser.set_defaults(**defaults)
208 parser.set_defaults(**defaults)
209
209
210 return parser
210 return parser
211
211
212 def parseargs(args, parser):
212 def parseargs(args, parser):
213 """Parse arguments with our OptionParser and validate results."""
213 """Parse arguments with our OptionParser and validate results."""
214 (options, args) = parser.parse_args(args)
214 (options, args) = parser.parse_args(args)
215
215
216 # jython is always pure
216 # jython is always pure
217 if 'java' in sys.platform or '__pypy__' in sys.modules:
217 if 'java' in sys.platform or '__pypy__' in sys.modules:
218 options.pure = True
218 options.pure = True
219
219
220 if options.with_hg:
220 if options.with_hg:
221 options.with_hg = os.path.expanduser(options.with_hg)
221 options.with_hg = os.path.expanduser(options.with_hg)
222 if not (os.path.isfile(options.with_hg) and
222 if not (os.path.isfile(options.with_hg) and
223 os.access(options.with_hg, os.X_OK)):
223 os.access(options.with_hg, os.X_OK)):
224 parser.error('--with-hg must specify an executable hg script')
224 parser.error('--with-hg must specify an executable hg script')
225 if not os.path.basename(options.with_hg) == 'hg':
225 if not os.path.basename(options.with_hg) == 'hg':
226 sys.stderr.write('warning: --with-hg should specify an hg script\n')
226 sys.stderr.write('warning: --with-hg should specify an hg script\n')
227 if options.local:
227 if options.local:
228 testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
228 testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
229 hgbin = os.path.join(os.path.dirname(testdir), 'hg')
229 hgbin = os.path.join(os.path.dirname(testdir), 'hg')
230 if os.name != 'nt' and not os.access(hgbin, os.X_OK):
230 if os.name != 'nt' and not os.access(hgbin, os.X_OK):
231 parser.error('--local specified, but %r not found or not executable'
231 parser.error('--local specified, but %r not found or not executable'
232 % hgbin)
232 % hgbin)
233 options.with_hg = hgbin
233 options.with_hg = hgbin
234
234
235 options.anycoverage = options.cover or options.annotate or options.htmlcov
235 options.anycoverage = options.cover or options.annotate or options.htmlcov
236 if options.anycoverage:
236 if options.anycoverage:
237 try:
237 try:
238 import coverage
238 import coverage
239 covver = version.StrictVersion(coverage.__version__).version
239 covver = version.StrictVersion(coverage.__version__).version
240 if covver < (3, 3):
240 if covver < (3, 3):
241 parser.error('coverage options require coverage 3.3 or later')
241 parser.error('coverage options require coverage 3.3 or later')
242 except ImportError:
242 except ImportError:
243 parser.error('coverage options now require the coverage package')
243 parser.error('coverage options now require the coverage package')
244
244
245 if options.anycoverage and options.local:
245 if options.anycoverage and options.local:
246 # this needs some path mangling somewhere, I guess
246 # this needs some path mangling somewhere, I guess
247 parser.error("sorry, coverage options do not work when --local "
247 parser.error("sorry, coverage options do not work when --local "
248 "is specified")
248 "is specified")
249
249
250 global verbose
250 global verbose
251 if options.verbose:
251 if options.verbose:
252 verbose = ''
252 verbose = ''
253
253
254 if options.tmpdir:
254 if options.tmpdir:
255 options.tmpdir = os.path.expanduser(options.tmpdir)
255 options.tmpdir = os.path.expanduser(options.tmpdir)
256
256
257 if options.jobs < 1:
257 if options.jobs < 1:
258 parser.error('--jobs must be positive')
258 parser.error('--jobs must be positive')
259 if options.interactive and options.debug:
259 if options.interactive and options.debug:
260 parser.error("-i/--interactive and -d/--debug are incompatible")
260 parser.error("-i/--interactive and -d/--debug are incompatible")
261 if options.debug:
261 if options.debug:
262 if options.timeout != defaults['timeout']:
262 if options.timeout != defaults['timeout']:
263 sys.stderr.write(
263 sys.stderr.write(
264 'warning: --timeout option ignored with --debug\n')
264 'warning: --timeout option ignored with --debug\n')
265 options.timeout = 0
265 options.timeout = 0
266 if options.py3k_warnings:
266 if options.py3k_warnings:
267 if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
267 if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
268 parser.error('--py3k-warnings can only be used on Python 2.6+')
268 parser.error('--py3k-warnings can only be used on Python 2.6+')
269 if options.blacklist:
269 if options.blacklist:
270 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
270 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
271 if options.whitelist:
271 if options.whitelist:
272 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
272 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
273 else:
273 else:
274 options.whitelisted = {}
274 options.whitelisted = {}
275
275
276 return (options, args)
276 return (options, args)
277
277
278 def rename(src, dst):
278 def rename(src, dst):
279 """Like os.rename(), trade atomicity and opened files friendliness
279 """Like os.rename(), trade atomicity and opened files friendliness
280 for existing destination support.
280 for existing destination support.
281 """
281 """
282 shutil.copy(src, dst)
282 shutil.copy(src, dst)
283 os.remove(src)
283 os.remove(src)
284
284
285 def getdiff(expected, output, ref, err):
285 def getdiff(expected, output, ref, err):
286 servefail = False
286 servefail = False
287 lines = []
287 lines = []
288 for line in difflib.unified_diff(expected, output, ref, err):
288 for line in difflib.unified_diff(expected, output, ref, err):
289 if line.startswith('+++') or line.startswith('---'):
289 if line.startswith('+++') or line.startswith('---'):
290 if line.endswith(' \n'):
290 if line.endswith(' \n'):
291 line = line[:-2] + '\n'
291 line = line[:-2] + '\n'
292 lines.append(line)
292 lines.append(line)
293 if not servefail and line.startswith(
293 if not servefail and line.startswith(
294 '+ abort: child process failed to start'):
294 '+ abort: child process failed to start'):
295 servefail = True
295 servefail = True
296
296
297 return servefail, lines
297 return servefail, lines
298
298
299 verbose = False
299 verbose = False
300 def vlog(*msg):
300 def vlog(*msg):
301 """Log only when in verbose mode."""
301 """Log only when in verbose mode."""
302 if verbose is False:
302 if verbose is False:
303 return
303 return
304
304
305 return log(*msg)
305 return log(*msg)
306
306
307 def log(*msg):
307 def log(*msg):
308 """Log something to stdout.
308 """Log something to stdout.
309
309
310 Arguments are strings to print.
310 Arguments are strings to print.
311 """
311 """
312 iolock.acquire()
312 iolock.acquire()
313 if verbose:
313 if verbose:
314 print verbose,
314 print verbose,
315 for m in msg:
315 for m in msg:
316 print m,
316 print m,
317 print
317 print
318 sys.stdout.flush()
318 sys.stdout.flush()
319 iolock.release()
319 iolock.release()
320
320
321 def terminate(proc):
321 def terminate(proc):
322 """Terminate subprocess (with fallback for Python versions < 2.6)"""
322 """Terminate subprocess (with fallback for Python versions < 2.6)"""
323 vlog('# Terminating process %d' % proc.pid)
323 vlog('# Terminating process %d' % proc.pid)
324 try:
324 try:
325 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
325 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
326 except OSError:
326 except OSError:
327 pass
327 pass
328
328
329 def killdaemons(pidfile):
329 def killdaemons(pidfile):
330 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
330 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
331 logfn=vlog)
331 logfn=vlog)
332
332
333 class Test(unittest.TestCase):
333 class Test(unittest.TestCase):
334 """Encapsulates a single, runnable test.
334 """Encapsulates a single, runnable test.
335
335
336 While this class conforms to the unittest.TestCase API, it differs in that
336 While this class conforms to the unittest.TestCase API, it differs in that
337 instances need to be instantiated manually. (Typically, unittest.TestCase
337 instances need to be instantiated manually. (Typically, unittest.TestCase
338 classes are instantiated automatically by scanning modules.)
338 classes are instantiated automatically by scanning modules.)
339 """
339 """
340
340
341 # Status code reserved for skipped tests (used by hghave).
341 # Status code reserved for skipped tests (used by hghave).
342 SKIPPED_STATUS = 80
342 SKIPPED_STATUS = 80
343
343
344 def __init__(self, path, tmpdir, keeptmpdir=False,
344 def __init__(self, path, tmpdir, keeptmpdir=False,
345 debug=False,
345 debug=False,
346 timeout=defaults['timeout'],
346 timeout=defaults['timeout'],
347 startport=defaults['port'], extraconfigopts=None,
347 startport=defaults['port'], extraconfigopts=None,
348 py3kwarnings=False, shell=None):
348 py3kwarnings=False, shell=None):
349 """Create a test from parameters.
349 """Create a test from parameters.
350
350
351 path is the full path to the file defining the test.
351 path is the full path to the file defining the test.
352
352
353 tmpdir is the main temporary directory to use for this test.
353 tmpdir is the main temporary directory to use for this test.
354
354
355 keeptmpdir determines whether to keep the test's temporary directory
355 keeptmpdir determines whether to keep the test's temporary directory
356 after execution. It defaults to removal (False).
356 after execution. It defaults to removal (False).
357
357
358 debug mode will make the test execute verbosely, with unfiltered
358 debug mode will make the test execute verbosely, with unfiltered
359 output.
359 output.
360
360
361 timeout controls the maximum run time of the test. It is ignored when
361 timeout controls the maximum run time of the test. It is ignored when
362 debug is True.
362 debug is True.
363
363
364 startport controls the starting port number to use for this test. Each
364 startport controls the starting port number to use for this test. Each
365 test will reserve 3 port numbers for execution. It is the caller's
365 test will reserve 3 port numbers for execution. It is the caller's
366 responsibility to allocate a non-overlapping port range to Test
366 responsibility to allocate a non-overlapping port range to Test
367 instances.
367 instances.
368
368
369 extraconfigopts is an iterable of extra hgrc config options. Values
369 extraconfigopts is an iterable of extra hgrc config options. Values
370 must have the form "key=value" (something understood by hgrc). Values
370 must have the form "key=value" (something understood by hgrc). Values
371 of the form "foo.key=value" will result in "[foo] key=value".
371 of the form "foo.key=value" will result in "[foo] key=value".
372
372
373 py3kwarnings enables Py3k warnings.
373 py3kwarnings enables Py3k warnings.
374
374
375 shell is the shell to execute tests in.
375 shell is the shell to execute tests in.
376 """
376 """
377
377
378 self.path = path
378 self.path = path
379 self.name = os.path.basename(path)
379 self.name = os.path.basename(path)
380 self._testdir = os.path.dirname(path)
380 self._testdir = os.path.dirname(path)
381 self.errpath = os.path.join(self._testdir, '%s.err' % self.name)
381 self.errpath = os.path.join(self._testdir, '%s.err' % self.name)
382
382
383 self._threadtmp = tmpdir
383 self._threadtmp = tmpdir
384 self._keeptmpdir = keeptmpdir
384 self._keeptmpdir = keeptmpdir
385 self._debug = debug
385 self._debug = debug
386 self._timeout = timeout
386 self._timeout = timeout
387 self._startport = startport
387 self._startport = startport
388 self._extraconfigopts = extraconfigopts or []
388 self._extraconfigopts = extraconfigopts or []
389 self._py3kwarnings = py3kwarnings
389 self._py3kwarnings = py3kwarnings
390 self._shell = shell
390 self._shell = shell
391
391
392 self._aborted = False
392 self._aborted = False
393 self._daemonpids = []
393 self._daemonpids = []
394 self._finished = None
394 self._finished = None
395 self._ret = None
395 self._ret = None
396 self._out = None
396 self._out = None
397 self._skipped = None
397 self._skipped = None
398 self._testtmp = None
398 self._testtmp = None
399
399
400 # If we're not in --debug mode and reference output file exists,
400 # If we're not in --debug mode and reference output file exists,
401 # check test output against it.
401 # check test output against it.
402 if debug:
402 if debug:
403 self._refout = None # to match "out is None"
403 self._refout = None # to match "out is None"
404 elif os.path.exists(self.refpath):
404 elif os.path.exists(self.refpath):
405 f = open(self.refpath, 'rb')
405 f = open(self.refpath, 'rb')
406 self._refout = f.read().splitlines(True)
406 self._refout = f.read().splitlines(True)
407 f.close()
407 f.close()
408 else:
408 else:
409 self._refout = []
409 self._refout = []
410
410
411 def __str__(self):
411 def __str__(self):
412 return self.name
412 return self.name
413
413
414 def shortDescription(self):
414 def shortDescription(self):
415 return self.name
415 return self.name
416
416
417 def setUp(self):
417 def setUp(self):
418 """Tasks to perform before run()."""
418 """Tasks to perform before run()."""
419 self._finished = False
419 self._finished = False
420 self._ret = None
420 self._ret = None
421 self._out = None
421 self._out = None
422 self._skipped = None
422 self._skipped = None
423
423
424 try:
424 try:
425 os.mkdir(self._threadtmp)
425 os.mkdir(self._threadtmp)
426 except OSError, e:
426 except OSError, e:
427 if e.errno != errno.EEXIST:
427 if e.errno != errno.EEXIST:
428 raise
428 raise
429
429
430 self._testtmp = os.path.join(self._threadtmp,
430 self._testtmp = os.path.join(self._threadtmp,
431 os.path.basename(self.path))
431 os.path.basename(self.path))
432 os.mkdir(self._testtmp)
432 os.mkdir(self._testtmp)
433
433
434 # Remove any previous output files.
434 # Remove any previous output files.
435 if os.path.exists(self.errpath):
435 if os.path.exists(self.errpath):
436 os.remove(self.errpath)
436 os.remove(self.errpath)
437
437
438 def run(self, result):
438 def run(self, result):
439 """Run this test and report results against a TestResult instance."""
439 """Run this test and report results against a TestResult instance."""
440 # This function is extremely similar to unittest.TestCase.run(). Once
440 # This function is extremely similar to unittest.TestCase.run(). Once
441 # we require Python 2.7 (or at least its version of unittest), this
441 # we require Python 2.7 (or at least its version of unittest), this
442 # function can largely go away.
442 # function can largely go away.
443 self._result = result
443 self._result = result
444 result.startTest(self)
444 result.startTest(self)
445 try:
445 try:
446 try:
446 try:
447 self.setUp()
447 self.setUp()
448 except (KeyboardInterrupt, SystemExit):
448 except (KeyboardInterrupt, SystemExit):
449 self._aborted = True
449 self._aborted = True
450 raise
450 raise
451 except Exception:
451 except Exception:
452 result.addError(self, sys.exc_info())
452 result.addError(self, sys.exc_info())
453 return
453 return
454
454
455 success = False
455 success = False
456 try:
456 try:
457 self.runTest()
457 self.runTest()
458 except KeyboardInterrupt:
458 except KeyboardInterrupt:
459 self._aborted = True
459 self._aborted = True
460 raise
460 raise
461 except SkipTest, e:
461 except SkipTest, e:
462 result.addSkip(self, str(e))
462 result.addSkip(self, str(e))
463 except IgnoreTest, e:
463 except IgnoreTest, e:
464 result.addIgnore(self, str(e))
464 result.addIgnore(self, str(e))
465 except WarnTest, e:
465 except WarnTest, e:
466 result.addWarn(self, str(e))
466 result.addWarn(self, str(e))
467 except self.failureException, e:
467 except self.failureException, e:
468 # This differs from unittest in that we don't capture
468 # This differs from unittest in that we don't capture
469 # the stack trace. This is for historical reasons and
469 # the stack trace. This is for historical reasons and
470 # this decision could be revisted in the future,
470 # this decision could be revisted in the future,
471 # especially for PythonTest instances.
471 # especially for PythonTest instances.
472 if result.addFailure(self, str(e)):
472 if result.addFailure(self, str(e)):
473 success = True
473 success = True
474 except Exception:
474 except Exception:
475 result.addError(self, sys.exc_info())
475 result.addError(self, sys.exc_info())
476 else:
476 else:
477 success = True
477 success = True
478
478
479 try:
479 try:
480 self.tearDown()
480 self.tearDown()
481 except (KeyboardInterrupt, SystemExit):
481 except (KeyboardInterrupt, SystemExit):
482 self._aborted = True
482 self._aborted = True
483 raise
483 raise
484 except Exception:
484 except Exception:
485 result.addError(self, sys.exc_info())
485 result.addError(self, sys.exc_info())
486 success = False
486 success = False
487
487
488 if success:
488 if success:
489 result.addSuccess(self)
489 result.addSuccess(self)
490 finally:
490 finally:
491 result.stopTest(self, interrupted=self._aborted)
491 result.stopTest(self, interrupted=self._aborted)
492
492
493 def runTest(self):
493 def runTest(self):
494 """Run this test instance.
494 """Run this test instance.
495
495
496 This will return a tuple describing the result of the test.
496 This will return a tuple describing the result of the test.
497 """
497 """
498 replacements = self._getreplacements()
498 replacements = self._getreplacements()
499 env = self._getenv()
499 env = self._getenv()
500 self._daemonpids.append(env['DAEMON_PIDS'])
500 self._daemonpids.append(env['DAEMON_PIDS'])
501 self._createhgrc(env['HGRCPATH'])
501 self._createhgrc(env['HGRCPATH'])
502
502
503 vlog('# Test', self.name)
503 vlog('# Test', self.name)
504
504
505 ret, out = self._run(replacements, env)
505 ret, out = self._run(replacements, env)
506 self._finished = True
506 self._finished = True
507 self._ret = ret
507 self._ret = ret
508 self._out = out
508 self._out = out
509
509
510 def describe(ret):
510 def describe(ret):
511 if ret < 0:
511 if ret < 0:
512 return 'killed by signal: %d' % -ret
512 return 'killed by signal: %d' % -ret
513 return 'returned error code %d' % ret
513 return 'returned error code %d' % ret
514
514
515 self._skipped = False
515 self._skipped = False
516
516
517 if ret == self.SKIPPED_STATUS:
517 if ret == self.SKIPPED_STATUS:
518 if out is None: # Debug mode, nothing to parse.
518 if out is None: # Debug mode, nothing to parse.
519 missing = ['unknown']
519 missing = ['unknown']
520 failed = None
520 failed = None
521 else:
521 else:
522 missing, failed = TTest.parsehghaveoutput(out)
522 missing, failed = TTest.parsehghaveoutput(out)
523
523
524 if not missing:
524 if not missing:
525 missing = ['irrelevant']
525 missing = ['irrelevant']
526
526
527 if failed:
527 if failed:
528 self.fail('hg have failed checking for %s' % failed[-1])
528 self.fail('hg have failed checking for %s' % failed[-1])
529 else:
529 else:
530 self._skipped = True
530 self._skipped = True
531 raise SkipTest(missing[-1])
531 raise SkipTest(missing[-1])
532 elif ret == 'timeout':
532 elif ret == 'timeout':
533 self.fail('timed out')
533 self.fail('timed out')
534 elif ret is False:
534 elif ret is False:
535 raise WarnTest('no result code from test')
535 raise WarnTest('no result code from test')
536 elif out != self._refout:
536 elif out != self._refout:
537 # Diff generation may rely on written .err file.
537 # Diff generation may rely on written .err file.
538 if (ret != 0 or out != self._refout) and not self._skipped \
538 if (ret != 0 or out != self._refout) and not self._skipped \
539 and not self._debug:
539 and not self._debug:
540 f = open(self.errpath, 'wb')
540 f = open(self.errpath, 'wb')
541 for line in out:
541 for line in out:
542 f.write(line)
542 f.write(line)
543 f.close()
543 f.close()
544
544
545 # The result object handles diff calculation for us.
545 # The result object handles diff calculation for us.
546 if self._result.addOutputMismatch(self, ret, out, self._refout):
546 if self._result.addOutputMismatch(self, ret, out, self._refout):
547 # change was accepted, skip failing
547 # change was accepted, skip failing
548 return
548 return
549
549
550 if ret:
550 if ret:
551 msg = 'output changed and ' + describe(ret)
551 msg = 'output changed and ' + describe(ret)
552 else:
552 else:
553 msg = 'output changed'
553 msg = 'output changed'
554
554
555 self.fail(msg)
555 self.fail(msg)
556 elif ret:
556 elif ret:
557 self.fail(describe(ret))
557 self.fail(describe(ret))
558
558
559 def tearDown(self):
559 def tearDown(self):
560 """Tasks to perform after run()."""
560 """Tasks to perform after run()."""
561 for entry in self._daemonpids:
561 for entry in self._daemonpids:
562 killdaemons(entry)
562 killdaemons(entry)
563 self._daemonpids = []
563 self._daemonpids = []
564
564
565 if not self._keeptmpdir:
565 if not self._keeptmpdir:
566 shutil.rmtree(self._testtmp, True)
566 shutil.rmtree(self._testtmp, True)
567 shutil.rmtree(self._threadtmp, True)
567 shutil.rmtree(self._threadtmp, True)
568
568
569 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
569 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
570 and not self._debug and self._out:
570 and not self._debug and self._out:
571 f = open(self.errpath, 'wb')
571 f = open(self.errpath, 'wb')
572 for line in self._out:
572 for line in self._out:
573 f.write(line)
573 f.write(line)
574 f.close()
574 f.close()
575
575
576 vlog("# Ret was:", self._ret)
576 vlog("# Ret was:", self._ret)
577
577
578 def _run(self, replacements, env):
578 def _run(self, replacements, env):
579 # This should be implemented in child classes to run tests.
579 # This should be implemented in child classes to run tests.
580 raise SkipTest('unknown test type')
580 raise SkipTest('unknown test type')
581
581
582 def abort(self):
582 def abort(self):
583 """Terminate execution of this test."""
583 """Terminate execution of this test."""
584 self._aborted = True
584 self._aborted = True
585
585
586 def _getreplacements(self):
586 def _getreplacements(self):
587 """Obtain a mapping of text replacements to apply to test output.
587 """Obtain a mapping of text replacements to apply to test output.
588
588
589 Test output needs to be normalized so it can be compared to expected
589 Test output needs to be normalized so it can be compared to expected
590 output. This function defines how some of that normalization will
590 output. This function defines how some of that normalization will
591 occur.
591 occur.
592 """
592 """
593 r = [
593 r = [
594 (r':%s\b' % self._startport, ':$HGPORT'),
594 (r':%s\b' % self._startport, ':$HGPORT'),
595 (r':%s\b' % (self._startport + 1), ':$HGPORT1'),
595 (r':%s\b' % (self._startport + 1), ':$HGPORT1'),
596 (r':%s\b' % (self._startport + 2), ':$HGPORT2'),
596 (r':%s\b' % (self._startport + 2), ':$HGPORT2'),
597 ]
597 ]
598
598
599 if os.name == 'nt':
599 if os.name == 'nt':
600 r.append(
600 r.append(
601 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
601 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
602 c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c
602 c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c
603 for c in self._testtmp), '$TESTTMP'))
603 for c in self._testtmp), '$TESTTMP'))
604 else:
604 else:
605 r.append((re.escape(self._testtmp), '$TESTTMP'))
605 r.append((re.escape(self._testtmp), '$TESTTMP'))
606
606
607 return r
607 return r
608
608
609 def _getenv(self):
609 def _getenv(self):
610 """Obtain environment variables to use during test execution."""
610 """Obtain environment variables to use during test execution."""
611 env = os.environ.copy()
611 env = os.environ.copy()
612 env['TESTTMP'] = self._testtmp
612 env['TESTTMP'] = self._testtmp
613 env['HOME'] = self._testtmp
613 env['HOME'] = self._testtmp
614 env["HGPORT"] = str(self._startport)
614 env["HGPORT"] = str(self._startport)
615 env["HGPORT1"] = str(self._startport + 1)
615 env["HGPORT1"] = str(self._startport + 1)
616 env["HGPORT2"] = str(self._startport + 2)
616 env["HGPORT2"] = str(self._startport + 2)
617 env["HGRCPATH"] = os.path.join(self._threadtmp, '.hgrc')
617 env["HGRCPATH"] = os.path.join(self._threadtmp, '.hgrc')
618 env["DAEMON_PIDS"] = os.path.join(self._threadtmp, 'daemon.pids')
618 env["DAEMON_PIDS"] = os.path.join(self._threadtmp, 'daemon.pids')
619 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
619 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
620 env["HGMERGE"] = "internal:merge"
620 env["HGMERGE"] = "internal:merge"
621 env["HGUSER"] = "test"
621 env["HGUSER"] = "test"
622 env["HGENCODING"] = "ascii"
622 env["HGENCODING"] = "ascii"
623 env["HGENCODINGMODE"] = "strict"
623 env["HGENCODINGMODE"] = "strict"
624
624
625 # Reset some environment variables to well-known values so that
625 # Reset some environment variables to well-known values so that
626 # the tests produce repeatable output.
626 # the tests produce repeatable output.
627 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
627 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
628 env['TZ'] = 'GMT'
628 env['TZ'] = 'GMT'
629 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
629 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
630 env['COLUMNS'] = '80'
630 env['COLUMNS'] = '80'
631 env['TERM'] = 'xterm'
631 env['TERM'] = 'xterm'
632
632
633 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
633 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
634 'NO_PROXY').split():
634 'NO_PROXY').split():
635 if k in env:
635 if k in env:
636 del env[k]
636 del env[k]
637
637
638 # unset env related to hooks
638 # unset env related to hooks
639 for k in env.keys():
639 for k in env.keys():
640 if k.startswith('HG_'):
640 if k.startswith('HG_'):
641 del env[k]
641 del env[k]
642
642
643 return env
643 return env
644
644
645 def _createhgrc(self, path):
645 def _createhgrc(self, path):
646 """Create an hgrc file for this test."""
646 """Create an hgrc file for this test."""
647 hgrc = open(path, 'wb')
647 hgrc = open(path, 'wb')
648 hgrc.write('[ui]\n')
648 hgrc.write('[ui]\n')
649 hgrc.write('slash = True\n')
649 hgrc.write('slash = True\n')
650 hgrc.write('interactive = False\n')
650 hgrc.write('interactive = False\n')
651 hgrc.write('mergemarkers = detailed\n')
651 hgrc.write('[defaults]\n')
652 hgrc.write('[defaults]\n')
652 hgrc.write('backout = -d "0 0"\n')
653 hgrc.write('backout = -d "0 0"\n')
653 hgrc.write('commit = -d "0 0"\n')
654 hgrc.write('commit = -d "0 0"\n')
654 hgrc.write('shelve = --date "0 0"\n')
655 hgrc.write('shelve = --date "0 0"\n')
655 hgrc.write('tag = -d "0 0"\n')
656 hgrc.write('tag = -d "0 0"\n')
656 for opt in self._extraconfigopts:
657 for opt in self._extraconfigopts:
657 section, key = opt.split('.', 1)
658 section, key = opt.split('.', 1)
658 assert '=' in key, ('extra config opt %s must '
659 assert '=' in key, ('extra config opt %s must '
659 'have an = for assignment' % opt)
660 'have an = for assignment' % opt)
660 hgrc.write('[%s]\n%s\n' % (section, key))
661 hgrc.write('[%s]\n%s\n' % (section, key))
661 hgrc.close()
662 hgrc.close()
662
663
663 def fail(self, msg):
664 def fail(self, msg):
664 # unittest differentiates between errored and failed.
665 # unittest differentiates between errored and failed.
665 # Failed is denoted by AssertionError (by default at least).
666 # Failed is denoted by AssertionError (by default at least).
666 raise AssertionError(msg)
667 raise AssertionError(msg)
667
668
668 class PythonTest(Test):
669 class PythonTest(Test):
669 """A Python-based test."""
670 """A Python-based test."""
670
671
671 @property
672 @property
672 def refpath(self):
673 def refpath(self):
673 return os.path.join(self._testdir, '%s.out' % self.name)
674 return os.path.join(self._testdir, '%s.out' % self.name)
674
675
675 def _run(self, replacements, env):
676 def _run(self, replacements, env):
676 py3kswitch = self._py3kwarnings and ' -3' or ''
677 py3kswitch = self._py3kwarnings and ' -3' or ''
677 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, self.path)
678 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, self.path)
678 vlog("# Running", cmd)
679 vlog("# Running", cmd)
679 if os.name == 'nt':
680 if os.name == 'nt':
680 replacements.append((r'\r\n', '\n'))
681 replacements.append((r'\r\n', '\n'))
681 result = run(cmd, self._testtmp, replacements, env,
682 result = run(cmd, self._testtmp, replacements, env,
682 debug=self._debug, timeout=self._timeout)
683 debug=self._debug, timeout=self._timeout)
683 if self._aborted:
684 if self._aborted:
684 raise KeyboardInterrupt()
685 raise KeyboardInterrupt()
685
686
686 return result
687 return result
687
688
688 class TTest(Test):
689 class TTest(Test):
689 """A "t test" is a test backed by a .t file."""
690 """A "t test" is a test backed by a .t file."""
690
691
691 SKIPPED_PREFIX = 'skipped: '
692 SKIPPED_PREFIX = 'skipped: '
692 FAILED_PREFIX = 'hghave check failed: '
693 FAILED_PREFIX = 'hghave check failed: '
693 NEEDESCAPE = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
694 NEEDESCAPE = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
694
695
695 ESCAPESUB = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
696 ESCAPESUB = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
696 ESCAPEMAP = dict((chr(i), r'\x%02x' % i) for i in range(256))
697 ESCAPEMAP = dict((chr(i), r'\x%02x' % i) for i in range(256))
697 ESCAPEMAP.update({'\\': '\\\\', '\r': r'\r'})
698 ESCAPEMAP.update({'\\': '\\\\', '\r': r'\r'})
698
699
699 @property
700 @property
700 def refpath(self):
701 def refpath(self):
701 return os.path.join(self._testdir, self.name)
702 return os.path.join(self._testdir, self.name)
702
703
703 def _run(self, replacements, env):
704 def _run(self, replacements, env):
704 f = open(self.path, 'rb')
705 f = open(self.path, 'rb')
705 lines = f.readlines()
706 lines = f.readlines()
706 f.close()
707 f.close()
707
708
708 salt, script, after, expected = self._parsetest(lines)
709 salt, script, after, expected = self._parsetest(lines)
709
710
710 # Write out the generated script.
711 # Write out the generated script.
711 fname = '%s.sh' % self._testtmp
712 fname = '%s.sh' % self._testtmp
712 f = open(fname, 'wb')
713 f = open(fname, 'wb')
713 for l in script:
714 for l in script:
714 f.write(l)
715 f.write(l)
715 f.close()
716 f.close()
716
717
717 cmd = '%s "%s"' % (self._shell, fname)
718 cmd = '%s "%s"' % (self._shell, fname)
718 vlog("# Running", cmd)
719 vlog("# Running", cmd)
719
720
720 exitcode, output = run(cmd, self._testtmp, replacements, env,
721 exitcode, output = run(cmd, self._testtmp, replacements, env,
721 debug=self._debug, timeout=self._timeout)
722 debug=self._debug, timeout=self._timeout)
722
723
723 if self._aborted:
724 if self._aborted:
724 raise KeyboardInterrupt()
725 raise KeyboardInterrupt()
725
726
726 # Do not merge output if skipped. Return hghave message instead.
727 # Do not merge output if skipped. Return hghave message instead.
727 # Similarly, with --debug, output is None.
728 # Similarly, with --debug, output is None.
728 if exitcode == self.SKIPPED_STATUS or output is None:
729 if exitcode == self.SKIPPED_STATUS or output is None:
729 return exitcode, output
730 return exitcode, output
730
731
731 return self._processoutput(exitcode, output, salt, after, expected)
732 return self._processoutput(exitcode, output, salt, after, expected)
732
733
733 def _hghave(self, reqs):
734 def _hghave(self, reqs):
734 # TODO do something smarter when all other uses of hghave are gone.
735 # TODO do something smarter when all other uses of hghave are gone.
735 tdir = self._testdir.replace('\\', '/')
736 tdir = self._testdir.replace('\\', '/')
736 proc = Popen4('%s -c "%s/hghave %s"' %
737 proc = Popen4('%s -c "%s/hghave %s"' %
737 (self._shell, tdir, ' '.join(reqs)),
738 (self._shell, tdir, ' '.join(reqs)),
738 self._testtmp, 0)
739 self._testtmp, 0)
739 stdout, stderr = proc.communicate()
740 stdout, stderr = proc.communicate()
740 ret = proc.wait()
741 ret = proc.wait()
741 if wifexited(ret):
742 if wifexited(ret):
742 ret = os.WEXITSTATUS(ret)
743 ret = os.WEXITSTATUS(ret)
743 if ret == 2:
744 if ret == 2:
744 print stdout
745 print stdout
745 sys.exit(1)
746 sys.exit(1)
746
747
747 return ret == 0
748 return ret == 0
748
749
749 def _parsetest(self, lines):
750 def _parsetest(self, lines):
750 # We generate a shell script which outputs unique markers to line
751 # We generate a shell script which outputs unique markers to line
751 # up script results with our source. These markers include input
752 # up script results with our source. These markers include input
752 # line number and the last return code.
753 # line number and the last return code.
753 salt = "SALT" + str(time.time())
754 salt = "SALT" + str(time.time())
754 def addsalt(line, inpython):
755 def addsalt(line, inpython):
755 if inpython:
756 if inpython:
756 script.append('%s %d 0\n' % (salt, line))
757 script.append('%s %d 0\n' % (salt, line))
757 else:
758 else:
758 script.append('echo %s %s $?\n' % (salt, line))
759 script.append('echo %s %s $?\n' % (salt, line))
759
760
760 script = []
761 script = []
761
762
762 # After we run the shell script, we re-unify the script output
763 # After we run the shell script, we re-unify the script output
763 # with non-active parts of the source, with synchronization by our
764 # with non-active parts of the source, with synchronization by our
764 # SALT line number markers. The after table contains the non-active
765 # SALT line number markers. The after table contains the non-active
765 # components, ordered by line number.
766 # components, ordered by line number.
766 after = {}
767 after = {}
767
768
768 # Expected shell script output.
769 # Expected shell script output.
769 expected = {}
770 expected = {}
770
771
771 pos = prepos = -1
772 pos = prepos = -1
772
773
773 # True or False when in a true or false conditional section
774 # True or False when in a true or false conditional section
774 skipping = None
775 skipping = None
775
776
776 # We keep track of whether or not we're in a Python block so we
777 # We keep track of whether or not we're in a Python block so we
777 # can generate the surrounding doctest magic.
778 # can generate the surrounding doctest magic.
778 inpython = False
779 inpython = False
779
780
780 if self._debug:
781 if self._debug:
781 script.append('set -x\n')
782 script.append('set -x\n')
782 if os.getenv('MSYSTEM'):
783 if os.getenv('MSYSTEM'):
783 script.append('alias pwd="pwd -W"\n')
784 script.append('alias pwd="pwd -W"\n')
784
785
785 for n, l in enumerate(lines):
786 for n, l in enumerate(lines):
786 if not l.endswith('\n'):
787 if not l.endswith('\n'):
787 l += '\n'
788 l += '\n'
788 if l.startswith('#if'):
789 if l.startswith('#if'):
789 lsplit = l.split()
790 lsplit = l.split()
790 if len(lsplit) < 2 or lsplit[0] != '#if':
791 if len(lsplit) < 2 or lsplit[0] != '#if':
791 after.setdefault(pos, []).append(' !!! invalid #if\n')
792 after.setdefault(pos, []).append(' !!! invalid #if\n')
792 if skipping is not None:
793 if skipping is not None:
793 after.setdefault(pos, []).append(' !!! nested #if\n')
794 after.setdefault(pos, []).append(' !!! nested #if\n')
794 skipping = not self._hghave(lsplit[1:])
795 skipping = not self._hghave(lsplit[1:])
795 after.setdefault(pos, []).append(l)
796 after.setdefault(pos, []).append(l)
796 elif l.startswith('#else'):
797 elif l.startswith('#else'):
797 if skipping is None:
798 if skipping is None:
798 after.setdefault(pos, []).append(' !!! missing #if\n')
799 after.setdefault(pos, []).append(' !!! missing #if\n')
799 skipping = not skipping
800 skipping = not skipping
800 after.setdefault(pos, []).append(l)
801 after.setdefault(pos, []).append(l)
801 elif l.startswith('#endif'):
802 elif l.startswith('#endif'):
802 if skipping is None:
803 if skipping is None:
803 after.setdefault(pos, []).append(' !!! missing #if\n')
804 after.setdefault(pos, []).append(' !!! missing #if\n')
804 skipping = None
805 skipping = None
805 after.setdefault(pos, []).append(l)
806 after.setdefault(pos, []).append(l)
806 elif skipping:
807 elif skipping:
807 after.setdefault(pos, []).append(l)
808 after.setdefault(pos, []).append(l)
808 elif l.startswith(' >>> '): # python inlines
809 elif l.startswith(' >>> '): # python inlines
809 after.setdefault(pos, []).append(l)
810 after.setdefault(pos, []).append(l)
810 prepos = pos
811 prepos = pos
811 pos = n
812 pos = n
812 if not inpython:
813 if not inpython:
813 # We've just entered a Python block. Add the header.
814 # We've just entered a Python block. Add the header.
814 inpython = True
815 inpython = True
815 addsalt(prepos, False) # Make sure we report the exit code.
816 addsalt(prepos, False) # Make sure we report the exit code.
816 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
817 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
817 addsalt(n, True)
818 addsalt(n, True)
818 script.append(l[2:])
819 script.append(l[2:])
819 elif l.startswith(' ... '): # python inlines
820 elif l.startswith(' ... '): # python inlines
820 after.setdefault(prepos, []).append(l)
821 after.setdefault(prepos, []).append(l)
821 script.append(l[2:])
822 script.append(l[2:])
822 elif l.startswith(' $ '): # commands
823 elif l.startswith(' $ '): # commands
823 if inpython:
824 if inpython:
824 script.append('EOF\n')
825 script.append('EOF\n')
825 inpython = False
826 inpython = False
826 after.setdefault(pos, []).append(l)
827 after.setdefault(pos, []).append(l)
827 prepos = pos
828 prepos = pos
828 pos = n
829 pos = n
829 addsalt(n, False)
830 addsalt(n, False)
830 cmd = l[4:].split()
831 cmd = l[4:].split()
831 if len(cmd) == 2 and cmd[0] == 'cd':
832 if len(cmd) == 2 and cmd[0] == 'cd':
832 l = ' $ cd %s || exit 1\n' % cmd[1]
833 l = ' $ cd %s || exit 1\n' % cmd[1]
833 script.append(l[4:])
834 script.append(l[4:])
834 elif l.startswith(' > '): # continuations
835 elif l.startswith(' > '): # continuations
835 after.setdefault(prepos, []).append(l)
836 after.setdefault(prepos, []).append(l)
836 script.append(l[4:])
837 script.append(l[4:])
837 elif l.startswith(' '): # results
838 elif l.startswith(' '): # results
838 # Queue up a list of expected results.
839 # Queue up a list of expected results.
839 expected.setdefault(pos, []).append(l[2:])
840 expected.setdefault(pos, []).append(l[2:])
840 else:
841 else:
841 if inpython:
842 if inpython:
842 script.append('EOF\n')
843 script.append('EOF\n')
843 inpython = False
844 inpython = False
844 # Non-command/result. Queue up for merged output.
845 # Non-command/result. Queue up for merged output.
845 after.setdefault(pos, []).append(l)
846 after.setdefault(pos, []).append(l)
846
847
847 if inpython:
848 if inpython:
848 script.append('EOF\n')
849 script.append('EOF\n')
849 if skipping is not None:
850 if skipping is not None:
850 after.setdefault(pos, []).append(' !!! missing #endif\n')
851 after.setdefault(pos, []).append(' !!! missing #endif\n')
851 addsalt(n + 1, False)
852 addsalt(n + 1, False)
852
853
853 return salt, script, after, expected
854 return salt, script, after, expected
854
855
855 def _processoutput(self, exitcode, output, salt, after, expected):
856 def _processoutput(self, exitcode, output, salt, after, expected):
856 # Merge the script output back into a unified test.
857 # Merge the script output back into a unified test.
857 warnonly = 1 # 1: not yet; 2: yes; 3: for sure not
858 warnonly = 1 # 1: not yet; 2: yes; 3: for sure not
858 if exitcode != 0:
859 if exitcode != 0:
859 warnonly = 3
860 warnonly = 3
860
861
861 pos = -1
862 pos = -1
862 postout = []
863 postout = []
863 for l in output:
864 for l in output:
864 lout, lcmd = l, None
865 lout, lcmd = l, None
865 if salt in l:
866 if salt in l:
866 lout, lcmd = l.split(salt, 1)
867 lout, lcmd = l.split(salt, 1)
867
868
868 if lout:
869 if lout:
869 if not lout.endswith('\n'):
870 if not lout.endswith('\n'):
870 lout += ' (no-eol)\n'
871 lout += ' (no-eol)\n'
871
872
872 # Find the expected output at the current position.
873 # Find the expected output at the current position.
873 el = None
874 el = None
874 if expected.get(pos, None):
875 if expected.get(pos, None):
875 el = expected[pos].pop(0)
876 el = expected[pos].pop(0)
876
877
877 r = TTest.linematch(el, lout)
878 r = TTest.linematch(el, lout)
878 if isinstance(r, str):
879 if isinstance(r, str):
879 if r == '+glob':
880 if r == '+glob':
880 lout = el[:-1] + ' (glob)\n'
881 lout = el[:-1] + ' (glob)\n'
881 r = '' # Warn only this line.
882 r = '' # Warn only this line.
882 elif r == '-glob':
883 elif r == '-glob':
883 lout = ''.join(el.rsplit(' (glob)', 1))
884 lout = ''.join(el.rsplit(' (glob)', 1))
884 r = '' # Warn only this line.
885 r = '' # Warn only this line.
885 else:
886 else:
886 log('\ninfo, unknown linematch result: %r\n' % r)
887 log('\ninfo, unknown linematch result: %r\n' % r)
887 r = False
888 r = False
888 if r:
889 if r:
889 postout.append(' ' + el)
890 postout.append(' ' + el)
890 else:
891 else:
891 if self.NEEDESCAPE(lout):
892 if self.NEEDESCAPE(lout):
892 lout = TTest._stringescape('%s (esc)\n' %
893 lout = TTest._stringescape('%s (esc)\n' %
893 lout.rstrip('\n'))
894 lout.rstrip('\n'))
894 postout.append(' ' + lout) # Let diff deal with it.
895 postout.append(' ' + lout) # Let diff deal with it.
895 if r != '': # If line failed.
896 if r != '': # If line failed.
896 warnonly = 3 # for sure not
897 warnonly = 3 # for sure not
897 elif warnonly == 1: # Is "not yet" and line is warn only.
898 elif warnonly == 1: # Is "not yet" and line is warn only.
898 warnonly = 2 # Yes do warn.
899 warnonly = 2 # Yes do warn.
899
900
900 if lcmd:
901 if lcmd:
901 # Add on last return code.
902 # Add on last return code.
902 ret = int(lcmd.split()[1])
903 ret = int(lcmd.split()[1])
903 if ret != 0:
904 if ret != 0:
904 postout.append(' [%s]\n' % ret)
905 postout.append(' [%s]\n' % ret)
905 if pos in after:
906 if pos in after:
906 # Merge in non-active test bits.
907 # Merge in non-active test bits.
907 postout += after.pop(pos)
908 postout += after.pop(pos)
908 pos = int(lcmd.split()[0])
909 pos = int(lcmd.split()[0])
909
910
910 if pos in after:
911 if pos in after:
911 postout += after.pop(pos)
912 postout += after.pop(pos)
912
913
913 if warnonly == 2:
914 if warnonly == 2:
914 exitcode = False # Set exitcode to warned.
915 exitcode = False # Set exitcode to warned.
915
916
916 return exitcode, postout
917 return exitcode, postout
917
918
918 @staticmethod
919 @staticmethod
919 def rematch(el, l):
920 def rematch(el, l):
920 try:
921 try:
921 # use \Z to ensure that the regex matches to the end of the string
922 # use \Z to ensure that the regex matches to the end of the string
922 if os.name == 'nt':
923 if os.name == 'nt':
923 return re.match(el + r'\r?\n\Z', l)
924 return re.match(el + r'\r?\n\Z', l)
924 return re.match(el + r'\n\Z', l)
925 return re.match(el + r'\n\Z', l)
925 except re.error:
926 except re.error:
926 # el is an invalid regex
927 # el is an invalid regex
927 return False
928 return False
928
929
929 @staticmethod
930 @staticmethod
930 def globmatch(el, l):
931 def globmatch(el, l):
931 # The only supported special characters are * and ? plus / which also
932 # The only supported special characters are * and ? plus / which also
932 # matches \ on windows. Escaping of these characters is supported.
933 # matches \ on windows. Escaping of these characters is supported.
933 if el + '\n' == l:
934 if el + '\n' == l:
934 if os.altsep:
935 if os.altsep:
935 # matching on "/" is not needed for this line
936 # matching on "/" is not needed for this line
936 return '-glob'
937 return '-glob'
937 return True
938 return True
938 i, n = 0, len(el)
939 i, n = 0, len(el)
939 res = ''
940 res = ''
940 while i < n:
941 while i < n:
941 c = el[i]
942 c = el[i]
942 i += 1
943 i += 1
943 if c == '\\' and el[i] in '*?\\/':
944 if c == '\\' and el[i] in '*?\\/':
944 res += el[i - 1:i + 1]
945 res += el[i - 1:i + 1]
945 i += 1
946 i += 1
946 elif c == '*':
947 elif c == '*':
947 res += '.*'
948 res += '.*'
948 elif c == '?':
949 elif c == '?':
949 res += '.'
950 res += '.'
950 elif c == '/' and os.altsep:
951 elif c == '/' and os.altsep:
951 res += '[/\\\\]'
952 res += '[/\\\\]'
952 else:
953 else:
953 res += re.escape(c)
954 res += re.escape(c)
954 return TTest.rematch(res, l)
955 return TTest.rematch(res, l)
955
956
956 @staticmethod
957 @staticmethod
957 def linematch(el, l):
958 def linematch(el, l):
958 if el == l: # perfect match (fast)
959 if el == l: # perfect match (fast)
959 return True
960 return True
960 if el:
961 if el:
961 if el.endswith(" (esc)\n"):
962 if el.endswith(" (esc)\n"):
962 el = el[:-7].decode('string-escape') + '\n'
963 el = el[:-7].decode('string-escape') + '\n'
963 if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
964 if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
964 return True
965 return True
965 if el.endswith(" (re)\n"):
966 if el.endswith(" (re)\n"):
966 return TTest.rematch(el[:-6], l)
967 return TTest.rematch(el[:-6], l)
967 if el.endswith(" (glob)\n"):
968 if el.endswith(" (glob)\n"):
968 return TTest.globmatch(el[:-8], l)
969 return TTest.globmatch(el[:-8], l)
969 if os.altsep and l.replace('\\', '/') == el:
970 if os.altsep and l.replace('\\', '/') == el:
970 return '+glob'
971 return '+glob'
971 return False
972 return False
972
973
973 @staticmethod
974 @staticmethod
974 def parsehghaveoutput(lines):
975 def parsehghaveoutput(lines):
975 '''Parse hghave log lines.
976 '''Parse hghave log lines.
976
977
977 Return tuple of lists (missing, failed):
978 Return tuple of lists (missing, failed):
978 * the missing/unknown features
979 * the missing/unknown features
979 * the features for which existence check failed'''
980 * the features for which existence check failed'''
980 missing = []
981 missing = []
981 failed = []
982 failed = []
982 for line in lines:
983 for line in lines:
983 if line.startswith(TTest.SKIPPED_PREFIX):
984 if line.startswith(TTest.SKIPPED_PREFIX):
984 line = line.splitlines()[0]
985 line = line.splitlines()[0]
985 missing.append(line[len(TTest.SKIPPED_PREFIX):])
986 missing.append(line[len(TTest.SKIPPED_PREFIX):])
986 elif line.startswith(TTest.FAILED_PREFIX):
987 elif line.startswith(TTest.FAILED_PREFIX):
987 line = line.splitlines()[0]
988 line = line.splitlines()[0]
988 failed.append(line[len(TTest.FAILED_PREFIX):])
989 failed.append(line[len(TTest.FAILED_PREFIX):])
989
990
990 return missing, failed
991 return missing, failed
991
992
992 @staticmethod
993 @staticmethod
993 def _escapef(m):
994 def _escapef(m):
994 return TTest.ESCAPEMAP[m.group(0)]
995 return TTest.ESCAPEMAP[m.group(0)]
995
996
996 @staticmethod
997 @staticmethod
997 def _stringescape(s):
998 def _stringescape(s):
998 return TTest.ESCAPESUB(TTest._escapef, s)
999 return TTest.ESCAPESUB(TTest._escapef, s)
999
1000
1000
1001
1001 wifexited = getattr(os, "WIFEXITED", lambda x: False)
1002 wifexited = getattr(os, "WIFEXITED", lambda x: False)
1002 def run(cmd, wd, replacements, env, debug=False, timeout=None):
1003 def run(cmd, wd, replacements, env, debug=False, timeout=None):
1003 """Run command in a sub-process, capturing the output (stdout and stderr).
1004 """Run command in a sub-process, capturing the output (stdout and stderr).
1004 Return a tuple (exitcode, output). output is None in debug mode."""
1005 Return a tuple (exitcode, output). output is None in debug mode."""
1005 if debug:
1006 if debug:
1006 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
1007 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
1007 ret = proc.wait()
1008 ret = proc.wait()
1008 return (ret, None)
1009 return (ret, None)
1009
1010
1010 proc = Popen4(cmd, wd, timeout, env)
1011 proc = Popen4(cmd, wd, timeout, env)
1011 def cleanup():
1012 def cleanup():
1012 terminate(proc)
1013 terminate(proc)
1013 ret = proc.wait()
1014 ret = proc.wait()
1014 if ret == 0:
1015 if ret == 0:
1015 ret = signal.SIGTERM << 8
1016 ret = signal.SIGTERM << 8
1016 killdaemons(env['DAEMON_PIDS'])
1017 killdaemons(env['DAEMON_PIDS'])
1017 return ret
1018 return ret
1018
1019
1019 output = ''
1020 output = ''
1020 proc.tochild.close()
1021 proc.tochild.close()
1021
1022
1022 try:
1023 try:
1023 output = proc.fromchild.read()
1024 output = proc.fromchild.read()
1024 except KeyboardInterrupt:
1025 except KeyboardInterrupt:
1025 vlog('# Handling keyboard interrupt')
1026 vlog('# Handling keyboard interrupt')
1026 cleanup()
1027 cleanup()
1027 raise
1028 raise
1028
1029
1029 ret = proc.wait()
1030 ret = proc.wait()
1030 if wifexited(ret):
1031 if wifexited(ret):
1031 ret = os.WEXITSTATUS(ret)
1032 ret = os.WEXITSTATUS(ret)
1032
1033
1033 if proc.timeout:
1034 if proc.timeout:
1034 ret = 'timeout'
1035 ret = 'timeout'
1035
1036
1036 if ret:
1037 if ret:
1037 killdaemons(env['DAEMON_PIDS'])
1038 killdaemons(env['DAEMON_PIDS'])
1038
1039
1039 for s, r in replacements:
1040 for s, r in replacements:
1040 output = re.sub(s, r, output)
1041 output = re.sub(s, r, output)
1041 return ret, output.splitlines(True)
1042 return ret, output.splitlines(True)
1042
1043
1043 iolock = threading.Lock()
1044 iolock = threading.Lock()
1044
1045
1045 class SkipTest(Exception):
1046 class SkipTest(Exception):
1046 """Raised to indicate that a test is to be skipped."""
1047 """Raised to indicate that a test is to be skipped."""
1047
1048
1048 class IgnoreTest(Exception):
1049 class IgnoreTest(Exception):
1049 """Raised to indicate that a test is to be ignored."""
1050 """Raised to indicate that a test is to be ignored."""
1050
1051
1051 class WarnTest(Exception):
1052 class WarnTest(Exception):
1052 """Raised to indicate that a test warned."""
1053 """Raised to indicate that a test warned."""
1053
1054
1054 class TestResult(unittest._TextTestResult):
1055 class TestResult(unittest._TextTestResult):
1055 """Holds results when executing via unittest."""
1056 """Holds results when executing via unittest."""
1056 # Don't worry too much about accessing the non-public _TextTestResult.
1057 # Don't worry too much about accessing the non-public _TextTestResult.
1057 # It is relatively common in Python testing tools.
1058 # It is relatively common in Python testing tools.
1058 def __init__(self, options, *args, **kwargs):
1059 def __init__(self, options, *args, **kwargs):
1059 super(TestResult, self).__init__(*args, **kwargs)
1060 super(TestResult, self).__init__(*args, **kwargs)
1060
1061
1061 self._options = options
1062 self._options = options
1062
1063
1063 # unittest.TestResult didn't have skipped until 2.7. We need to
1064 # unittest.TestResult didn't have skipped until 2.7. We need to
1064 # polyfill it.
1065 # polyfill it.
1065 self.skipped = []
1066 self.skipped = []
1066
1067
1067 # We have a custom "ignored" result that isn't present in any Python
1068 # We have a custom "ignored" result that isn't present in any Python
1068 # unittest implementation. It is very similar to skipped. It may make
1069 # unittest implementation. It is very similar to skipped. It may make
1069 # sense to map it into skip some day.
1070 # sense to map it into skip some day.
1070 self.ignored = []
1071 self.ignored = []
1071
1072
1072 # We have a custom "warned" result that isn't present in any Python
1073 # We have a custom "warned" result that isn't present in any Python
1073 # unittest implementation. It is very similar to failed. It may make
1074 # unittest implementation. It is very similar to failed. It may make
1074 # sense to map it into fail some day.
1075 # sense to map it into fail some day.
1075 self.warned = []
1076 self.warned = []
1076
1077
1077 self.times = []
1078 self.times = []
1078 self._started = {}
1079 self._started = {}
1079
1080
1080 def addFailure(self, test, reason):
1081 def addFailure(self, test, reason):
1081 self.failures.append((test, reason))
1082 self.failures.append((test, reason))
1082
1083
1083 if self._options.first:
1084 if self._options.first:
1084 self.stop()
1085 self.stop()
1085 else:
1086 else:
1086 if not self._options.nodiff:
1087 if not self._options.nodiff:
1087 self.stream.write('\nERROR: %s output changed\n' % test)
1088 self.stream.write('\nERROR: %s output changed\n' % test)
1088
1089
1089 self.stream.write('!')
1090 self.stream.write('!')
1090
1091
1091 def addError(self, *args, **kwargs):
1092 def addError(self, *args, **kwargs):
1092 super(TestResult, self).addError(*args, **kwargs)
1093 super(TestResult, self).addError(*args, **kwargs)
1093
1094
1094 if self._options.first:
1095 if self._options.first:
1095 self.stop()
1096 self.stop()
1096
1097
1097 # Polyfill.
1098 # Polyfill.
1098 def addSkip(self, test, reason):
1099 def addSkip(self, test, reason):
1099 self.skipped.append((test, reason))
1100 self.skipped.append((test, reason))
1100
1101
1101 if self.showAll:
1102 if self.showAll:
1102 self.stream.writeln('skipped %s' % reason)
1103 self.stream.writeln('skipped %s' % reason)
1103 else:
1104 else:
1104 self.stream.write('s')
1105 self.stream.write('s')
1105 self.stream.flush()
1106 self.stream.flush()
1106
1107
1107 def addIgnore(self, test, reason):
1108 def addIgnore(self, test, reason):
1108 self.ignored.append((test, reason))
1109 self.ignored.append((test, reason))
1109
1110
1110 if self.showAll:
1111 if self.showAll:
1111 self.stream.writeln('ignored %s' % reason)
1112 self.stream.writeln('ignored %s' % reason)
1112 else:
1113 else:
1113 if reason != 'not retesting':
1114 if reason != 'not retesting':
1114 self.stream.write('i')
1115 self.stream.write('i')
1115 self.stream.flush()
1116 self.stream.flush()
1116
1117
1117 def addWarn(self, test, reason):
1118 def addWarn(self, test, reason):
1118 self.warned.append((test, reason))
1119 self.warned.append((test, reason))
1119
1120
1120 if self._options.first:
1121 if self._options.first:
1121 self.stop()
1122 self.stop()
1122
1123
1123 if self.showAll:
1124 if self.showAll:
1124 self.stream.writeln('warned %s' % reason)
1125 self.stream.writeln('warned %s' % reason)
1125 else:
1126 else:
1126 self.stream.write('~')
1127 self.stream.write('~')
1127 self.stream.flush()
1128 self.stream.flush()
1128
1129
1129 def addOutputMismatch(self, test, ret, got, expected):
1130 def addOutputMismatch(self, test, ret, got, expected):
1130 """Record a mismatch in test output for a particular test."""
1131 """Record a mismatch in test output for a particular test."""
1131
1132
1132 accepted = False
1133 accepted = False
1133
1134
1134 iolock.acquire()
1135 iolock.acquire()
1135 if self._options.nodiff:
1136 if self._options.nodiff:
1136 pass
1137 pass
1137 elif self._options.view:
1138 elif self._options.view:
1138 os.system("%s %s %s" % (self._view, test.refpath, test.errpath))
1139 os.system("%s %s %s" % (self._view, test.refpath, test.errpath))
1139 else:
1140 else:
1140 failed, lines = getdiff(expected, got,
1141 failed, lines = getdiff(expected, got,
1141 test.refpath, test.errpath)
1142 test.refpath, test.errpath)
1142 if failed:
1143 if failed:
1143 self.addFailure(test, 'diff generation failed')
1144 self.addFailure(test, 'diff generation failed')
1144 else:
1145 else:
1145 self.stream.write('\n')
1146 self.stream.write('\n')
1146 for line in lines:
1147 for line in lines:
1147 self.stream.write(line)
1148 self.stream.write(line)
1148 self.stream.flush()
1149 self.stream.flush()
1149
1150
1150 # handle interactive prompt without releasing iolock
1151 # handle interactive prompt without releasing iolock
1151 if self._options.interactive:
1152 if self._options.interactive:
1152 self.stream.write('Accept this change? [n] ')
1153 self.stream.write('Accept this change? [n] ')
1153 answer = sys.stdin.readline().strip()
1154 answer = sys.stdin.readline().strip()
1154 if answer.lower() in ('y', 'yes'):
1155 if answer.lower() in ('y', 'yes'):
1155 if test.name.endswith('.t'):
1156 if test.name.endswith('.t'):
1156 rename(test.errpath, test.path)
1157 rename(test.errpath, test.path)
1157 else:
1158 else:
1158 rename(test.errpath, '%s.out' % test.path)
1159 rename(test.errpath, '%s.out' % test.path)
1159 accepted = True
1160 accepted = True
1160
1161
1161 iolock.release()
1162 iolock.release()
1162
1163
1163 return accepted
1164 return accepted
1164
1165
1165 def startTest(self, test):
1166 def startTest(self, test):
1166 super(TestResult, self).startTest(test)
1167 super(TestResult, self).startTest(test)
1167
1168
1168 self._started[test.name] = time.time()
1169 self._started[test.name] = time.time()
1169
1170
1170 def stopTest(self, test, interrupted=False):
1171 def stopTest(self, test, interrupted=False):
1171 super(TestResult, self).stopTest(test)
1172 super(TestResult, self).stopTest(test)
1172
1173
1173 self.times.append((test.name, time.time() - self._started[test.name]))
1174 self.times.append((test.name, time.time() - self._started[test.name]))
1174 del self._started[test.name]
1175 del self._started[test.name]
1175
1176
1176 if interrupted:
1177 if interrupted:
1177 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
1178 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
1178 test.name, self.times[-1][1]))
1179 test.name, self.times[-1][1]))
1179
1180
1180 class TestSuite(unittest.TestSuite):
1181 class TestSuite(unittest.TestSuite):
1181 """Custom unitest TestSuite that knows how to execute Mercurial tests."""
1182 """Custom unitest TestSuite that knows how to execute Mercurial tests."""
1182
1183
1183 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
1184 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
1184 retest=False, keywords=None, loop=False,
1185 retest=False, keywords=None, loop=False,
1185 *args, **kwargs):
1186 *args, **kwargs):
1186 """Create a new instance that can run tests with a configuration.
1187 """Create a new instance that can run tests with a configuration.
1187
1188
1188 testdir specifies the directory where tests are executed from. This
1189 testdir specifies the directory where tests are executed from. This
1189 is typically the ``tests`` directory from Mercurial's source
1190 is typically the ``tests`` directory from Mercurial's source
1190 repository.
1191 repository.
1191
1192
1192 jobs specifies the number of jobs to run concurrently. Each test
1193 jobs specifies the number of jobs to run concurrently. Each test
1193 executes on its own thread. Tests actually spawn new processes, so
1194 executes on its own thread. Tests actually spawn new processes, so
1194 state mutation should not be an issue.
1195 state mutation should not be an issue.
1195
1196
1196 whitelist and blacklist denote tests that have been whitelisted and
1197 whitelist and blacklist denote tests that have been whitelisted and
1197 blacklisted, respectively. These arguments don't belong in TestSuite.
1198 blacklisted, respectively. These arguments don't belong in TestSuite.
1198 Instead, whitelist and blacklist should be handled by the thing that
1199 Instead, whitelist and blacklist should be handled by the thing that
1199 populates the TestSuite with tests. They are present to preserve
1200 populates the TestSuite with tests. They are present to preserve
1200 backwards compatible behavior which reports skipped tests as part
1201 backwards compatible behavior which reports skipped tests as part
1201 of the results.
1202 of the results.
1202
1203
1203 retest denotes whether to retest failed tests. This arguably belongs
1204 retest denotes whether to retest failed tests. This arguably belongs
1204 outside of TestSuite.
1205 outside of TestSuite.
1205
1206
1206 keywords denotes key words that will be used to filter which tests
1207 keywords denotes key words that will be used to filter which tests
1207 to execute. This arguably belongs outside of TestSuite.
1208 to execute. This arguably belongs outside of TestSuite.
1208
1209
1209 loop denotes whether to loop over tests forever.
1210 loop denotes whether to loop over tests forever.
1210 """
1211 """
1211 super(TestSuite, self).__init__(*args, **kwargs)
1212 super(TestSuite, self).__init__(*args, **kwargs)
1212
1213
1213 self._jobs = jobs
1214 self._jobs = jobs
1214 self._whitelist = whitelist
1215 self._whitelist = whitelist
1215 self._blacklist = blacklist
1216 self._blacklist = blacklist
1216 self._retest = retest
1217 self._retest = retest
1217 self._keywords = keywords
1218 self._keywords = keywords
1218 self._loop = loop
1219 self._loop = loop
1219
1220
1220 def run(self, result):
1221 def run(self, result):
1221 # We have a number of filters that need to be applied. We do this
1222 # We have a number of filters that need to be applied. We do this
1222 # here instead of inside Test because it makes the running logic for
1223 # here instead of inside Test because it makes the running logic for
1223 # Test simpler.
1224 # Test simpler.
1224 tests = []
1225 tests = []
1225 for test in self._tests:
1226 for test in self._tests:
1226 if not os.path.exists(test.path):
1227 if not os.path.exists(test.path):
1227 result.addSkip(test, "Doesn't exist")
1228 result.addSkip(test, "Doesn't exist")
1228 continue
1229 continue
1229
1230
1230 if not (self._whitelist and test.name in self._whitelist):
1231 if not (self._whitelist and test.name in self._whitelist):
1231 if self._blacklist and test.name in self._blacklist:
1232 if self._blacklist and test.name in self._blacklist:
1232 result.addSkip(test, 'blacklisted')
1233 result.addSkip(test, 'blacklisted')
1233 continue
1234 continue
1234
1235
1235 if self._retest and not os.path.exists(test.errpath):
1236 if self._retest and not os.path.exists(test.errpath):
1236 result.addIgnore(test, 'not retesting')
1237 result.addIgnore(test, 'not retesting')
1237 continue
1238 continue
1238
1239
1239 if self._keywords:
1240 if self._keywords:
1240 f = open(test.path, 'rb')
1241 f = open(test.path, 'rb')
1241 t = f.read().lower() + test.name.lower()
1242 t = f.read().lower() + test.name.lower()
1242 f.close()
1243 f.close()
1243 ignored = False
1244 ignored = False
1244 for k in self._keywords.lower().split():
1245 for k in self._keywords.lower().split():
1245 if k not in t:
1246 if k not in t:
1246 result.addIgnore(test, "doesn't match keyword")
1247 result.addIgnore(test, "doesn't match keyword")
1247 ignored = True
1248 ignored = True
1248 break
1249 break
1249
1250
1250 if ignored:
1251 if ignored:
1251 continue
1252 continue
1252
1253
1253 tests.append(test)
1254 tests.append(test)
1254
1255
1255 runtests = list(tests)
1256 runtests = list(tests)
1256 done = queue.Queue()
1257 done = queue.Queue()
1257 running = 0
1258 running = 0
1258
1259
1259 def job(test, result):
1260 def job(test, result):
1260 try:
1261 try:
1261 test(result)
1262 test(result)
1262 done.put(None)
1263 done.put(None)
1263 except KeyboardInterrupt:
1264 except KeyboardInterrupt:
1264 pass
1265 pass
1265 except: # re-raises
1266 except: # re-raises
1266 done.put(('!', test, 'run-test raised an error, see traceback'))
1267 done.put(('!', test, 'run-test raised an error, see traceback'))
1267 raise
1268 raise
1268
1269
1269 try:
1270 try:
1270 while tests or running:
1271 while tests or running:
1271 if not done.empty() or running == self._jobs or not tests:
1272 if not done.empty() or running == self._jobs or not tests:
1272 try:
1273 try:
1273 done.get(True, 1)
1274 done.get(True, 1)
1274 if result and result.shouldStop:
1275 if result and result.shouldStop:
1275 break
1276 break
1276 except queue.Empty:
1277 except queue.Empty:
1277 continue
1278 continue
1278 running -= 1
1279 running -= 1
1279 if tests and not running == self._jobs:
1280 if tests and not running == self._jobs:
1280 test = tests.pop(0)
1281 test = tests.pop(0)
1281 if self._loop:
1282 if self._loop:
1282 tests.append(test)
1283 tests.append(test)
1283 t = threading.Thread(target=job, name=test.name,
1284 t = threading.Thread(target=job, name=test.name,
1284 args=(test, result))
1285 args=(test, result))
1285 t.start()
1286 t.start()
1286 running += 1
1287 running += 1
1287 except KeyboardInterrupt:
1288 except KeyboardInterrupt:
1288 for test in runtests:
1289 for test in runtests:
1289 test.abort()
1290 test.abort()
1290
1291
1291 return result
1292 return result
1292
1293
1293 class TextTestRunner(unittest.TextTestRunner):
1294 class TextTestRunner(unittest.TextTestRunner):
1294 """Custom unittest test runner that uses appropriate settings."""
1295 """Custom unittest test runner that uses appropriate settings."""
1295
1296
1296 def __init__(self, runner, *args, **kwargs):
1297 def __init__(self, runner, *args, **kwargs):
1297 super(TextTestRunner, self).__init__(*args, **kwargs)
1298 super(TextTestRunner, self).__init__(*args, **kwargs)
1298
1299
1299 self._runner = runner
1300 self._runner = runner
1300
1301
1301 def run(self, test):
1302 def run(self, test):
1302 result = TestResult(self._runner.options, self.stream,
1303 result = TestResult(self._runner.options, self.stream,
1303 self.descriptions, self.verbosity)
1304 self.descriptions, self.verbosity)
1304
1305
1305 test(result)
1306 test(result)
1306
1307
1307 failed = len(result.failures)
1308 failed = len(result.failures)
1308 warned = len(result.warned)
1309 warned = len(result.warned)
1309 skipped = len(result.skipped)
1310 skipped = len(result.skipped)
1310 ignored = len(result.ignored)
1311 ignored = len(result.ignored)
1311
1312
1312 self.stream.writeln('')
1313 self.stream.writeln('')
1313
1314
1314 if not self._runner.options.noskips:
1315 if not self._runner.options.noskips:
1315 for test, msg in result.skipped:
1316 for test, msg in result.skipped:
1316 self.stream.writeln('Skipped %s: %s' % (test.name, msg))
1317 self.stream.writeln('Skipped %s: %s' % (test.name, msg))
1317 for test, msg in result.warned:
1318 for test, msg in result.warned:
1318 self.stream.writeln('Warned %s: %s' % (test.name, msg))
1319 self.stream.writeln('Warned %s: %s' % (test.name, msg))
1319 for test, msg in result.failures:
1320 for test, msg in result.failures:
1320 self.stream.writeln('Failed %s: %s' % (test.name, msg))
1321 self.stream.writeln('Failed %s: %s' % (test.name, msg))
1321 for test, msg in result.errors:
1322 for test, msg in result.errors:
1322 self.stream.writeln('Errored %s: %s' % (test.name, msg))
1323 self.stream.writeln('Errored %s: %s' % (test.name, msg))
1323
1324
1324 self._runner._checkhglib('Tested')
1325 self._runner._checkhglib('Tested')
1325
1326
1326 # When '--retest' is enabled, only failure tests run. At this point
1327 # When '--retest' is enabled, only failure tests run. At this point
1327 # "result.testsRun" holds the count of failure test that has run. But
1328 # "result.testsRun" holds the count of failure test that has run. But
1328 # as while printing output, we have subtracted the skipped and ignored
1329 # as while printing output, we have subtracted the skipped and ignored
1329 # count from "result.testsRun". Therefore, to make the count remain
1330 # count from "result.testsRun". Therefore, to make the count remain
1330 # the same, we need to add skipped and ignored count in here.
1331 # the same, we need to add skipped and ignored count in here.
1331 if self._runner.options.retest:
1332 if self._runner.options.retest:
1332 result.testsRun = result.testsRun + skipped + ignored
1333 result.testsRun = result.testsRun + skipped + ignored
1333
1334
1334 # This differs from unittest's default output in that we don't count
1335 # This differs from unittest's default output in that we don't count
1335 # skipped and ignored tests as part of the total test count.
1336 # skipped and ignored tests as part of the total test count.
1336 self.stream.writeln('# Ran %d tests, %d skipped, %d warned, %d failed.'
1337 self.stream.writeln('# Ran %d tests, %d skipped, %d warned, %d failed.'
1337 % (result.testsRun - skipped - ignored,
1338 % (result.testsRun - skipped - ignored,
1338 skipped + ignored, warned, failed))
1339 skipped + ignored, warned, failed))
1339 if failed:
1340 if failed:
1340 self.stream.writeln('python hash seed: %s' %
1341 self.stream.writeln('python hash seed: %s' %
1341 os.environ['PYTHONHASHSEED'])
1342 os.environ['PYTHONHASHSEED'])
1342 if self._runner.options.time:
1343 if self._runner.options.time:
1343 self.printtimes(result.times)
1344 self.printtimes(result.times)
1344
1345
1345 return result
1346 return result
1346
1347
1347 def printtimes(self, times):
1348 def printtimes(self, times):
1348 self.stream.writeln('# Producing time report')
1349 self.stream.writeln('# Producing time report')
1349 times.sort(key=lambda t: (t[1], t[0]), reverse=True)
1350 times.sort(key=lambda t: (t[1], t[0]), reverse=True)
1350 cols = '%7.3f %s'
1351 cols = '%7.3f %s'
1351 self.stream.writeln('%-7s %s' % ('Time', 'Test'))
1352 self.stream.writeln('%-7s %s' % ('Time', 'Test'))
1352 for test, timetaken in times:
1353 for test, timetaken in times:
1353 self.stream.writeln(cols % (timetaken, test))
1354 self.stream.writeln(cols % (timetaken, test))
1354
1355
1355 class TestRunner(object):
1356 class TestRunner(object):
1356 """Holds context for executing tests.
1357 """Holds context for executing tests.
1357
1358
1358 Tests rely on a lot of state. This object holds it for them.
1359 Tests rely on a lot of state. This object holds it for them.
1359 """
1360 """
1360
1361
1361 # Programs required to run tests.
1362 # Programs required to run tests.
1362 REQUIREDTOOLS = [
1363 REQUIREDTOOLS = [
1363 os.path.basename(sys.executable),
1364 os.path.basename(sys.executable),
1364 'diff',
1365 'diff',
1365 'grep',
1366 'grep',
1366 'unzip',
1367 'unzip',
1367 'gunzip',
1368 'gunzip',
1368 'bunzip2',
1369 'bunzip2',
1369 'sed',
1370 'sed',
1370 ]
1371 ]
1371
1372
1372 # Maps file extensions to test class.
1373 # Maps file extensions to test class.
1373 TESTTYPES = [
1374 TESTTYPES = [
1374 ('.py', PythonTest),
1375 ('.py', PythonTest),
1375 ('.t', TTest),
1376 ('.t', TTest),
1376 ]
1377 ]
1377
1378
1378 def __init__(self):
1379 def __init__(self):
1379 self.options = None
1380 self.options = None
1380 self._testdir = None
1381 self._testdir = None
1381 self._hgtmp = None
1382 self._hgtmp = None
1382 self._installdir = None
1383 self._installdir = None
1383 self._bindir = None
1384 self._bindir = None
1384 self._tmpbinddir = None
1385 self._tmpbinddir = None
1385 self._pythondir = None
1386 self._pythondir = None
1386 self._coveragefile = None
1387 self._coveragefile = None
1387 self._createdfiles = []
1388 self._createdfiles = []
1388 self._hgpath = None
1389 self._hgpath = None
1389
1390
1390 def run(self, args, parser=None):
1391 def run(self, args, parser=None):
1391 """Run the test suite."""
1392 """Run the test suite."""
1392 oldmask = os.umask(022)
1393 oldmask = os.umask(022)
1393 try:
1394 try:
1394 parser = parser or getparser()
1395 parser = parser or getparser()
1395 options, args = parseargs(args, parser)
1396 options, args = parseargs(args, parser)
1396 self.options = options
1397 self.options = options
1397
1398
1398 self._checktools()
1399 self._checktools()
1399 tests = self.findtests(args)
1400 tests = self.findtests(args)
1400 return self._run(tests)
1401 return self._run(tests)
1401 finally:
1402 finally:
1402 os.umask(oldmask)
1403 os.umask(oldmask)
1403
1404
1404 def _run(self, tests):
1405 def _run(self, tests):
1405 if self.options.random:
1406 if self.options.random:
1406 random.shuffle(tests)
1407 random.shuffle(tests)
1407 else:
1408 else:
1408 # keywords for slow tests
1409 # keywords for slow tests
1409 slow = 'svn gendoc check-code-hg'.split()
1410 slow = 'svn gendoc check-code-hg'.split()
1410 def sortkey(f):
1411 def sortkey(f):
1411 # run largest tests first, as they tend to take the longest
1412 # run largest tests first, as they tend to take the longest
1412 try:
1413 try:
1413 val = -os.stat(f).st_size
1414 val = -os.stat(f).st_size
1414 except OSError, e:
1415 except OSError, e:
1415 if e.errno != errno.ENOENT:
1416 if e.errno != errno.ENOENT:
1416 raise
1417 raise
1417 return -1e9 # file does not exist, tell early
1418 return -1e9 # file does not exist, tell early
1418 for kw in slow:
1419 for kw in slow:
1419 if kw in f:
1420 if kw in f:
1420 val *= 10
1421 val *= 10
1421 return val
1422 return val
1422 tests.sort(key=sortkey)
1423 tests.sort(key=sortkey)
1423
1424
1424 self._testdir = os.environ['TESTDIR'] = os.getcwd()
1425 self._testdir = os.environ['TESTDIR'] = os.getcwd()
1425
1426
1426 if 'PYTHONHASHSEED' not in os.environ:
1427 if 'PYTHONHASHSEED' not in os.environ:
1427 # use a random python hash seed all the time
1428 # use a random python hash seed all the time
1428 # we do the randomness ourself to know what seed is used
1429 # we do the randomness ourself to know what seed is used
1429 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
1430 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
1430
1431
1431 if self.options.tmpdir:
1432 if self.options.tmpdir:
1432 self.options.keep_tmpdir = True
1433 self.options.keep_tmpdir = True
1433 tmpdir = self.options.tmpdir
1434 tmpdir = self.options.tmpdir
1434 if os.path.exists(tmpdir):
1435 if os.path.exists(tmpdir):
1435 # Meaning of tmpdir has changed since 1.3: we used to create
1436 # Meaning of tmpdir has changed since 1.3: we used to create
1436 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
1437 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
1437 # tmpdir already exists.
1438 # tmpdir already exists.
1438 print "error: temp dir %r already exists" % tmpdir
1439 print "error: temp dir %r already exists" % tmpdir
1439 return 1
1440 return 1
1440
1441
1441 # Automatically removing tmpdir sounds convenient, but could
1442 # Automatically removing tmpdir sounds convenient, but could
1442 # really annoy anyone in the habit of using "--tmpdir=/tmp"
1443 # really annoy anyone in the habit of using "--tmpdir=/tmp"
1443 # or "--tmpdir=$HOME".
1444 # or "--tmpdir=$HOME".
1444 #vlog("# Removing temp dir", tmpdir)
1445 #vlog("# Removing temp dir", tmpdir)
1445 #shutil.rmtree(tmpdir)
1446 #shutil.rmtree(tmpdir)
1446 os.makedirs(tmpdir)
1447 os.makedirs(tmpdir)
1447 else:
1448 else:
1448 d = None
1449 d = None
1449 if os.name == 'nt':
1450 if os.name == 'nt':
1450 # without this, we get the default temp dir location, but
1451 # without this, we get the default temp dir location, but
1451 # in all lowercase, which causes troubles with paths (issue3490)
1452 # in all lowercase, which causes troubles with paths (issue3490)
1452 d = os.getenv('TMP')
1453 d = os.getenv('TMP')
1453 tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
1454 tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
1454 self._hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
1455 self._hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
1455
1456
1456 if self.options.with_hg:
1457 if self.options.with_hg:
1457 self._installdir = None
1458 self._installdir = None
1458 self._bindir = os.path.dirname(os.path.realpath(
1459 self._bindir = os.path.dirname(os.path.realpath(
1459 self.options.with_hg))
1460 self.options.with_hg))
1460 self._tmpbindir = os.path.join(self._hgtmp, 'install', 'bin')
1461 self._tmpbindir = os.path.join(self._hgtmp, 'install', 'bin')
1461 os.makedirs(self._tmpbindir)
1462 os.makedirs(self._tmpbindir)
1462
1463
1463 # This looks redundant with how Python initializes sys.path from
1464 # This looks redundant with how Python initializes sys.path from
1464 # the location of the script being executed. Needed because the
1465 # the location of the script being executed. Needed because the
1465 # "hg" specified by --with-hg is not the only Python script
1466 # "hg" specified by --with-hg is not the only Python script
1466 # executed in the test suite that needs to import 'mercurial'
1467 # executed in the test suite that needs to import 'mercurial'
1467 # ... which means it's not really redundant at all.
1468 # ... which means it's not really redundant at all.
1468 self._pythondir = self._bindir
1469 self._pythondir = self._bindir
1469 else:
1470 else:
1470 self._installdir = os.path.join(self._hgtmp, "install")
1471 self._installdir = os.path.join(self._hgtmp, "install")
1471 self._bindir = os.environ["BINDIR"] = \
1472 self._bindir = os.environ["BINDIR"] = \
1472 os.path.join(self._installdir, "bin")
1473 os.path.join(self._installdir, "bin")
1473 self._tmpbindir = self._bindir
1474 self._tmpbindir = self._bindir
1474 self._pythondir = os.path.join(self._installdir, "lib", "python")
1475 self._pythondir = os.path.join(self._installdir, "lib", "python")
1475
1476
1476 os.environ["BINDIR"] = self._bindir
1477 os.environ["BINDIR"] = self._bindir
1477 os.environ["PYTHON"] = PYTHON
1478 os.environ["PYTHON"] = PYTHON
1478
1479
1479 path = [self._bindir] + os.environ["PATH"].split(os.pathsep)
1480 path = [self._bindir] + os.environ["PATH"].split(os.pathsep)
1480 if self._tmpbindir != self._bindir:
1481 if self._tmpbindir != self._bindir:
1481 path = [self._tmpbindir] + path
1482 path = [self._tmpbindir] + path
1482 os.environ["PATH"] = os.pathsep.join(path)
1483 os.environ["PATH"] = os.pathsep.join(path)
1483
1484
1484 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
1485 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
1485 # can run .../tests/run-tests.py test-foo where test-foo
1486 # can run .../tests/run-tests.py test-foo where test-foo
1486 # adds an extension to HGRC. Also include run-test.py directory to
1487 # adds an extension to HGRC. Also include run-test.py directory to
1487 # import modules like heredoctest.
1488 # import modules like heredoctest.
1488 pypath = [self._pythondir, self._testdir,
1489 pypath = [self._pythondir, self._testdir,
1489 os.path.abspath(os.path.dirname(__file__))]
1490 os.path.abspath(os.path.dirname(__file__))]
1490 # We have to augment PYTHONPATH, rather than simply replacing
1491 # We have to augment PYTHONPATH, rather than simply replacing
1491 # it, in case external libraries are only available via current
1492 # it, in case external libraries are only available via current
1492 # PYTHONPATH. (In particular, the Subversion bindings on OS X
1493 # PYTHONPATH. (In particular, the Subversion bindings on OS X
1493 # are in /opt/subversion.)
1494 # are in /opt/subversion.)
1494 oldpypath = os.environ.get(IMPL_PATH)
1495 oldpypath = os.environ.get(IMPL_PATH)
1495 if oldpypath:
1496 if oldpypath:
1496 pypath.append(oldpypath)
1497 pypath.append(oldpypath)
1497 os.environ[IMPL_PATH] = os.pathsep.join(pypath)
1498 os.environ[IMPL_PATH] = os.pathsep.join(pypath)
1498
1499
1499 self._coveragefile = os.path.join(self._testdir, '.coverage')
1500 self._coveragefile = os.path.join(self._testdir, '.coverage')
1500
1501
1501 vlog("# Using TESTDIR", self._testdir)
1502 vlog("# Using TESTDIR", self._testdir)
1502 vlog("# Using HGTMP", self._hgtmp)
1503 vlog("# Using HGTMP", self._hgtmp)
1503 vlog("# Using PATH", os.environ["PATH"])
1504 vlog("# Using PATH", os.environ["PATH"])
1504 vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
1505 vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
1505
1506
1506 try:
1507 try:
1507 return self._runtests(tests) or 0
1508 return self._runtests(tests) or 0
1508 finally:
1509 finally:
1509 time.sleep(.1)
1510 time.sleep(.1)
1510 self._cleanup()
1511 self._cleanup()
1511
1512
1512 def findtests(self, args):
1513 def findtests(self, args):
1513 """Finds possible test files from arguments.
1514 """Finds possible test files from arguments.
1514
1515
1515 If you wish to inject custom tests into the test harness, this would
1516 If you wish to inject custom tests into the test harness, this would
1516 be a good function to monkeypatch or override in a derived class.
1517 be a good function to monkeypatch or override in a derived class.
1517 """
1518 """
1518 if not args:
1519 if not args:
1519 if self.options.changed:
1520 if self.options.changed:
1520 proc = Popen4('hg st --rev "%s" -man0 .' %
1521 proc = Popen4('hg st --rev "%s" -man0 .' %
1521 self.options.changed, None, 0)
1522 self.options.changed, None, 0)
1522 stdout, stderr = proc.communicate()
1523 stdout, stderr = proc.communicate()
1523 args = stdout.strip('\0').split('\0')
1524 args = stdout.strip('\0').split('\0')
1524 else:
1525 else:
1525 args = os.listdir('.')
1526 args = os.listdir('.')
1526
1527
1527 return [t for t in args
1528 return [t for t in args
1528 if os.path.basename(t).startswith('test-')
1529 if os.path.basename(t).startswith('test-')
1529 and (t.endswith('.py') or t.endswith('.t'))]
1530 and (t.endswith('.py') or t.endswith('.t'))]
1530
1531
1531 def _runtests(self, tests):
1532 def _runtests(self, tests):
1532 try:
1533 try:
1533 if self._installdir:
1534 if self._installdir:
1534 self._installhg()
1535 self._installhg()
1535 self._checkhglib("Testing")
1536 self._checkhglib("Testing")
1536 else:
1537 else:
1537 self._usecorrectpython()
1538 self._usecorrectpython()
1538
1539
1539 if self.options.restart:
1540 if self.options.restart:
1540 orig = list(tests)
1541 orig = list(tests)
1541 while tests:
1542 while tests:
1542 if os.path.exists(tests[0] + ".err"):
1543 if os.path.exists(tests[0] + ".err"):
1543 break
1544 break
1544 tests.pop(0)
1545 tests.pop(0)
1545 if not tests:
1546 if not tests:
1546 print "running all tests"
1547 print "running all tests"
1547 tests = orig
1548 tests = orig
1548
1549
1549 tests = [self._gettest(t, i) for i, t in enumerate(tests)]
1550 tests = [self._gettest(t, i) for i, t in enumerate(tests)]
1550
1551
1551 failed = False
1552 failed = False
1552 warned = False
1553 warned = False
1553
1554
1554 suite = TestSuite(self._testdir,
1555 suite = TestSuite(self._testdir,
1555 jobs=self.options.jobs,
1556 jobs=self.options.jobs,
1556 whitelist=self.options.whitelisted,
1557 whitelist=self.options.whitelisted,
1557 blacklist=self.options.blacklist,
1558 blacklist=self.options.blacklist,
1558 retest=self.options.retest,
1559 retest=self.options.retest,
1559 keywords=self.options.keywords,
1560 keywords=self.options.keywords,
1560 loop=self.options.loop,
1561 loop=self.options.loop,
1561 tests=tests)
1562 tests=tests)
1562 verbosity = 1
1563 verbosity = 1
1563 if self.options.verbose:
1564 if self.options.verbose:
1564 verbosity = 2
1565 verbosity = 2
1565 runner = TextTestRunner(self, verbosity=verbosity)
1566 runner = TextTestRunner(self, verbosity=verbosity)
1566 result = runner.run(suite)
1567 result = runner.run(suite)
1567
1568
1568 if result.failures:
1569 if result.failures:
1569 failed = True
1570 failed = True
1570 if result.warned:
1571 if result.warned:
1571 warned = True
1572 warned = True
1572
1573
1573 if self.options.anycoverage:
1574 if self.options.anycoverage:
1574 self._outputcoverage()
1575 self._outputcoverage()
1575 except KeyboardInterrupt:
1576 except KeyboardInterrupt:
1576 failed = True
1577 failed = True
1577 print "\ninterrupted!"
1578 print "\ninterrupted!"
1578
1579
1579 if failed:
1580 if failed:
1580 return 1
1581 return 1
1581 if warned:
1582 if warned:
1582 return 80
1583 return 80
1583
1584
1584 def _gettest(self, test, count):
1585 def _gettest(self, test, count):
1585 """Obtain a Test by looking at its filename.
1586 """Obtain a Test by looking at its filename.
1586
1587
1587 Returns a Test instance. The Test may not be runnable if it doesn't
1588 Returns a Test instance. The Test may not be runnable if it doesn't
1588 map to a known type.
1589 map to a known type.
1589 """
1590 """
1590 lctest = test.lower()
1591 lctest = test.lower()
1591 testcls = Test
1592 testcls = Test
1592
1593
1593 for ext, cls in self.TESTTYPES:
1594 for ext, cls in self.TESTTYPES:
1594 if lctest.endswith(ext):
1595 if lctest.endswith(ext):
1595 testcls = cls
1596 testcls = cls
1596 break
1597 break
1597
1598
1598 refpath = os.path.join(self._testdir, test)
1599 refpath = os.path.join(self._testdir, test)
1599 tmpdir = os.path.join(self._hgtmp, 'child%d' % count)
1600 tmpdir = os.path.join(self._hgtmp, 'child%d' % count)
1600
1601
1601 return testcls(refpath, tmpdir,
1602 return testcls(refpath, tmpdir,
1602 keeptmpdir=self.options.keep_tmpdir,
1603 keeptmpdir=self.options.keep_tmpdir,
1603 debug=self.options.debug,
1604 debug=self.options.debug,
1604 timeout=self.options.timeout,
1605 timeout=self.options.timeout,
1605 startport=self.options.port + count * 3,
1606 startport=self.options.port + count * 3,
1606 extraconfigopts=self.options.extra_config_opt,
1607 extraconfigopts=self.options.extra_config_opt,
1607 py3kwarnings=self.options.py3k_warnings,
1608 py3kwarnings=self.options.py3k_warnings,
1608 shell=self.options.shell)
1609 shell=self.options.shell)
1609
1610
1610 def _cleanup(self):
1611 def _cleanup(self):
1611 """Clean up state from this test invocation."""
1612 """Clean up state from this test invocation."""
1612
1613
1613 if self.options.keep_tmpdir:
1614 if self.options.keep_tmpdir:
1614 return
1615 return
1615
1616
1616 vlog("# Cleaning up HGTMP", self._hgtmp)
1617 vlog("# Cleaning up HGTMP", self._hgtmp)
1617 shutil.rmtree(self._hgtmp, True)
1618 shutil.rmtree(self._hgtmp, True)
1618 for f in self._createdfiles:
1619 for f in self._createdfiles:
1619 try:
1620 try:
1620 os.remove(f)
1621 os.remove(f)
1621 except OSError:
1622 except OSError:
1622 pass
1623 pass
1623
1624
1624 def _usecorrectpython(self):
1625 def _usecorrectpython(self):
1625 """Configure the environment to use the appropriate Python in tests."""
1626 """Configure the environment to use the appropriate Python in tests."""
1626 # Tests must use the same interpreter as us or bad things will happen.
1627 # Tests must use the same interpreter as us or bad things will happen.
1627 pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
1628 pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
1628 if getattr(os, 'symlink', None):
1629 if getattr(os, 'symlink', None):
1629 vlog("# Making python executable in test path a symlink to '%s'" %
1630 vlog("# Making python executable in test path a symlink to '%s'" %
1630 sys.executable)
1631 sys.executable)
1631 mypython = os.path.join(self._tmpbindir, pyexename)
1632 mypython = os.path.join(self._tmpbindir, pyexename)
1632 try:
1633 try:
1633 if os.readlink(mypython) == sys.executable:
1634 if os.readlink(mypython) == sys.executable:
1634 return
1635 return
1635 os.unlink(mypython)
1636 os.unlink(mypython)
1636 except OSError, err:
1637 except OSError, err:
1637 if err.errno != errno.ENOENT:
1638 if err.errno != errno.ENOENT:
1638 raise
1639 raise
1639 if self._findprogram(pyexename) != sys.executable:
1640 if self._findprogram(pyexename) != sys.executable:
1640 try:
1641 try:
1641 os.symlink(sys.executable, mypython)
1642 os.symlink(sys.executable, mypython)
1642 self._createdfiles.append(mypython)
1643 self._createdfiles.append(mypython)
1643 except OSError, err:
1644 except OSError, err:
1644 # child processes may race, which is harmless
1645 # child processes may race, which is harmless
1645 if err.errno != errno.EEXIST:
1646 if err.errno != errno.EEXIST:
1646 raise
1647 raise
1647 else:
1648 else:
1648 exedir, exename = os.path.split(sys.executable)
1649 exedir, exename = os.path.split(sys.executable)
1649 vlog("# Modifying search path to find %s as %s in '%s'" %
1650 vlog("# Modifying search path to find %s as %s in '%s'" %
1650 (exename, pyexename, exedir))
1651 (exename, pyexename, exedir))
1651 path = os.environ['PATH'].split(os.pathsep)
1652 path = os.environ['PATH'].split(os.pathsep)
1652 while exedir in path:
1653 while exedir in path:
1653 path.remove(exedir)
1654 path.remove(exedir)
1654 os.environ['PATH'] = os.pathsep.join([exedir] + path)
1655 os.environ['PATH'] = os.pathsep.join([exedir] + path)
1655 if not self._findprogram(pyexename):
1656 if not self._findprogram(pyexename):
1656 print "WARNING: Cannot find %s in search path" % pyexename
1657 print "WARNING: Cannot find %s in search path" % pyexename
1657
1658
1658 def _installhg(self):
1659 def _installhg(self):
1659 """Install hg into the test environment.
1660 """Install hg into the test environment.
1660
1661
1661 This will also configure hg with the appropriate testing settings.
1662 This will also configure hg with the appropriate testing settings.
1662 """
1663 """
1663 vlog("# Performing temporary installation of HG")
1664 vlog("# Performing temporary installation of HG")
1664 installerrs = os.path.join("tests", "install.err")
1665 installerrs = os.path.join("tests", "install.err")
1665 compiler = ''
1666 compiler = ''
1666 if self.options.compiler:
1667 if self.options.compiler:
1667 compiler = '--compiler ' + self.options.compiler
1668 compiler = '--compiler ' + self.options.compiler
1668 pure = self.options.pure and "--pure" or ""
1669 pure = self.options.pure and "--pure" or ""
1669 py3 = ''
1670 py3 = ''
1670 if sys.version_info[0] == 3:
1671 if sys.version_info[0] == 3:
1671 py3 = '--c2to3'
1672 py3 = '--c2to3'
1672
1673
1673 # Run installer in hg root
1674 # Run installer in hg root
1674 script = os.path.realpath(sys.argv[0])
1675 script = os.path.realpath(sys.argv[0])
1675 hgroot = os.path.dirname(os.path.dirname(script))
1676 hgroot = os.path.dirname(os.path.dirname(script))
1676 os.chdir(hgroot)
1677 os.chdir(hgroot)
1677 nohome = '--home=""'
1678 nohome = '--home=""'
1678 if os.name == 'nt':
1679 if os.name == 'nt':
1679 # The --home="" trick works only on OS where os.sep == '/'
1680 # The --home="" trick works only on OS where os.sep == '/'
1680 # because of a distutils convert_path() fast-path. Avoid it at
1681 # because of a distutils convert_path() fast-path. Avoid it at
1681 # least on Windows for now, deal with .pydistutils.cfg bugs
1682 # least on Windows for now, deal with .pydistutils.cfg bugs
1682 # when they happen.
1683 # when they happen.
1683 nohome = ''
1684 nohome = ''
1684 cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
1685 cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
1685 ' build %(compiler)s --build-base="%(base)s"'
1686 ' build %(compiler)s --build-base="%(base)s"'
1686 ' install --force --prefix="%(prefix)s"'
1687 ' install --force --prefix="%(prefix)s"'
1687 ' --install-lib="%(libdir)s"'
1688 ' --install-lib="%(libdir)s"'
1688 ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
1689 ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
1689 % {'exe': sys.executable, 'py3': py3, 'pure': pure,
1690 % {'exe': sys.executable, 'py3': py3, 'pure': pure,
1690 'compiler': compiler,
1691 'compiler': compiler,
1691 'base': os.path.join(self._hgtmp, "build"),
1692 'base': os.path.join(self._hgtmp, "build"),
1692 'prefix': self._installdir, 'libdir': self._pythondir,
1693 'prefix': self._installdir, 'libdir': self._pythondir,
1693 'bindir': self._bindir,
1694 'bindir': self._bindir,
1694 'nohome': nohome, 'logfile': installerrs})
1695 'nohome': nohome, 'logfile': installerrs})
1695 vlog("# Running", cmd)
1696 vlog("# Running", cmd)
1696 if os.system(cmd) == 0:
1697 if os.system(cmd) == 0:
1697 if not self.options.verbose:
1698 if not self.options.verbose:
1698 os.remove(installerrs)
1699 os.remove(installerrs)
1699 else:
1700 else:
1700 f = open(installerrs, 'rb')
1701 f = open(installerrs, 'rb')
1701 for line in f:
1702 for line in f:
1702 print line,
1703 print line,
1703 f.close()
1704 f.close()
1704 sys.exit(1)
1705 sys.exit(1)
1705 os.chdir(self._testdir)
1706 os.chdir(self._testdir)
1706
1707
1707 self._usecorrectpython()
1708 self._usecorrectpython()
1708
1709
1709 if self.options.py3k_warnings and not self.options.anycoverage:
1710 if self.options.py3k_warnings and not self.options.anycoverage:
1710 vlog("# Updating hg command to enable Py3k Warnings switch")
1711 vlog("# Updating hg command to enable Py3k Warnings switch")
1711 f = open(os.path.join(self._bindir, 'hg'), 'rb')
1712 f = open(os.path.join(self._bindir, 'hg'), 'rb')
1712 lines = [line.rstrip() for line in f]
1713 lines = [line.rstrip() for line in f]
1713 lines[0] += ' -3'
1714 lines[0] += ' -3'
1714 f.close()
1715 f.close()
1715 f = open(os.path.join(self._bindir, 'hg'), 'wb')
1716 f = open(os.path.join(self._bindir, 'hg'), 'wb')
1716 for line in lines:
1717 for line in lines:
1717 f.write(line + '\n')
1718 f.write(line + '\n')
1718 f.close()
1719 f.close()
1719
1720
1720 hgbat = os.path.join(self._bindir, 'hg.bat')
1721 hgbat = os.path.join(self._bindir, 'hg.bat')
1721 if os.path.isfile(hgbat):
1722 if os.path.isfile(hgbat):
1722 # hg.bat expects to be put in bin/scripts while run-tests.py
1723 # hg.bat expects to be put in bin/scripts while run-tests.py
1723 # installation layout put it in bin/ directly. Fix it
1724 # installation layout put it in bin/ directly. Fix it
1724 f = open(hgbat, 'rb')
1725 f = open(hgbat, 'rb')
1725 data = f.read()
1726 data = f.read()
1726 f.close()
1727 f.close()
1727 if '"%~dp0..\python" "%~dp0hg" %*' in data:
1728 if '"%~dp0..\python" "%~dp0hg" %*' in data:
1728 data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
1729 data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
1729 '"%~dp0python" "%~dp0hg" %*')
1730 '"%~dp0python" "%~dp0hg" %*')
1730 f = open(hgbat, 'wb')
1731 f = open(hgbat, 'wb')
1731 f.write(data)
1732 f.write(data)
1732 f.close()
1733 f.close()
1733 else:
1734 else:
1734 print 'WARNING: cannot fix hg.bat reference to python.exe'
1735 print 'WARNING: cannot fix hg.bat reference to python.exe'
1735
1736
1736 if self.options.anycoverage:
1737 if self.options.anycoverage:
1737 custom = os.path.join(self._testdir, 'sitecustomize.py')
1738 custom = os.path.join(self._testdir, 'sitecustomize.py')
1738 target = os.path.join(self._pythondir, 'sitecustomize.py')
1739 target = os.path.join(self._pythondir, 'sitecustomize.py')
1739 vlog('# Installing coverage trigger to %s' % target)
1740 vlog('# Installing coverage trigger to %s' % target)
1740 shutil.copyfile(custom, target)
1741 shutil.copyfile(custom, target)
1741 rc = os.path.join(self._testdir, '.coveragerc')
1742 rc = os.path.join(self._testdir, '.coveragerc')
1742 vlog('# Installing coverage rc to %s' % rc)
1743 vlog('# Installing coverage rc to %s' % rc)
1743 os.environ['COVERAGE_PROCESS_START'] = rc
1744 os.environ['COVERAGE_PROCESS_START'] = rc
1744 fn = os.path.join(self._installdir, '..', '.coverage')
1745 fn = os.path.join(self._installdir, '..', '.coverage')
1745 os.environ['COVERAGE_FILE'] = fn
1746 os.environ['COVERAGE_FILE'] = fn
1746
1747
1747 def _checkhglib(self, verb):
1748 def _checkhglib(self, verb):
1748 """Ensure that the 'mercurial' package imported by python is
1749 """Ensure that the 'mercurial' package imported by python is
1749 the one we expect it to be. If not, print a warning to stderr."""
1750 the one we expect it to be. If not, print a warning to stderr."""
1750 if ((self._bindir == self._pythondir) and
1751 if ((self._bindir == self._pythondir) and
1751 (self._bindir != self._tmpbindir)):
1752 (self._bindir != self._tmpbindir)):
1752 # The pythondir has been infered from --with-hg flag.
1753 # The pythondir has been infered from --with-hg flag.
1753 # We cannot expect anything sensible here
1754 # We cannot expect anything sensible here
1754 return
1755 return
1755 expecthg = os.path.join(self._pythondir, 'mercurial')
1756 expecthg = os.path.join(self._pythondir, 'mercurial')
1756 actualhg = self._gethgpath()
1757 actualhg = self._gethgpath()
1757 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
1758 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
1758 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
1759 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
1759 ' (expected %s)\n'
1760 ' (expected %s)\n'
1760 % (verb, actualhg, expecthg))
1761 % (verb, actualhg, expecthg))
1761 def _gethgpath(self):
1762 def _gethgpath(self):
1762 """Return the path to the mercurial package that is actually found by
1763 """Return the path to the mercurial package that is actually found by
1763 the current Python interpreter."""
1764 the current Python interpreter."""
1764 if self._hgpath is not None:
1765 if self._hgpath is not None:
1765 return self._hgpath
1766 return self._hgpath
1766
1767
1767 cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
1768 cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
1768 pipe = os.popen(cmd % PYTHON)
1769 pipe = os.popen(cmd % PYTHON)
1769 try:
1770 try:
1770 self._hgpath = pipe.read().strip()
1771 self._hgpath = pipe.read().strip()
1771 finally:
1772 finally:
1772 pipe.close()
1773 pipe.close()
1773
1774
1774 return self._hgpath
1775 return self._hgpath
1775
1776
1776 def _outputcoverage(self):
1777 def _outputcoverage(self):
1777 """Produce code coverage output."""
1778 """Produce code coverage output."""
1778 vlog('# Producing coverage report')
1779 vlog('# Producing coverage report')
1779 os.chdir(self._pythondir)
1780 os.chdir(self._pythondir)
1780
1781
1781 def covrun(*args):
1782 def covrun(*args):
1782 cmd = 'coverage %s' % ' '.join(args)
1783 cmd = 'coverage %s' % ' '.join(args)
1783 vlog('# Running: %s' % cmd)
1784 vlog('# Running: %s' % cmd)
1784 os.system(cmd)
1785 os.system(cmd)
1785
1786
1786 covrun('-c')
1787 covrun('-c')
1787 omit = ','.join(os.path.join(x, '*') for x in
1788 omit = ','.join(os.path.join(x, '*') for x in
1788 [self._bindir, self._testdir])
1789 [self._bindir, self._testdir])
1789 covrun('-i', '-r', '"--omit=%s"' % omit) # report
1790 covrun('-i', '-r', '"--omit=%s"' % omit) # report
1790 if self.options.htmlcov:
1791 if self.options.htmlcov:
1791 htmldir = os.path.join(self._testdir, 'htmlcov')
1792 htmldir = os.path.join(self._testdir, 'htmlcov')
1792 covrun('-i', '-b', '"--directory=%s"' % htmldir,
1793 covrun('-i', '-b', '"--directory=%s"' % htmldir,
1793 '"--omit=%s"' % omit)
1794 '"--omit=%s"' % omit)
1794 if self.options.annotate:
1795 if self.options.annotate:
1795 adir = os.path.join(self._testdir, 'annotated')
1796 adir = os.path.join(self._testdir, 'annotated')
1796 if not os.path.isdir(adir):
1797 if not os.path.isdir(adir):
1797 os.mkdir(adir)
1798 os.mkdir(adir)
1798 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
1799 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
1799
1800
1800 def _findprogram(self, program):
1801 def _findprogram(self, program):
1801 """Search PATH for a executable program"""
1802 """Search PATH for a executable program"""
1802 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
1803 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
1803 name = os.path.join(p, program)
1804 name = os.path.join(p, program)
1804 if os.name == 'nt' or os.access(name, os.X_OK):
1805 if os.name == 'nt' or os.access(name, os.X_OK):
1805 return name
1806 return name
1806 return None
1807 return None
1807
1808
1808 def _checktools(self):
1809 def _checktools(self):
1809 """Ensure tools required to run tests are present."""
1810 """Ensure tools required to run tests are present."""
1810 for p in self.REQUIREDTOOLS:
1811 for p in self.REQUIREDTOOLS:
1811 if os.name == 'nt' and not p.endswith('.exe'):
1812 if os.name == 'nt' and not p.endswith('.exe'):
1812 p += '.exe'
1813 p += '.exe'
1813 found = self._findprogram(p)
1814 found = self._findprogram(p)
1814 if found:
1815 if found:
1815 vlog("# Found prerequisite", p, "at", found)
1816 vlog("# Found prerequisite", p, "at", found)
1816 else:
1817 else:
1817 print "WARNING: Did not find prerequisite tool: %s " % p
1818 print "WARNING: Did not find prerequisite tool: %s " % p
1818
1819
1819 if __name__ == '__main__':
1820 if __name__ == '__main__':
1820 runner = TestRunner()
1821 runner = TestRunner()
1821 sys.exit(runner.run(sys.argv[1:]))
1822 sys.exit(runner.run(sys.argv[1:]))
@@ -1,64 +1,65 b''
1 Create a repository:
1 Create a repository:
2
2
3 $ hg config
3 $ hg config
4 defaults.backout=-d "0 0"
4 defaults.backout=-d "0 0"
5 defaults.commit=-d "0 0"
5 defaults.commit=-d "0 0"
6 defaults.shelve=--date "0 0"
6 defaults.shelve=--date "0 0"
7 defaults.tag=-d "0 0"
7 defaults.tag=-d "0 0"
8 ui.slash=True
8 ui.slash=True
9 ui.interactive=False
9 ui.interactive=False
10 ui.mergemarkers=detailed
10 $ hg init t
11 $ hg init t
11 $ cd t
12 $ cd t
12
13
13 Make a changeset:
14 Make a changeset:
14
15
15 $ echo a > a
16 $ echo a > a
16 $ hg add a
17 $ hg add a
17 $ hg commit -m test
18 $ hg commit -m test
18
19
19 This command is ancient:
20 This command is ancient:
20
21
21 $ hg history
22 $ hg history
22 changeset: 0:acb14030fe0a
23 changeset: 0:acb14030fe0a
23 tag: tip
24 tag: tip
24 user: test
25 user: test
25 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
26 summary: test
27 summary: test
27
28
28
29
29 Verify that updating to revision 0 via commands.update() works properly
30 Verify that updating to revision 0 via commands.update() works properly
30
31
31 $ cat <<EOF > update_to_rev0.py
32 $ cat <<EOF > update_to_rev0.py
32 > from mercurial import ui, hg, commands
33 > from mercurial import ui, hg, commands
33 > myui = ui.ui()
34 > myui = ui.ui()
34 > repo = hg.repository(myui, path='.')
35 > repo = hg.repository(myui, path='.')
35 > commands.update(myui, repo, rev=0)
36 > commands.update(myui, repo, rev=0)
36 > EOF
37 > EOF
37 $ hg up null
38 $ hg up null
38 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
39 $ python ./update_to_rev0.py
40 $ python ./update_to_rev0.py
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 $ hg identify -n
42 $ hg identify -n
42 0
43 0
43
44
44
45
45 Poke around at hashes:
46 Poke around at hashes:
46
47
47 $ hg manifest --debug
48 $ hg manifest --debug
48 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
49 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
49
50
50 $ hg cat a
51 $ hg cat a
51 a
52 a
52
53
53 Verify should succeed:
54 Verify should succeed:
54
55
55 $ hg verify
56 $ hg verify
56 checking changesets
57 checking changesets
57 checking manifests
58 checking manifests
58 crosschecking files in changesets and manifests
59 crosschecking files in changesets and manifests
59 checking files
60 checking files
60 1 files, 1 changesets, 1 total revisions
61 1 files, 1 changesets, 1 total revisions
61
62
62 At the end...
63 At the end...
63
64
64 $ cd ..
65 $ cd ..
@@ -1,260 +1,262 b''
1
1
2 testing hellomessage:
2 testing hellomessage:
3
3
4 o, 'capabilities: getencoding runcommand\nencoding: ***'
4 o, 'capabilities: getencoding runcommand\nencoding: ***'
5 runcommand id
5 runcommand id
6 000000000000 tip
6 000000000000 tip
7
7
8 testing unknowncommand:
8 testing unknowncommand:
9
9
10 abort: unknown command unknowncommand
10 abort: unknown command unknowncommand
11
11
12 testing checkruncommand:
12 testing checkruncommand:
13
13
14 runcommand
14 runcommand
15 Mercurial Distributed SCM
15 Mercurial Distributed SCM
16
16
17 basic commands:
17 basic commands:
18
18
19 add add the specified files on the next commit
19 add add the specified files on the next commit
20 annotate show changeset information by line for each file
20 annotate show changeset information by line for each file
21 clone make a copy of an existing repository
21 clone make a copy of an existing repository
22 commit commit the specified files or all outstanding changes
22 commit commit the specified files or all outstanding changes
23 diff diff repository (or selected files)
23 diff diff repository (or selected files)
24 export dump the header and diffs for one or more changesets
24 export dump the header and diffs for one or more changesets
25 forget forget the specified files on the next commit
25 forget forget the specified files on the next commit
26 init create a new repository in the given directory
26 init create a new repository in the given directory
27 log show revision history of entire repository or files
27 log show revision history of entire repository or files
28 merge merge working directory with another revision
28 merge merge working directory with another revision
29 pull pull changes from the specified source
29 pull pull changes from the specified source
30 push push changes to the specified destination
30 push push changes to the specified destination
31 remove remove the specified files on the next commit
31 remove remove the specified files on the next commit
32 serve start stand-alone webserver
32 serve start stand-alone webserver
33 status show changed files in the working directory
33 status show changed files in the working directory
34 summary summarize working directory state
34 summary summarize working directory state
35 update update working directory (or switch revisions)
35 update update working directory (or switch revisions)
36
36
37 use "hg help" for the full list of commands or "hg -v" for details
37 use "hg help" for the full list of commands or "hg -v" for details
38 runcommand id --quiet
38 runcommand id --quiet
39 000000000000
39 000000000000
40 runcommand id
40 runcommand id
41 000000000000 tip
41 000000000000 tip
42 runcommand id --config ui.quiet=True
42 runcommand id --config ui.quiet=True
43 000000000000
43 000000000000
44 runcommand id
44 runcommand id
45 000000000000 tip
45 000000000000 tip
46 runcommand id -runknown
46 runcommand id -runknown
47 abort: unknown revision 'unknown'!
47 abort: unknown revision 'unknown'!
48 [255]
48 [255]
49
49
50 testing inputeof:
50 testing inputeof:
51
51
52 server exit code = 1
52 server exit code = 1
53
53
54 testing serverinput:
54 testing serverinput:
55
55
56 runcommand import -
56 runcommand import -
57 applying patch from stdin
57 applying patch from stdin
58 runcommand log
58 runcommand log
59 changeset: 0:eff892de26ec
59 changeset: 0:eff892de26ec
60 tag: tip
60 tag: tip
61 user: test
61 user: test
62 date: Thu Jan 01 00:00:00 1970 +0000
62 date: Thu Jan 01 00:00:00 1970 +0000
63 summary: 1
63 summary: 1
64
64
65
65
66 testing cwd:
66 testing cwd:
67
67
68 runcommand --cwd foo st bar
68 runcommand --cwd foo st bar
69 ? bar
69 ? bar
70 runcommand st foo/bar
70 runcommand st foo/bar
71 ? foo/bar
71 ? foo/bar
72
72
73 testing localhgrc:
73 testing localhgrc:
74
74
75 runcommand showconfig
75 runcommand showconfig
76 bundle.mainreporoot=$TESTTMP/repo
76 bundle.mainreporoot=$TESTTMP/repo
77 defaults.backout=-d "0 0"
77 defaults.backout=-d "0 0"
78 defaults.commit=-d "0 0"
78 defaults.commit=-d "0 0"
79 defaults.shelve=--date "0 0"
79 defaults.shelve=--date "0 0"
80 defaults.tag=-d "0 0"
80 defaults.tag=-d "0 0"
81 ui.slash=True
81 ui.slash=True
82 ui.interactive=False
82 ui.interactive=False
83 ui.mergemarkers=detailed
83 ui.foo=bar
84 ui.foo=bar
84 ui.nontty=true
85 ui.nontty=true
85 runcommand init foo
86 runcommand init foo
86 runcommand -R foo showconfig ui defaults
87 runcommand -R foo showconfig ui defaults
87 defaults.backout=-d "0 0"
88 defaults.backout=-d "0 0"
88 defaults.commit=-d "0 0"
89 defaults.commit=-d "0 0"
89 defaults.shelve=--date "0 0"
90 defaults.shelve=--date "0 0"
90 defaults.tag=-d "0 0"
91 defaults.tag=-d "0 0"
91 ui.slash=True
92 ui.slash=True
92 ui.interactive=False
93 ui.interactive=False
94 ui.mergemarkers=detailed
93 ui.nontty=true
95 ui.nontty=true
94
96
95 testing hookoutput:
97 testing hookoutput:
96
98
97 runcommand --config hooks.pre-identify=python:test-commandserver.hook id
99 runcommand --config hooks.pre-identify=python:test-commandserver.hook id
98 hook talking
100 hook talking
99 now try to read something: 'some input'
101 now try to read something: 'some input'
100 eff892de26ec tip
102 eff892de26ec tip
101
103
102 testing outsidechanges:
104 testing outsidechanges:
103
105
104 runcommand status
106 runcommand status
105 M a
107 M a
106 runcommand tip
108 runcommand tip
107 changeset: 1:d3a0a68be6de
109 changeset: 1:d3a0a68be6de
108 tag: tip
110 tag: tip
109 user: test
111 user: test
110 date: Thu Jan 01 00:00:00 1970 +0000
112 date: Thu Jan 01 00:00:00 1970 +0000
111 summary: 2
113 summary: 2
112
114
113 runcommand status
115 runcommand status
114
116
115 testing bookmarks:
117 testing bookmarks:
116
118
117 runcommand bookmarks
119 runcommand bookmarks
118 no bookmarks set
120 no bookmarks set
119 runcommand bookmarks
121 runcommand bookmarks
120 bm1 1:d3a0a68be6de
122 bm1 1:d3a0a68be6de
121 bm2 1:d3a0a68be6de
123 bm2 1:d3a0a68be6de
122 runcommand bookmarks
124 runcommand bookmarks
123 * bm1 1:d3a0a68be6de
125 * bm1 1:d3a0a68be6de
124 bm2 1:d3a0a68be6de
126 bm2 1:d3a0a68be6de
125 runcommand bookmarks bm3
127 runcommand bookmarks bm3
126 runcommand commit -Amm
128 runcommand commit -Amm
127 runcommand bookmarks
129 runcommand bookmarks
128 bm1 1:d3a0a68be6de
130 bm1 1:d3a0a68be6de
129 bm2 1:d3a0a68be6de
131 bm2 1:d3a0a68be6de
130 * bm3 2:aef17e88f5f0
132 * bm3 2:aef17e88f5f0
131
133
132 testing tagscache:
134 testing tagscache:
133
135
134 runcommand id -t -r 0
136 runcommand id -t -r 0
135
137
136 runcommand id -t -r 0
138 runcommand id -t -r 0
137 foo
139 foo
138
140
139 testing setphase:
141 testing setphase:
140
142
141 runcommand phase -r .
143 runcommand phase -r .
142 3: draft
144 3: draft
143 runcommand phase -r .
145 runcommand phase -r .
144 3: public
146 3: public
145
147
146 testing rollback:
148 testing rollback:
147
149
148 runcommand phase -r . -p
150 runcommand phase -r . -p
149 no phases changed
151 no phases changed
150 [1]
152 [1]
151 runcommand commit -Am.
153 runcommand commit -Am.
152 runcommand rollback
154 runcommand rollback
153 repository tip rolled back to revision 3 (undo commit)
155 repository tip rolled back to revision 3 (undo commit)
154 working directory now based on revision 3
156 working directory now based on revision 3
155 runcommand phase -r .
157 runcommand phase -r .
156 3: public
158 3: public
157
159
158 testing branch:
160 testing branch:
159
161
160 runcommand branch
162 runcommand branch
161 default
163 default
162 marked working directory as branch foo
164 marked working directory as branch foo
163 (branches are permanent and global, did you want a bookmark?)
165 (branches are permanent and global, did you want a bookmark?)
164 runcommand branch
166 runcommand branch
165 foo
167 foo
166 marked working directory as branch default
168 marked working directory as branch default
167 (branches are permanent and global, did you want a bookmark?)
169 (branches are permanent and global, did you want a bookmark?)
168
170
169 testing hgignore:
171 testing hgignore:
170
172
171 runcommand commit -Am.
173 runcommand commit -Am.
172 adding .hgignore
174 adding .hgignore
173 runcommand status -i -u
175 runcommand status -i -u
174 I ignored-file
176 I ignored-file
175
177
176 testing phasecacheafterstrip:
178 testing phasecacheafterstrip:
177
179
178 runcommand update -C 0
180 runcommand update -C 0
179 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
181 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
180 (leaving bookmark bm3)
182 (leaving bookmark bm3)
181 runcommand commit -Am. a
183 runcommand commit -Am. a
182 created new head
184 created new head
183 runcommand log -Gq
185 runcommand log -Gq
184 @ 5:731265503d86
186 @ 5:731265503d86
185 |
187 |
186 | o 4:7966c8e3734d
188 | o 4:7966c8e3734d
187 | |
189 | |
188 | o 3:b9b85890c400
190 | o 3:b9b85890c400
189 | |
191 | |
190 | o 2:aef17e88f5f0
192 | o 2:aef17e88f5f0
191 | |
193 | |
192 | o 1:d3a0a68be6de
194 | o 1:d3a0a68be6de
193 |/
195 |/
194 o 0:eff892de26ec
196 o 0:eff892de26ec
195
197
196 runcommand phase -p .
198 runcommand phase -p .
197 runcommand phase .
199 runcommand phase .
198 5: public
200 5: public
199 runcommand branches
201 runcommand branches
200 default 1:731265503d86
202 default 1:731265503d86
201
203
202 testing obsolete:
204 testing obsolete:
203
205
204 runcommand up null
206 runcommand up null
205 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
207 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
206 runcommand phase -df tip
208 runcommand phase -df tip
207 runcommand log --hidden
209 runcommand log --hidden
208 changeset: 1:731265503d86
210 changeset: 1:731265503d86
209 tag: tip
211 tag: tip
210 user: test
212 user: test
211 date: Thu Jan 01 00:00:00 1970 +0000
213 date: Thu Jan 01 00:00:00 1970 +0000
212 summary: .
214 summary: .
213
215
214 changeset: 0:eff892de26ec
216 changeset: 0:eff892de26ec
215 bookmark: bm1
217 bookmark: bm1
216 bookmark: bm2
218 bookmark: bm2
217 bookmark: bm3
219 bookmark: bm3
218 user: test
220 user: test
219 date: Thu Jan 01 00:00:00 1970 +0000
221 date: Thu Jan 01 00:00:00 1970 +0000
220 summary: 1
222 summary: 1
221
223
222 runcommand log
224 runcommand log
223 changeset: 0:eff892de26ec
225 changeset: 0:eff892de26ec
224 bookmark: bm1
226 bookmark: bm1
225 bookmark: bm2
227 bookmark: bm2
226 bookmark: bm3
228 bookmark: bm3
227 tag: tip
229 tag: tip
228 user: test
230 user: test
229 date: Thu Jan 01 00:00:00 1970 +0000
231 date: Thu Jan 01 00:00:00 1970 +0000
230 summary: 1
232 summary: 1
231
233
232
234
233 testing mqoutsidechanges:
235 testing mqoutsidechanges:
234
236
235 runcommand qapplied
237 runcommand qapplied
236 runcommand qapplied
238 runcommand qapplied
237 0.diff
239 0.diff
238 runcommand qpop --all
240 runcommand qpop --all
239 popping 0.diff
241 popping 0.diff
240 patch queue now empty
242 patch queue now empty
241 runcommand qqueue --active
243 runcommand qqueue --active
242 foo
244 foo
243
245
244 testing getpass:
246 testing getpass:
245
247
246 runcommand debuggetpass --config ui.interactive=True
248 runcommand debuggetpass --config ui.interactive=True
247 password: 1234
249 password: 1234
248
250
249 testing hellomessage:
251 testing hellomessage:
250
252
251 o, 'capabilities: getencoding runcommand\nencoding: ***'
253 o, 'capabilities: getencoding runcommand\nencoding: ***'
252 runcommand id
254 runcommand id
253 abort: there is no Mercurial repository here (.hg not found)
255 abort: there is no Mercurial repository here (.hg not found)
254 [255]
256 [255]
255
257
256 testing startwithoutrepo:
258 testing startwithoutrepo:
257
259
258 runcommand init repo2
260 runcommand init repo2
259 runcommand id -R repo2
261 runcommand id -R repo2
260 000000000000 tip
262 000000000000 tip
General Comments 0
You need to be logged in to leave comments. Login now