##// END OF EJS Templates
ui: invoke editor for committing with HGEDITFORM environment variable...
FUJIWARA Katsunori -
r22205:9fa42972 default
parent child Browse files
Show More
@@ -1,2698 +1,2698 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
14 import changelog
14 import changelog
15 import bookmarks
15 import bookmarks
16 import lock as lockmod
16 import lock as lockmod
17
17
18 def parsealiases(cmd):
18 def parsealiases(cmd):
19 return cmd.lstrip("^").split("|")
19 return cmd.lstrip("^").split("|")
20
20
21 def findpossible(cmd, table, strict=False):
21 def findpossible(cmd, table, strict=False):
22 """
22 """
23 Return cmd -> (aliases, command table entry)
23 Return cmd -> (aliases, command table entry)
24 for each matching command.
24 for each matching command.
25 Return debug commands (or their aliases) only if no normal command matches.
25 Return debug commands (or their aliases) only if no normal command matches.
26 """
26 """
27 choice = {}
27 choice = {}
28 debugchoice = {}
28 debugchoice = {}
29
29
30 if cmd in table:
30 if cmd in table:
31 # short-circuit exact matches, "log" alias beats "^log|history"
31 # short-circuit exact matches, "log" alias beats "^log|history"
32 keys = [cmd]
32 keys = [cmd]
33 else:
33 else:
34 keys = table.keys()
34 keys = table.keys()
35
35
36 for e in keys:
36 for e in keys:
37 aliases = parsealiases(e)
37 aliases = parsealiases(e)
38 found = None
38 found = None
39 if cmd in aliases:
39 if cmd in aliases:
40 found = cmd
40 found = cmd
41 elif not strict:
41 elif not strict:
42 for a in aliases:
42 for a in aliases:
43 if a.startswith(cmd):
43 if a.startswith(cmd):
44 found = a
44 found = a
45 break
45 break
46 if found is not None:
46 if found is not None:
47 if aliases[0].startswith("debug") or found.startswith("debug"):
47 if aliases[0].startswith("debug") or found.startswith("debug"):
48 debugchoice[found] = (aliases, table[e])
48 debugchoice[found] = (aliases, table[e])
49 else:
49 else:
50 choice[found] = (aliases, table[e])
50 choice[found] = (aliases, table[e])
51
51
52 if not choice and debugchoice:
52 if not choice and debugchoice:
53 choice = debugchoice
53 choice = debugchoice
54
54
55 return choice
55 return choice
56
56
57 def findcmd(cmd, table, strict=True):
57 def findcmd(cmd, table, strict=True):
58 """Return (aliases, command table entry) for command string."""
58 """Return (aliases, command table entry) for command string."""
59 choice = findpossible(cmd, table, strict)
59 choice = findpossible(cmd, table, strict)
60
60
61 if cmd in choice:
61 if cmd in choice:
62 return choice[cmd]
62 return choice[cmd]
63
63
64 if len(choice) > 1:
64 if len(choice) > 1:
65 clist = choice.keys()
65 clist = choice.keys()
66 clist.sort()
66 clist.sort()
67 raise error.AmbiguousCommand(cmd, clist)
67 raise error.AmbiguousCommand(cmd, clist)
68
68
69 if choice:
69 if choice:
70 return choice.values()[0]
70 return choice.values()[0]
71
71
72 raise error.UnknownCommand(cmd)
72 raise error.UnknownCommand(cmd)
73
73
74 def findrepo(p):
74 def findrepo(p):
75 while not os.path.isdir(os.path.join(p, ".hg")):
75 while not os.path.isdir(os.path.join(p, ".hg")):
76 oldp, p = p, os.path.dirname(p)
76 oldp, p = p, os.path.dirname(p)
77 if p == oldp:
77 if p == oldp:
78 return None
78 return None
79
79
80 return p
80 return p
81
81
82 def bailifchanged(repo):
82 def bailifchanged(repo):
83 if repo.dirstate.p2() != nullid:
83 if repo.dirstate.p2() != nullid:
84 raise util.Abort(_('outstanding uncommitted merge'))
84 raise util.Abort(_('outstanding uncommitted merge'))
85 modified, added, removed, deleted = repo.status()[:4]
85 modified, added, removed, deleted = repo.status()[:4]
86 if modified or added or removed or deleted:
86 if modified or added or removed or deleted:
87 raise util.Abort(_('uncommitted changes'))
87 raise util.Abort(_('uncommitted changes'))
88 ctx = repo[None]
88 ctx = repo[None]
89 for s in sorted(ctx.substate):
89 for s in sorted(ctx.substate):
90 if ctx.sub(s).dirty():
90 if ctx.sub(s).dirty():
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
92
92
93 def logmessage(ui, opts):
93 def logmessage(ui, opts):
94 """ get the log message according to -m and -l option """
94 """ get the log message according to -m and -l option """
95 message = opts.get('message')
95 message = opts.get('message')
96 logfile = opts.get('logfile')
96 logfile = opts.get('logfile')
97
97
98 if message and logfile:
98 if message and logfile:
99 raise util.Abort(_('options --message and --logfile are mutually '
99 raise util.Abort(_('options --message and --logfile are mutually '
100 'exclusive'))
100 'exclusive'))
101 if not message and logfile:
101 if not message and logfile:
102 try:
102 try:
103 if logfile == '-':
103 if logfile == '-':
104 message = ui.fin.read()
104 message = ui.fin.read()
105 else:
105 else:
106 message = '\n'.join(util.readfile(logfile).splitlines())
106 message = '\n'.join(util.readfile(logfile).splitlines())
107 except IOError, inst:
107 except IOError, inst:
108 raise util.Abort(_("can't read commit message '%s': %s") %
108 raise util.Abort(_("can't read commit message '%s': %s") %
109 (logfile, inst.strerror))
109 (logfile, inst.strerror))
110 return message
110 return message
111
111
112 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
112 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
113 editform='', **opts):
113 editform='', **opts):
114 """get appropriate commit message editor according to '--edit' option
114 """get appropriate commit message editor according to '--edit' option
115
115
116 'finishdesc' is a function to be called with edited commit message
116 'finishdesc' is a function to be called with edited commit message
117 (= 'description' of the new changeset) just after editing, but
117 (= 'description' of the new changeset) just after editing, but
118 before checking empty-ness. It should return actual text to be
118 before checking empty-ness. It should return actual text to be
119 stored into history. This allows to change description before
119 stored into history. This allows to change description before
120 storing.
120 storing.
121
121
122 'extramsg' is a extra message to be shown in the editor instead of
122 'extramsg' is a extra message to be shown in the editor instead of
123 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
123 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
124 is automatically added.
124 is automatically added.
125
125
126 'editform' is a dot-separated list of names, to distinguish
126 'editform' is a dot-separated list of names, to distinguish
127 the purpose of commit text editing.
127 the purpose of commit text editing.
128
128
129 'getcommiteditor' returns 'commitforceeditor' regardless of
129 'getcommiteditor' returns 'commitforceeditor' regardless of
130 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
130 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
131 they are specific for usage in MQ.
131 they are specific for usage in MQ.
132 """
132 """
133 if edit or finishdesc or extramsg:
133 if edit or finishdesc or extramsg:
134 return lambda r, c, s: commitforceeditor(r, c, s,
134 return lambda r, c, s: commitforceeditor(r, c, s,
135 finishdesc=finishdesc,
135 finishdesc=finishdesc,
136 extramsg=extramsg,
136 extramsg=extramsg,
137 editform=editform)
137 editform=editform)
138 elif editform:
138 elif editform:
139 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
139 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
140 else:
140 else:
141 return commiteditor
141 return commiteditor
142
142
143 def loglimit(opts):
143 def loglimit(opts):
144 """get the log limit according to option -l/--limit"""
144 """get the log limit according to option -l/--limit"""
145 limit = opts.get('limit')
145 limit = opts.get('limit')
146 if limit:
146 if limit:
147 try:
147 try:
148 limit = int(limit)
148 limit = int(limit)
149 except ValueError:
149 except ValueError:
150 raise util.Abort(_('limit must be a positive integer'))
150 raise util.Abort(_('limit must be a positive integer'))
151 if limit <= 0:
151 if limit <= 0:
152 raise util.Abort(_('limit must be positive'))
152 raise util.Abort(_('limit must be positive'))
153 else:
153 else:
154 limit = None
154 limit = None
155 return limit
155 return limit
156
156
157 def makefilename(repo, pat, node, desc=None,
157 def makefilename(repo, pat, node, desc=None,
158 total=None, seqno=None, revwidth=None, pathname=None):
158 total=None, seqno=None, revwidth=None, pathname=None):
159 node_expander = {
159 node_expander = {
160 'H': lambda: hex(node),
160 'H': lambda: hex(node),
161 'R': lambda: str(repo.changelog.rev(node)),
161 'R': lambda: str(repo.changelog.rev(node)),
162 'h': lambda: short(node),
162 'h': lambda: short(node),
163 'm': lambda: re.sub('[^\w]', '_', str(desc))
163 'm': lambda: re.sub('[^\w]', '_', str(desc))
164 }
164 }
165 expander = {
165 expander = {
166 '%': lambda: '%',
166 '%': lambda: '%',
167 'b': lambda: os.path.basename(repo.root),
167 'b': lambda: os.path.basename(repo.root),
168 }
168 }
169
169
170 try:
170 try:
171 if node:
171 if node:
172 expander.update(node_expander)
172 expander.update(node_expander)
173 if node:
173 if node:
174 expander['r'] = (lambda:
174 expander['r'] = (lambda:
175 str(repo.changelog.rev(node)).zfill(revwidth or 0))
175 str(repo.changelog.rev(node)).zfill(revwidth or 0))
176 if total is not None:
176 if total is not None:
177 expander['N'] = lambda: str(total)
177 expander['N'] = lambda: str(total)
178 if seqno is not None:
178 if seqno is not None:
179 expander['n'] = lambda: str(seqno)
179 expander['n'] = lambda: str(seqno)
180 if total is not None and seqno is not None:
180 if total is not None and seqno is not None:
181 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
181 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
182 if pathname is not None:
182 if pathname is not None:
183 expander['s'] = lambda: os.path.basename(pathname)
183 expander['s'] = lambda: os.path.basename(pathname)
184 expander['d'] = lambda: os.path.dirname(pathname) or '.'
184 expander['d'] = lambda: os.path.dirname(pathname) or '.'
185 expander['p'] = lambda: pathname
185 expander['p'] = lambda: pathname
186
186
187 newname = []
187 newname = []
188 patlen = len(pat)
188 patlen = len(pat)
189 i = 0
189 i = 0
190 while i < patlen:
190 while i < patlen:
191 c = pat[i]
191 c = pat[i]
192 if c == '%':
192 if c == '%':
193 i += 1
193 i += 1
194 c = pat[i]
194 c = pat[i]
195 c = expander[c]()
195 c = expander[c]()
196 newname.append(c)
196 newname.append(c)
197 i += 1
197 i += 1
198 return ''.join(newname)
198 return ''.join(newname)
199 except KeyError, inst:
199 except KeyError, inst:
200 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
200 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
201 inst.args[0])
201 inst.args[0])
202
202
203 def makefileobj(repo, pat, node=None, desc=None, total=None,
203 def makefileobj(repo, pat, node=None, desc=None, total=None,
204 seqno=None, revwidth=None, mode='wb', modemap=None,
204 seqno=None, revwidth=None, mode='wb', modemap=None,
205 pathname=None):
205 pathname=None):
206
206
207 writable = mode not in ('r', 'rb')
207 writable = mode not in ('r', 'rb')
208
208
209 if not pat or pat == '-':
209 if not pat or pat == '-':
210 fp = writable and repo.ui.fout or repo.ui.fin
210 fp = writable and repo.ui.fout or repo.ui.fin
211 if util.safehasattr(fp, 'fileno'):
211 if util.safehasattr(fp, 'fileno'):
212 return os.fdopen(os.dup(fp.fileno()), mode)
212 return os.fdopen(os.dup(fp.fileno()), mode)
213 else:
213 else:
214 # if this fp can't be duped properly, return
214 # if this fp can't be duped properly, return
215 # a dummy object that can be closed
215 # a dummy object that can be closed
216 class wrappedfileobj(object):
216 class wrappedfileobj(object):
217 noop = lambda x: None
217 noop = lambda x: None
218 def __init__(self, f):
218 def __init__(self, f):
219 self.f = f
219 self.f = f
220 def __getattr__(self, attr):
220 def __getattr__(self, attr):
221 if attr == 'close':
221 if attr == 'close':
222 return self.noop
222 return self.noop
223 else:
223 else:
224 return getattr(self.f, attr)
224 return getattr(self.f, attr)
225
225
226 return wrappedfileobj(fp)
226 return wrappedfileobj(fp)
227 if util.safehasattr(pat, 'write') and writable:
227 if util.safehasattr(pat, 'write') and writable:
228 return pat
228 return pat
229 if util.safehasattr(pat, 'read') and 'r' in mode:
229 if util.safehasattr(pat, 'read') and 'r' in mode:
230 return pat
230 return pat
231 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
231 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
232 if modemap is not None:
232 if modemap is not None:
233 mode = modemap.get(fn, mode)
233 mode = modemap.get(fn, mode)
234 if mode == 'wb':
234 if mode == 'wb':
235 modemap[fn] = 'ab'
235 modemap[fn] = 'ab'
236 return open(fn, mode)
236 return open(fn, mode)
237
237
238 def openrevlog(repo, cmd, file_, opts):
238 def openrevlog(repo, cmd, file_, opts):
239 """opens the changelog, manifest, a filelog or a given revlog"""
239 """opens the changelog, manifest, a filelog or a given revlog"""
240 cl = opts['changelog']
240 cl = opts['changelog']
241 mf = opts['manifest']
241 mf = opts['manifest']
242 msg = None
242 msg = None
243 if cl and mf:
243 if cl and mf:
244 msg = _('cannot specify --changelog and --manifest at the same time')
244 msg = _('cannot specify --changelog and --manifest at the same time')
245 elif cl or mf:
245 elif cl or mf:
246 if file_:
246 if file_:
247 msg = _('cannot specify filename with --changelog or --manifest')
247 msg = _('cannot specify filename with --changelog or --manifest')
248 elif not repo:
248 elif not repo:
249 msg = _('cannot specify --changelog or --manifest '
249 msg = _('cannot specify --changelog or --manifest '
250 'without a repository')
250 'without a repository')
251 if msg:
251 if msg:
252 raise util.Abort(msg)
252 raise util.Abort(msg)
253
253
254 r = None
254 r = None
255 if repo:
255 if repo:
256 if cl:
256 if cl:
257 r = repo.unfiltered().changelog
257 r = repo.unfiltered().changelog
258 elif mf:
258 elif mf:
259 r = repo.manifest
259 r = repo.manifest
260 elif file_:
260 elif file_:
261 filelog = repo.file(file_)
261 filelog = repo.file(file_)
262 if len(filelog):
262 if len(filelog):
263 r = filelog
263 r = filelog
264 if not r:
264 if not r:
265 if not file_:
265 if not file_:
266 raise error.CommandError(cmd, _('invalid arguments'))
266 raise error.CommandError(cmd, _('invalid arguments'))
267 if not os.path.isfile(file_):
267 if not os.path.isfile(file_):
268 raise util.Abort(_("revlog '%s' not found") % file_)
268 raise util.Abort(_("revlog '%s' not found") % file_)
269 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
269 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
270 file_[:-2] + ".i")
270 file_[:-2] + ".i")
271 return r
271 return r
272
272
273 def copy(ui, repo, pats, opts, rename=False):
273 def copy(ui, repo, pats, opts, rename=False):
274 # called with the repo lock held
274 # called with the repo lock held
275 #
275 #
276 # hgsep => pathname that uses "/" to separate directories
276 # hgsep => pathname that uses "/" to separate directories
277 # ossep => pathname that uses os.sep to separate directories
277 # ossep => pathname that uses os.sep to separate directories
278 cwd = repo.getcwd()
278 cwd = repo.getcwd()
279 targets = {}
279 targets = {}
280 after = opts.get("after")
280 after = opts.get("after")
281 dryrun = opts.get("dry_run")
281 dryrun = opts.get("dry_run")
282 wctx = repo[None]
282 wctx = repo[None]
283
283
284 def walkpat(pat):
284 def walkpat(pat):
285 srcs = []
285 srcs = []
286 badstates = after and '?' or '?r'
286 badstates = after and '?' or '?r'
287 m = scmutil.match(repo[None], [pat], opts, globbed=True)
287 m = scmutil.match(repo[None], [pat], opts, globbed=True)
288 for abs in repo.walk(m):
288 for abs in repo.walk(m):
289 state = repo.dirstate[abs]
289 state = repo.dirstate[abs]
290 rel = m.rel(abs)
290 rel = m.rel(abs)
291 exact = m.exact(abs)
291 exact = m.exact(abs)
292 if state in badstates:
292 if state in badstates:
293 if exact and state == '?':
293 if exact and state == '?':
294 ui.warn(_('%s: not copying - file is not managed\n') % rel)
294 ui.warn(_('%s: not copying - file is not managed\n') % rel)
295 if exact and state == 'r':
295 if exact and state == 'r':
296 ui.warn(_('%s: not copying - file has been marked for'
296 ui.warn(_('%s: not copying - file has been marked for'
297 ' remove\n') % rel)
297 ' remove\n') % rel)
298 continue
298 continue
299 # abs: hgsep
299 # abs: hgsep
300 # rel: ossep
300 # rel: ossep
301 srcs.append((abs, rel, exact))
301 srcs.append((abs, rel, exact))
302 return srcs
302 return srcs
303
303
304 # abssrc: hgsep
304 # abssrc: hgsep
305 # relsrc: ossep
305 # relsrc: ossep
306 # otarget: ossep
306 # otarget: ossep
307 def copyfile(abssrc, relsrc, otarget, exact):
307 def copyfile(abssrc, relsrc, otarget, exact):
308 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
308 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
309 if '/' in abstarget:
309 if '/' in abstarget:
310 # We cannot normalize abstarget itself, this would prevent
310 # We cannot normalize abstarget itself, this would prevent
311 # case only renames, like a => A.
311 # case only renames, like a => A.
312 abspath, absname = abstarget.rsplit('/', 1)
312 abspath, absname = abstarget.rsplit('/', 1)
313 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
313 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
314 reltarget = repo.pathto(abstarget, cwd)
314 reltarget = repo.pathto(abstarget, cwd)
315 target = repo.wjoin(abstarget)
315 target = repo.wjoin(abstarget)
316 src = repo.wjoin(abssrc)
316 src = repo.wjoin(abssrc)
317 state = repo.dirstate[abstarget]
317 state = repo.dirstate[abstarget]
318
318
319 scmutil.checkportable(ui, abstarget)
319 scmutil.checkportable(ui, abstarget)
320
320
321 # check for collisions
321 # check for collisions
322 prevsrc = targets.get(abstarget)
322 prevsrc = targets.get(abstarget)
323 if prevsrc is not None:
323 if prevsrc is not None:
324 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
324 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
325 (reltarget, repo.pathto(abssrc, cwd),
325 (reltarget, repo.pathto(abssrc, cwd),
326 repo.pathto(prevsrc, cwd)))
326 repo.pathto(prevsrc, cwd)))
327 return
327 return
328
328
329 # check for overwrites
329 # check for overwrites
330 exists = os.path.lexists(target)
330 exists = os.path.lexists(target)
331 samefile = False
331 samefile = False
332 if exists and abssrc != abstarget:
332 if exists and abssrc != abstarget:
333 if (repo.dirstate.normalize(abssrc) ==
333 if (repo.dirstate.normalize(abssrc) ==
334 repo.dirstate.normalize(abstarget)):
334 repo.dirstate.normalize(abstarget)):
335 if not rename:
335 if not rename:
336 ui.warn(_("%s: can't copy - same file\n") % reltarget)
336 ui.warn(_("%s: can't copy - same file\n") % reltarget)
337 return
337 return
338 exists = False
338 exists = False
339 samefile = True
339 samefile = True
340
340
341 if not after and exists or after and state in 'mn':
341 if not after and exists or after and state in 'mn':
342 if not opts['force']:
342 if not opts['force']:
343 ui.warn(_('%s: not overwriting - file exists\n') %
343 ui.warn(_('%s: not overwriting - file exists\n') %
344 reltarget)
344 reltarget)
345 return
345 return
346
346
347 if after:
347 if after:
348 if not exists:
348 if not exists:
349 if rename:
349 if rename:
350 ui.warn(_('%s: not recording move - %s does not exist\n') %
350 ui.warn(_('%s: not recording move - %s does not exist\n') %
351 (relsrc, reltarget))
351 (relsrc, reltarget))
352 else:
352 else:
353 ui.warn(_('%s: not recording copy - %s does not exist\n') %
353 ui.warn(_('%s: not recording copy - %s does not exist\n') %
354 (relsrc, reltarget))
354 (relsrc, reltarget))
355 return
355 return
356 elif not dryrun:
356 elif not dryrun:
357 try:
357 try:
358 if exists:
358 if exists:
359 os.unlink(target)
359 os.unlink(target)
360 targetdir = os.path.dirname(target) or '.'
360 targetdir = os.path.dirname(target) or '.'
361 if not os.path.isdir(targetdir):
361 if not os.path.isdir(targetdir):
362 os.makedirs(targetdir)
362 os.makedirs(targetdir)
363 if samefile:
363 if samefile:
364 tmp = target + "~hgrename"
364 tmp = target + "~hgrename"
365 os.rename(src, tmp)
365 os.rename(src, tmp)
366 os.rename(tmp, target)
366 os.rename(tmp, target)
367 else:
367 else:
368 util.copyfile(src, target)
368 util.copyfile(src, target)
369 srcexists = True
369 srcexists = True
370 except IOError, inst:
370 except IOError, inst:
371 if inst.errno == errno.ENOENT:
371 if inst.errno == errno.ENOENT:
372 ui.warn(_('%s: deleted in working copy\n') % relsrc)
372 ui.warn(_('%s: deleted in working copy\n') % relsrc)
373 srcexists = False
373 srcexists = False
374 else:
374 else:
375 ui.warn(_('%s: cannot copy - %s\n') %
375 ui.warn(_('%s: cannot copy - %s\n') %
376 (relsrc, inst.strerror))
376 (relsrc, inst.strerror))
377 return True # report a failure
377 return True # report a failure
378
378
379 if ui.verbose or not exact:
379 if ui.verbose or not exact:
380 if rename:
380 if rename:
381 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
381 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
382 else:
382 else:
383 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
383 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
384
384
385 targets[abstarget] = abssrc
385 targets[abstarget] = abssrc
386
386
387 # fix up dirstate
387 # fix up dirstate
388 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
388 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
389 dryrun=dryrun, cwd=cwd)
389 dryrun=dryrun, cwd=cwd)
390 if rename and not dryrun:
390 if rename and not dryrun:
391 if not after and srcexists and not samefile:
391 if not after and srcexists and not samefile:
392 util.unlinkpath(repo.wjoin(abssrc))
392 util.unlinkpath(repo.wjoin(abssrc))
393 wctx.forget([abssrc])
393 wctx.forget([abssrc])
394
394
395 # pat: ossep
395 # pat: ossep
396 # dest ossep
396 # dest ossep
397 # srcs: list of (hgsep, hgsep, ossep, bool)
397 # srcs: list of (hgsep, hgsep, ossep, bool)
398 # return: function that takes hgsep and returns ossep
398 # return: function that takes hgsep and returns ossep
399 def targetpathfn(pat, dest, srcs):
399 def targetpathfn(pat, dest, srcs):
400 if os.path.isdir(pat):
400 if os.path.isdir(pat):
401 abspfx = pathutil.canonpath(repo.root, cwd, pat)
401 abspfx = pathutil.canonpath(repo.root, cwd, pat)
402 abspfx = util.localpath(abspfx)
402 abspfx = util.localpath(abspfx)
403 if destdirexists:
403 if destdirexists:
404 striplen = len(os.path.split(abspfx)[0])
404 striplen = len(os.path.split(abspfx)[0])
405 else:
405 else:
406 striplen = len(abspfx)
406 striplen = len(abspfx)
407 if striplen:
407 if striplen:
408 striplen += len(os.sep)
408 striplen += len(os.sep)
409 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
409 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
410 elif destdirexists:
410 elif destdirexists:
411 res = lambda p: os.path.join(dest,
411 res = lambda p: os.path.join(dest,
412 os.path.basename(util.localpath(p)))
412 os.path.basename(util.localpath(p)))
413 else:
413 else:
414 res = lambda p: dest
414 res = lambda p: dest
415 return res
415 return res
416
416
417 # pat: ossep
417 # pat: ossep
418 # dest ossep
418 # dest ossep
419 # srcs: list of (hgsep, hgsep, ossep, bool)
419 # srcs: list of (hgsep, hgsep, ossep, bool)
420 # return: function that takes hgsep and returns ossep
420 # return: function that takes hgsep and returns ossep
421 def targetpathafterfn(pat, dest, srcs):
421 def targetpathafterfn(pat, dest, srcs):
422 if matchmod.patkind(pat):
422 if matchmod.patkind(pat):
423 # a mercurial pattern
423 # a mercurial pattern
424 res = lambda p: os.path.join(dest,
424 res = lambda p: os.path.join(dest,
425 os.path.basename(util.localpath(p)))
425 os.path.basename(util.localpath(p)))
426 else:
426 else:
427 abspfx = pathutil.canonpath(repo.root, cwd, pat)
427 abspfx = pathutil.canonpath(repo.root, cwd, pat)
428 if len(abspfx) < len(srcs[0][0]):
428 if len(abspfx) < len(srcs[0][0]):
429 # A directory. Either the target path contains the last
429 # A directory. Either the target path contains the last
430 # component of the source path or it does not.
430 # component of the source path or it does not.
431 def evalpath(striplen):
431 def evalpath(striplen):
432 score = 0
432 score = 0
433 for s in srcs:
433 for s in srcs:
434 t = os.path.join(dest, util.localpath(s[0])[striplen:])
434 t = os.path.join(dest, util.localpath(s[0])[striplen:])
435 if os.path.lexists(t):
435 if os.path.lexists(t):
436 score += 1
436 score += 1
437 return score
437 return score
438
438
439 abspfx = util.localpath(abspfx)
439 abspfx = util.localpath(abspfx)
440 striplen = len(abspfx)
440 striplen = len(abspfx)
441 if striplen:
441 if striplen:
442 striplen += len(os.sep)
442 striplen += len(os.sep)
443 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
443 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
444 score = evalpath(striplen)
444 score = evalpath(striplen)
445 striplen1 = len(os.path.split(abspfx)[0])
445 striplen1 = len(os.path.split(abspfx)[0])
446 if striplen1:
446 if striplen1:
447 striplen1 += len(os.sep)
447 striplen1 += len(os.sep)
448 if evalpath(striplen1) > score:
448 if evalpath(striplen1) > score:
449 striplen = striplen1
449 striplen = striplen1
450 res = lambda p: os.path.join(dest,
450 res = lambda p: os.path.join(dest,
451 util.localpath(p)[striplen:])
451 util.localpath(p)[striplen:])
452 else:
452 else:
453 # a file
453 # a file
454 if destdirexists:
454 if destdirexists:
455 res = lambda p: os.path.join(dest,
455 res = lambda p: os.path.join(dest,
456 os.path.basename(util.localpath(p)))
456 os.path.basename(util.localpath(p)))
457 else:
457 else:
458 res = lambda p: dest
458 res = lambda p: dest
459 return res
459 return res
460
460
461
461
462 pats = scmutil.expandpats(pats)
462 pats = scmutil.expandpats(pats)
463 if not pats:
463 if not pats:
464 raise util.Abort(_('no source or destination specified'))
464 raise util.Abort(_('no source or destination specified'))
465 if len(pats) == 1:
465 if len(pats) == 1:
466 raise util.Abort(_('no destination specified'))
466 raise util.Abort(_('no destination specified'))
467 dest = pats.pop()
467 dest = pats.pop()
468 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
468 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
469 if not destdirexists:
469 if not destdirexists:
470 if len(pats) > 1 or matchmod.patkind(pats[0]):
470 if len(pats) > 1 or matchmod.patkind(pats[0]):
471 raise util.Abort(_('with multiple sources, destination must be an '
471 raise util.Abort(_('with multiple sources, destination must be an '
472 'existing directory'))
472 'existing directory'))
473 if util.endswithsep(dest):
473 if util.endswithsep(dest):
474 raise util.Abort(_('destination %s is not a directory') % dest)
474 raise util.Abort(_('destination %s is not a directory') % dest)
475
475
476 tfn = targetpathfn
476 tfn = targetpathfn
477 if after:
477 if after:
478 tfn = targetpathafterfn
478 tfn = targetpathafterfn
479 copylist = []
479 copylist = []
480 for pat in pats:
480 for pat in pats:
481 srcs = walkpat(pat)
481 srcs = walkpat(pat)
482 if not srcs:
482 if not srcs:
483 continue
483 continue
484 copylist.append((tfn(pat, dest, srcs), srcs))
484 copylist.append((tfn(pat, dest, srcs), srcs))
485 if not copylist:
485 if not copylist:
486 raise util.Abort(_('no files to copy'))
486 raise util.Abort(_('no files to copy'))
487
487
488 errors = 0
488 errors = 0
489 for targetpath, srcs in copylist:
489 for targetpath, srcs in copylist:
490 for abssrc, relsrc, exact in srcs:
490 for abssrc, relsrc, exact in srcs:
491 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
491 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
492 errors += 1
492 errors += 1
493
493
494 if errors:
494 if errors:
495 ui.warn(_('(consider using --after)\n'))
495 ui.warn(_('(consider using --after)\n'))
496
496
497 return errors != 0
497 return errors != 0
498
498
499 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
499 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
500 runargs=None, appendpid=False):
500 runargs=None, appendpid=False):
501 '''Run a command as a service.'''
501 '''Run a command as a service.'''
502
502
503 def writepid(pid):
503 def writepid(pid):
504 if opts['pid_file']:
504 if opts['pid_file']:
505 mode = appendpid and 'a' or 'w'
505 mode = appendpid and 'a' or 'w'
506 fp = open(opts['pid_file'], mode)
506 fp = open(opts['pid_file'], mode)
507 fp.write(str(pid) + '\n')
507 fp.write(str(pid) + '\n')
508 fp.close()
508 fp.close()
509
509
510 if opts['daemon'] and not opts['daemon_pipefds']:
510 if opts['daemon'] and not opts['daemon_pipefds']:
511 # Signal child process startup with file removal
511 # Signal child process startup with file removal
512 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
512 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
513 os.close(lockfd)
513 os.close(lockfd)
514 try:
514 try:
515 if not runargs:
515 if not runargs:
516 runargs = util.hgcmd() + sys.argv[1:]
516 runargs = util.hgcmd() + sys.argv[1:]
517 runargs.append('--daemon-pipefds=%s' % lockpath)
517 runargs.append('--daemon-pipefds=%s' % lockpath)
518 # Don't pass --cwd to the child process, because we've already
518 # Don't pass --cwd to the child process, because we've already
519 # changed directory.
519 # changed directory.
520 for i in xrange(1, len(runargs)):
520 for i in xrange(1, len(runargs)):
521 if runargs[i].startswith('--cwd='):
521 if runargs[i].startswith('--cwd='):
522 del runargs[i]
522 del runargs[i]
523 break
523 break
524 elif runargs[i].startswith('--cwd'):
524 elif runargs[i].startswith('--cwd'):
525 del runargs[i:i + 2]
525 del runargs[i:i + 2]
526 break
526 break
527 def condfn():
527 def condfn():
528 return not os.path.exists(lockpath)
528 return not os.path.exists(lockpath)
529 pid = util.rundetached(runargs, condfn)
529 pid = util.rundetached(runargs, condfn)
530 if pid < 0:
530 if pid < 0:
531 raise util.Abort(_('child process failed to start'))
531 raise util.Abort(_('child process failed to start'))
532 writepid(pid)
532 writepid(pid)
533 finally:
533 finally:
534 try:
534 try:
535 os.unlink(lockpath)
535 os.unlink(lockpath)
536 except OSError, e:
536 except OSError, e:
537 if e.errno != errno.ENOENT:
537 if e.errno != errno.ENOENT:
538 raise
538 raise
539 if parentfn:
539 if parentfn:
540 return parentfn(pid)
540 return parentfn(pid)
541 else:
541 else:
542 return
542 return
543
543
544 if initfn:
544 if initfn:
545 initfn()
545 initfn()
546
546
547 if not opts['daemon']:
547 if not opts['daemon']:
548 writepid(os.getpid())
548 writepid(os.getpid())
549
549
550 if opts['daemon_pipefds']:
550 if opts['daemon_pipefds']:
551 lockpath = opts['daemon_pipefds']
551 lockpath = opts['daemon_pipefds']
552 try:
552 try:
553 os.setsid()
553 os.setsid()
554 except AttributeError:
554 except AttributeError:
555 pass
555 pass
556 os.unlink(lockpath)
556 os.unlink(lockpath)
557 util.hidewindow()
557 util.hidewindow()
558 sys.stdout.flush()
558 sys.stdout.flush()
559 sys.stderr.flush()
559 sys.stderr.flush()
560
560
561 nullfd = os.open(os.devnull, os.O_RDWR)
561 nullfd = os.open(os.devnull, os.O_RDWR)
562 logfilefd = nullfd
562 logfilefd = nullfd
563 if logfile:
563 if logfile:
564 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
564 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
565 os.dup2(nullfd, 0)
565 os.dup2(nullfd, 0)
566 os.dup2(logfilefd, 1)
566 os.dup2(logfilefd, 1)
567 os.dup2(logfilefd, 2)
567 os.dup2(logfilefd, 2)
568 if nullfd not in (0, 1, 2):
568 if nullfd not in (0, 1, 2):
569 os.close(nullfd)
569 os.close(nullfd)
570 if logfile and logfilefd not in (0, 1, 2):
570 if logfile and logfilefd not in (0, 1, 2):
571 os.close(logfilefd)
571 os.close(logfilefd)
572
572
573 if runfn:
573 if runfn:
574 return runfn()
574 return runfn()
575
575
576 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
576 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
577 """Utility function used by commands.import to import a single patch
577 """Utility function used by commands.import to import a single patch
578
578
579 This function is explicitly defined here to help the evolve extension to
579 This function is explicitly defined here to help the evolve extension to
580 wrap this part of the import logic.
580 wrap this part of the import logic.
581
581
582 The API is currently a bit ugly because it a simple code translation from
582 The API is currently a bit ugly because it a simple code translation from
583 the import command. Feel free to make it better.
583 the import command. Feel free to make it better.
584
584
585 :hunk: a patch (as a binary string)
585 :hunk: a patch (as a binary string)
586 :parents: nodes that will be parent of the created commit
586 :parents: nodes that will be parent of the created commit
587 :opts: the full dict of option passed to the import command
587 :opts: the full dict of option passed to the import command
588 :msgs: list to save commit message to.
588 :msgs: list to save commit message to.
589 (used in case we need to save it when failing)
589 (used in case we need to save it when failing)
590 :updatefunc: a function that update a repo to a given node
590 :updatefunc: a function that update a repo to a given node
591 updatefunc(<repo>, <node>)
591 updatefunc(<repo>, <node>)
592 """
592 """
593 tmpname, message, user, date, branch, nodeid, p1, p2 = \
593 tmpname, message, user, date, branch, nodeid, p1, p2 = \
594 patch.extract(ui, hunk)
594 patch.extract(ui, hunk)
595
595
596 editor = getcommiteditor(editform='import.normal', **opts)
596 editor = getcommiteditor(editform='import.normal', **opts)
597 update = not opts.get('bypass')
597 update = not opts.get('bypass')
598 strip = opts["strip"]
598 strip = opts["strip"]
599 sim = float(opts.get('similarity') or 0)
599 sim = float(opts.get('similarity') or 0)
600 if not tmpname:
600 if not tmpname:
601 return (None, None, False)
601 return (None, None, False)
602 msg = _('applied to working directory')
602 msg = _('applied to working directory')
603
603
604 rejects = False
604 rejects = False
605
605
606 try:
606 try:
607 cmdline_message = logmessage(ui, opts)
607 cmdline_message = logmessage(ui, opts)
608 if cmdline_message:
608 if cmdline_message:
609 # pickup the cmdline msg
609 # pickup the cmdline msg
610 message = cmdline_message
610 message = cmdline_message
611 elif message:
611 elif message:
612 # pickup the patch msg
612 # pickup the patch msg
613 message = message.strip()
613 message = message.strip()
614 else:
614 else:
615 # launch the editor
615 # launch the editor
616 message = None
616 message = None
617 ui.debug('message:\n%s\n' % message)
617 ui.debug('message:\n%s\n' % message)
618
618
619 if len(parents) == 1:
619 if len(parents) == 1:
620 parents.append(repo[nullid])
620 parents.append(repo[nullid])
621 if opts.get('exact'):
621 if opts.get('exact'):
622 if not nodeid or not p1:
622 if not nodeid or not p1:
623 raise util.Abort(_('not a Mercurial patch'))
623 raise util.Abort(_('not a Mercurial patch'))
624 p1 = repo[p1]
624 p1 = repo[p1]
625 p2 = repo[p2 or nullid]
625 p2 = repo[p2 or nullid]
626 elif p2:
626 elif p2:
627 try:
627 try:
628 p1 = repo[p1]
628 p1 = repo[p1]
629 p2 = repo[p2]
629 p2 = repo[p2]
630 # Without any options, consider p2 only if the
630 # Without any options, consider p2 only if the
631 # patch is being applied on top of the recorded
631 # patch is being applied on top of the recorded
632 # first parent.
632 # first parent.
633 if p1 != parents[0]:
633 if p1 != parents[0]:
634 p1 = parents[0]
634 p1 = parents[0]
635 p2 = repo[nullid]
635 p2 = repo[nullid]
636 except error.RepoError:
636 except error.RepoError:
637 p1, p2 = parents
637 p1, p2 = parents
638 else:
638 else:
639 p1, p2 = parents
639 p1, p2 = parents
640
640
641 n = None
641 n = None
642 if update:
642 if update:
643 if p1 != parents[0]:
643 if p1 != parents[0]:
644 updatefunc(repo, p1.node())
644 updatefunc(repo, p1.node())
645 if p2 != parents[1]:
645 if p2 != parents[1]:
646 repo.setparents(p1.node(), p2.node())
646 repo.setparents(p1.node(), p2.node())
647
647
648 if opts.get('exact') or opts.get('import_branch'):
648 if opts.get('exact') or opts.get('import_branch'):
649 repo.dirstate.setbranch(branch or 'default')
649 repo.dirstate.setbranch(branch or 'default')
650
650
651 partial = opts.get('partial', False)
651 partial = opts.get('partial', False)
652 files = set()
652 files = set()
653 try:
653 try:
654 patch.patch(ui, repo, tmpname, strip=strip, files=files,
654 patch.patch(ui, repo, tmpname, strip=strip, files=files,
655 eolmode=None, similarity=sim / 100.0)
655 eolmode=None, similarity=sim / 100.0)
656 except patch.PatchError, e:
656 except patch.PatchError, e:
657 if not partial:
657 if not partial:
658 raise util.Abort(str(e))
658 raise util.Abort(str(e))
659 if partial:
659 if partial:
660 rejects = True
660 rejects = True
661
661
662 files = list(files)
662 files = list(files)
663 if opts.get('no_commit'):
663 if opts.get('no_commit'):
664 if message:
664 if message:
665 msgs.append(message)
665 msgs.append(message)
666 else:
666 else:
667 if opts.get('exact') or p2:
667 if opts.get('exact') or p2:
668 # If you got here, you either use --force and know what
668 # If you got here, you either use --force and know what
669 # you are doing or used --exact or a merge patch while
669 # you are doing or used --exact or a merge patch while
670 # being updated to its first parent.
670 # being updated to its first parent.
671 m = None
671 m = None
672 else:
672 else:
673 m = scmutil.matchfiles(repo, files or [])
673 m = scmutil.matchfiles(repo, files or [])
674 n = repo.commit(message, opts.get('user') or user,
674 n = repo.commit(message, opts.get('user') or user,
675 opts.get('date') or date, match=m,
675 opts.get('date') or date, match=m,
676 editor=editor, force=partial)
676 editor=editor, force=partial)
677 else:
677 else:
678 if opts.get('exact') or opts.get('import_branch'):
678 if opts.get('exact') or opts.get('import_branch'):
679 branch = branch or 'default'
679 branch = branch or 'default'
680 else:
680 else:
681 branch = p1.branch()
681 branch = p1.branch()
682 store = patch.filestore()
682 store = patch.filestore()
683 try:
683 try:
684 files = set()
684 files = set()
685 try:
685 try:
686 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
686 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
687 files, eolmode=None)
687 files, eolmode=None)
688 except patch.PatchError, e:
688 except patch.PatchError, e:
689 raise util.Abort(str(e))
689 raise util.Abort(str(e))
690 editor = getcommiteditor(editform='import.bypass')
690 editor = getcommiteditor(editform='import.bypass')
691 memctx = context.makememctx(repo, (p1.node(), p2.node()),
691 memctx = context.makememctx(repo, (p1.node(), p2.node()),
692 message,
692 message,
693 opts.get('user') or user,
693 opts.get('user') or user,
694 opts.get('date') or date,
694 opts.get('date') or date,
695 branch, files, store,
695 branch, files, store,
696 editor=editor)
696 editor=editor)
697 n = memctx.commit()
697 n = memctx.commit()
698 finally:
698 finally:
699 store.close()
699 store.close()
700 if opts.get('exact') and hex(n) != nodeid:
700 if opts.get('exact') and hex(n) != nodeid:
701 raise util.Abort(_('patch is damaged or loses information'))
701 raise util.Abort(_('patch is damaged or loses information'))
702 if n:
702 if n:
703 # i18n: refers to a short changeset id
703 # i18n: refers to a short changeset id
704 msg = _('created %s') % short(n)
704 msg = _('created %s') % short(n)
705 return (msg, n, rejects)
705 return (msg, n, rejects)
706 finally:
706 finally:
707 os.unlink(tmpname)
707 os.unlink(tmpname)
708
708
709 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
709 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
710 opts=None):
710 opts=None):
711 '''export changesets as hg patches.'''
711 '''export changesets as hg patches.'''
712
712
713 total = len(revs)
713 total = len(revs)
714 revwidth = max([len(str(rev)) for rev in revs])
714 revwidth = max([len(str(rev)) for rev in revs])
715 filemode = {}
715 filemode = {}
716
716
717 def single(rev, seqno, fp):
717 def single(rev, seqno, fp):
718 ctx = repo[rev]
718 ctx = repo[rev]
719 node = ctx.node()
719 node = ctx.node()
720 parents = [p.node() for p in ctx.parents() if p]
720 parents = [p.node() for p in ctx.parents() if p]
721 branch = ctx.branch()
721 branch = ctx.branch()
722 if switch_parent:
722 if switch_parent:
723 parents.reverse()
723 parents.reverse()
724 prev = (parents and parents[0]) or nullid
724 prev = (parents and parents[0]) or nullid
725
725
726 shouldclose = False
726 shouldclose = False
727 if not fp and len(template) > 0:
727 if not fp and len(template) > 0:
728 desc_lines = ctx.description().rstrip().split('\n')
728 desc_lines = ctx.description().rstrip().split('\n')
729 desc = desc_lines[0] #Commit always has a first line.
729 desc = desc_lines[0] #Commit always has a first line.
730 fp = makefileobj(repo, template, node, desc=desc, total=total,
730 fp = makefileobj(repo, template, node, desc=desc, total=total,
731 seqno=seqno, revwidth=revwidth, mode='wb',
731 seqno=seqno, revwidth=revwidth, mode='wb',
732 modemap=filemode)
732 modemap=filemode)
733 if fp != template:
733 if fp != template:
734 shouldclose = True
734 shouldclose = True
735 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
735 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
736 repo.ui.note("%s\n" % fp.name)
736 repo.ui.note("%s\n" % fp.name)
737
737
738 if not fp:
738 if not fp:
739 write = repo.ui.write
739 write = repo.ui.write
740 else:
740 else:
741 def write(s, **kw):
741 def write(s, **kw):
742 fp.write(s)
742 fp.write(s)
743
743
744
744
745 write("# HG changeset patch\n")
745 write("# HG changeset patch\n")
746 write("# User %s\n" % ctx.user())
746 write("# User %s\n" % ctx.user())
747 write("# Date %d %d\n" % ctx.date())
747 write("# Date %d %d\n" % ctx.date())
748 write("# %s\n" % util.datestr(ctx.date()))
748 write("# %s\n" % util.datestr(ctx.date()))
749 if branch and branch != 'default':
749 if branch and branch != 'default':
750 write("# Branch %s\n" % branch)
750 write("# Branch %s\n" % branch)
751 write("# Node ID %s\n" % hex(node))
751 write("# Node ID %s\n" % hex(node))
752 write("# Parent %s\n" % hex(prev))
752 write("# Parent %s\n" % hex(prev))
753 if len(parents) > 1:
753 if len(parents) > 1:
754 write("# Parent %s\n" % hex(parents[1]))
754 write("# Parent %s\n" % hex(parents[1]))
755 write(ctx.description().rstrip())
755 write(ctx.description().rstrip())
756 write("\n\n")
756 write("\n\n")
757
757
758 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
758 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
759 write(chunk, label=label)
759 write(chunk, label=label)
760
760
761 if shouldclose:
761 if shouldclose:
762 fp.close()
762 fp.close()
763
763
764 for seqno, rev in enumerate(revs):
764 for seqno, rev in enumerate(revs):
765 single(rev, seqno + 1, fp)
765 single(rev, seqno + 1, fp)
766
766
767 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
767 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
768 changes=None, stat=False, fp=None, prefix='',
768 changes=None, stat=False, fp=None, prefix='',
769 listsubrepos=False):
769 listsubrepos=False):
770 '''show diff or diffstat.'''
770 '''show diff or diffstat.'''
771 if fp is None:
771 if fp is None:
772 write = ui.write
772 write = ui.write
773 else:
773 else:
774 def write(s, **kw):
774 def write(s, **kw):
775 fp.write(s)
775 fp.write(s)
776
776
777 if stat:
777 if stat:
778 diffopts = diffopts.copy(context=0)
778 diffopts = diffopts.copy(context=0)
779 width = 80
779 width = 80
780 if not ui.plain():
780 if not ui.plain():
781 width = ui.termwidth()
781 width = ui.termwidth()
782 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
782 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
783 prefix=prefix)
783 prefix=prefix)
784 for chunk, label in patch.diffstatui(util.iterlines(chunks),
784 for chunk, label in patch.diffstatui(util.iterlines(chunks),
785 width=width,
785 width=width,
786 git=diffopts.git):
786 git=diffopts.git):
787 write(chunk, label=label)
787 write(chunk, label=label)
788 else:
788 else:
789 for chunk, label in patch.diffui(repo, node1, node2, match,
789 for chunk, label in patch.diffui(repo, node1, node2, match,
790 changes, diffopts, prefix=prefix):
790 changes, diffopts, prefix=prefix):
791 write(chunk, label=label)
791 write(chunk, label=label)
792
792
793 if listsubrepos:
793 if listsubrepos:
794 ctx1 = repo[node1]
794 ctx1 = repo[node1]
795 ctx2 = repo[node2]
795 ctx2 = repo[node2]
796 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
796 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
797 tempnode2 = node2
797 tempnode2 = node2
798 try:
798 try:
799 if node2 is not None:
799 if node2 is not None:
800 tempnode2 = ctx2.substate[subpath][1]
800 tempnode2 = ctx2.substate[subpath][1]
801 except KeyError:
801 except KeyError:
802 # A subrepo that existed in node1 was deleted between node1 and
802 # A subrepo that existed in node1 was deleted between node1 and
803 # node2 (inclusive). Thus, ctx2's substate won't contain that
803 # node2 (inclusive). Thus, ctx2's substate won't contain that
804 # subpath. The best we can do is to ignore it.
804 # subpath. The best we can do is to ignore it.
805 tempnode2 = None
805 tempnode2 = None
806 submatch = matchmod.narrowmatcher(subpath, match)
806 submatch = matchmod.narrowmatcher(subpath, match)
807 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
807 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
808 stat=stat, fp=fp, prefix=prefix)
808 stat=stat, fp=fp, prefix=prefix)
809
809
810 class changeset_printer(object):
810 class changeset_printer(object):
811 '''show changeset information when templating not requested.'''
811 '''show changeset information when templating not requested.'''
812
812
813 def __init__(self, ui, repo, patch, diffopts, buffered):
813 def __init__(self, ui, repo, patch, diffopts, buffered):
814 self.ui = ui
814 self.ui = ui
815 self.repo = repo
815 self.repo = repo
816 self.buffered = buffered
816 self.buffered = buffered
817 self.patch = patch
817 self.patch = patch
818 self.diffopts = diffopts
818 self.diffopts = diffopts
819 self.header = {}
819 self.header = {}
820 self.hunk = {}
820 self.hunk = {}
821 self.lastheader = None
821 self.lastheader = None
822 self.footer = None
822 self.footer = None
823
823
824 def flush(self, rev):
824 def flush(self, rev):
825 if rev in self.header:
825 if rev in self.header:
826 h = self.header[rev]
826 h = self.header[rev]
827 if h != self.lastheader:
827 if h != self.lastheader:
828 self.lastheader = h
828 self.lastheader = h
829 self.ui.write(h)
829 self.ui.write(h)
830 del self.header[rev]
830 del self.header[rev]
831 if rev in self.hunk:
831 if rev in self.hunk:
832 self.ui.write(self.hunk[rev])
832 self.ui.write(self.hunk[rev])
833 del self.hunk[rev]
833 del self.hunk[rev]
834 return 1
834 return 1
835 return 0
835 return 0
836
836
837 def close(self):
837 def close(self):
838 if self.footer:
838 if self.footer:
839 self.ui.write(self.footer)
839 self.ui.write(self.footer)
840
840
841 def show(self, ctx, copies=None, matchfn=None, **props):
841 def show(self, ctx, copies=None, matchfn=None, **props):
842 if self.buffered:
842 if self.buffered:
843 self.ui.pushbuffer()
843 self.ui.pushbuffer()
844 self._show(ctx, copies, matchfn, props)
844 self._show(ctx, copies, matchfn, props)
845 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
845 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
846 else:
846 else:
847 self._show(ctx, copies, matchfn, props)
847 self._show(ctx, copies, matchfn, props)
848
848
849 def _show(self, ctx, copies, matchfn, props):
849 def _show(self, ctx, copies, matchfn, props):
850 '''show a single changeset or file revision'''
850 '''show a single changeset or file revision'''
851 changenode = ctx.node()
851 changenode = ctx.node()
852 rev = ctx.rev()
852 rev = ctx.rev()
853
853
854 if self.ui.quiet:
854 if self.ui.quiet:
855 self.ui.write("%d:%s\n" % (rev, short(changenode)),
855 self.ui.write("%d:%s\n" % (rev, short(changenode)),
856 label='log.node')
856 label='log.node')
857 return
857 return
858
858
859 log = self.repo.changelog
859 log = self.repo.changelog
860 date = util.datestr(ctx.date())
860 date = util.datestr(ctx.date())
861
861
862 hexfunc = self.ui.debugflag and hex or short
862 hexfunc = self.ui.debugflag and hex or short
863
863
864 parents = [(p, hexfunc(log.node(p)))
864 parents = [(p, hexfunc(log.node(p)))
865 for p in self._meaningful_parentrevs(log, rev)]
865 for p in self._meaningful_parentrevs(log, rev)]
866
866
867 # i18n: column positioning for "hg log"
867 # i18n: column positioning for "hg log"
868 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
868 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
869 label='log.changeset changeset.%s' % ctx.phasestr())
869 label='log.changeset changeset.%s' % ctx.phasestr())
870
870
871 branch = ctx.branch()
871 branch = ctx.branch()
872 # don't show the default branch name
872 # don't show the default branch name
873 if branch != 'default':
873 if branch != 'default':
874 # i18n: column positioning for "hg log"
874 # i18n: column positioning for "hg log"
875 self.ui.write(_("branch: %s\n") % branch,
875 self.ui.write(_("branch: %s\n") % branch,
876 label='log.branch')
876 label='log.branch')
877 for bookmark in self.repo.nodebookmarks(changenode):
877 for bookmark in self.repo.nodebookmarks(changenode):
878 # i18n: column positioning for "hg log"
878 # i18n: column positioning for "hg log"
879 self.ui.write(_("bookmark: %s\n") % bookmark,
879 self.ui.write(_("bookmark: %s\n") % bookmark,
880 label='log.bookmark')
880 label='log.bookmark')
881 for tag in self.repo.nodetags(changenode):
881 for tag in self.repo.nodetags(changenode):
882 # i18n: column positioning for "hg log"
882 # i18n: column positioning for "hg log"
883 self.ui.write(_("tag: %s\n") % tag,
883 self.ui.write(_("tag: %s\n") % tag,
884 label='log.tag')
884 label='log.tag')
885 if self.ui.debugflag and ctx.phase():
885 if self.ui.debugflag and ctx.phase():
886 # i18n: column positioning for "hg log"
886 # i18n: column positioning for "hg log"
887 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
887 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
888 label='log.phase')
888 label='log.phase')
889 for parent in parents:
889 for parent in parents:
890 # i18n: column positioning for "hg log"
890 # i18n: column positioning for "hg log"
891 self.ui.write(_("parent: %d:%s\n") % parent,
891 self.ui.write(_("parent: %d:%s\n") % parent,
892 label='log.parent changeset.%s' % ctx.phasestr())
892 label='log.parent changeset.%s' % ctx.phasestr())
893
893
894 if self.ui.debugflag:
894 if self.ui.debugflag:
895 mnode = ctx.manifestnode()
895 mnode = ctx.manifestnode()
896 # i18n: column positioning for "hg log"
896 # i18n: column positioning for "hg log"
897 self.ui.write(_("manifest: %d:%s\n") %
897 self.ui.write(_("manifest: %d:%s\n") %
898 (self.repo.manifest.rev(mnode), hex(mnode)),
898 (self.repo.manifest.rev(mnode), hex(mnode)),
899 label='ui.debug log.manifest')
899 label='ui.debug log.manifest')
900 # i18n: column positioning for "hg log"
900 # i18n: column positioning for "hg log"
901 self.ui.write(_("user: %s\n") % ctx.user(),
901 self.ui.write(_("user: %s\n") % ctx.user(),
902 label='log.user')
902 label='log.user')
903 # i18n: column positioning for "hg log"
903 # i18n: column positioning for "hg log"
904 self.ui.write(_("date: %s\n") % date,
904 self.ui.write(_("date: %s\n") % date,
905 label='log.date')
905 label='log.date')
906
906
907 if self.ui.debugflag:
907 if self.ui.debugflag:
908 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
908 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
909 for key, value in zip([# i18n: column positioning for "hg log"
909 for key, value in zip([# i18n: column positioning for "hg log"
910 _("files:"),
910 _("files:"),
911 # i18n: column positioning for "hg log"
911 # i18n: column positioning for "hg log"
912 _("files+:"),
912 _("files+:"),
913 # i18n: column positioning for "hg log"
913 # i18n: column positioning for "hg log"
914 _("files-:")], files):
914 _("files-:")], files):
915 if value:
915 if value:
916 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
916 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
917 label='ui.debug log.files')
917 label='ui.debug log.files')
918 elif ctx.files() and self.ui.verbose:
918 elif ctx.files() and self.ui.verbose:
919 # i18n: column positioning for "hg log"
919 # i18n: column positioning for "hg log"
920 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
920 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
921 label='ui.note log.files')
921 label='ui.note log.files')
922 if copies and self.ui.verbose:
922 if copies and self.ui.verbose:
923 copies = ['%s (%s)' % c for c in copies]
923 copies = ['%s (%s)' % c for c in copies]
924 # i18n: column positioning for "hg log"
924 # i18n: column positioning for "hg log"
925 self.ui.write(_("copies: %s\n") % ' '.join(copies),
925 self.ui.write(_("copies: %s\n") % ' '.join(copies),
926 label='ui.note log.copies')
926 label='ui.note log.copies')
927
927
928 extra = ctx.extra()
928 extra = ctx.extra()
929 if extra and self.ui.debugflag:
929 if extra and self.ui.debugflag:
930 for key, value in sorted(extra.items()):
930 for key, value in sorted(extra.items()):
931 # i18n: column positioning for "hg log"
931 # i18n: column positioning for "hg log"
932 self.ui.write(_("extra: %s=%s\n")
932 self.ui.write(_("extra: %s=%s\n")
933 % (key, value.encode('string_escape')),
933 % (key, value.encode('string_escape')),
934 label='ui.debug log.extra')
934 label='ui.debug log.extra')
935
935
936 description = ctx.description().strip()
936 description = ctx.description().strip()
937 if description:
937 if description:
938 if self.ui.verbose:
938 if self.ui.verbose:
939 self.ui.write(_("description:\n"),
939 self.ui.write(_("description:\n"),
940 label='ui.note log.description')
940 label='ui.note log.description')
941 self.ui.write(description,
941 self.ui.write(description,
942 label='ui.note log.description')
942 label='ui.note log.description')
943 self.ui.write("\n\n")
943 self.ui.write("\n\n")
944 else:
944 else:
945 # i18n: column positioning for "hg log"
945 # i18n: column positioning for "hg log"
946 self.ui.write(_("summary: %s\n") %
946 self.ui.write(_("summary: %s\n") %
947 description.splitlines()[0],
947 description.splitlines()[0],
948 label='log.summary')
948 label='log.summary')
949 self.ui.write("\n")
949 self.ui.write("\n")
950
950
951 self.showpatch(changenode, matchfn)
951 self.showpatch(changenode, matchfn)
952
952
953 def showpatch(self, node, matchfn):
953 def showpatch(self, node, matchfn):
954 if not matchfn:
954 if not matchfn:
955 matchfn = self.patch
955 matchfn = self.patch
956 if matchfn:
956 if matchfn:
957 stat = self.diffopts.get('stat')
957 stat = self.diffopts.get('stat')
958 diff = self.diffopts.get('patch')
958 diff = self.diffopts.get('patch')
959 diffopts = patch.diffopts(self.ui, self.diffopts)
959 diffopts = patch.diffopts(self.ui, self.diffopts)
960 prev = self.repo.changelog.parents(node)[0]
960 prev = self.repo.changelog.parents(node)[0]
961 if stat:
961 if stat:
962 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
962 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
963 match=matchfn, stat=True)
963 match=matchfn, stat=True)
964 if diff:
964 if diff:
965 if stat:
965 if stat:
966 self.ui.write("\n")
966 self.ui.write("\n")
967 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
967 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
968 match=matchfn, stat=False)
968 match=matchfn, stat=False)
969 self.ui.write("\n")
969 self.ui.write("\n")
970
970
971 def _meaningful_parentrevs(self, log, rev):
971 def _meaningful_parentrevs(self, log, rev):
972 """Return list of meaningful (or all if debug) parentrevs for rev.
972 """Return list of meaningful (or all if debug) parentrevs for rev.
973
973
974 For merges (two non-nullrev revisions) both parents are meaningful.
974 For merges (two non-nullrev revisions) both parents are meaningful.
975 Otherwise the first parent revision is considered meaningful if it
975 Otherwise the first parent revision is considered meaningful if it
976 is not the preceding revision.
976 is not the preceding revision.
977 """
977 """
978 parents = log.parentrevs(rev)
978 parents = log.parentrevs(rev)
979 if not self.ui.debugflag and parents[1] == nullrev:
979 if not self.ui.debugflag and parents[1] == nullrev:
980 if parents[0] >= rev - 1:
980 if parents[0] >= rev - 1:
981 parents = []
981 parents = []
982 else:
982 else:
983 parents = [parents[0]]
983 parents = [parents[0]]
984 return parents
984 return parents
985
985
986
986
987 class changeset_templater(changeset_printer):
987 class changeset_templater(changeset_printer):
988 '''format changeset information.'''
988 '''format changeset information.'''
989
989
990 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
990 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
991 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
991 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
992 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
992 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
993 defaulttempl = {
993 defaulttempl = {
994 'parent': '{rev}:{node|formatnode} ',
994 'parent': '{rev}:{node|formatnode} ',
995 'manifest': '{rev}:{node|formatnode}',
995 'manifest': '{rev}:{node|formatnode}',
996 'file_copy': '{name} ({source})',
996 'file_copy': '{name} ({source})',
997 'extra': '{key}={value|stringescape}'
997 'extra': '{key}={value|stringescape}'
998 }
998 }
999 # filecopy is preserved for compatibility reasons
999 # filecopy is preserved for compatibility reasons
1000 defaulttempl['filecopy'] = defaulttempl['file_copy']
1000 defaulttempl['filecopy'] = defaulttempl['file_copy']
1001 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1001 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1002 cache=defaulttempl)
1002 cache=defaulttempl)
1003 if tmpl:
1003 if tmpl:
1004 self.t.cache['changeset'] = tmpl
1004 self.t.cache['changeset'] = tmpl
1005
1005
1006 self.cache = {}
1006 self.cache = {}
1007
1007
1008 def _meaningful_parentrevs(self, ctx):
1008 def _meaningful_parentrevs(self, ctx):
1009 """Return list of meaningful (or all if debug) parentrevs for rev.
1009 """Return list of meaningful (or all if debug) parentrevs for rev.
1010 """
1010 """
1011 parents = ctx.parents()
1011 parents = ctx.parents()
1012 if len(parents) > 1:
1012 if len(parents) > 1:
1013 return parents
1013 return parents
1014 if self.ui.debugflag:
1014 if self.ui.debugflag:
1015 return [parents[0], self.repo['null']]
1015 return [parents[0], self.repo['null']]
1016 if parents[0].rev() >= ctx.rev() - 1:
1016 if parents[0].rev() >= ctx.rev() - 1:
1017 return []
1017 return []
1018 return parents
1018 return parents
1019
1019
1020 def _show(self, ctx, copies, matchfn, props):
1020 def _show(self, ctx, copies, matchfn, props):
1021 '''show a single changeset or file revision'''
1021 '''show a single changeset or file revision'''
1022
1022
1023 showlist = templatekw.showlist
1023 showlist = templatekw.showlist
1024
1024
1025 # showparents() behaviour depends on ui trace level which
1025 # showparents() behaviour depends on ui trace level which
1026 # causes unexpected behaviours at templating level and makes
1026 # causes unexpected behaviours at templating level and makes
1027 # it harder to extract it in a standalone function. Its
1027 # it harder to extract it in a standalone function. Its
1028 # behaviour cannot be changed so leave it here for now.
1028 # behaviour cannot be changed so leave it here for now.
1029 def showparents(**args):
1029 def showparents(**args):
1030 ctx = args['ctx']
1030 ctx = args['ctx']
1031 parents = [[('rev', p.rev()), ('node', p.hex())]
1031 parents = [[('rev', p.rev()), ('node', p.hex())]
1032 for p in self._meaningful_parentrevs(ctx)]
1032 for p in self._meaningful_parentrevs(ctx)]
1033 return showlist('parent', parents, **args)
1033 return showlist('parent', parents, **args)
1034
1034
1035 props = props.copy()
1035 props = props.copy()
1036 props.update(templatekw.keywords)
1036 props.update(templatekw.keywords)
1037 props['parents'] = showparents
1037 props['parents'] = showparents
1038 props['templ'] = self.t
1038 props['templ'] = self.t
1039 props['ctx'] = ctx
1039 props['ctx'] = ctx
1040 props['repo'] = self.repo
1040 props['repo'] = self.repo
1041 props['revcache'] = {'copies': copies}
1041 props['revcache'] = {'copies': copies}
1042 props['cache'] = self.cache
1042 props['cache'] = self.cache
1043
1043
1044 # find correct templates for current mode
1044 # find correct templates for current mode
1045
1045
1046 tmplmodes = [
1046 tmplmodes = [
1047 (True, None),
1047 (True, None),
1048 (self.ui.verbose, 'verbose'),
1048 (self.ui.verbose, 'verbose'),
1049 (self.ui.quiet, 'quiet'),
1049 (self.ui.quiet, 'quiet'),
1050 (self.ui.debugflag, 'debug'),
1050 (self.ui.debugflag, 'debug'),
1051 ]
1051 ]
1052
1052
1053 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1053 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1054 for mode, postfix in tmplmodes:
1054 for mode, postfix in tmplmodes:
1055 for type in types:
1055 for type in types:
1056 cur = postfix and ('%s_%s' % (type, postfix)) or type
1056 cur = postfix and ('%s_%s' % (type, postfix)) or type
1057 if mode and cur in self.t:
1057 if mode and cur in self.t:
1058 types[type] = cur
1058 types[type] = cur
1059
1059
1060 try:
1060 try:
1061
1061
1062 # write header
1062 # write header
1063 if types['header']:
1063 if types['header']:
1064 h = templater.stringify(self.t(types['header'], **props))
1064 h = templater.stringify(self.t(types['header'], **props))
1065 if self.buffered:
1065 if self.buffered:
1066 self.header[ctx.rev()] = h
1066 self.header[ctx.rev()] = h
1067 else:
1067 else:
1068 if self.lastheader != h:
1068 if self.lastheader != h:
1069 self.lastheader = h
1069 self.lastheader = h
1070 self.ui.write(h)
1070 self.ui.write(h)
1071
1071
1072 # write changeset metadata, then patch if requested
1072 # write changeset metadata, then patch if requested
1073 key = types['changeset']
1073 key = types['changeset']
1074 self.ui.write(templater.stringify(self.t(key, **props)))
1074 self.ui.write(templater.stringify(self.t(key, **props)))
1075 self.showpatch(ctx.node(), matchfn)
1075 self.showpatch(ctx.node(), matchfn)
1076
1076
1077 if types['footer']:
1077 if types['footer']:
1078 if not self.footer:
1078 if not self.footer:
1079 self.footer = templater.stringify(self.t(types['footer'],
1079 self.footer = templater.stringify(self.t(types['footer'],
1080 **props))
1080 **props))
1081
1081
1082 except KeyError, inst:
1082 except KeyError, inst:
1083 msg = _("%s: no key named '%s'")
1083 msg = _("%s: no key named '%s'")
1084 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1084 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1085 except SyntaxError, inst:
1085 except SyntaxError, inst:
1086 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1086 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1087
1087
1088 def gettemplate(ui, tmpl, style):
1088 def gettemplate(ui, tmpl, style):
1089 """
1089 """
1090 Find the template matching the given template spec or style.
1090 Find the template matching the given template spec or style.
1091 """
1091 """
1092
1092
1093 # ui settings
1093 # ui settings
1094 if not tmpl and not style:
1094 if not tmpl and not style:
1095 tmpl = ui.config('ui', 'logtemplate')
1095 tmpl = ui.config('ui', 'logtemplate')
1096 if tmpl:
1096 if tmpl:
1097 try:
1097 try:
1098 tmpl = templater.parsestring(tmpl)
1098 tmpl = templater.parsestring(tmpl)
1099 except SyntaxError:
1099 except SyntaxError:
1100 tmpl = templater.parsestring(tmpl, quoted=False)
1100 tmpl = templater.parsestring(tmpl, quoted=False)
1101 return tmpl, None
1101 return tmpl, None
1102 else:
1102 else:
1103 style = util.expandpath(ui.config('ui', 'style', ''))
1103 style = util.expandpath(ui.config('ui', 'style', ''))
1104
1104
1105 if style:
1105 if style:
1106 mapfile = style
1106 mapfile = style
1107 if not os.path.split(mapfile)[0]:
1107 if not os.path.split(mapfile)[0]:
1108 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1108 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1109 or templater.templatepath(mapfile))
1109 or templater.templatepath(mapfile))
1110 if mapname:
1110 if mapname:
1111 mapfile = mapname
1111 mapfile = mapname
1112 return None, mapfile
1112 return None, mapfile
1113
1113
1114 if not tmpl:
1114 if not tmpl:
1115 return None, None
1115 return None, None
1116
1116
1117 # looks like a literal template?
1117 # looks like a literal template?
1118 if '{' in tmpl:
1118 if '{' in tmpl:
1119 return tmpl, None
1119 return tmpl, None
1120
1120
1121 # perhaps a stock style?
1121 # perhaps a stock style?
1122 if not os.path.split(tmpl)[0]:
1122 if not os.path.split(tmpl)[0]:
1123 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1123 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1124 or templater.templatepath(tmpl))
1124 or templater.templatepath(tmpl))
1125 if mapname and os.path.isfile(mapname):
1125 if mapname and os.path.isfile(mapname):
1126 return None, mapname
1126 return None, mapname
1127
1127
1128 # perhaps it's a reference to [templates]
1128 # perhaps it's a reference to [templates]
1129 t = ui.config('templates', tmpl)
1129 t = ui.config('templates', tmpl)
1130 if t:
1130 if t:
1131 try:
1131 try:
1132 tmpl = templater.parsestring(t)
1132 tmpl = templater.parsestring(t)
1133 except SyntaxError:
1133 except SyntaxError:
1134 tmpl = templater.parsestring(t, quoted=False)
1134 tmpl = templater.parsestring(t, quoted=False)
1135 return tmpl, None
1135 return tmpl, None
1136
1136
1137 if tmpl == 'list':
1137 if tmpl == 'list':
1138 ui.write(_("available styles: %s\n") % templater.stylelist())
1138 ui.write(_("available styles: %s\n") % templater.stylelist())
1139 raise util.Abort(_("specify a template"))
1139 raise util.Abort(_("specify a template"))
1140
1140
1141 # perhaps it's a path to a map or a template
1141 # perhaps it's a path to a map or a template
1142 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1142 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1143 # is it a mapfile for a style?
1143 # is it a mapfile for a style?
1144 if os.path.basename(tmpl).startswith("map-"):
1144 if os.path.basename(tmpl).startswith("map-"):
1145 return None, os.path.realpath(tmpl)
1145 return None, os.path.realpath(tmpl)
1146 tmpl = open(tmpl).read()
1146 tmpl = open(tmpl).read()
1147 return tmpl, None
1147 return tmpl, None
1148
1148
1149 # constant string?
1149 # constant string?
1150 return tmpl, None
1150 return tmpl, None
1151
1151
1152 def show_changeset(ui, repo, opts, buffered=False):
1152 def show_changeset(ui, repo, opts, buffered=False):
1153 """show one changeset using template or regular display.
1153 """show one changeset using template or regular display.
1154
1154
1155 Display format will be the first non-empty hit of:
1155 Display format will be the first non-empty hit of:
1156 1. option 'template'
1156 1. option 'template'
1157 2. option 'style'
1157 2. option 'style'
1158 3. [ui] setting 'logtemplate'
1158 3. [ui] setting 'logtemplate'
1159 4. [ui] setting 'style'
1159 4. [ui] setting 'style'
1160 If all of these values are either the unset or the empty string,
1160 If all of these values are either the unset or the empty string,
1161 regular display via changeset_printer() is done.
1161 regular display via changeset_printer() is done.
1162 """
1162 """
1163 # options
1163 # options
1164 patch = None
1164 patch = None
1165 if opts.get('patch') or opts.get('stat'):
1165 if opts.get('patch') or opts.get('stat'):
1166 patch = scmutil.matchall(repo)
1166 patch = scmutil.matchall(repo)
1167
1167
1168 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1168 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1169
1169
1170 if not tmpl and not mapfile:
1170 if not tmpl and not mapfile:
1171 return changeset_printer(ui, repo, patch, opts, buffered)
1171 return changeset_printer(ui, repo, patch, opts, buffered)
1172
1172
1173 try:
1173 try:
1174 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1174 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1175 except SyntaxError, inst:
1175 except SyntaxError, inst:
1176 raise util.Abort(inst.args[0])
1176 raise util.Abort(inst.args[0])
1177 return t
1177 return t
1178
1178
1179 def showmarker(ui, marker):
1179 def showmarker(ui, marker):
1180 """utility function to display obsolescence marker in a readable way
1180 """utility function to display obsolescence marker in a readable way
1181
1181
1182 To be used by debug function."""
1182 To be used by debug function."""
1183 ui.write(hex(marker.precnode()))
1183 ui.write(hex(marker.precnode()))
1184 for repl in marker.succnodes():
1184 for repl in marker.succnodes():
1185 ui.write(' ')
1185 ui.write(' ')
1186 ui.write(hex(repl))
1186 ui.write(hex(repl))
1187 ui.write(' %X ' % marker._data[2])
1187 ui.write(' %X ' % marker._data[2])
1188 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1188 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1189 sorted(marker.metadata().items()))))
1189 sorted(marker.metadata().items()))))
1190 ui.write('\n')
1190 ui.write('\n')
1191
1191
1192 def finddate(ui, repo, date):
1192 def finddate(ui, repo, date):
1193 """Find the tipmost changeset that matches the given date spec"""
1193 """Find the tipmost changeset that matches the given date spec"""
1194
1194
1195 df = util.matchdate(date)
1195 df = util.matchdate(date)
1196 m = scmutil.matchall(repo)
1196 m = scmutil.matchall(repo)
1197 results = {}
1197 results = {}
1198
1198
1199 def prep(ctx, fns):
1199 def prep(ctx, fns):
1200 d = ctx.date()
1200 d = ctx.date()
1201 if df(d[0]):
1201 if df(d[0]):
1202 results[ctx.rev()] = d
1202 results[ctx.rev()] = d
1203
1203
1204 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1204 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1205 rev = ctx.rev()
1205 rev = ctx.rev()
1206 if rev in results:
1206 if rev in results:
1207 ui.status(_("found revision %s from %s\n") %
1207 ui.status(_("found revision %s from %s\n") %
1208 (rev, util.datestr(results[rev])))
1208 (rev, util.datestr(results[rev])))
1209 return str(rev)
1209 return str(rev)
1210
1210
1211 raise util.Abort(_("revision matching date not found"))
1211 raise util.Abort(_("revision matching date not found"))
1212
1212
1213 def increasingwindows(windowsize=8, sizelimit=512):
1213 def increasingwindows(windowsize=8, sizelimit=512):
1214 while True:
1214 while True:
1215 yield windowsize
1215 yield windowsize
1216 if windowsize < sizelimit:
1216 if windowsize < sizelimit:
1217 windowsize *= 2
1217 windowsize *= 2
1218
1218
1219 class FileWalkError(Exception):
1219 class FileWalkError(Exception):
1220 pass
1220 pass
1221
1221
1222 def walkfilerevs(repo, match, follow, revs, fncache):
1222 def walkfilerevs(repo, match, follow, revs, fncache):
1223 '''Walks the file history for the matched files.
1223 '''Walks the file history for the matched files.
1224
1224
1225 Returns the changeset revs that are involved in the file history.
1225 Returns the changeset revs that are involved in the file history.
1226
1226
1227 Throws FileWalkError if the file history can't be walked using
1227 Throws FileWalkError if the file history can't be walked using
1228 filelogs alone.
1228 filelogs alone.
1229 '''
1229 '''
1230 wanted = set()
1230 wanted = set()
1231 copies = []
1231 copies = []
1232 minrev, maxrev = min(revs), max(revs)
1232 minrev, maxrev = min(revs), max(revs)
1233 def filerevgen(filelog, last):
1233 def filerevgen(filelog, last):
1234 """
1234 """
1235 Only files, no patterns. Check the history of each file.
1235 Only files, no patterns. Check the history of each file.
1236
1236
1237 Examines filelog entries within minrev, maxrev linkrev range
1237 Examines filelog entries within minrev, maxrev linkrev range
1238 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1238 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1239 tuples in backwards order
1239 tuples in backwards order
1240 """
1240 """
1241 cl_count = len(repo)
1241 cl_count = len(repo)
1242 revs = []
1242 revs = []
1243 for j in xrange(0, last + 1):
1243 for j in xrange(0, last + 1):
1244 linkrev = filelog.linkrev(j)
1244 linkrev = filelog.linkrev(j)
1245 if linkrev < minrev:
1245 if linkrev < minrev:
1246 continue
1246 continue
1247 # only yield rev for which we have the changelog, it can
1247 # only yield rev for which we have the changelog, it can
1248 # happen while doing "hg log" during a pull or commit
1248 # happen while doing "hg log" during a pull or commit
1249 if linkrev >= cl_count:
1249 if linkrev >= cl_count:
1250 break
1250 break
1251
1251
1252 parentlinkrevs = []
1252 parentlinkrevs = []
1253 for p in filelog.parentrevs(j):
1253 for p in filelog.parentrevs(j):
1254 if p != nullrev:
1254 if p != nullrev:
1255 parentlinkrevs.append(filelog.linkrev(p))
1255 parentlinkrevs.append(filelog.linkrev(p))
1256 n = filelog.node(j)
1256 n = filelog.node(j)
1257 revs.append((linkrev, parentlinkrevs,
1257 revs.append((linkrev, parentlinkrevs,
1258 follow and filelog.renamed(n)))
1258 follow and filelog.renamed(n)))
1259
1259
1260 return reversed(revs)
1260 return reversed(revs)
1261 def iterfiles():
1261 def iterfiles():
1262 pctx = repo['.']
1262 pctx = repo['.']
1263 for filename in match.files():
1263 for filename in match.files():
1264 if follow:
1264 if follow:
1265 if filename not in pctx:
1265 if filename not in pctx:
1266 raise util.Abort(_('cannot follow file not in parent '
1266 raise util.Abort(_('cannot follow file not in parent '
1267 'revision: "%s"') % filename)
1267 'revision: "%s"') % filename)
1268 yield filename, pctx[filename].filenode()
1268 yield filename, pctx[filename].filenode()
1269 else:
1269 else:
1270 yield filename, None
1270 yield filename, None
1271 for filename_node in copies:
1271 for filename_node in copies:
1272 yield filename_node
1272 yield filename_node
1273
1273
1274 for file_, node in iterfiles():
1274 for file_, node in iterfiles():
1275 filelog = repo.file(file_)
1275 filelog = repo.file(file_)
1276 if not len(filelog):
1276 if not len(filelog):
1277 if node is None:
1277 if node is None:
1278 # A zero count may be a directory or deleted file, so
1278 # A zero count may be a directory or deleted file, so
1279 # try to find matching entries on the slow path.
1279 # try to find matching entries on the slow path.
1280 if follow:
1280 if follow:
1281 raise util.Abort(
1281 raise util.Abort(
1282 _('cannot follow nonexistent file: "%s"') % file_)
1282 _('cannot follow nonexistent file: "%s"') % file_)
1283 raise FileWalkError("Cannot walk via filelog")
1283 raise FileWalkError("Cannot walk via filelog")
1284 else:
1284 else:
1285 continue
1285 continue
1286
1286
1287 if node is None:
1287 if node is None:
1288 last = len(filelog) - 1
1288 last = len(filelog) - 1
1289 else:
1289 else:
1290 last = filelog.rev(node)
1290 last = filelog.rev(node)
1291
1291
1292
1292
1293 # keep track of all ancestors of the file
1293 # keep track of all ancestors of the file
1294 ancestors = set([filelog.linkrev(last)])
1294 ancestors = set([filelog.linkrev(last)])
1295
1295
1296 # iterate from latest to oldest revision
1296 # iterate from latest to oldest revision
1297 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1297 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1298 if not follow:
1298 if not follow:
1299 if rev > maxrev:
1299 if rev > maxrev:
1300 continue
1300 continue
1301 else:
1301 else:
1302 # Note that last might not be the first interesting
1302 # Note that last might not be the first interesting
1303 # rev to us:
1303 # rev to us:
1304 # if the file has been changed after maxrev, we'll
1304 # if the file has been changed after maxrev, we'll
1305 # have linkrev(last) > maxrev, and we still need
1305 # have linkrev(last) > maxrev, and we still need
1306 # to explore the file graph
1306 # to explore the file graph
1307 if rev not in ancestors:
1307 if rev not in ancestors:
1308 continue
1308 continue
1309 # XXX insert 1327 fix here
1309 # XXX insert 1327 fix here
1310 if flparentlinkrevs:
1310 if flparentlinkrevs:
1311 ancestors.update(flparentlinkrevs)
1311 ancestors.update(flparentlinkrevs)
1312
1312
1313 fncache.setdefault(rev, []).append(file_)
1313 fncache.setdefault(rev, []).append(file_)
1314 wanted.add(rev)
1314 wanted.add(rev)
1315 if copied:
1315 if copied:
1316 copies.append(copied)
1316 copies.append(copied)
1317
1317
1318 return wanted
1318 return wanted
1319
1319
1320 def walkchangerevs(repo, match, opts, prepare):
1320 def walkchangerevs(repo, match, opts, prepare):
1321 '''Iterate over files and the revs in which they changed.
1321 '''Iterate over files and the revs in which they changed.
1322
1322
1323 Callers most commonly need to iterate backwards over the history
1323 Callers most commonly need to iterate backwards over the history
1324 in which they are interested. Doing so has awful (quadratic-looking)
1324 in which they are interested. Doing so has awful (quadratic-looking)
1325 performance, so we use iterators in a "windowed" way.
1325 performance, so we use iterators in a "windowed" way.
1326
1326
1327 We walk a window of revisions in the desired order. Within the
1327 We walk a window of revisions in the desired order. Within the
1328 window, we first walk forwards to gather data, then in the desired
1328 window, we first walk forwards to gather data, then in the desired
1329 order (usually backwards) to display it.
1329 order (usually backwards) to display it.
1330
1330
1331 This function returns an iterator yielding contexts. Before
1331 This function returns an iterator yielding contexts. Before
1332 yielding each context, the iterator will first call the prepare
1332 yielding each context, the iterator will first call the prepare
1333 function on each context in the window in forward order.'''
1333 function on each context in the window in forward order.'''
1334
1334
1335 follow = opts.get('follow') or opts.get('follow_first')
1335 follow = opts.get('follow') or opts.get('follow_first')
1336
1336
1337 if opts.get('rev'):
1337 if opts.get('rev'):
1338 revs = scmutil.revrange(repo, opts.get('rev'))
1338 revs = scmutil.revrange(repo, opts.get('rev'))
1339 elif follow:
1339 elif follow:
1340 revs = repo.revs('reverse(:.)')
1340 revs = repo.revs('reverse(:.)')
1341 else:
1341 else:
1342 revs = revset.spanset(repo)
1342 revs = revset.spanset(repo)
1343 revs.reverse()
1343 revs.reverse()
1344 if not revs:
1344 if not revs:
1345 return []
1345 return []
1346 wanted = set()
1346 wanted = set()
1347 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1347 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1348 fncache = {}
1348 fncache = {}
1349 change = repo.changectx
1349 change = repo.changectx
1350
1350
1351 # First step is to fill wanted, the set of revisions that we want to yield.
1351 # First step is to fill wanted, the set of revisions that we want to yield.
1352 # When it does not induce extra cost, we also fill fncache for revisions in
1352 # When it does not induce extra cost, we also fill fncache for revisions in
1353 # wanted: a cache of filenames that were changed (ctx.files()) and that
1353 # wanted: a cache of filenames that were changed (ctx.files()) and that
1354 # match the file filtering conditions.
1354 # match the file filtering conditions.
1355
1355
1356 if not slowpath and not match.files():
1356 if not slowpath and not match.files():
1357 # No files, no patterns. Display all revs.
1357 # No files, no patterns. Display all revs.
1358 wanted = revs
1358 wanted = revs
1359
1359
1360 if not slowpath and match.files():
1360 if not slowpath and match.files():
1361 # We only have to read through the filelog to find wanted revisions
1361 # We only have to read through the filelog to find wanted revisions
1362
1362
1363 try:
1363 try:
1364 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1364 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1365 except FileWalkError:
1365 except FileWalkError:
1366 slowpath = True
1366 slowpath = True
1367
1367
1368 # We decided to fall back to the slowpath because at least one
1368 # We decided to fall back to the slowpath because at least one
1369 # of the paths was not a file. Check to see if at least one of them
1369 # of the paths was not a file. Check to see if at least one of them
1370 # existed in history, otherwise simply return
1370 # existed in history, otherwise simply return
1371 for path in match.files():
1371 for path in match.files():
1372 if path == '.' or path in repo.store:
1372 if path == '.' or path in repo.store:
1373 break
1373 break
1374 else:
1374 else:
1375 return []
1375 return []
1376
1376
1377 if slowpath:
1377 if slowpath:
1378 # We have to read the changelog to match filenames against
1378 # We have to read the changelog to match filenames against
1379 # changed files
1379 # changed files
1380
1380
1381 if follow:
1381 if follow:
1382 raise util.Abort(_('can only follow copies/renames for explicit '
1382 raise util.Abort(_('can only follow copies/renames for explicit '
1383 'filenames'))
1383 'filenames'))
1384
1384
1385 # The slow path checks files modified in every changeset.
1385 # The slow path checks files modified in every changeset.
1386 # This is really slow on large repos, so compute the set lazily.
1386 # This is really slow on large repos, so compute the set lazily.
1387 class lazywantedset(object):
1387 class lazywantedset(object):
1388 def __init__(self):
1388 def __init__(self):
1389 self.set = set()
1389 self.set = set()
1390 self.revs = set(revs)
1390 self.revs = set(revs)
1391
1391
1392 # No need to worry about locality here because it will be accessed
1392 # No need to worry about locality here because it will be accessed
1393 # in the same order as the increasing window below.
1393 # in the same order as the increasing window below.
1394 def __contains__(self, value):
1394 def __contains__(self, value):
1395 if value in self.set:
1395 if value in self.set:
1396 return True
1396 return True
1397 elif not value in self.revs:
1397 elif not value in self.revs:
1398 return False
1398 return False
1399 else:
1399 else:
1400 self.revs.discard(value)
1400 self.revs.discard(value)
1401 ctx = change(value)
1401 ctx = change(value)
1402 matches = filter(match, ctx.files())
1402 matches = filter(match, ctx.files())
1403 if matches:
1403 if matches:
1404 fncache[value] = matches
1404 fncache[value] = matches
1405 self.set.add(value)
1405 self.set.add(value)
1406 return True
1406 return True
1407 return False
1407 return False
1408
1408
1409 def discard(self, value):
1409 def discard(self, value):
1410 self.revs.discard(value)
1410 self.revs.discard(value)
1411 self.set.discard(value)
1411 self.set.discard(value)
1412
1412
1413 wanted = lazywantedset()
1413 wanted = lazywantedset()
1414
1414
1415 class followfilter(object):
1415 class followfilter(object):
1416 def __init__(self, onlyfirst=False):
1416 def __init__(self, onlyfirst=False):
1417 self.startrev = nullrev
1417 self.startrev = nullrev
1418 self.roots = set()
1418 self.roots = set()
1419 self.onlyfirst = onlyfirst
1419 self.onlyfirst = onlyfirst
1420
1420
1421 def match(self, rev):
1421 def match(self, rev):
1422 def realparents(rev):
1422 def realparents(rev):
1423 if self.onlyfirst:
1423 if self.onlyfirst:
1424 return repo.changelog.parentrevs(rev)[0:1]
1424 return repo.changelog.parentrevs(rev)[0:1]
1425 else:
1425 else:
1426 return filter(lambda x: x != nullrev,
1426 return filter(lambda x: x != nullrev,
1427 repo.changelog.parentrevs(rev))
1427 repo.changelog.parentrevs(rev))
1428
1428
1429 if self.startrev == nullrev:
1429 if self.startrev == nullrev:
1430 self.startrev = rev
1430 self.startrev = rev
1431 return True
1431 return True
1432
1432
1433 if rev > self.startrev:
1433 if rev > self.startrev:
1434 # forward: all descendants
1434 # forward: all descendants
1435 if not self.roots:
1435 if not self.roots:
1436 self.roots.add(self.startrev)
1436 self.roots.add(self.startrev)
1437 for parent in realparents(rev):
1437 for parent in realparents(rev):
1438 if parent in self.roots:
1438 if parent in self.roots:
1439 self.roots.add(rev)
1439 self.roots.add(rev)
1440 return True
1440 return True
1441 else:
1441 else:
1442 # backwards: all parents
1442 # backwards: all parents
1443 if not self.roots:
1443 if not self.roots:
1444 self.roots.update(realparents(self.startrev))
1444 self.roots.update(realparents(self.startrev))
1445 if rev in self.roots:
1445 if rev in self.roots:
1446 self.roots.remove(rev)
1446 self.roots.remove(rev)
1447 self.roots.update(realparents(rev))
1447 self.roots.update(realparents(rev))
1448 return True
1448 return True
1449
1449
1450 return False
1450 return False
1451
1451
1452 # it might be worthwhile to do this in the iterator if the rev range
1452 # it might be worthwhile to do this in the iterator if the rev range
1453 # is descending and the prune args are all within that range
1453 # is descending and the prune args are all within that range
1454 for rev in opts.get('prune', ()):
1454 for rev in opts.get('prune', ()):
1455 rev = repo[rev].rev()
1455 rev = repo[rev].rev()
1456 ff = followfilter()
1456 ff = followfilter()
1457 stop = min(revs[0], revs[-1])
1457 stop = min(revs[0], revs[-1])
1458 for x in xrange(rev, stop - 1, -1):
1458 for x in xrange(rev, stop - 1, -1):
1459 if ff.match(x):
1459 if ff.match(x):
1460 wanted = wanted - [x]
1460 wanted = wanted - [x]
1461
1461
1462 # Now that wanted is correctly initialized, we can iterate over the
1462 # Now that wanted is correctly initialized, we can iterate over the
1463 # revision range, yielding only revisions in wanted.
1463 # revision range, yielding only revisions in wanted.
1464 def iterate():
1464 def iterate():
1465 if follow and not match.files():
1465 if follow and not match.files():
1466 ff = followfilter(onlyfirst=opts.get('follow_first'))
1466 ff = followfilter(onlyfirst=opts.get('follow_first'))
1467 def want(rev):
1467 def want(rev):
1468 return ff.match(rev) and rev in wanted
1468 return ff.match(rev) and rev in wanted
1469 else:
1469 else:
1470 def want(rev):
1470 def want(rev):
1471 return rev in wanted
1471 return rev in wanted
1472
1472
1473 it = iter(revs)
1473 it = iter(revs)
1474 stopiteration = False
1474 stopiteration = False
1475 for windowsize in increasingwindows():
1475 for windowsize in increasingwindows():
1476 nrevs = []
1476 nrevs = []
1477 for i in xrange(windowsize):
1477 for i in xrange(windowsize):
1478 try:
1478 try:
1479 rev = it.next()
1479 rev = it.next()
1480 if want(rev):
1480 if want(rev):
1481 nrevs.append(rev)
1481 nrevs.append(rev)
1482 except (StopIteration):
1482 except (StopIteration):
1483 stopiteration = True
1483 stopiteration = True
1484 break
1484 break
1485 for rev in sorted(nrevs):
1485 for rev in sorted(nrevs):
1486 fns = fncache.get(rev)
1486 fns = fncache.get(rev)
1487 ctx = change(rev)
1487 ctx = change(rev)
1488 if not fns:
1488 if not fns:
1489 def fns_generator():
1489 def fns_generator():
1490 for f in ctx.files():
1490 for f in ctx.files():
1491 if match(f):
1491 if match(f):
1492 yield f
1492 yield f
1493 fns = fns_generator()
1493 fns = fns_generator()
1494 prepare(ctx, fns)
1494 prepare(ctx, fns)
1495 for rev in nrevs:
1495 for rev in nrevs:
1496 yield change(rev)
1496 yield change(rev)
1497
1497
1498 if stopiteration:
1498 if stopiteration:
1499 break
1499 break
1500
1500
1501 return iterate()
1501 return iterate()
1502
1502
1503 def _makefollowlogfilematcher(repo, files, followfirst):
1503 def _makefollowlogfilematcher(repo, files, followfirst):
1504 # When displaying a revision with --patch --follow FILE, we have
1504 # When displaying a revision with --patch --follow FILE, we have
1505 # to know which file of the revision must be diffed. With
1505 # to know which file of the revision must be diffed. With
1506 # --follow, we want the names of the ancestors of FILE in the
1506 # --follow, we want the names of the ancestors of FILE in the
1507 # revision, stored in "fcache". "fcache" is populated by
1507 # revision, stored in "fcache". "fcache" is populated by
1508 # reproducing the graph traversal already done by --follow revset
1508 # reproducing the graph traversal already done by --follow revset
1509 # and relating linkrevs to file names (which is not "correct" but
1509 # and relating linkrevs to file names (which is not "correct" but
1510 # good enough).
1510 # good enough).
1511 fcache = {}
1511 fcache = {}
1512 fcacheready = [False]
1512 fcacheready = [False]
1513 pctx = repo['.']
1513 pctx = repo['.']
1514
1514
1515 def populate():
1515 def populate():
1516 for fn in files:
1516 for fn in files:
1517 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1517 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1518 for c in i:
1518 for c in i:
1519 fcache.setdefault(c.linkrev(), set()).add(c.path())
1519 fcache.setdefault(c.linkrev(), set()).add(c.path())
1520
1520
1521 def filematcher(rev):
1521 def filematcher(rev):
1522 if not fcacheready[0]:
1522 if not fcacheready[0]:
1523 # Lazy initialization
1523 # Lazy initialization
1524 fcacheready[0] = True
1524 fcacheready[0] = True
1525 populate()
1525 populate()
1526 return scmutil.matchfiles(repo, fcache.get(rev, []))
1526 return scmutil.matchfiles(repo, fcache.get(rev, []))
1527
1527
1528 return filematcher
1528 return filematcher
1529
1529
1530 def _makenofollowlogfilematcher(repo, pats, opts):
1530 def _makenofollowlogfilematcher(repo, pats, opts):
1531 '''hook for extensions to override the filematcher for non-follow cases'''
1531 '''hook for extensions to override the filematcher for non-follow cases'''
1532 return None
1532 return None
1533
1533
1534 def _makelogrevset(repo, pats, opts, revs):
1534 def _makelogrevset(repo, pats, opts, revs):
1535 """Return (expr, filematcher) where expr is a revset string built
1535 """Return (expr, filematcher) where expr is a revset string built
1536 from log options and file patterns or None. If --stat or --patch
1536 from log options and file patterns or None. If --stat or --patch
1537 are not passed filematcher is None. Otherwise it is a callable
1537 are not passed filematcher is None. Otherwise it is a callable
1538 taking a revision number and returning a match objects filtering
1538 taking a revision number and returning a match objects filtering
1539 the files to be detailed when displaying the revision.
1539 the files to be detailed when displaying the revision.
1540 """
1540 """
1541 opt2revset = {
1541 opt2revset = {
1542 'no_merges': ('not merge()', None),
1542 'no_merges': ('not merge()', None),
1543 'only_merges': ('merge()', None),
1543 'only_merges': ('merge()', None),
1544 '_ancestors': ('ancestors(%(val)s)', None),
1544 '_ancestors': ('ancestors(%(val)s)', None),
1545 '_fancestors': ('_firstancestors(%(val)s)', None),
1545 '_fancestors': ('_firstancestors(%(val)s)', None),
1546 '_descendants': ('descendants(%(val)s)', None),
1546 '_descendants': ('descendants(%(val)s)', None),
1547 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1547 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1548 '_matchfiles': ('_matchfiles(%(val)s)', None),
1548 '_matchfiles': ('_matchfiles(%(val)s)', None),
1549 'date': ('date(%(val)r)', None),
1549 'date': ('date(%(val)r)', None),
1550 'branch': ('branch(%(val)r)', ' or '),
1550 'branch': ('branch(%(val)r)', ' or '),
1551 '_patslog': ('filelog(%(val)r)', ' or '),
1551 '_patslog': ('filelog(%(val)r)', ' or '),
1552 '_patsfollow': ('follow(%(val)r)', ' or '),
1552 '_patsfollow': ('follow(%(val)r)', ' or '),
1553 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1553 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1554 'keyword': ('keyword(%(val)r)', ' or '),
1554 'keyword': ('keyword(%(val)r)', ' or '),
1555 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1555 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1556 'user': ('user(%(val)r)', ' or '),
1556 'user': ('user(%(val)r)', ' or '),
1557 }
1557 }
1558
1558
1559 opts = dict(opts)
1559 opts = dict(opts)
1560 # follow or not follow?
1560 # follow or not follow?
1561 follow = opts.get('follow') or opts.get('follow_first')
1561 follow = opts.get('follow') or opts.get('follow_first')
1562 followfirst = opts.get('follow_first') and 1 or 0
1562 followfirst = opts.get('follow_first') and 1 or 0
1563 # --follow with FILE behaviour depends on revs...
1563 # --follow with FILE behaviour depends on revs...
1564 it = iter(revs)
1564 it = iter(revs)
1565 startrev = it.next()
1565 startrev = it.next()
1566 try:
1566 try:
1567 followdescendants = startrev < it.next()
1567 followdescendants = startrev < it.next()
1568 except (StopIteration):
1568 except (StopIteration):
1569 followdescendants = False
1569 followdescendants = False
1570
1570
1571 # branch and only_branch are really aliases and must be handled at
1571 # branch and only_branch are really aliases and must be handled at
1572 # the same time
1572 # the same time
1573 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1573 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1574 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1574 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1575 # pats/include/exclude are passed to match.match() directly in
1575 # pats/include/exclude are passed to match.match() directly in
1576 # _matchfiles() revset but walkchangerevs() builds its matcher with
1576 # _matchfiles() revset but walkchangerevs() builds its matcher with
1577 # scmutil.match(). The difference is input pats are globbed on
1577 # scmutil.match(). The difference is input pats are globbed on
1578 # platforms without shell expansion (windows).
1578 # platforms without shell expansion (windows).
1579 pctx = repo[None]
1579 pctx = repo[None]
1580 match, pats = scmutil.matchandpats(pctx, pats, opts)
1580 match, pats = scmutil.matchandpats(pctx, pats, opts)
1581 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1581 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1582 if not slowpath:
1582 if not slowpath:
1583 for f in match.files():
1583 for f in match.files():
1584 if follow and f not in pctx:
1584 if follow and f not in pctx:
1585 # If the file exists, it may be a directory, so let it
1585 # If the file exists, it may be a directory, so let it
1586 # take the slow path.
1586 # take the slow path.
1587 if os.path.exists(repo.wjoin(f)):
1587 if os.path.exists(repo.wjoin(f)):
1588 slowpath = True
1588 slowpath = True
1589 continue
1589 continue
1590 else:
1590 else:
1591 raise util.Abort(_('cannot follow file not in parent '
1591 raise util.Abort(_('cannot follow file not in parent '
1592 'revision: "%s"') % f)
1592 'revision: "%s"') % f)
1593 filelog = repo.file(f)
1593 filelog = repo.file(f)
1594 if not filelog:
1594 if not filelog:
1595 # A zero count may be a directory or deleted file, so
1595 # A zero count may be a directory or deleted file, so
1596 # try to find matching entries on the slow path.
1596 # try to find matching entries on the slow path.
1597 if follow:
1597 if follow:
1598 raise util.Abort(
1598 raise util.Abort(
1599 _('cannot follow nonexistent file: "%s"') % f)
1599 _('cannot follow nonexistent file: "%s"') % f)
1600 slowpath = True
1600 slowpath = True
1601
1601
1602 # We decided to fall back to the slowpath because at least one
1602 # We decided to fall back to the slowpath because at least one
1603 # of the paths was not a file. Check to see if at least one of them
1603 # of the paths was not a file. Check to see if at least one of them
1604 # existed in history - in that case, we'll continue down the
1604 # existed in history - in that case, we'll continue down the
1605 # slowpath; otherwise, we can turn off the slowpath
1605 # slowpath; otherwise, we can turn off the slowpath
1606 if slowpath:
1606 if slowpath:
1607 for path in match.files():
1607 for path in match.files():
1608 if path == '.' or path in repo.store:
1608 if path == '.' or path in repo.store:
1609 break
1609 break
1610 else:
1610 else:
1611 slowpath = False
1611 slowpath = False
1612
1612
1613 if slowpath:
1613 if slowpath:
1614 # See walkchangerevs() slow path.
1614 # See walkchangerevs() slow path.
1615 #
1615 #
1616 # pats/include/exclude cannot be represented as separate
1616 # pats/include/exclude cannot be represented as separate
1617 # revset expressions as their filtering logic applies at file
1617 # revset expressions as their filtering logic applies at file
1618 # level. For instance "-I a -X a" matches a revision touching
1618 # level. For instance "-I a -X a" matches a revision touching
1619 # "a" and "b" while "file(a) and not file(b)" does
1619 # "a" and "b" while "file(a) and not file(b)" does
1620 # not. Besides, filesets are evaluated against the working
1620 # not. Besides, filesets are evaluated against the working
1621 # directory.
1621 # directory.
1622 matchargs = ['r:', 'd:relpath']
1622 matchargs = ['r:', 'd:relpath']
1623 for p in pats:
1623 for p in pats:
1624 matchargs.append('p:' + p)
1624 matchargs.append('p:' + p)
1625 for p in opts.get('include', []):
1625 for p in opts.get('include', []):
1626 matchargs.append('i:' + p)
1626 matchargs.append('i:' + p)
1627 for p in opts.get('exclude', []):
1627 for p in opts.get('exclude', []):
1628 matchargs.append('x:' + p)
1628 matchargs.append('x:' + p)
1629 matchargs = ','.join(('%r' % p) for p in matchargs)
1629 matchargs = ','.join(('%r' % p) for p in matchargs)
1630 opts['_matchfiles'] = matchargs
1630 opts['_matchfiles'] = matchargs
1631 else:
1631 else:
1632 if follow:
1632 if follow:
1633 fpats = ('_patsfollow', '_patsfollowfirst')
1633 fpats = ('_patsfollow', '_patsfollowfirst')
1634 fnopats = (('_ancestors', '_fancestors'),
1634 fnopats = (('_ancestors', '_fancestors'),
1635 ('_descendants', '_fdescendants'))
1635 ('_descendants', '_fdescendants'))
1636 if pats:
1636 if pats:
1637 # follow() revset interprets its file argument as a
1637 # follow() revset interprets its file argument as a
1638 # manifest entry, so use match.files(), not pats.
1638 # manifest entry, so use match.files(), not pats.
1639 opts[fpats[followfirst]] = list(match.files())
1639 opts[fpats[followfirst]] = list(match.files())
1640 else:
1640 else:
1641 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1641 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1642 else:
1642 else:
1643 opts['_patslog'] = list(pats)
1643 opts['_patslog'] = list(pats)
1644
1644
1645 filematcher = None
1645 filematcher = None
1646 if opts.get('patch') or opts.get('stat'):
1646 if opts.get('patch') or opts.get('stat'):
1647 # When following files, track renames via a special matcher.
1647 # When following files, track renames via a special matcher.
1648 # If we're forced to take the slowpath it means we're following
1648 # If we're forced to take the slowpath it means we're following
1649 # at least one pattern/directory, so don't bother with rename tracking.
1649 # at least one pattern/directory, so don't bother with rename tracking.
1650 if follow and not match.always() and not slowpath:
1650 if follow and not match.always() and not slowpath:
1651 # _makelogfilematcher expects its files argument to be relative to
1651 # _makelogfilematcher expects its files argument to be relative to
1652 # the repo root, so use match.files(), not pats.
1652 # the repo root, so use match.files(), not pats.
1653 filematcher = _makefollowlogfilematcher(repo, match.files(),
1653 filematcher = _makefollowlogfilematcher(repo, match.files(),
1654 followfirst)
1654 followfirst)
1655 else:
1655 else:
1656 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1656 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1657 if filematcher is None:
1657 if filematcher is None:
1658 filematcher = lambda rev: match
1658 filematcher = lambda rev: match
1659
1659
1660 expr = []
1660 expr = []
1661 for op, val in opts.iteritems():
1661 for op, val in opts.iteritems():
1662 if not val:
1662 if not val:
1663 continue
1663 continue
1664 if op not in opt2revset:
1664 if op not in opt2revset:
1665 continue
1665 continue
1666 revop, andor = opt2revset[op]
1666 revop, andor = opt2revset[op]
1667 if '%(val)' not in revop:
1667 if '%(val)' not in revop:
1668 expr.append(revop)
1668 expr.append(revop)
1669 else:
1669 else:
1670 if not isinstance(val, list):
1670 if not isinstance(val, list):
1671 e = revop % {'val': val}
1671 e = revop % {'val': val}
1672 else:
1672 else:
1673 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1673 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1674 expr.append(e)
1674 expr.append(e)
1675
1675
1676 if expr:
1676 if expr:
1677 expr = '(' + ' and '.join(expr) + ')'
1677 expr = '(' + ' and '.join(expr) + ')'
1678 else:
1678 else:
1679 expr = None
1679 expr = None
1680 return expr, filematcher
1680 return expr, filematcher
1681
1681
1682 def getgraphlogrevs(repo, pats, opts):
1682 def getgraphlogrevs(repo, pats, opts):
1683 """Return (revs, expr, filematcher) where revs is an iterable of
1683 """Return (revs, expr, filematcher) where revs is an iterable of
1684 revision numbers, expr is a revset string built from log options
1684 revision numbers, expr is a revset string built from log options
1685 and file patterns or None, and used to filter 'revs'. If --stat or
1685 and file patterns or None, and used to filter 'revs'. If --stat or
1686 --patch are not passed filematcher is None. Otherwise it is a
1686 --patch are not passed filematcher is None. Otherwise it is a
1687 callable taking a revision number and returning a match objects
1687 callable taking a revision number and returning a match objects
1688 filtering the files to be detailed when displaying the revision.
1688 filtering the files to be detailed when displaying the revision.
1689 """
1689 """
1690 if not len(repo):
1690 if not len(repo):
1691 return [], None, None
1691 return [], None, None
1692 limit = loglimit(opts)
1692 limit = loglimit(opts)
1693 # Default --rev value depends on --follow but --follow behaviour
1693 # Default --rev value depends on --follow but --follow behaviour
1694 # depends on revisions resolved from --rev...
1694 # depends on revisions resolved from --rev...
1695 follow = opts.get('follow') or opts.get('follow_first')
1695 follow = opts.get('follow') or opts.get('follow_first')
1696 possiblyunsorted = False # whether revs might need sorting
1696 possiblyunsorted = False # whether revs might need sorting
1697 if opts.get('rev'):
1697 if opts.get('rev'):
1698 revs = scmutil.revrange(repo, opts['rev'])
1698 revs = scmutil.revrange(repo, opts['rev'])
1699 # Don't sort here because _makelogrevset might depend on the
1699 # Don't sort here because _makelogrevset might depend on the
1700 # order of revs
1700 # order of revs
1701 possiblyunsorted = True
1701 possiblyunsorted = True
1702 else:
1702 else:
1703 if follow and len(repo) > 0:
1703 if follow and len(repo) > 0:
1704 revs = repo.revs('reverse(:.)')
1704 revs = repo.revs('reverse(:.)')
1705 else:
1705 else:
1706 revs = revset.spanset(repo)
1706 revs = revset.spanset(repo)
1707 revs.reverse()
1707 revs.reverse()
1708 if not revs:
1708 if not revs:
1709 return revset.baseset(), None, None
1709 return revset.baseset(), None, None
1710 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1710 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1711 if possiblyunsorted:
1711 if possiblyunsorted:
1712 revs.sort(reverse=True)
1712 revs.sort(reverse=True)
1713 if expr:
1713 if expr:
1714 # Revset matchers often operate faster on revisions in changelog
1714 # Revset matchers often operate faster on revisions in changelog
1715 # order, because most filters deal with the changelog.
1715 # order, because most filters deal with the changelog.
1716 revs.reverse()
1716 revs.reverse()
1717 matcher = revset.match(repo.ui, expr)
1717 matcher = revset.match(repo.ui, expr)
1718 # Revset matches can reorder revisions. "A or B" typically returns
1718 # Revset matches can reorder revisions. "A or B" typically returns
1719 # returns the revision matching A then the revision matching B. Sort
1719 # returns the revision matching A then the revision matching B. Sort
1720 # again to fix that.
1720 # again to fix that.
1721 revs = matcher(repo, revs)
1721 revs = matcher(repo, revs)
1722 revs.sort(reverse=True)
1722 revs.sort(reverse=True)
1723 if limit is not None:
1723 if limit is not None:
1724 limitedrevs = revset.baseset()
1724 limitedrevs = revset.baseset()
1725 for idx, rev in enumerate(revs):
1725 for idx, rev in enumerate(revs):
1726 if idx >= limit:
1726 if idx >= limit:
1727 break
1727 break
1728 limitedrevs.append(rev)
1728 limitedrevs.append(rev)
1729 revs = limitedrevs
1729 revs = limitedrevs
1730
1730
1731 return revs, expr, filematcher
1731 return revs, expr, filematcher
1732
1732
1733 def getlogrevs(repo, pats, opts):
1733 def getlogrevs(repo, pats, opts):
1734 """Return (revs, expr, filematcher) where revs is an iterable of
1734 """Return (revs, expr, filematcher) where revs is an iterable of
1735 revision numbers, expr is a revset string built from log options
1735 revision numbers, expr is a revset string built from log options
1736 and file patterns or None, and used to filter 'revs'. If --stat or
1736 and file patterns or None, and used to filter 'revs'. If --stat or
1737 --patch are not passed filematcher is None. Otherwise it is a
1737 --patch are not passed filematcher is None. Otherwise it is a
1738 callable taking a revision number and returning a match objects
1738 callable taking a revision number and returning a match objects
1739 filtering the files to be detailed when displaying the revision.
1739 filtering the files to be detailed when displaying the revision.
1740 """
1740 """
1741 limit = loglimit(opts)
1741 limit = loglimit(opts)
1742 # Default --rev value depends on --follow but --follow behaviour
1742 # Default --rev value depends on --follow but --follow behaviour
1743 # depends on revisions resolved from --rev...
1743 # depends on revisions resolved from --rev...
1744 follow = opts.get('follow') or opts.get('follow_first')
1744 follow = opts.get('follow') or opts.get('follow_first')
1745 if opts.get('rev'):
1745 if opts.get('rev'):
1746 revs = scmutil.revrange(repo, opts['rev'])
1746 revs = scmutil.revrange(repo, opts['rev'])
1747 elif follow:
1747 elif follow:
1748 revs = repo.revs('reverse(:.)')
1748 revs = repo.revs('reverse(:.)')
1749 else:
1749 else:
1750 revs = revset.spanset(repo)
1750 revs = revset.spanset(repo)
1751 revs.reverse()
1751 revs.reverse()
1752 if not revs:
1752 if not revs:
1753 return revset.baseset([]), None, None
1753 return revset.baseset([]), None, None
1754 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1754 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1755 if expr:
1755 if expr:
1756 # Revset matchers often operate faster on revisions in changelog
1756 # Revset matchers often operate faster on revisions in changelog
1757 # order, because most filters deal with the changelog.
1757 # order, because most filters deal with the changelog.
1758 if not opts.get('rev'):
1758 if not opts.get('rev'):
1759 revs.reverse()
1759 revs.reverse()
1760 matcher = revset.match(repo.ui, expr)
1760 matcher = revset.match(repo.ui, expr)
1761 # Revset matches can reorder revisions. "A or B" typically returns
1761 # Revset matches can reorder revisions. "A or B" typically returns
1762 # returns the revision matching A then the revision matching B. Sort
1762 # returns the revision matching A then the revision matching B. Sort
1763 # again to fix that.
1763 # again to fix that.
1764 revs = matcher(repo, revs)
1764 revs = matcher(repo, revs)
1765 if not opts.get('rev'):
1765 if not opts.get('rev'):
1766 revs.sort(reverse=True)
1766 revs.sort(reverse=True)
1767 if limit is not None:
1767 if limit is not None:
1768 count = 0
1768 count = 0
1769 limitedrevs = revset.baseset([])
1769 limitedrevs = revset.baseset([])
1770 it = iter(revs)
1770 it = iter(revs)
1771 while count < limit:
1771 while count < limit:
1772 try:
1772 try:
1773 limitedrevs.append(it.next())
1773 limitedrevs.append(it.next())
1774 except (StopIteration):
1774 except (StopIteration):
1775 break
1775 break
1776 count += 1
1776 count += 1
1777 revs = limitedrevs
1777 revs = limitedrevs
1778
1778
1779 return revs, expr, filematcher
1779 return revs, expr, filematcher
1780
1780
1781 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1781 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1782 filematcher=None):
1782 filematcher=None):
1783 seen, state = [], graphmod.asciistate()
1783 seen, state = [], graphmod.asciistate()
1784 for rev, type, ctx, parents in dag:
1784 for rev, type, ctx, parents in dag:
1785 char = 'o'
1785 char = 'o'
1786 if ctx.node() in showparents:
1786 if ctx.node() in showparents:
1787 char = '@'
1787 char = '@'
1788 elif ctx.obsolete():
1788 elif ctx.obsolete():
1789 char = 'x'
1789 char = 'x'
1790 copies = None
1790 copies = None
1791 if getrenamed and ctx.rev():
1791 if getrenamed and ctx.rev():
1792 copies = []
1792 copies = []
1793 for fn in ctx.files():
1793 for fn in ctx.files():
1794 rename = getrenamed(fn, ctx.rev())
1794 rename = getrenamed(fn, ctx.rev())
1795 if rename:
1795 if rename:
1796 copies.append((fn, rename[0]))
1796 copies.append((fn, rename[0]))
1797 revmatchfn = None
1797 revmatchfn = None
1798 if filematcher is not None:
1798 if filematcher is not None:
1799 revmatchfn = filematcher(ctx.rev())
1799 revmatchfn = filematcher(ctx.rev())
1800 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1800 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1801 lines = displayer.hunk.pop(rev).split('\n')
1801 lines = displayer.hunk.pop(rev).split('\n')
1802 if not lines[-1]:
1802 if not lines[-1]:
1803 del lines[-1]
1803 del lines[-1]
1804 displayer.flush(rev)
1804 displayer.flush(rev)
1805 edges = edgefn(type, char, lines, seen, rev, parents)
1805 edges = edgefn(type, char, lines, seen, rev, parents)
1806 for type, char, lines, coldata in edges:
1806 for type, char, lines, coldata in edges:
1807 graphmod.ascii(ui, state, type, char, lines, coldata)
1807 graphmod.ascii(ui, state, type, char, lines, coldata)
1808 displayer.close()
1808 displayer.close()
1809
1809
1810 def graphlog(ui, repo, *pats, **opts):
1810 def graphlog(ui, repo, *pats, **opts):
1811 # Parameters are identical to log command ones
1811 # Parameters are identical to log command ones
1812 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1812 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1813 revdag = graphmod.dagwalker(repo, revs)
1813 revdag = graphmod.dagwalker(repo, revs)
1814
1814
1815 getrenamed = None
1815 getrenamed = None
1816 if opts.get('copies'):
1816 if opts.get('copies'):
1817 endrev = None
1817 endrev = None
1818 if opts.get('rev'):
1818 if opts.get('rev'):
1819 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1819 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1820 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1820 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1821 displayer = show_changeset(ui, repo, opts, buffered=True)
1821 displayer = show_changeset(ui, repo, opts, buffered=True)
1822 showparents = [ctx.node() for ctx in repo[None].parents()]
1822 showparents = [ctx.node() for ctx in repo[None].parents()]
1823 displaygraph(ui, revdag, displayer, showparents,
1823 displaygraph(ui, revdag, displayer, showparents,
1824 graphmod.asciiedges, getrenamed, filematcher)
1824 graphmod.asciiedges, getrenamed, filematcher)
1825
1825
1826 def checkunsupportedgraphflags(pats, opts):
1826 def checkunsupportedgraphflags(pats, opts):
1827 for op in ["newest_first"]:
1827 for op in ["newest_first"]:
1828 if op in opts and opts[op]:
1828 if op in opts and opts[op]:
1829 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1829 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1830 % op.replace("_", "-"))
1830 % op.replace("_", "-"))
1831
1831
1832 def graphrevs(repo, nodes, opts):
1832 def graphrevs(repo, nodes, opts):
1833 limit = loglimit(opts)
1833 limit = loglimit(opts)
1834 nodes.reverse()
1834 nodes.reverse()
1835 if limit is not None:
1835 if limit is not None:
1836 nodes = nodes[:limit]
1836 nodes = nodes[:limit]
1837 return graphmod.nodes(repo, nodes)
1837 return graphmod.nodes(repo, nodes)
1838
1838
1839 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1839 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1840 join = lambda f: os.path.join(prefix, f)
1840 join = lambda f: os.path.join(prefix, f)
1841 bad = []
1841 bad = []
1842 oldbad = match.bad
1842 oldbad = match.bad
1843 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1843 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1844 names = []
1844 names = []
1845 wctx = repo[None]
1845 wctx = repo[None]
1846 cca = None
1846 cca = None
1847 abort, warn = scmutil.checkportabilityalert(ui)
1847 abort, warn = scmutil.checkportabilityalert(ui)
1848 if abort or warn:
1848 if abort or warn:
1849 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1849 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1850 for f in repo.walk(match):
1850 for f in repo.walk(match):
1851 exact = match.exact(f)
1851 exact = match.exact(f)
1852 if exact or not explicitonly and f not in repo.dirstate:
1852 if exact or not explicitonly and f not in repo.dirstate:
1853 if cca:
1853 if cca:
1854 cca(f)
1854 cca(f)
1855 names.append(f)
1855 names.append(f)
1856 if ui.verbose or not exact:
1856 if ui.verbose or not exact:
1857 ui.status(_('adding %s\n') % match.rel(join(f)))
1857 ui.status(_('adding %s\n') % match.rel(join(f)))
1858
1858
1859 for subpath in sorted(wctx.substate):
1859 for subpath in sorted(wctx.substate):
1860 sub = wctx.sub(subpath)
1860 sub = wctx.sub(subpath)
1861 try:
1861 try:
1862 submatch = matchmod.narrowmatcher(subpath, match)
1862 submatch = matchmod.narrowmatcher(subpath, match)
1863 if listsubrepos:
1863 if listsubrepos:
1864 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1864 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1865 False))
1865 False))
1866 else:
1866 else:
1867 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1867 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1868 True))
1868 True))
1869 except error.LookupError:
1869 except error.LookupError:
1870 ui.status(_("skipping missing subrepository: %s\n")
1870 ui.status(_("skipping missing subrepository: %s\n")
1871 % join(subpath))
1871 % join(subpath))
1872
1872
1873 if not dryrun:
1873 if not dryrun:
1874 rejected = wctx.add(names, prefix)
1874 rejected = wctx.add(names, prefix)
1875 bad.extend(f for f in rejected if f in match.files())
1875 bad.extend(f for f in rejected if f in match.files())
1876 return bad
1876 return bad
1877
1877
1878 def forget(ui, repo, match, prefix, explicitonly):
1878 def forget(ui, repo, match, prefix, explicitonly):
1879 join = lambda f: os.path.join(prefix, f)
1879 join = lambda f: os.path.join(prefix, f)
1880 bad = []
1880 bad = []
1881 oldbad = match.bad
1881 oldbad = match.bad
1882 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1882 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1883 wctx = repo[None]
1883 wctx = repo[None]
1884 forgot = []
1884 forgot = []
1885 s = repo.status(match=match, clean=True)
1885 s = repo.status(match=match, clean=True)
1886 forget = sorted(s[0] + s[1] + s[3] + s[6])
1886 forget = sorted(s[0] + s[1] + s[3] + s[6])
1887 if explicitonly:
1887 if explicitonly:
1888 forget = [f for f in forget if match.exact(f)]
1888 forget = [f for f in forget if match.exact(f)]
1889
1889
1890 for subpath in sorted(wctx.substate):
1890 for subpath in sorted(wctx.substate):
1891 sub = wctx.sub(subpath)
1891 sub = wctx.sub(subpath)
1892 try:
1892 try:
1893 submatch = matchmod.narrowmatcher(subpath, match)
1893 submatch = matchmod.narrowmatcher(subpath, match)
1894 subbad, subforgot = sub.forget(ui, submatch, prefix)
1894 subbad, subforgot = sub.forget(ui, submatch, prefix)
1895 bad.extend([subpath + '/' + f for f in subbad])
1895 bad.extend([subpath + '/' + f for f in subbad])
1896 forgot.extend([subpath + '/' + f for f in subforgot])
1896 forgot.extend([subpath + '/' + f for f in subforgot])
1897 except error.LookupError:
1897 except error.LookupError:
1898 ui.status(_("skipping missing subrepository: %s\n")
1898 ui.status(_("skipping missing subrepository: %s\n")
1899 % join(subpath))
1899 % join(subpath))
1900
1900
1901 if not explicitonly:
1901 if not explicitonly:
1902 for f in match.files():
1902 for f in match.files():
1903 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1903 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1904 if f not in forgot:
1904 if f not in forgot:
1905 if os.path.exists(match.rel(join(f))):
1905 if os.path.exists(match.rel(join(f))):
1906 ui.warn(_('not removing %s: '
1906 ui.warn(_('not removing %s: '
1907 'file is already untracked\n')
1907 'file is already untracked\n')
1908 % match.rel(join(f)))
1908 % match.rel(join(f)))
1909 bad.append(f)
1909 bad.append(f)
1910
1910
1911 for f in forget:
1911 for f in forget:
1912 if ui.verbose or not match.exact(f):
1912 if ui.verbose or not match.exact(f):
1913 ui.status(_('removing %s\n') % match.rel(join(f)))
1913 ui.status(_('removing %s\n') % match.rel(join(f)))
1914
1914
1915 rejected = wctx.forget(forget, prefix)
1915 rejected = wctx.forget(forget, prefix)
1916 bad.extend(f for f in rejected if f in match.files())
1916 bad.extend(f for f in rejected if f in match.files())
1917 forgot.extend(forget)
1917 forgot.extend(forget)
1918 return bad, forgot
1918 return bad, forgot
1919
1919
1920 def cat(ui, repo, ctx, matcher, prefix, **opts):
1920 def cat(ui, repo, ctx, matcher, prefix, **opts):
1921 err = 1
1921 err = 1
1922
1922
1923 def write(path):
1923 def write(path):
1924 fp = makefileobj(repo, opts.get('output'), ctx.node(),
1924 fp = makefileobj(repo, opts.get('output'), ctx.node(),
1925 pathname=os.path.join(prefix, path))
1925 pathname=os.path.join(prefix, path))
1926 data = ctx[path].data()
1926 data = ctx[path].data()
1927 if opts.get('decode'):
1927 if opts.get('decode'):
1928 data = repo.wwritedata(path, data)
1928 data = repo.wwritedata(path, data)
1929 fp.write(data)
1929 fp.write(data)
1930 fp.close()
1930 fp.close()
1931
1931
1932 # Automation often uses hg cat on single files, so special case it
1932 # Automation often uses hg cat on single files, so special case it
1933 # for performance to avoid the cost of parsing the manifest.
1933 # for performance to avoid the cost of parsing the manifest.
1934 if len(matcher.files()) == 1 and not matcher.anypats():
1934 if len(matcher.files()) == 1 and not matcher.anypats():
1935 file = matcher.files()[0]
1935 file = matcher.files()[0]
1936 mf = repo.manifest
1936 mf = repo.manifest
1937 mfnode = ctx._changeset[0]
1937 mfnode = ctx._changeset[0]
1938 if mf.find(mfnode, file)[0]:
1938 if mf.find(mfnode, file)[0]:
1939 write(file)
1939 write(file)
1940 return 0
1940 return 0
1941
1941
1942 # Don't warn about "missing" files that are really in subrepos
1942 # Don't warn about "missing" files that are really in subrepos
1943 bad = matcher.bad
1943 bad = matcher.bad
1944
1944
1945 def badfn(path, msg):
1945 def badfn(path, msg):
1946 for subpath in ctx.substate:
1946 for subpath in ctx.substate:
1947 if path.startswith(subpath):
1947 if path.startswith(subpath):
1948 return
1948 return
1949 bad(path, msg)
1949 bad(path, msg)
1950
1950
1951 matcher.bad = badfn
1951 matcher.bad = badfn
1952
1952
1953 for abs in ctx.walk(matcher):
1953 for abs in ctx.walk(matcher):
1954 write(abs)
1954 write(abs)
1955 err = 0
1955 err = 0
1956
1956
1957 matcher.bad = bad
1957 matcher.bad = bad
1958
1958
1959 for subpath in sorted(ctx.substate):
1959 for subpath in sorted(ctx.substate):
1960 sub = ctx.sub(subpath)
1960 sub = ctx.sub(subpath)
1961 try:
1961 try:
1962 submatch = matchmod.narrowmatcher(subpath, matcher)
1962 submatch = matchmod.narrowmatcher(subpath, matcher)
1963
1963
1964 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
1964 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
1965 **opts):
1965 **opts):
1966 err = 0
1966 err = 0
1967 except error.RepoLookupError:
1967 except error.RepoLookupError:
1968 ui.status(_("skipping missing subrepository: %s\n")
1968 ui.status(_("skipping missing subrepository: %s\n")
1969 % os.path.join(prefix, subpath))
1969 % os.path.join(prefix, subpath))
1970
1970
1971 return err
1971 return err
1972
1972
1973 def duplicatecopies(repo, rev, fromrev, skiprev=None):
1973 def duplicatecopies(repo, rev, fromrev, skiprev=None):
1974 '''reproduce copies from fromrev to rev in the dirstate
1974 '''reproduce copies from fromrev to rev in the dirstate
1975
1975
1976 If skiprev is specified, it's a revision that should be used to
1976 If skiprev is specified, it's a revision that should be used to
1977 filter copy records. Any copies that occur between fromrev and
1977 filter copy records. Any copies that occur between fromrev and
1978 skiprev will not be duplicated, even if they appear in the set of
1978 skiprev will not be duplicated, even if they appear in the set of
1979 copies between fromrev and rev.
1979 copies between fromrev and rev.
1980 '''
1980 '''
1981 exclude = {}
1981 exclude = {}
1982 if skiprev is not None:
1982 if skiprev is not None:
1983 exclude = copies.pathcopies(repo[fromrev], repo[skiprev])
1983 exclude = copies.pathcopies(repo[fromrev], repo[skiprev])
1984 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1984 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1985 # copies.pathcopies returns backward renames, so dst might not
1985 # copies.pathcopies returns backward renames, so dst might not
1986 # actually be in the dirstate
1986 # actually be in the dirstate
1987 if dst in exclude:
1987 if dst in exclude:
1988 continue
1988 continue
1989 if repo.dirstate[dst] in "nma":
1989 if repo.dirstate[dst] in "nma":
1990 repo.dirstate.copy(src, dst)
1990 repo.dirstate.copy(src, dst)
1991
1991
1992 def commit(ui, repo, commitfunc, pats, opts):
1992 def commit(ui, repo, commitfunc, pats, opts):
1993 '''commit the specified files or all outstanding changes'''
1993 '''commit the specified files or all outstanding changes'''
1994 date = opts.get('date')
1994 date = opts.get('date')
1995 if date:
1995 if date:
1996 opts['date'] = util.parsedate(date)
1996 opts['date'] = util.parsedate(date)
1997 message = logmessage(ui, opts)
1997 message = logmessage(ui, opts)
1998
1998
1999 # extract addremove carefully -- this function can be called from a command
1999 # extract addremove carefully -- this function can be called from a command
2000 # that doesn't support addremove
2000 # that doesn't support addremove
2001 if opts.get('addremove'):
2001 if opts.get('addremove'):
2002 scmutil.addremove(repo, pats, opts)
2002 scmutil.addremove(repo, pats, opts)
2003
2003
2004 return commitfunc(ui, repo, message,
2004 return commitfunc(ui, repo, message,
2005 scmutil.match(repo[None], pats, opts), opts)
2005 scmutil.match(repo[None], pats, opts), opts)
2006
2006
2007 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2007 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2008 ui.note(_('amending changeset %s\n') % old)
2008 ui.note(_('amending changeset %s\n') % old)
2009 base = old.p1()
2009 base = old.p1()
2010
2010
2011 wlock = lock = newid = None
2011 wlock = lock = newid = None
2012 try:
2012 try:
2013 wlock = repo.wlock()
2013 wlock = repo.wlock()
2014 lock = repo.lock()
2014 lock = repo.lock()
2015 tr = repo.transaction('amend')
2015 tr = repo.transaction('amend')
2016 try:
2016 try:
2017 # See if we got a message from -m or -l, if not, open the editor
2017 # See if we got a message from -m or -l, if not, open the editor
2018 # with the message of the changeset to amend
2018 # with the message of the changeset to amend
2019 message = logmessage(ui, opts)
2019 message = logmessage(ui, opts)
2020 # ensure logfile does not conflict with later enforcement of the
2020 # ensure logfile does not conflict with later enforcement of the
2021 # message. potential logfile content has been processed by
2021 # message. potential logfile content has been processed by
2022 # `logmessage` anyway.
2022 # `logmessage` anyway.
2023 opts.pop('logfile')
2023 opts.pop('logfile')
2024 # First, do a regular commit to record all changes in the working
2024 # First, do a regular commit to record all changes in the working
2025 # directory (if there are any)
2025 # directory (if there are any)
2026 ui.callhooks = False
2026 ui.callhooks = False
2027 currentbookmark = repo._bookmarkcurrent
2027 currentbookmark = repo._bookmarkcurrent
2028 try:
2028 try:
2029 repo._bookmarkcurrent = None
2029 repo._bookmarkcurrent = None
2030 opts['message'] = 'temporary amend commit for %s' % old
2030 opts['message'] = 'temporary amend commit for %s' % old
2031 node = commit(ui, repo, commitfunc, pats, opts)
2031 node = commit(ui, repo, commitfunc, pats, opts)
2032 finally:
2032 finally:
2033 repo._bookmarkcurrent = currentbookmark
2033 repo._bookmarkcurrent = currentbookmark
2034 ui.callhooks = True
2034 ui.callhooks = True
2035 ctx = repo[node]
2035 ctx = repo[node]
2036
2036
2037 # Participating changesets:
2037 # Participating changesets:
2038 #
2038 #
2039 # node/ctx o - new (intermediate) commit that contains changes
2039 # node/ctx o - new (intermediate) commit that contains changes
2040 # | from working dir to go into amending commit
2040 # | from working dir to go into amending commit
2041 # | (or a workingctx if there were no changes)
2041 # | (or a workingctx if there were no changes)
2042 # |
2042 # |
2043 # old o - changeset to amend
2043 # old o - changeset to amend
2044 # |
2044 # |
2045 # base o - parent of amending changeset
2045 # base o - parent of amending changeset
2046
2046
2047 # Update extra dict from amended commit (e.g. to preserve graft
2047 # Update extra dict from amended commit (e.g. to preserve graft
2048 # source)
2048 # source)
2049 extra.update(old.extra())
2049 extra.update(old.extra())
2050
2050
2051 # Also update it from the intermediate commit or from the wctx
2051 # Also update it from the intermediate commit or from the wctx
2052 extra.update(ctx.extra())
2052 extra.update(ctx.extra())
2053
2053
2054 if len(old.parents()) > 1:
2054 if len(old.parents()) > 1:
2055 # ctx.files() isn't reliable for merges, so fall back to the
2055 # ctx.files() isn't reliable for merges, so fall back to the
2056 # slower repo.status() method
2056 # slower repo.status() method
2057 files = set([fn for st in repo.status(base, old)[:3]
2057 files = set([fn for st in repo.status(base, old)[:3]
2058 for fn in st])
2058 for fn in st])
2059 else:
2059 else:
2060 files = set(old.files())
2060 files = set(old.files())
2061
2061
2062 # Second, we use either the commit we just did, or if there were no
2062 # Second, we use either the commit we just did, or if there were no
2063 # changes the parent of the working directory as the version of the
2063 # changes the parent of the working directory as the version of the
2064 # files in the final amend commit
2064 # files in the final amend commit
2065 if node:
2065 if node:
2066 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2066 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2067
2067
2068 user = ctx.user()
2068 user = ctx.user()
2069 date = ctx.date()
2069 date = ctx.date()
2070 # Recompute copies (avoid recording a -> b -> a)
2070 # Recompute copies (avoid recording a -> b -> a)
2071 copied = copies.pathcopies(base, ctx)
2071 copied = copies.pathcopies(base, ctx)
2072
2072
2073 # Prune files which were reverted by the updates: if old
2073 # Prune files which were reverted by the updates: if old
2074 # introduced file X and our intermediate commit, node,
2074 # introduced file X and our intermediate commit, node,
2075 # renamed that file, then those two files are the same and
2075 # renamed that file, then those two files are the same and
2076 # we can discard X from our list of files. Likewise if X
2076 # we can discard X from our list of files. Likewise if X
2077 # was deleted, it's no longer relevant
2077 # was deleted, it's no longer relevant
2078 files.update(ctx.files())
2078 files.update(ctx.files())
2079
2079
2080 def samefile(f):
2080 def samefile(f):
2081 if f in ctx.manifest():
2081 if f in ctx.manifest():
2082 a = ctx.filectx(f)
2082 a = ctx.filectx(f)
2083 if f in base.manifest():
2083 if f in base.manifest():
2084 b = base.filectx(f)
2084 b = base.filectx(f)
2085 return (not a.cmp(b)
2085 return (not a.cmp(b)
2086 and a.flags() == b.flags())
2086 and a.flags() == b.flags())
2087 else:
2087 else:
2088 return False
2088 return False
2089 else:
2089 else:
2090 return f not in base.manifest()
2090 return f not in base.manifest()
2091 files = [f for f in files if not samefile(f)]
2091 files = [f for f in files if not samefile(f)]
2092
2092
2093 def filectxfn(repo, ctx_, path):
2093 def filectxfn(repo, ctx_, path):
2094 try:
2094 try:
2095 fctx = ctx[path]
2095 fctx = ctx[path]
2096 flags = fctx.flags()
2096 flags = fctx.flags()
2097 mctx = context.memfilectx(repo,
2097 mctx = context.memfilectx(repo,
2098 fctx.path(), fctx.data(),
2098 fctx.path(), fctx.data(),
2099 islink='l' in flags,
2099 islink='l' in flags,
2100 isexec='x' in flags,
2100 isexec='x' in flags,
2101 copied=copied.get(path))
2101 copied=copied.get(path))
2102 return mctx
2102 return mctx
2103 except KeyError:
2103 except KeyError:
2104 raise IOError
2104 raise IOError
2105 else:
2105 else:
2106 ui.note(_('copying changeset %s to %s\n') % (old, base))
2106 ui.note(_('copying changeset %s to %s\n') % (old, base))
2107
2107
2108 # Use version of files as in the old cset
2108 # Use version of files as in the old cset
2109 def filectxfn(repo, ctx_, path):
2109 def filectxfn(repo, ctx_, path):
2110 try:
2110 try:
2111 return old.filectx(path)
2111 return old.filectx(path)
2112 except KeyError:
2112 except KeyError:
2113 raise IOError
2113 raise IOError
2114
2114
2115 user = opts.get('user') or old.user()
2115 user = opts.get('user') or old.user()
2116 date = opts.get('date') or old.date()
2116 date = opts.get('date') or old.date()
2117 editform = 'commit.amend'
2117 editform = 'commit.amend'
2118 editor = getcommiteditor(editform=editform, **opts)
2118 editor = getcommiteditor(editform=editform, **opts)
2119 if not message:
2119 if not message:
2120 editor = getcommiteditor(edit=True, editform=editform)
2120 editor = getcommiteditor(edit=True, editform=editform)
2121 message = old.description()
2121 message = old.description()
2122
2122
2123 pureextra = extra.copy()
2123 pureextra = extra.copy()
2124 extra['amend_source'] = old.hex()
2124 extra['amend_source'] = old.hex()
2125
2125
2126 new = context.memctx(repo,
2126 new = context.memctx(repo,
2127 parents=[base.node(), old.p2().node()],
2127 parents=[base.node(), old.p2().node()],
2128 text=message,
2128 text=message,
2129 files=files,
2129 files=files,
2130 filectxfn=filectxfn,
2130 filectxfn=filectxfn,
2131 user=user,
2131 user=user,
2132 date=date,
2132 date=date,
2133 extra=extra,
2133 extra=extra,
2134 editor=editor)
2134 editor=editor)
2135
2135
2136 newdesc = changelog.stripdesc(new.description())
2136 newdesc = changelog.stripdesc(new.description())
2137 if ((not node)
2137 if ((not node)
2138 and newdesc == old.description()
2138 and newdesc == old.description()
2139 and user == old.user()
2139 and user == old.user()
2140 and date == old.date()
2140 and date == old.date()
2141 and pureextra == old.extra()):
2141 and pureextra == old.extra()):
2142 # nothing changed. continuing here would create a new node
2142 # nothing changed. continuing here would create a new node
2143 # anyway because of the amend_source noise.
2143 # anyway because of the amend_source noise.
2144 #
2144 #
2145 # This not what we expect from amend.
2145 # This not what we expect from amend.
2146 return old.node()
2146 return old.node()
2147
2147
2148 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2148 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2149 try:
2149 try:
2150 if opts.get('secret'):
2150 if opts.get('secret'):
2151 commitphase = 'secret'
2151 commitphase = 'secret'
2152 else:
2152 else:
2153 commitphase = old.phase()
2153 commitphase = old.phase()
2154 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2154 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2155 newid = repo.commitctx(new)
2155 newid = repo.commitctx(new)
2156 finally:
2156 finally:
2157 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2157 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2158 if newid != old.node():
2158 if newid != old.node():
2159 # Reroute the working copy parent to the new changeset
2159 # Reroute the working copy parent to the new changeset
2160 repo.setparents(newid, nullid)
2160 repo.setparents(newid, nullid)
2161
2161
2162 # Move bookmarks from old parent to amend commit
2162 # Move bookmarks from old parent to amend commit
2163 bms = repo.nodebookmarks(old.node())
2163 bms = repo.nodebookmarks(old.node())
2164 if bms:
2164 if bms:
2165 marks = repo._bookmarks
2165 marks = repo._bookmarks
2166 for bm in bms:
2166 for bm in bms:
2167 marks[bm] = newid
2167 marks[bm] = newid
2168 marks.write()
2168 marks.write()
2169 #commit the whole amend process
2169 #commit the whole amend process
2170 if obsolete._enabled and newid != old.node():
2170 if obsolete._enabled and newid != old.node():
2171 # mark the new changeset as successor of the rewritten one
2171 # mark the new changeset as successor of the rewritten one
2172 new = repo[newid]
2172 new = repo[newid]
2173 obs = [(old, (new,))]
2173 obs = [(old, (new,))]
2174 if node:
2174 if node:
2175 obs.append((ctx, ()))
2175 obs.append((ctx, ()))
2176
2176
2177 obsolete.createmarkers(repo, obs)
2177 obsolete.createmarkers(repo, obs)
2178 tr.close()
2178 tr.close()
2179 finally:
2179 finally:
2180 tr.release()
2180 tr.release()
2181 if (not obsolete._enabled) and newid != old.node():
2181 if (not obsolete._enabled) and newid != old.node():
2182 # Strip the intermediate commit (if there was one) and the amended
2182 # Strip the intermediate commit (if there was one) and the amended
2183 # commit
2183 # commit
2184 if node:
2184 if node:
2185 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2185 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2186 ui.note(_('stripping amended changeset %s\n') % old)
2186 ui.note(_('stripping amended changeset %s\n') % old)
2187 repair.strip(ui, repo, old.node(), topic='amend-backup')
2187 repair.strip(ui, repo, old.node(), topic='amend-backup')
2188 finally:
2188 finally:
2189 if newid is None:
2189 if newid is None:
2190 repo.dirstate.invalidate()
2190 repo.dirstate.invalidate()
2191 lockmod.release(lock, wlock)
2191 lockmod.release(lock, wlock)
2192 return newid
2192 return newid
2193
2193
2194 def commiteditor(repo, ctx, subs, editform=''):
2194 def commiteditor(repo, ctx, subs, editform=''):
2195 if ctx.description():
2195 if ctx.description():
2196 return ctx.description()
2196 return ctx.description()
2197 return commitforceeditor(repo, ctx, subs, editform=editform)
2197 return commitforceeditor(repo, ctx, subs, editform=editform)
2198
2198
2199 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2199 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2200 editform=''):
2200 editform=''):
2201 if not extramsg:
2201 if not extramsg:
2202 extramsg = _("Leave message empty to abort commit.")
2202 extramsg = _("Leave message empty to abort commit.")
2203
2203
2204 forms = [e for e in editform.split('.') if e]
2204 forms = [e for e in editform.split('.') if e]
2205 forms.insert(0, 'changeset')
2205 forms.insert(0, 'changeset')
2206 while forms:
2206 while forms:
2207 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2207 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2208 if tmpl:
2208 if tmpl:
2209 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2209 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2210 break
2210 break
2211 forms.pop()
2211 forms.pop()
2212 else:
2212 else:
2213 committext = buildcommittext(repo, ctx, subs, extramsg)
2213 committext = buildcommittext(repo, ctx, subs, extramsg)
2214
2214
2215 # run editor in the repository root
2215 # run editor in the repository root
2216 olddir = os.getcwd()
2216 olddir = os.getcwd()
2217 os.chdir(repo.root)
2217 os.chdir(repo.root)
2218 text = repo.ui.edit(committext, ctx.user(), ctx.extra())
2218 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2219 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2219 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2220 os.chdir(olddir)
2220 os.chdir(olddir)
2221
2221
2222 if finishdesc:
2222 if finishdesc:
2223 text = finishdesc(text)
2223 text = finishdesc(text)
2224 if not text.strip():
2224 if not text.strip():
2225 raise util.Abort(_("empty commit message"))
2225 raise util.Abort(_("empty commit message"))
2226
2226
2227 return text
2227 return text
2228
2228
2229 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2229 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2230 ui = repo.ui
2230 ui = repo.ui
2231 tmpl, mapfile = gettemplate(ui, tmpl, None)
2231 tmpl, mapfile = gettemplate(ui, tmpl, None)
2232
2232
2233 try:
2233 try:
2234 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2234 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2235 except SyntaxError, inst:
2235 except SyntaxError, inst:
2236 raise util.Abort(inst.args[0])
2236 raise util.Abort(inst.args[0])
2237
2237
2238 for k, v in repo.ui.configitems('committemplate'):
2238 for k, v in repo.ui.configitems('committemplate'):
2239 if k != 'changeset':
2239 if k != 'changeset':
2240 t.t.cache[k] = v
2240 t.t.cache[k] = v
2241
2241
2242 if not extramsg:
2242 if not extramsg:
2243 extramsg = '' # ensure that extramsg is string
2243 extramsg = '' # ensure that extramsg is string
2244
2244
2245 ui.pushbuffer()
2245 ui.pushbuffer()
2246 t.show(ctx, extramsg=extramsg)
2246 t.show(ctx, extramsg=extramsg)
2247 return ui.popbuffer()
2247 return ui.popbuffer()
2248
2248
2249 def buildcommittext(repo, ctx, subs, extramsg):
2249 def buildcommittext(repo, ctx, subs, extramsg):
2250 edittext = []
2250 edittext = []
2251 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2251 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2252 if ctx.description():
2252 if ctx.description():
2253 edittext.append(ctx.description())
2253 edittext.append(ctx.description())
2254 edittext.append("")
2254 edittext.append("")
2255 edittext.append("") # Empty line between message and comments.
2255 edittext.append("") # Empty line between message and comments.
2256 edittext.append(_("HG: Enter commit message."
2256 edittext.append(_("HG: Enter commit message."
2257 " Lines beginning with 'HG:' are removed."))
2257 " Lines beginning with 'HG:' are removed."))
2258 edittext.append("HG: %s" % extramsg)
2258 edittext.append("HG: %s" % extramsg)
2259 edittext.append("HG: --")
2259 edittext.append("HG: --")
2260 edittext.append(_("HG: user: %s") % ctx.user())
2260 edittext.append(_("HG: user: %s") % ctx.user())
2261 if ctx.p2():
2261 if ctx.p2():
2262 edittext.append(_("HG: branch merge"))
2262 edittext.append(_("HG: branch merge"))
2263 if ctx.branch():
2263 if ctx.branch():
2264 edittext.append(_("HG: branch '%s'") % ctx.branch())
2264 edittext.append(_("HG: branch '%s'") % ctx.branch())
2265 if bookmarks.iscurrent(repo):
2265 if bookmarks.iscurrent(repo):
2266 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2266 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2267 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2267 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2268 edittext.extend([_("HG: added %s") % f for f in added])
2268 edittext.extend([_("HG: added %s") % f for f in added])
2269 edittext.extend([_("HG: changed %s") % f for f in modified])
2269 edittext.extend([_("HG: changed %s") % f for f in modified])
2270 edittext.extend([_("HG: removed %s") % f for f in removed])
2270 edittext.extend([_("HG: removed %s") % f for f in removed])
2271 if not added and not modified and not removed:
2271 if not added and not modified and not removed:
2272 edittext.append(_("HG: no files changed"))
2272 edittext.append(_("HG: no files changed"))
2273 edittext.append("")
2273 edittext.append("")
2274
2274
2275 return "\n".join(edittext)
2275 return "\n".join(edittext)
2276
2276
2277 def commitstatus(repo, node, branch, bheads=None, opts={}):
2277 def commitstatus(repo, node, branch, bheads=None, opts={}):
2278 ctx = repo[node]
2278 ctx = repo[node]
2279 parents = ctx.parents()
2279 parents = ctx.parents()
2280
2280
2281 if (not opts.get('amend') and bheads and node not in bheads and not
2281 if (not opts.get('amend') and bheads and node not in bheads and not
2282 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2282 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2283 repo.ui.status(_('created new head\n'))
2283 repo.ui.status(_('created new head\n'))
2284 # The message is not printed for initial roots. For the other
2284 # The message is not printed for initial roots. For the other
2285 # changesets, it is printed in the following situations:
2285 # changesets, it is printed in the following situations:
2286 #
2286 #
2287 # Par column: for the 2 parents with ...
2287 # Par column: for the 2 parents with ...
2288 # N: null or no parent
2288 # N: null or no parent
2289 # B: parent is on another named branch
2289 # B: parent is on another named branch
2290 # C: parent is a regular non head changeset
2290 # C: parent is a regular non head changeset
2291 # H: parent was a branch head of the current branch
2291 # H: parent was a branch head of the current branch
2292 # Msg column: whether we print "created new head" message
2292 # Msg column: whether we print "created new head" message
2293 # In the following, it is assumed that there already exists some
2293 # In the following, it is assumed that there already exists some
2294 # initial branch heads of the current branch, otherwise nothing is
2294 # initial branch heads of the current branch, otherwise nothing is
2295 # printed anyway.
2295 # printed anyway.
2296 #
2296 #
2297 # Par Msg Comment
2297 # Par Msg Comment
2298 # N N y additional topo root
2298 # N N y additional topo root
2299 #
2299 #
2300 # B N y additional branch root
2300 # B N y additional branch root
2301 # C N y additional topo head
2301 # C N y additional topo head
2302 # H N n usual case
2302 # H N n usual case
2303 #
2303 #
2304 # B B y weird additional branch root
2304 # B B y weird additional branch root
2305 # C B y branch merge
2305 # C B y branch merge
2306 # H B n merge with named branch
2306 # H B n merge with named branch
2307 #
2307 #
2308 # C C y additional head from merge
2308 # C C y additional head from merge
2309 # C H n merge with a head
2309 # C H n merge with a head
2310 #
2310 #
2311 # H H n head merge: head count decreases
2311 # H H n head merge: head count decreases
2312
2312
2313 if not opts.get('close_branch'):
2313 if not opts.get('close_branch'):
2314 for r in parents:
2314 for r in parents:
2315 if r.closesbranch() and r.branch() == branch:
2315 if r.closesbranch() and r.branch() == branch:
2316 repo.ui.status(_('reopening closed branch head %d\n') % r)
2316 repo.ui.status(_('reopening closed branch head %d\n') % r)
2317
2317
2318 if repo.ui.debugflag:
2318 if repo.ui.debugflag:
2319 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2319 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2320 elif repo.ui.verbose:
2320 elif repo.ui.verbose:
2321 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2321 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2322
2322
2323 def revert(ui, repo, ctx, parents, *pats, **opts):
2323 def revert(ui, repo, ctx, parents, *pats, **opts):
2324 parent, p2 = parents
2324 parent, p2 = parents
2325 node = ctx.node()
2325 node = ctx.node()
2326
2326
2327 mf = ctx.manifest()
2327 mf = ctx.manifest()
2328 if node == p2:
2328 if node == p2:
2329 parent = p2
2329 parent = p2
2330 if node == parent:
2330 if node == parent:
2331 pmf = mf
2331 pmf = mf
2332 else:
2332 else:
2333 pmf = None
2333 pmf = None
2334
2334
2335 # need all matching names in dirstate and manifest of target rev,
2335 # need all matching names in dirstate and manifest of target rev,
2336 # so have to walk both. do not print errors if files exist in one
2336 # so have to walk both. do not print errors if files exist in one
2337 # but not other.
2337 # but not other.
2338
2338
2339 # `names` is a mapping for all elements in working copy and target revision
2339 # `names` is a mapping for all elements in working copy and target revision
2340 # The mapping is in the form:
2340 # The mapping is in the form:
2341 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2341 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2342 names = {}
2342 names = {}
2343
2343
2344 wlock = repo.wlock()
2344 wlock = repo.wlock()
2345 try:
2345 try:
2346 ## filling of the `names` mapping
2346 ## filling of the `names` mapping
2347 # walk dirstate to fill `names`
2347 # walk dirstate to fill `names`
2348
2348
2349 m = scmutil.match(repo[None], pats, opts)
2349 m = scmutil.match(repo[None], pats, opts)
2350 m.bad = lambda x, y: False
2350 m.bad = lambda x, y: False
2351 for abs in repo.walk(m):
2351 for abs in repo.walk(m):
2352 names[abs] = m.rel(abs), m.exact(abs)
2352 names[abs] = m.rel(abs), m.exact(abs)
2353
2353
2354 # walk target manifest to fill `names`
2354 # walk target manifest to fill `names`
2355
2355
2356 def badfn(path, msg):
2356 def badfn(path, msg):
2357 if path in names:
2357 if path in names:
2358 return
2358 return
2359 if path in ctx.substate:
2359 if path in ctx.substate:
2360 return
2360 return
2361 path_ = path + '/'
2361 path_ = path + '/'
2362 for f in names:
2362 for f in names:
2363 if f.startswith(path_):
2363 if f.startswith(path_):
2364 return
2364 return
2365 ui.warn("%s: %s\n" % (m.rel(path), msg))
2365 ui.warn("%s: %s\n" % (m.rel(path), msg))
2366
2366
2367 m = scmutil.match(ctx, pats, opts)
2367 m = scmutil.match(ctx, pats, opts)
2368 m.bad = badfn
2368 m.bad = badfn
2369 for abs in ctx.walk(m):
2369 for abs in ctx.walk(m):
2370 if abs not in names:
2370 if abs not in names:
2371 names[abs] = m.rel(abs), m.exact(abs)
2371 names[abs] = m.rel(abs), m.exact(abs)
2372
2372
2373 # get the list of subrepos that must be reverted
2373 # get the list of subrepos that must be reverted
2374 targetsubs = sorted(s for s in ctx.substate if m(s))
2374 targetsubs = sorted(s for s in ctx.substate if m(s))
2375
2375
2376 # Find status of all file in `names`.
2376 # Find status of all file in `names`.
2377 m = scmutil.matchfiles(repo, names)
2377 m = scmutil.matchfiles(repo, names)
2378
2378
2379 changes = repo.status(node1=node, match=m, clean=True)
2379 changes = repo.status(node1=node, match=m, clean=True)
2380 modified = set(changes[0])
2380 modified = set(changes[0])
2381 added = set(changes[1])
2381 added = set(changes[1])
2382 removed = set(changes[2])
2382 removed = set(changes[2])
2383 _deleted = set(changes[3])
2383 _deleted = set(changes[3])
2384 clean = set(changes[6])
2384 clean = set(changes[6])
2385
2385
2386 # split between files known in target manifest and the others
2386 # split between files known in target manifest and the others
2387 smf = set(mf)
2387 smf = set(mf)
2388
2388
2389 # determine the exact nature of the deleted changesets
2389 # determine the exact nature of the deleted changesets
2390 _deletedadded = _deleted - smf
2390 _deletedadded = _deleted - smf
2391 _deletedmodified = _deleted - _deletedadded
2391 _deletedmodified = _deleted - _deletedadded
2392 added |= _deletedadded
2392 added |= _deletedadded
2393 modified |= _deletedmodified
2393 modified |= _deletedmodified
2394
2394
2395 # We need to account for the state of file in the dirstate
2395 # We need to account for the state of file in the dirstate
2396 #
2396 #
2397 # Even, when we revert agains something else than parent. this will
2397 # Even, when we revert agains something else than parent. this will
2398 # slightly alter the behavior of revert (doing back up or not, delete
2398 # slightly alter the behavior of revert (doing back up or not, delete
2399 # or just forget etc)
2399 # or just forget etc)
2400 if parent == node:
2400 if parent == node:
2401 dsmodified = modified
2401 dsmodified = modified
2402 dsadded = added
2402 dsadded = added
2403 dsremoved = removed
2403 dsremoved = removed
2404 modified, added, removed = set(), set(), set()
2404 modified, added, removed = set(), set(), set()
2405 else:
2405 else:
2406 changes = repo.status(node1=parent, match=m)
2406 changes = repo.status(node1=parent, match=m)
2407 dsmodified = set(changes[0])
2407 dsmodified = set(changes[0])
2408 dsadded = set(changes[1])
2408 dsadded = set(changes[1])
2409 dsremoved = set(changes[2])
2409 dsremoved = set(changes[2])
2410 dsadded |= _deletedadded
2410 dsadded |= _deletedadded
2411
2411
2412 # only take into account for removes between wc and target
2412 # only take into account for removes between wc and target
2413 clean |= dsremoved - removed
2413 clean |= dsremoved - removed
2414 dsremoved &= removed
2414 dsremoved &= removed
2415 # distinct between dirstate remove and other
2415 # distinct between dirstate remove and other
2416 removed -= dsremoved
2416 removed -= dsremoved
2417
2417
2418 # tell newly modified apart.
2418 # tell newly modified apart.
2419 dsmodified &= modified
2419 dsmodified &= modified
2420 dsmodified |= modified & dsadded # dirstate added may needs backup
2420 dsmodified |= modified & dsadded # dirstate added may needs backup
2421 modified -= dsmodified
2421 modified -= dsmodified
2422
2422
2423 # if f is a rename, update `names` to also revert the source
2423 # if f is a rename, update `names` to also revert the source
2424 cwd = repo.getcwd()
2424 cwd = repo.getcwd()
2425 for f in dsadded:
2425 for f in dsadded:
2426 src = repo.dirstate.copied(f)
2426 src = repo.dirstate.copied(f)
2427 if src and src not in names and repo.dirstate[src] == 'r':
2427 if src and src not in names and repo.dirstate[src] == 'r':
2428 dsremoved.add(src)
2428 dsremoved.add(src)
2429 names[src] = (repo.pathto(src, cwd), True)
2429 names[src] = (repo.pathto(src, cwd), True)
2430
2430
2431 ## computation of the action to performs on `names` content.
2431 ## computation of the action to performs on `names` content.
2432
2432
2433 def removeforget(abs):
2433 def removeforget(abs):
2434 if repo.dirstate[abs] == 'a':
2434 if repo.dirstate[abs] == 'a':
2435 return _('forgetting %s\n')
2435 return _('forgetting %s\n')
2436 return _('removing %s\n')
2436 return _('removing %s\n')
2437
2437
2438 missingmodified = dsmodified - smf
2438 missingmodified = dsmodified - smf
2439 dsmodified -= missingmodified
2439 dsmodified -= missingmodified
2440 missingadded = dsadded - smf
2440 missingadded = dsadded - smf
2441 dsadded -= missingadded
2441 dsadded -= missingadded
2442
2442
2443 # action to be actually performed by revert
2443 # action to be actually performed by revert
2444 # (<list of file>, message>) tuple
2444 # (<list of file>, message>) tuple
2445 actions = {'revert': ([], _('reverting %s\n')),
2445 actions = {'revert': ([], _('reverting %s\n')),
2446 'add': ([], _('adding %s\n')),
2446 'add': ([], _('adding %s\n')),
2447 'remove': ([], removeforget),
2447 'remove': ([], removeforget),
2448 'undelete': ([], _('undeleting %s\n'))}
2448 'undelete': ([], _('undeleting %s\n'))}
2449
2449
2450 disptable = (
2450 disptable = (
2451 # dispatch table:
2451 # dispatch table:
2452 # file state
2452 # file state
2453 # action
2453 # action
2454 # make backup
2454 # make backup
2455 (modified, (actions['revert'], False)),
2455 (modified, (actions['revert'], False)),
2456 (dsmodified, (actions['revert'], True)),
2456 (dsmodified, (actions['revert'], True)),
2457 (missingmodified, (actions['remove'], True)),
2457 (missingmodified, (actions['remove'], True)),
2458 (dsadded, (actions['revert'], True)),
2458 (dsadded, (actions['revert'], True)),
2459 (missingadded, (actions['remove'], False)),
2459 (missingadded, (actions['remove'], False)),
2460 (removed, (actions['add'], True)),
2460 (removed, (actions['add'], True)),
2461 (dsremoved, (actions['undelete'], True)),
2461 (dsremoved, (actions['undelete'], True)),
2462 (clean, (None, False)),
2462 (clean, (None, False)),
2463 )
2463 )
2464
2464
2465 for abs, (rel, exact) in sorted(names.items()):
2465 for abs, (rel, exact) in sorted(names.items()):
2466 # hash on file in target manifest (or None if missing from target)
2466 # hash on file in target manifest (or None if missing from target)
2467 mfentry = mf.get(abs)
2467 mfentry = mf.get(abs)
2468 # target file to be touch on disk (relative to cwd)
2468 # target file to be touch on disk (relative to cwd)
2469 target = repo.wjoin(abs)
2469 target = repo.wjoin(abs)
2470 def handle(xlist, dobackup):
2470 def handle(xlist, dobackup):
2471 xlist[0].append(abs)
2471 xlist[0].append(abs)
2472 if (dobackup and not opts.get('no_backup') and
2472 if (dobackup and not opts.get('no_backup') and
2473 os.path.lexists(target) and
2473 os.path.lexists(target) and
2474 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2474 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2475 bakname = "%s.orig" % rel
2475 bakname = "%s.orig" % rel
2476 ui.note(_('saving current version of %s as %s\n') %
2476 ui.note(_('saving current version of %s as %s\n') %
2477 (rel, bakname))
2477 (rel, bakname))
2478 if not opts.get('dry_run'):
2478 if not opts.get('dry_run'):
2479 util.rename(target, bakname)
2479 util.rename(target, bakname)
2480 if ui.verbose or not exact:
2480 if ui.verbose or not exact:
2481 msg = xlist[1]
2481 msg = xlist[1]
2482 if not isinstance(msg, basestring):
2482 if not isinstance(msg, basestring):
2483 msg = msg(abs)
2483 msg = msg(abs)
2484 ui.status(msg % rel)
2484 ui.status(msg % rel)
2485 # search the entry in the dispatch table.
2485 # search the entry in the dispatch table.
2486 # if the file is in any of this sets, it was touched in the working
2486 # if the file is in any of this sets, it was touched in the working
2487 # directory parent and we are sure it needs to be reverted.
2487 # directory parent and we are sure it needs to be reverted.
2488 for table, (action, backup) in disptable:
2488 for table, (action, backup) in disptable:
2489 if abs not in table:
2489 if abs not in table:
2490 continue
2490 continue
2491 if action is None:
2491 if action is None:
2492 if exact:
2492 if exact:
2493 ui.warn(_('no changes needed to %s\n') % rel)
2493 ui.warn(_('no changes needed to %s\n') % rel)
2494
2494
2495 else:
2495 else:
2496 handle(action, backup)
2496 handle(action, backup)
2497 break
2497 break
2498 else:
2498 else:
2499 # Not touched in current dirstate.
2499 # Not touched in current dirstate.
2500
2500
2501 # file is unknown in parent, restore older version or ignore.
2501 # file is unknown in parent, restore older version or ignore.
2502 if abs not in repo.dirstate:
2502 if abs not in repo.dirstate:
2503 if exact:
2503 if exact:
2504 ui.warn(_('file not managed: %s\n') % rel)
2504 ui.warn(_('file not managed: %s\n') % rel)
2505 continue
2505 continue
2506
2506
2507 # parent is target, no changes mean no changes
2507 # parent is target, no changes mean no changes
2508 if node == parent:
2508 if node == parent:
2509 if exact:
2509 if exact:
2510 ui.warn(_('no changes needed to %s\n') % rel)
2510 ui.warn(_('no changes needed to %s\n') % rel)
2511 continue
2511 continue
2512 # no change in dirstate but parent and target may differ
2512 # no change in dirstate but parent and target may differ
2513 if pmf is None:
2513 if pmf is None:
2514 # only need parent manifest in this unlikely case,
2514 # only need parent manifest in this unlikely case,
2515 # so do not read by default
2515 # so do not read by default
2516 pmf = repo[parent].manifest()
2516 pmf = repo[parent].manifest()
2517 if abs in pmf and mfentry:
2517 if abs in pmf and mfentry:
2518 # if version of file is same in parent and target
2518 # if version of file is same in parent and target
2519 # manifests, do nothing
2519 # manifests, do nothing
2520 if (pmf[abs] != mfentry or
2520 if (pmf[abs] != mfentry or
2521 pmf.flags(abs) != mf.flags(abs)):
2521 pmf.flags(abs) != mf.flags(abs)):
2522 handle(actions['revert'], False)
2522 handle(actions['revert'], False)
2523 else:
2523 else:
2524 handle(actions['remove'], False)
2524 handle(actions['remove'], False)
2525
2525
2526 if not opts.get('dry_run'):
2526 if not opts.get('dry_run'):
2527 _performrevert(repo, parents, ctx, actions)
2527 _performrevert(repo, parents, ctx, actions)
2528
2528
2529 if targetsubs:
2529 if targetsubs:
2530 # Revert the subrepos on the revert list
2530 # Revert the subrepos on the revert list
2531 for sub in targetsubs:
2531 for sub in targetsubs:
2532 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2532 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2533 finally:
2533 finally:
2534 wlock.release()
2534 wlock.release()
2535
2535
2536 def _performrevert(repo, parents, ctx, actions):
2536 def _performrevert(repo, parents, ctx, actions):
2537 """function that actually perform all the actions computed for revert
2537 """function that actually perform all the actions computed for revert
2538
2538
2539 This is an independent function to let extension to plug in and react to
2539 This is an independent function to let extension to plug in and react to
2540 the imminent revert.
2540 the imminent revert.
2541
2541
2542 Make sure you have the working directory locked when calling this function.
2542 Make sure you have the working directory locked when calling this function.
2543 """
2543 """
2544 parent, p2 = parents
2544 parent, p2 = parents
2545 node = ctx.node()
2545 node = ctx.node()
2546 def checkout(f):
2546 def checkout(f):
2547 fc = ctx[f]
2547 fc = ctx[f]
2548 repo.wwrite(f, fc.data(), fc.flags())
2548 repo.wwrite(f, fc.data(), fc.flags())
2549
2549
2550 audit_path = pathutil.pathauditor(repo.root)
2550 audit_path = pathutil.pathauditor(repo.root)
2551 for f in actions['remove'][0]:
2551 for f in actions['remove'][0]:
2552 if repo.dirstate[f] == 'a':
2552 if repo.dirstate[f] == 'a':
2553 repo.dirstate.drop(f)
2553 repo.dirstate.drop(f)
2554 continue
2554 continue
2555 audit_path(f)
2555 audit_path(f)
2556 try:
2556 try:
2557 util.unlinkpath(repo.wjoin(f))
2557 util.unlinkpath(repo.wjoin(f))
2558 except OSError:
2558 except OSError:
2559 pass
2559 pass
2560 repo.dirstate.remove(f)
2560 repo.dirstate.remove(f)
2561
2561
2562 normal = None
2562 normal = None
2563 if node == parent:
2563 if node == parent:
2564 # We're reverting to our parent. If possible, we'd like status
2564 # We're reverting to our parent. If possible, we'd like status
2565 # to report the file as clean. We have to use normallookup for
2565 # to report the file as clean. We have to use normallookup for
2566 # merges to avoid losing information about merged/dirty files.
2566 # merges to avoid losing information about merged/dirty files.
2567 if p2 != nullid:
2567 if p2 != nullid:
2568 normal = repo.dirstate.normallookup
2568 normal = repo.dirstate.normallookup
2569 else:
2569 else:
2570 normal = repo.dirstate.normal
2570 normal = repo.dirstate.normal
2571 for f in actions['revert'][0]:
2571 for f in actions['revert'][0]:
2572 checkout(f)
2572 checkout(f)
2573 if normal:
2573 if normal:
2574 normal(f)
2574 normal(f)
2575
2575
2576 for f in actions['add'][0]:
2576 for f in actions['add'][0]:
2577 checkout(f)
2577 checkout(f)
2578 repo.dirstate.add(f)
2578 repo.dirstate.add(f)
2579
2579
2580 normal = repo.dirstate.normallookup
2580 normal = repo.dirstate.normallookup
2581 if node == parent and p2 == nullid:
2581 if node == parent and p2 == nullid:
2582 normal = repo.dirstate.normal
2582 normal = repo.dirstate.normal
2583 for f in actions['undelete'][0]:
2583 for f in actions['undelete'][0]:
2584 checkout(f)
2584 checkout(f)
2585 normal(f)
2585 normal(f)
2586
2586
2587 copied = copies.pathcopies(repo[parent], ctx)
2587 copied = copies.pathcopies(repo[parent], ctx)
2588
2588
2589 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2589 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2590 if f in copied:
2590 if f in copied:
2591 repo.dirstate.copy(copied[f], f)
2591 repo.dirstate.copy(copied[f], f)
2592
2592
2593 def command(table):
2593 def command(table):
2594 """Returns a function object to be used as a decorator for making commands.
2594 """Returns a function object to be used as a decorator for making commands.
2595
2595
2596 This function receives a command table as its argument. The table should
2596 This function receives a command table as its argument. The table should
2597 be a dict.
2597 be a dict.
2598
2598
2599 The returned function can be used as a decorator for adding commands
2599 The returned function can be used as a decorator for adding commands
2600 to that command table. This function accepts multiple arguments to define
2600 to that command table. This function accepts multiple arguments to define
2601 a command.
2601 a command.
2602
2602
2603 The first argument is the command name.
2603 The first argument is the command name.
2604
2604
2605 The options argument is an iterable of tuples defining command arguments.
2605 The options argument is an iterable of tuples defining command arguments.
2606 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2606 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2607
2607
2608 The synopsis argument defines a short, one line summary of how to use the
2608 The synopsis argument defines a short, one line summary of how to use the
2609 command. This shows up in the help output.
2609 command. This shows up in the help output.
2610
2610
2611 The norepo argument defines whether the command does not require a
2611 The norepo argument defines whether the command does not require a
2612 local repository. Most commands operate against a repository, thus the
2612 local repository. Most commands operate against a repository, thus the
2613 default is False.
2613 default is False.
2614
2614
2615 The optionalrepo argument defines whether the command optionally requires
2615 The optionalrepo argument defines whether the command optionally requires
2616 a local repository.
2616 a local repository.
2617
2617
2618 The inferrepo argument defines whether to try to find a repository from the
2618 The inferrepo argument defines whether to try to find a repository from the
2619 command line arguments. If True, arguments will be examined for potential
2619 command line arguments. If True, arguments will be examined for potential
2620 repository locations. See ``findrepo()``. If a repository is found, it
2620 repository locations. See ``findrepo()``. If a repository is found, it
2621 will be used.
2621 will be used.
2622 """
2622 """
2623 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2623 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2624 inferrepo=False):
2624 inferrepo=False):
2625 def decorator(func):
2625 def decorator(func):
2626 if synopsis:
2626 if synopsis:
2627 table[name] = func, list(options), synopsis
2627 table[name] = func, list(options), synopsis
2628 else:
2628 else:
2629 table[name] = func, list(options)
2629 table[name] = func, list(options)
2630
2630
2631 if norepo:
2631 if norepo:
2632 # Avoid import cycle.
2632 # Avoid import cycle.
2633 import commands
2633 import commands
2634 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2634 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2635
2635
2636 if optionalrepo:
2636 if optionalrepo:
2637 import commands
2637 import commands
2638 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2638 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2639
2639
2640 if inferrepo:
2640 if inferrepo:
2641 import commands
2641 import commands
2642 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2642 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2643
2643
2644 return func
2644 return func
2645 return decorator
2645 return decorator
2646
2646
2647 return cmd
2647 return cmd
2648
2648
2649 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2649 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2650 # commands.outgoing. "missing" is "missing" of the result of
2650 # commands.outgoing. "missing" is "missing" of the result of
2651 # "findcommonoutgoing()"
2651 # "findcommonoutgoing()"
2652 outgoinghooks = util.hooks()
2652 outgoinghooks = util.hooks()
2653
2653
2654 # a list of (ui, repo) functions called by commands.summary
2654 # a list of (ui, repo) functions called by commands.summary
2655 summaryhooks = util.hooks()
2655 summaryhooks = util.hooks()
2656
2656
2657 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2657 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2658 #
2658 #
2659 # functions should return tuple of booleans below, if 'changes' is None:
2659 # functions should return tuple of booleans below, if 'changes' is None:
2660 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2660 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2661 #
2661 #
2662 # otherwise, 'changes' is a tuple of tuples below:
2662 # otherwise, 'changes' is a tuple of tuples below:
2663 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2663 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2664 # - (desturl, destbranch, destpeer, outgoing)
2664 # - (desturl, destbranch, destpeer, outgoing)
2665 summaryremotehooks = util.hooks()
2665 summaryremotehooks = util.hooks()
2666
2666
2667 # A list of state files kept by multistep operations like graft.
2667 # A list of state files kept by multistep operations like graft.
2668 # Since graft cannot be aborted, it is considered 'clearable' by update.
2668 # Since graft cannot be aborted, it is considered 'clearable' by update.
2669 # note: bisect is intentionally excluded
2669 # note: bisect is intentionally excluded
2670 # (state file, clearable, allowcommit, error, hint)
2670 # (state file, clearable, allowcommit, error, hint)
2671 unfinishedstates = [
2671 unfinishedstates = [
2672 ('graftstate', True, False, _('graft in progress'),
2672 ('graftstate', True, False, _('graft in progress'),
2673 _("use 'hg graft --continue' or 'hg update' to abort")),
2673 _("use 'hg graft --continue' or 'hg update' to abort")),
2674 ('updatestate', True, False, _('last update was interrupted'),
2674 ('updatestate', True, False, _('last update was interrupted'),
2675 _("use 'hg update' to get a consistent checkout"))
2675 _("use 'hg update' to get a consistent checkout"))
2676 ]
2676 ]
2677
2677
2678 def checkunfinished(repo, commit=False):
2678 def checkunfinished(repo, commit=False):
2679 '''Look for an unfinished multistep operation, like graft, and abort
2679 '''Look for an unfinished multistep operation, like graft, and abort
2680 if found. It's probably good to check this right before
2680 if found. It's probably good to check this right before
2681 bailifchanged().
2681 bailifchanged().
2682 '''
2682 '''
2683 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2683 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2684 if commit and allowcommit:
2684 if commit and allowcommit:
2685 continue
2685 continue
2686 if repo.vfs.exists(f):
2686 if repo.vfs.exists(f):
2687 raise util.Abort(msg, hint=hint)
2687 raise util.Abort(msg, hint=hint)
2688
2688
2689 def clearunfinished(repo):
2689 def clearunfinished(repo):
2690 '''Check for unfinished operations (as above), and clear the ones
2690 '''Check for unfinished operations (as above), and clear the ones
2691 that are clearable.
2691 that are clearable.
2692 '''
2692 '''
2693 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2693 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2694 if not clearable and repo.vfs.exists(f):
2694 if not clearable and repo.vfs.exists(f):
2695 raise util.Abort(msg, hint=hint)
2695 raise util.Abort(msg, hint=hint)
2696 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2696 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2697 if clearable and repo.vfs.exists(f):
2697 if clearable and repo.vfs.exists(f):
2698 util.unlink(repo.join(f))
2698 util.unlink(repo.join(f))
@@ -1,1682 +1,1686 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. ``"$@"`` (with quotes) expands to all
232 arguments separated by a space. ``"$@"`` (with quotes) expands to all
233 arguments quoted individually and separated by a space. These expansions
233 arguments quoted individually and separated by a space. These expansions
234 happen before the command is passed to the shell.
234 happen before the command is passed to the shell.
235
235
236 Shell aliases are executed in an environment where ``$HG`` expands to
236 Shell aliases are executed in an environment where ``$HG`` expands to
237 the path of the Mercurial that was used to execute the alias. This is
237 the path of the Mercurial that was used to execute the alias. This is
238 useful when you want to call further Mercurial commands in a shell
238 useful when you want to call further Mercurial commands in a shell
239 alias, as was done above for the purge alias. In addition,
239 alias, as was done above for the purge alias. In addition,
240 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
240 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
241 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
241 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
242
242
243 .. note::
243 .. note::
244
244
245 Some global configuration options such as ``-R`` are
245 Some global configuration options such as ``-R`` are
246 processed before shell aliases and will thus not be passed to
246 processed before shell aliases and will thus not be passed to
247 aliases.
247 aliases.
248
248
249
249
250 ``annotate``
250 ``annotate``
251 ------------
251 ------------
252
252
253 Settings used when displaying file annotations. All values are
253 Settings used when displaying file annotations. All values are
254 Booleans and default to False. See ``diff`` section for related
254 Booleans and default to False. See ``diff`` section for related
255 options for the diff command.
255 options for the diff command.
256
256
257 ``ignorews``
257 ``ignorews``
258 Ignore white space when comparing lines.
258 Ignore white space when comparing lines.
259
259
260 ``ignorewsamount``
260 ``ignorewsamount``
261 Ignore changes in the amount of white space.
261 Ignore changes in the amount of white space.
262
262
263 ``ignoreblanklines``
263 ``ignoreblanklines``
264 Ignore changes whose lines are all blank.
264 Ignore changes whose lines are all blank.
265
265
266
266
267 ``auth``
267 ``auth``
268 --------
268 --------
269
269
270 Authentication credentials for HTTP authentication. This section
270 Authentication credentials for HTTP authentication. This section
271 allows you to store usernames and passwords for use when logging
271 allows you to store usernames and passwords for use when logging
272 *into* HTTP servers. See the ``[web]`` configuration section if
272 *into* HTTP servers. See the ``[web]`` configuration section if
273 you want to configure *who* can login to your HTTP server.
273 you want to configure *who* can login to your HTTP server.
274
274
275 Each line has the following format::
275 Each line has the following format::
276
276
277 <name>.<argument> = <value>
277 <name>.<argument> = <value>
278
278
279 where ``<name>`` is used to group arguments into authentication
279 where ``<name>`` is used to group arguments into authentication
280 entries. Example::
280 entries. Example::
281
281
282 foo.prefix = hg.intevation.org/mercurial
282 foo.prefix = hg.intevation.org/mercurial
283 foo.username = foo
283 foo.username = foo
284 foo.password = bar
284 foo.password = bar
285 foo.schemes = http https
285 foo.schemes = http https
286
286
287 bar.prefix = secure.example.org
287 bar.prefix = secure.example.org
288 bar.key = path/to/file.key
288 bar.key = path/to/file.key
289 bar.cert = path/to/file.cert
289 bar.cert = path/to/file.cert
290 bar.schemes = https
290 bar.schemes = https
291
291
292 Supported arguments:
292 Supported arguments:
293
293
294 ``prefix``
294 ``prefix``
295 Either ``*`` or a URI prefix with or without the scheme part.
295 Either ``*`` or a URI prefix with or without the scheme part.
296 The authentication entry with the longest matching prefix is used
296 The authentication entry with the longest matching prefix is used
297 (where ``*`` matches everything and counts as a match of length
297 (where ``*`` matches everything and counts as a match of length
298 1). If the prefix doesn't include a scheme, the match is performed
298 1). If the prefix doesn't include a scheme, the match is performed
299 against the URI with its scheme stripped as well, and the schemes
299 against the URI with its scheme stripped as well, and the schemes
300 argument, q.v., is then subsequently consulted.
300 argument, q.v., is then subsequently consulted.
301
301
302 ``username``
302 ``username``
303 Optional. Username to authenticate with. If not given, and the
303 Optional. Username to authenticate with. If not given, and the
304 remote site requires basic or digest authentication, the user will
304 remote site requires basic or digest authentication, the user will
305 be prompted for it. Environment variables are expanded in the
305 be prompted for it. Environment variables are expanded in the
306 username letting you do ``foo.username = $USER``. If the URI
306 username letting you do ``foo.username = $USER``. If the URI
307 includes a username, only ``[auth]`` entries with a matching
307 includes a username, only ``[auth]`` entries with a matching
308 username or without a username will be considered.
308 username or without a username will be considered.
309
309
310 ``password``
310 ``password``
311 Optional. Password to authenticate with. If not given, and the
311 Optional. Password to authenticate with. If not given, and the
312 remote site requires basic or digest authentication, the user
312 remote site requires basic or digest authentication, the user
313 will be prompted for it.
313 will be prompted for it.
314
314
315 ``key``
315 ``key``
316 Optional. PEM encoded client certificate key file. Environment
316 Optional. PEM encoded client certificate key file. Environment
317 variables are expanded in the filename.
317 variables are expanded in the filename.
318
318
319 ``cert``
319 ``cert``
320 Optional. PEM encoded client certificate chain file. Environment
320 Optional. PEM encoded client certificate chain file. Environment
321 variables are expanded in the filename.
321 variables are expanded in the filename.
322
322
323 ``schemes``
323 ``schemes``
324 Optional. Space separated list of URI schemes to use this
324 Optional. Space separated list of URI schemes to use this
325 authentication entry with. Only used if the prefix doesn't include
325 authentication entry with. Only used if the prefix doesn't include
326 a scheme. Supported schemes are http and https. They will match
326 a scheme. Supported schemes are http and https. They will match
327 static-http and static-https respectively, as well.
327 static-http and static-https respectively, as well.
328 Default: https.
328 Default: https.
329
329
330 If no suitable authentication entry is found, the user is prompted
330 If no suitable authentication entry is found, the user is prompted
331 for credentials as usual if required by the remote.
331 for credentials as usual if required by the remote.
332
332
333
333
334 ``committemplate``
334 ``committemplate``
335 ------------------
335 ------------------
336
336
337 ``changeset`` configuration in this section is used as the template to
337 ``changeset`` configuration in this section is used as the template to
338 customize the text shown in the editor when committing.
338 customize the text shown in the editor when committing.
339
339
340 In addition to pre-defined template keywords, commit log specific one
340 In addition to pre-defined template keywords, commit log specific one
341 below can be used for customization:
341 below can be used for customization:
342
342
343 ``extramsg``
343 ``extramsg``
344 String: Extra message (typically 'Leave message empty to abort
344 String: Extra message (typically 'Leave message empty to abort
345 commit.'). This may be changed by some commands or extensions.
345 commit.'). This may be changed by some commands or extensions.
346
346
347 For example, the template configuration below shows as same text as
347 For example, the template configuration below shows as same text as
348 one shown by default::
348 one shown by default::
349
349
350 [committemplate]
350 [committemplate]
351 changeset = {desc}\n\n
351 changeset = {desc}\n\n
352 HG: Enter commit message. Lines beginning with 'HG:' are removed.
352 HG: Enter commit message. Lines beginning with 'HG:' are removed.
353 HG: {extramsg}
353 HG: {extramsg}
354 HG: --
354 HG: --
355 HG: user: {author}\n{ifeq(p2rev, "-1", "",
355 HG: user: {author}\n{ifeq(p2rev, "-1", "",
356 "HG: branch merge\n")
356 "HG: branch merge\n")
357 }HG: branch '{branch}'\n{if(currentbookmark,
357 }HG: branch '{branch}'\n{if(currentbookmark,
358 "HG: bookmark '{currentbookmark}'\n") }{subrepos %
358 "HG: bookmark '{currentbookmark}'\n") }{subrepos %
359 "HG: subrepo {subrepo}\n" }{file_adds %
359 "HG: subrepo {subrepo}\n" }{file_adds %
360 "HG: added {file}\n" }{file_mods %
360 "HG: added {file}\n" }{file_mods %
361 "HG: changed {file}\n" }{file_dels %
361 "HG: changed {file}\n" }{file_dels %
362 "HG: removed {file}\n" }{if(files, "",
362 "HG: removed {file}\n" }{if(files, "",
363 "HG: no files changed\n")}
363 "HG: no files changed\n")}
364
364
365 .. note::
365 .. note::
366
366
367 For some problematic encodings (see :hg:`help win32mbcs` for
367 For some problematic encodings (see :hg:`help win32mbcs` for
368 detail), this customization should be configured carefully, to
368 detail), this customization should be configured carefully, to
369 avoid showing broken characters.
369 avoid showing broken characters.
370
370
371 For example, if multibyte character ending with backslash (0x5c) is
371 For example, if multibyte character ending with backslash (0x5c) is
372 followed by ASCII character 'n' in the customized template,
372 followed by ASCII character 'n' in the customized template,
373 sequence of backslash and 'n' is treated as line-feed unexpectedly
373 sequence of backslash and 'n' is treated as line-feed unexpectedly
374 (and multibyte character is broken, too).
374 (and multibyte character is broken, too).
375
375
376 Customized template is used for commands below (``--edit`` may be
376 Customized template is used for commands below (``--edit`` may be
377 required):
377 required):
378
378
379 - :hg:`backout`
379 - :hg:`backout`
380 - :hg:`commit`
380 - :hg:`commit`
381 - :hg:`fetch` (for merge commit only)
381 - :hg:`fetch` (for merge commit only)
382 - :hg:`graft`
382 - :hg:`graft`
383 - :hg:`histedit`
383 - :hg:`histedit`
384 - :hg:`import`
384 - :hg:`import`
385 - :hg:`qfold`, :hg:`qnew` and :hg:`qrefresh`
385 - :hg:`qfold`, :hg:`qnew` and :hg:`qrefresh`
386 - :hg:`rebase`
386 - :hg:`rebase`
387 - :hg:`shelve`
387 - :hg:`shelve`
388 - :hg:`sign`
388 - :hg:`sign`
389 - :hg:`tag`
389 - :hg:`tag`
390 - :hg:`transplant`
390 - :hg:`transplant`
391
391
392 Configuring items below instead of ``changeset`` allows showing
392 Configuring items below instead of ``changeset`` allows showing
393 customized message only for specific actions, or showing different
393 customized message only for specific actions, or showing different
394 messages for each actions.
394 messages for each actions.
395
395
396 - ``changeset.backout`` for :hg:`backout`
396 - ``changeset.backout`` for :hg:`backout`
397 - ``changeset.commit.amend`` for :hg:`commit --amend`
397 - ``changeset.commit.amend`` for :hg:`commit --amend`
398 - ``changeset.commit.normal`` for :hg:`commit` without ``--amend``
398 - ``changeset.commit.normal`` for :hg:`commit` without ``--amend``
399 - ``changeset.fetch`` for :hg:`fetch` (impling merge commit)
399 - ``changeset.fetch`` for :hg:`fetch` (impling merge commit)
400 - ``changeset.gpg.sign`` for :hg:`sign`
400 - ``changeset.gpg.sign`` for :hg:`sign`
401 - ``changeset.graft`` for :hg:`graft`
401 - ``changeset.graft`` for :hg:`graft`
402 - ``changeset.histedit.edit`` for ``edit`` of :hg:`histedit`
402 - ``changeset.histedit.edit`` for ``edit`` of :hg:`histedit`
403 - ``changeset.histedit.fold`` for ``fold`` of :hg:`histedit`
403 - ``changeset.histedit.fold`` for ``fold`` of :hg:`histedit`
404 - ``changeset.histedit.mess`` for ``mess`` of :hg:`histedit`
404 - ``changeset.histedit.mess`` for ``mess`` of :hg:`histedit`
405 - ``changeset.histedit.pick`` for ``pick`` of :hg:`histedit`
405 - ``changeset.histedit.pick`` for ``pick`` of :hg:`histedit`
406 - ``changeset.import.bypass`` for :hg:`import --bypass`
406 - ``changeset.import.bypass`` for :hg:`import --bypass`
407 - ``changeset.import.normal`` for :hg:`import` without ``--bypass``
407 - ``changeset.import.normal`` for :hg:`import` without ``--bypass``
408 - ``changeset.mq.qnew`` for :hg:`qnew`
408 - ``changeset.mq.qnew`` for :hg:`qnew`
409 - ``changeset.mq.qfold`` for :hg:`qfold`
409 - ``changeset.mq.qfold`` for :hg:`qfold`
410 - ``changeset.mq.qrefresh`` for :hg:`qrefresh`
410 - ``changeset.mq.qrefresh`` for :hg:`qrefresh`
411 - ``changeset.rebase.collapse`` for :hg:`rebase --collapse`
411 - ``changeset.rebase.collapse`` for :hg:`rebase --collapse`
412 - ``changeset.rebase.normal`` for :hg:`rebase` without ``--collapse``
412 - ``changeset.rebase.normal`` for :hg:`rebase` without ``--collapse``
413 - ``changeset.shelve.shelve`` for :hg:`shelve`
413 - ``changeset.shelve.shelve`` for :hg:`shelve`
414 - ``changeset.tag.add`` for :hg:`tag` without ``--remove``
414 - ``changeset.tag.add`` for :hg:`tag` without ``--remove``
415 - ``changeset.tag.remove`` for :hg:`tag --remove`
415 - ``changeset.tag.remove`` for :hg:`tag --remove`
416 - ``changeset.transplant`` for :hg:`transplant`
416 - ``changeset.transplant`` for :hg:`transplant`
417
417
418 These dot-separated lists of names are treated as hierarchical ones.
418 These dot-separated lists of names are treated as hierarchical ones.
419 For example, ``changeset.tag.remove`` customizes the commit message
419 For example, ``changeset.tag.remove`` customizes the commit message
420 only for :hg:`tag --remove`, but ``changeset.tag`` customizes the
420 only for :hg:`tag --remove`, but ``changeset.tag`` customizes the
421 commit message for :hg:`tag` regardless of ``--remove`` option.
421 commit message for :hg:`tag` regardless of ``--remove`` option.
422
422
423 At the external editor invocation for committing, corresponding
424 dot-separated list of names without ``changeset.`` prefix
425 (e.g. ``commit.normal``) is in ``HGEDITFORM`` environment variable.
426
423 In this section, items other than ``changeset`` can be referred from
427 In this section, items other than ``changeset`` can be referred from
424 others. For example, the configuration to list committed files up
428 others. For example, the configuration to list committed files up
425 below can be referred as ``{listupfiles}``::
429 below can be referred as ``{listupfiles}``::
426
430
427 [committemplate]
431 [committemplate]
428 listupfiles = {file_adds %
432 listupfiles = {file_adds %
429 "HG: added {file}\n" }{file_mods %
433 "HG: added {file}\n" }{file_mods %
430 "HG: changed {file}\n" }{file_dels %
434 "HG: changed {file}\n" }{file_dels %
431 "HG: removed {file}\n" }{if(files, "",
435 "HG: removed {file}\n" }{if(files, "",
432 "HG: no files changed\n")}
436 "HG: no files changed\n")}
433
437
434 ``decode/encode``
438 ``decode/encode``
435 -----------------
439 -----------------
436
440
437 Filters for transforming files on checkout/checkin. This would
441 Filters for transforming files on checkout/checkin. This would
438 typically be used for newline processing or other
442 typically be used for newline processing or other
439 localization/canonicalization of files.
443 localization/canonicalization of files.
440
444
441 Filters consist of a filter pattern followed by a filter command.
445 Filters consist of a filter pattern followed by a filter command.
442 Filter patterns are globs by default, rooted at the repository root.
446 Filter patterns are globs by default, rooted at the repository root.
443 For example, to match any file ending in ``.txt`` in the root
447 For example, to match any file ending in ``.txt`` in the root
444 directory only, use the pattern ``*.txt``. To match any file ending
448 directory only, use the pattern ``*.txt``. To match any file ending
445 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
449 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
446 For each file only the first matching filter applies.
450 For each file only the first matching filter applies.
447
451
448 The filter command can start with a specifier, either ``pipe:`` or
452 The filter command can start with a specifier, either ``pipe:`` or
449 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
453 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
450
454
451 A ``pipe:`` command must accept data on stdin and return the transformed
455 A ``pipe:`` command must accept data on stdin and return the transformed
452 data on stdout.
456 data on stdout.
453
457
454 Pipe example::
458 Pipe example::
455
459
456 [encode]
460 [encode]
457 # uncompress gzip files on checkin to improve delta compression
461 # uncompress gzip files on checkin to improve delta compression
458 # note: not necessarily a good idea, just an example
462 # note: not necessarily a good idea, just an example
459 *.gz = pipe: gunzip
463 *.gz = pipe: gunzip
460
464
461 [decode]
465 [decode]
462 # recompress gzip files when writing them to the working dir (we
466 # recompress gzip files when writing them to the working dir (we
463 # can safely omit "pipe:", because it's the default)
467 # can safely omit "pipe:", because it's the default)
464 *.gz = gzip
468 *.gz = gzip
465
469
466 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
470 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
467 with the name of a temporary file that contains the data to be
471 with the name of a temporary file that contains the data to be
468 filtered by the command. The string ``OUTFILE`` is replaced with the name
472 filtered by the command. The string ``OUTFILE`` is replaced with the name
469 of an empty temporary file, where the filtered data must be written by
473 of an empty temporary file, where the filtered data must be written by
470 the command.
474 the command.
471
475
472 .. note::
476 .. note::
473
477
474 The tempfile mechanism is recommended for Windows systems,
478 The tempfile mechanism is recommended for Windows systems,
475 where the standard shell I/O redirection operators often have
479 where the standard shell I/O redirection operators often have
476 strange effects and may corrupt the contents of your files.
480 strange effects and may corrupt the contents of your files.
477
481
478 This filter mechanism is used internally by the ``eol`` extension to
482 This filter mechanism is used internally by the ``eol`` extension to
479 translate line ending characters between Windows (CRLF) and Unix (LF)
483 translate line ending characters between Windows (CRLF) and Unix (LF)
480 format. We suggest you use the ``eol`` extension for convenience.
484 format. We suggest you use the ``eol`` extension for convenience.
481
485
482
486
483 ``defaults``
487 ``defaults``
484 ------------
488 ------------
485
489
486 (defaults are deprecated. Don't use them. Use aliases instead)
490 (defaults are deprecated. Don't use them. Use aliases instead)
487
491
488 Use the ``[defaults]`` section to define command defaults, i.e. the
492 Use the ``[defaults]`` section to define command defaults, i.e. the
489 default options/arguments to pass to the specified commands.
493 default options/arguments to pass to the specified commands.
490
494
491 The following example makes :hg:`log` run in verbose mode, and
495 The following example makes :hg:`log` run in verbose mode, and
492 :hg:`status` show only the modified files, by default::
496 :hg:`status` show only the modified files, by default::
493
497
494 [defaults]
498 [defaults]
495 log = -v
499 log = -v
496 status = -m
500 status = -m
497
501
498 The actual commands, instead of their aliases, must be used when
502 The actual commands, instead of their aliases, must be used when
499 defining command defaults. The command defaults will also be applied
503 defining command defaults. The command defaults will also be applied
500 to the aliases of the commands defined.
504 to the aliases of the commands defined.
501
505
502
506
503 ``diff``
507 ``diff``
504 --------
508 --------
505
509
506 Settings used when displaying diffs. Everything except for ``unified``
510 Settings used when displaying diffs. Everything except for ``unified``
507 is a Boolean and defaults to False. See ``annotate`` section for
511 is a Boolean and defaults to False. See ``annotate`` section for
508 related options for the annotate command.
512 related options for the annotate command.
509
513
510 ``git``
514 ``git``
511 Use git extended diff format.
515 Use git extended diff format.
512
516
513 ``nodates``
517 ``nodates``
514 Don't include dates in diff headers.
518 Don't include dates in diff headers.
515
519
516 ``showfunc``
520 ``showfunc``
517 Show which function each change is in.
521 Show which function each change is in.
518
522
519 ``ignorews``
523 ``ignorews``
520 Ignore white space when comparing lines.
524 Ignore white space when comparing lines.
521
525
522 ``ignorewsamount``
526 ``ignorewsamount``
523 Ignore changes in the amount of white space.
527 Ignore changes in the amount of white space.
524
528
525 ``ignoreblanklines``
529 ``ignoreblanklines``
526 Ignore changes whose lines are all blank.
530 Ignore changes whose lines are all blank.
527
531
528 ``unified``
532 ``unified``
529 Number of lines of context to show.
533 Number of lines of context to show.
530
534
531 ``email``
535 ``email``
532 ---------
536 ---------
533
537
534 Settings for extensions that send email messages.
538 Settings for extensions that send email messages.
535
539
536 ``from``
540 ``from``
537 Optional. Email address to use in "From" header and SMTP envelope
541 Optional. Email address to use in "From" header and SMTP envelope
538 of outgoing messages.
542 of outgoing messages.
539
543
540 ``to``
544 ``to``
541 Optional. Comma-separated list of recipients' email addresses.
545 Optional. Comma-separated list of recipients' email addresses.
542
546
543 ``cc``
547 ``cc``
544 Optional. Comma-separated list of carbon copy recipients'
548 Optional. Comma-separated list of carbon copy recipients'
545 email addresses.
549 email addresses.
546
550
547 ``bcc``
551 ``bcc``
548 Optional. Comma-separated list of blind carbon copy recipients'
552 Optional. Comma-separated list of blind carbon copy recipients'
549 email addresses.
553 email addresses.
550
554
551 ``method``
555 ``method``
552 Optional. Method to use to send email messages. If value is ``smtp``
556 Optional. Method to use to send email messages. If value is ``smtp``
553 (default), use SMTP (see the ``[smtp]`` section for configuration).
557 (default), use SMTP (see the ``[smtp]`` section for configuration).
554 Otherwise, use as name of program to run that acts like sendmail
558 Otherwise, use as name of program to run that acts like sendmail
555 (takes ``-f`` option for sender, list of recipients on command line,
559 (takes ``-f`` option for sender, list of recipients on command line,
556 message on stdin). Normally, setting this to ``sendmail`` or
560 message on stdin). Normally, setting this to ``sendmail`` or
557 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
561 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
558
562
559 ``charsets``
563 ``charsets``
560 Optional. Comma-separated list of character sets considered
564 Optional. Comma-separated list of character sets considered
561 convenient for recipients. Addresses, headers, and parts not
565 convenient for recipients. Addresses, headers, and parts not
562 containing patches of outgoing messages will be encoded in the
566 containing patches of outgoing messages will be encoded in the
563 first character set to which conversion from local encoding
567 first character set to which conversion from local encoding
564 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
568 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
565 conversion fails, the text in question is sent as is. Defaults to
569 conversion fails, the text in question is sent as is. Defaults to
566 empty (explicit) list.
570 empty (explicit) list.
567
571
568 Order of outgoing email character sets:
572 Order of outgoing email character sets:
569
573
570 1. ``us-ascii``: always first, regardless of settings
574 1. ``us-ascii``: always first, regardless of settings
571 2. ``email.charsets``: in order given by user
575 2. ``email.charsets``: in order given by user
572 3. ``ui.fallbackencoding``: if not in email.charsets
576 3. ``ui.fallbackencoding``: if not in email.charsets
573 4. ``$HGENCODING``: if not in email.charsets
577 4. ``$HGENCODING``: if not in email.charsets
574 5. ``utf-8``: always last, regardless of settings
578 5. ``utf-8``: always last, regardless of settings
575
579
576 Email example::
580 Email example::
577
581
578 [email]
582 [email]
579 from = Joseph User <joe.user@example.com>
583 from = Joseph User <joe.user@example.com>
580 method = /usr/sbin/sendmail
584 method = /usr/sbin/sendmail
581 # charsets for western Europeans
585 # charsets for western Europeans
582 # us-ascii, utf-8 omitted, as they are tried first and last
586 # us-ascii, utf-8 omitted, as they are tried first and last
583 charsets = iso-8859-1, iso-8859-15, windows-1252
587 charsets = iso-8859-1, iso-8859-15, windows-1252
584
588
585
589
586 ``extensions``
590 ``extensions``
587 --------------
591 --------------
588
592
589 Mercurial has an extension mechanism for adding new features. To
593 Mercurial has an extension mechanism for adding new features. To
590 enable an extension, create an entry for it in this section.
594 enable an extension, create an entry for it in this section.
591
595
592 If you know that the extension is already in Python's search path,
596 If you know that the extension is already in Python's search path,
593 you can give the name of the module, followed by ``=``, with nothing
597 you can give the name of the module, followed by ``=``, with nothing
594 after the ``=``.
598 after the ``=``.
595
599
596 Otherwise, give a name that you choose, followed by ``=``, followed by
600 Otherwise, give a name that you choose, followed by ``=``, followed by
597 the path to the ``.py`` file (including the file name extension) that
601 the path to the ``.py`` file (including the file name extension) that
598 defines the extension.
602 defines the extension.
599
603
600 To explicitly disable an extension that is enabled in an hgrc of
604 To explicitly disable an extension that is enabled in an hgrc of
601 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
605 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
602 or ``foo = !`` when path is not supplied.
606 or ``foo = !`` when path is not supplied.
603
607
604 Example for ``~/.hgrc``::
608 Example for ``~/.hgrc``::
605
609
606 [extensions]
610 [extensions]
607 # (the progress extension will get loaded from Mercurial's path)
611 # (the progress extension will get loaded from Mercurial's path)
608 progress =
612 progress =
609 # (this extension will get loaded from the file specified)
613 # (this extension will get loaded from the file specified)
610 myfeature = ~/.hgext/myfeature.py
614 myfeature = ~/.hgext/myfeature.py
611
615
612
616
613 ``format``
617 ``format``
614 ----------
618 ----------
615
619
616 ``usestore``
620 ``usestore``
617 Enable or disable the "store" repository format which improves
621 Enable or disable the "store" repository format which improves
618 compatibility with systems that fold case or otherwise mangle
622 compatibility with systems that fold case or otherwise mangle
619 filenames. Enabled by default. Disabling this option will allow
623 filenames. Enabled by default. Disabling this option will allow
620 you to store longer filenames in some situations at the expense of
624 you to store longer filenames in some situations at the expense of
621 compatibility and ensures that the on-disk format of newly created
625 compatibility and ensures that the on-disk format of newly created
622 repositories will be compatible with Mercurial before version 0.9.4.
626 repositories will be compatible with Mercurial before version 0.9.4.
623
627
624 ``usefncache``
628 ``usefncache``
625 Enable or disable the "fncache" repository format which enhances
629 Enable or disable the "fncache" repository format which enhances
626 the "store" repository format (which has to be enabled to use
630 the "store" repository format (which has to be enabled to use
627 fncache) to allow longer filenames and avoids using Windows
631 fncache) to allow longer filenames and avoids using Windows
628 reserved names, e.g. "nul". Enabled by default. Disabling this
632 reserved names, e.g. "nul". Enabled by default. Disabling this
629 option ensures that the on-disk format of newly created
633 option ensures that the on-disk format of newly created
630 repositories will be compatible with Mercurial before version 1.1.
634 repositories will be compatible with Mercurial before version 1.1.
631
635
632 ``dotencode``
636 ``dotencode``
633 Enable or disable the "dotencode" repository format which enhances
637 Enable or disable the "dotencode" repository format which enhances
634 the "fncache" repository format (which has to be enabled to use
638 the "fncache" repository format (which has to be enabled to use
635 dotencode) to avoid issues with filenames starting with ._ on
639 dotencode) to avoid issues with filenames starting with ._ on
636 Mac OS X and spaces on Windows. Enabled by default. Disabling this
640 Mac OS X and spaces on Windows. Enabled by default. Disabling this
637 option ensures that the on-disk format of newly created
641 option ensures that the on-disk format of newly created
638 repositories will be compatible with Mercurial before version 1.7.
642 repositories will be compatible with Mercurial before version 1.7.
639
643
640 ``graph``
644 ``graph``
641 ---------
645 ---------
642
646
643 Web graph view configuration. This section let you change graph
647 Web graph view configuration. This section let you change graph
644 elements display properties by branches, for instance to make the
648 elements display properties by branches, for instance to make the
645 ``default`` branch stand out.
649 ``default`` branch stand out.
646
650
647 Each line has the following format::
651 Each line has the following format::
648
652
649 <branch>.<argument> = <value>
653 <branch>.<argument> = <value>
650
654
651 where ``<branch>`` is the name of the branch being
655 where ``<branch>`` is the name of the branch being
652 customized. Example::
656 customized. Example::
653
657
654 [graph]
658 [graph]
655 # 2px width
659 # 2px width
656 default.width = 2
660 default.width = 2
657 # red color
661 # red color
658 default.color = FF0000
662 default.color = FF0000
659
663
660 Supported arguments:
664 Supported arguments:
661
665
662 ``width``
666 ``width``
663 Set branch edges width in pixels.
667 Set branch edges width in pixels.
664
668
665 ``color``
669 ``color``
666 Set branch edges color in hexadecimal RGB notation.
670 Set branch edges color in hexadecimal RGB notation.
667
671
668 ``hooks``
672 ``hooks``
669 ---------
673 ---------
670
674
671 Commands or Python functions that get automatically executed by
675 Commands or Python functions that get automatically executed by
672 various actions such as starting or finishing a commit. Multiple
676 various actions such as starting or finishing a commit. Multiple
673 hooks can be run for the same action by appending a suffix to the
677 hooks can be run for the same action by appending a suffix to the
674 action. Overriding a site-wide hook can be done by changing its
678 action. Overriding a site-wide hook can be done by changing its
675 value or setting it to an empty string. Hooks can be prioritized
679 value or setting it to an empty string. Hooks can be prioritized
676 by adding a prefix of ``priority`` to the hook name on a new line
680 by adding a prefix of ``priority`` to the hook name on a new line
677 and setting the priority. The default priority is 0 if
681 and setting the priority. The default priority is 0 if
678 not specified.
682 not specified.
679
683
680 Example ``.hg/hgrc``::
684 Example ``.hg/hgrc``::
681
685
682 [hooks]
686 [hooks]
683 # update working directory after adding changesets
687 # update working directory after adding changesets
684 changegroup.update = hg update
688 changegroup.update = hg update
685 # do not use the site-wide hook
689 # do not use the site-wide hook
686 incoming =
690 incoming =
687 incoming.email = /my/email/hook
691 incoming.email = /my/email/hook
688 incoming.autobuild = /my/build/hook
692 incoming.autobuild = /my/build/hook
689 # force autobuild hook to run before other incoming hooks
693 # force autobuild hook to run before other incoming hooks
690 priority.incoming.autobuild = 1
694 priority.incoming.autobuild = 1
691
695
692 Most hooks are run with environment variables set that give useful
696 Most hooks are run with environment variables set that give useful
693 additional information. For each hook below, the environment
697 additional information. For each hook below, the environment
694 variables it is passed are listed with names of the form ``$HG_foo``.
698 variables it is passed are listed with names of the form ``$HG_foo``.
695
699
696 ``changegroup``
700 ``changegroup``
697 Run after a changegroup has been added via push, pull or unbundle.
701 Run after a changegroup has been added via push, pull or unbundle.
698 ID of the first new changeset is in ``$HG_NODE``. URL from which
702 ID of the first new changeset is in ``$HG_NODE``. URL from which
699 changes came is in ``$HG_URL``.
703 changes came is in ``$HG_URL``.
700
704
701 ``commit``
705 ``commit``
702 Run after a changeset has been created in the local repository. ID
706 Run after a changeset has been created in the local repository. ID
703 of the newly created changeset is in ``$HG_NODE``. Parent changeset
707 of the newly created changeset is in ``$HG_NODE``. Parent changeset
704 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
708 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
705
709
706 ``incoming``
710 ``incoming``
707 Run after a changeset has been pulled, pushed, or unbundled into
711 Run after a changeset has been pulled, pushed, or unbundled into
708 the local repository. The ID of the newly arrived changeset is in
712 the local repository. The ID of the newly arrived changeset is in
709 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
713 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
710
714
711 ``outgoing``
715 ``outgoing``
712 Run after sending changes from local repository to another. ID of
716 Run after sending changes from local repository to another. ID of
713 first changeset sent is in ``$HG_NODE``. Source of operation is in
717 first changeset sent is in ``$HG_NODE``. Source of operation is in
714 ``$HG_SOURCE``; see "preoutgoing" hook for description.
718 ``$HG_SOURCE``; see "preoutgoing" hook for description.
715
719
716 ``post-<command>``
720 ``post-<command>``
717 Run after successful invocations of the associated command. The
721 Run after successful invocations of the associated command. The
718 contents of the command line are passed as ``$HG_ARGS`` and the result
722 contents of the command line are passed as ``$HG_ARGS`` and the result
719 code in ``$HG_RESULT``. Parsed command line arguments are passed as
723 code in ``$HG_RESULT``. Parsed command line arguments are passed as
720 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
724 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
721 the python data internally passed to <command>. ``$HG_OPTS`` is a
725 the python data internally passed to <command>. ``$HG_OPTS`` is a
722 dictionary of options (with unspecified options set to their defaults).
726 dictionary of options (with unspecified options set to their defaults).
723 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
727 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
724
728
725 ``pre-<command>``
729 ``pre-<command>``
726 Run before executing the associated command. The contents of the
730 Run before executing the associated command. The contents of the
727 command line are passed as ``$HG_ARGS``. Parsed command line arguments
731 command line are passed as ``$HG_ARGS``. Parsed command line arguments
728 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
732 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
729 representations of the data internally passed to <command>. ``$HG_OPTS``
733 representations of the data internally passed to <command>. ``$HG_OPTS``
730 is a dictionary of options (with unspecified options set to their
734 is a dictionary of options (with unspecified options set to their
731 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
735 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
732 failure, the command doesn't execute and Mercurial returns the failure
736 failure, the command doesn't execute and Mercurial returns the failure
733 code.
737 code.
734
738
735 ``prechangegroup``
739 ``prechangegroup``
736 Run before a changegroup is added via push, pull or unbundle. Exit
740 Run before a changegroup is added via push, pull or unbundle. Exit
737 status 0 allows the changegroup to proceed. Non-zero status will
741 status 0 allows the changegroup to proceed. Non-zero status will
738 cause the push, pull or unbundle to fail. URL from which changes
742 cause the push, pull or unbundle to fail. URL from which changes
739 will come is in ``$HG_URL``.
743 will come is in ``$HG_URL``.
740
744
741 ``precommit``
745 ``precommit``
742 Run before starting a local commit. Exit status 0 allows the
746 Run before starting a local commit. Exit status 0 allows the
743 commit to proceed. Non-zero status will cause the commit to fail.
747 commit to proceed. Non-zero status will cause the commit to fail.
744 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
748 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
745
749
746 ``prelistkeys``
750 ``prelistkeys``
747 Run before listing pushkeys (like bookmarks) in the
751 Run before listing pushkeys (like bookmarks) in the
748 repository. Non-zero status will cause failure. The key namespace is
752 repository. Non-zero status will cause failure. The key namespace is
749 in ``$HG_NAMESPACE``.
753 in ``$HG_NAMESPACE``.
750
754
751 ``preoutgoing``
755 ``preoutgoing``
752 Run before collecting changes to send from the local repository to
756 Run before collecting changes to send from the local repository to
753 another. Non-zero status will cause failure. This lets you prevent
757 another. Non-zero status will cause failure. This lets you prevent
754 pull over HTTP or SSH. Also prevents against local pull, push
758 pull over HTTP or SSH. Also prevents against local pull, push
755 (outbound) or bundle commands, but not effective, since you can
759 (outbound) or bundle commands, but not effective, since you can
756 just copy files instead then. Source of operation is in
760 just copy files instead then. Source of operation is in
757 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
761 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
758 SSH or HTTP repository. If "push", "pull" or "bundle", operation
762 SSH or HTTP repository. If "push", "pull" or "bundle", operation
759 is happening on behalf of repository on same system.
763 is happening on behalf of repository on same system.
760
764
761 ``prepushkey``
765 ``prepushkey``
762 Run before a pushkey (like a bookmark) is added to the
766 Run before a pushkey (like a bookmark) is added to the
763 repository. Non-zero status will cause the key to be rejected. The
767 repository. Non-zero status will cause the key to be rejected. The
764 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
768 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
765 the old value (if any) is in ``$HG_OLD``, and the new value is in
769 the old value (if any) is in ``$HG_OLD``, and the new value is in
766 ``$HG_NEW``.
770 ``$HG_NEW``.
767
771
768 ``pretag``
772 ``pretag``
769 Run before creating a tag. Exit status 0 allows the tag to be
773 Run before creating a tag. Exit status 0 allows the tag to be
770 created. Non-zero status will cause the tag to fail. ID of
774 created. Non-zero status will cause the tag to fail. ID of
771 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
775 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
772 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
776 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
773
777
774 ``pretxnchangegroup``
778 ``pretxnchangegroup``
775 Run after a changegroup has been added via push, pull or unbundle,
779 Run after a changegroup has been added via push, pull or unbundle,
776 but before the transaction has been committed. Changegroup is
780 but before the transaction has been committed. Changegroup is
777 visible to hook program. This lets you validate incoming changes
781 visible to hook program. This lets you validate incoming changes
778 before accepting them. Passed the ID of the first new changeset in
782 before accepting them. Passed the ID of the first new changeset in
779 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
783 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
780 status will cause the transaction to be rolled back and the push,
784 status will cause the transaction to be rolled back and the push,
781 pull or unbundle will fail. URL that was source of changes is in
785 pull or unbundle will fail. URL that was source of changes is in
782 ``$HG_URL``.
786 ``$HG_URL``.
783
787
784 ``pretxncommit``
788 ``pretxncommit``
785 Run after a changeset has been created but the transaction not yet
789 Run after a changeset has been created but the transaction not yet
786 committed. Changeset is visible to hook program. This lets you
790 committed. Changeset is visible to hook program. This lets you
787 validate commit message and changes. Exit status 0 allows the
791 validate commit message and changes. Exit status 0 allows the
788 commit to proceed. Non-zero status will cause the transaction to
792 commit to proceed. Non-zero status will cause the transaction to
789 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
793 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
790 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
794 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
791
795
792 ``preupdate``
796 ``preupdate``
793 Run before updating the working directory. Exit status 0 allows
797 Run before updating the working directory. Exit status 0 allows
794 the update to proceed. Non-zero status will prevent the update.
798 the update to proceed. Non-zero status will prevent the update.
795 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
799 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
796 of second new parent is in ``$HG_PARENT2``.
800 of second new parent is in ``$HG_PARENT2``.
797
801
798 ``listkeys``
802 ``listkeys``
799 Run after listing pushkeys (like bookmarks) in the repository. The
803 Run after listing pushkeys (like bookmarks) in the repository. The
800 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
804 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
801 dictionary containing the keys and values.
805 dictionary containing the keys and values.
802
806
803 ``pushkey``
807 ``pushkey``
804 Run after a pushkey (like a bookmark) is added to the
808 Run after a pushkey (like a bookmark) is added to the
805 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
809 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
806 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
810 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
807 value is in ``$HG_NEW``.
811 value is in ``$HG_NEW``.
808
812
809 ``tag``
813 ``tag``
810 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
814 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
811 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
815 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
812 repository if ``$HG_LOCAL=0``.
816 repository if ``$HG_LOCAL=0``.
813
817
814 ``update``
818 ``update``
815 Run after updating the working directory. Changeset ID of first
819 Run after updating the working directory. Changeset ID of first
816 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
820 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
817 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
821 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
818 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
822 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
819
823
820 .. note::
824 .. note::
821
825
822 It is generally better to use standard hooks rather than the
826 It is generally better to use standard hooks rather than the
823 generic pre- and post- command hooks as they are guaranteed to be
827 generic pre- and post- command hooks as they are guaranteed to be
824 called in the appropriate contexts for influencing transactions.
828 called in the appropriate contexts for influencing transactions.
825 Also, hooks like "commit" will be called in all contexts that
829 Also, hooks like "commit" will be called in all contexts that
826 generate a commit (e.g. tag) and not just the commit command.
830 generate a commit (e.g. tag) and not just the commit command.
827
831
828 .. note::
832 .. note::
829
833
830 Environment variables with empty values may not be passed to
834 Environment variables with empty values may not be passed to
831 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
835 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
832 will have an empty value under Unix-like platforms for non-merge
836 will have an empty value under Unix-like platforms for non-merge
833 changesets, while it will not be available at all under Windows.
837 changesets, while it will not be available at all under Windows.
834
838
835 The syntax for Python hooks is as follows::
839 The syntax for Python hooks is as follows::
836
840
837 hookname = python:modulename.submodule.callable
841 hookname = python:modulename.submodule.callable
838 hookname = python:/path/to/python/module.py:callable
842 hookname = python:/path/to/python/module.py:callable
839
843
840 Python hooks are run within the Mercurial process. Each hook is
844 Python hooks are run within the Mercurial process. Each hook is
841 called with at least three keyword arguments: a ui object (keyword
845 called with at least three keyword arguments: a ui object (keyword
842 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
846 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
843 keyword that tells what kind of hook is used. Arguments listed as
847 keyword that tells what kind of hook is used. Arguments listed as
844 environment variables above are passed as keyword arguments, with no
848 environment variables above are passed as keyword arguments, with no
845 ``HG_`` prefix, and names in lower case.
849 ``HG_`` prefix, and names in lower case.
846
850
847 If a Python hook returns a "true" value or raises an exception, this
851 If a Python hook returns a "true" value or raises an exception, this
848 is treated as a failure.
852 is treated as a failure.
849
853
850
854
851 ``hostfingerprints``
855 ``hostfingerprints``
852 --------------------
856 --------------------
853
857
854 Fingerprints of the certificates of known HTTPS servers.
858 Fingerprints of the certificates of known HTTPS servers.
855 A HTTPS connection to a server with a fingerprint configured here will
859 A HTTPS connection to a server with a fingerprint configured here will
856 only succeed if the servers certificate matches the fingerprint.
860 only succeed if the servers certificate matches the fingerprint.
857 This is very similar to how ssh known hosts works.
861 This is very similar to how ssh known hosts works.
858 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
862 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
859 The CA chain and web.cacerts is not used for servers with a fingerprint.
863 The CA chain and web.cacerts is not used for servers with a fingerprint.
860
864
861 For example::
865 For example::
862
866
863 [hostfingerprints]
867 [hostfingerprints]
864 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
868 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
865
869
866 This feature is only supported when using Python 2.6 or later.
870 This feature is only supported when using Python 2.6 or later.
867
871
868
872
869 ``http_proxy``
873 ``http_proxy``
870 --------------
874 --------------
871
875
872 Used to access web-based Mercurial repositories through a HTTP
876 Used to access web-based Mercurial repositories through a HTTP
873 proxy.
877 proxy.
874
878
875 ``host``
879 ``host``
876 Host name and (optional) port of the proxy server, for example
880 Host name and (optional) port of the proxy server, for example
877 "myproxy:8000".
881 "myproxy:8000".
878
882
879 ``no``
883 ``no``
880 Optional. Comma-separated list of host names that should bypass
884 Optional. Comma-separated list of host names that should bypass
881 the proxy.
885 the proxy.
882
886
883 ``passwd``
887 ``passwd``
884 Optional. Password to authenticate with at the proxy server.
888 Optional. Password to authenticate with at the proxy server.
885
889
886 ``user``
890 ``user``
887 Optional. User name to authenticate with at the proxy server.
891 Optional. User name to authenticate with at the proxy server.
888
892
889 ``always``
893 ``always``
890 Optional. Always use the proxy, even for localhost and any entries
894 Optional. Always use the proxy, even for localhost and any entries
891 in ``http_proxy.no``. True or False. Default: False.
895 in ``http_proxy.no``. True or False. Default: False.
892
896
893 ``merge-patterns``
897 ``merge-patterns``
894 ------------------
898 ------------------
895
899
896 This section specifies merge tools to associate with particular file
900 This section specifies merge tools to associate with particular file
897 patterns. Tools matched here will take precedence over the default
901 patterns. Tools matched here will take precedence over the default
898 merge tool. Patterns are globs by default, rooted at the repository
902 merge tool. Patterns are globs by default, rooted at the repository
899 root.
903 root.
900
904
901 Example::
905 Example::
902
906
903 [merge-patterns]
907 [merge-patterns]
904 **.c = kdiff3
908 **.c = kdiff3
905 **.jpg = myimgmerge
909 **.jpg = myimgmerge
906
910
907 ``merge-tools``
911 ``merge-tools``
908 ---------------
912 ---------------
909
913
910 This section configures external merge tools to use for file-level
914 This section configures external merge tools to use for file-level
911 merges. This section has likely been preconfigured at install time.
915 merges. This section has likely been preconfigured at install time.
912 Use :hg:`config merge-tools` to check the existing configuration.
916 Use :hg:`config merge-tools` to check the existing configuration.
913 Also see :hg:`help merge-tools` for more details.
917 Also see :hg:`help merge-tools` for more details.
914
918
915 Example ``~/.hgrc``::
919 Example ``~/.hgrc``::
916
920
917 [merge-tools]
921 [merge-tools]
918 # Override stock tool location
922 # Override stock tool location
919 kdiff3.executable = ~/bin/kdiff3
923 kdiff3.executable = ~/bin/kdiff3
920 # Specify command line
924 # Specify command line
921 kdiff3.args = $base $local $other -o $output
925 kdiff3.args = $base $local $other -o $output
922 # Give higher priority
926 # Give higher priority
923 kdiff3.priority = 1
927 kdiff3.priority = 1
924
928
925 # Changing the priority of preconfigured tool
929 # Changing the priority of preconfigured tool
926 vimdiff.priority = 0
930 vimdiff.priority = 0
927
931
928 # Define new tool
932 # Define new tool
929 myHtmlTool.args = -m $local $other $base $output
933 myHtmlTool.args = -m $local $other $base $output
930 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
934 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
931 myHtmlTool.priority = 1
935 myHtmlTool.priority = 1
932
936
933 Supported arguments:
937 Supported arguments:
934
938
935 ``priority``
939 ``priority``
936 The priority in which to evaluate this tool.
940 The priority in which to evaluate this tool.
937 Default: 0.
941 Default: 0.
938
942
939 ``executable``
943 ``executable``
940 Either just the name of the executable or its pathname. On Windows,
944 Either just the name of the executable or its pathname. On Windows,
941 the path can use environment variables with ${ProgramFiles} syntax.
945 the path can use environment variables with ${ProgramFiles} syntax.
942 Default: the tool name.
946 Default: the tool name.
943
947
944 ``args``
948 ``args``
945 The arguments to pass to the tool executable. You can refer to the
949 The arguments to pass to the tool executable. You can refer to the
946 files being merged as well as the output file through these
950 files being merged as well as the output file through these
947 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
951 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
948 of ``$local`` and ``$other`` can vary depending on which action is being
952 of ``$local`` and ``$other`` can vary depending on which action is being
949 performed. During and update or merge, ``$local`` represents the original
953 performed. During and update or merge, ``$local`` represents the original
950 state of the file, while ``$other`` represents the commit you are updating
954 state of the file, while ``$other`` represents the commit you are updating
951 to or the commit you are merging with. During a rebase ``$local``
955 to or the commit you are merging with. During a rebase ``$local``
952 represents the destination of the rebase, and ``$other`` represents the
956 represents the destination of the rebase, and ``$other`` represents the
953 commit being rebased.
957 commit being rebased.
954 Default: ``$local $base $other``
958 Default: ``$local $base $other``
955
959
956 ``premerge``
960 ``premerge``
957 Attempt to run internal non-interactive 3-way merge tool before
961 Attempt to run internal non-interactive 3-way merge tool before
958 launching external tool. Options are ``true``, ``false``, ``keep`` or
962 launching external tool. Options are ``true``, ``false``, ``keep`` or
959 ``keep-merge3``. The ``keep`` option will leave markers in the file if the
963 ``keep-merge3``. The ``keep`` option will leave markers in the file if the
960 premerge fails. The ``keep-merge3`` will do the same but include information
964 premerge fails. The ``keep-merge3`` will do the same but include information
961 about the base of the merge in the marker (see internal:merge3).
965 about the base of the merge in the marker (see internal:merge3).
962 Default: True
966 Default: True
963
967
964 ``binary``
968 ``binary``
965 This tool can merge binary files. Defaults to False, unless tool
969 This tool can merge binary files. Defaults to False, unless tool
966 was selected by file pattern match.
970 was selected by file pattern match.
967
971
968 ``symlink``
972 ``symlink``
969 This tool can merge symlinks. Defaults to False, even if tool was
973 This tool can merge symlinks. Defaults to False, even if tool was
970 selected by file pattern match.
974 selected by file pattern match.
971
975
972 ``check``
976 ``check``
973 A list of merge success-checking options:
977 A list of merge success-checking options:
974
978
975 ``changed``
979 ``changed``
976 Ask whether merge was successful when the merged file shows no changes.
980 Ask whether merge was successful when the merged file shows no changes.
977 ``conflicts``
981 ``conflicts``
978 Check whether there are conflicts even though the tool reported success.
982 Check whether there are conflicts even though the tool reported success.
979 ``prompt``
983 ``prompt``
980 Always prompt for merge success, regardless of success reported by tool.
984 Always prompt for merge success, regardless of success reported by tool.
981
985
982 ``fixeol``
986 ``fixeol``
983 Attempt to fix up EOL changes caused by the merge tool.
987 Attempt to fix up EOL changes caused by the merge tool.
984 Default: False
988 Default: False
985
989
986 ``gui``
990 ``gui``
987 This tool requires a graphical interface to run. Default: False
991 This tool requires a graphical interface to run. Default: False
988
992
989 ``regkey``
993 ``regkey``
990 Windows registry key which describes install location of this
994 Windows registry key which describes install location of this
991 tool. Mercurial will search for this key first under
995 tool. Mercurial will search for this key first under
992 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
996 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
993 Default: None
997 Default: None
994
998
995 ``regkeyalt``
999 ``regkeyalt``
996 An alternate Windows registry key to try if the first key is not
1000 An alternate Windows registry key to try if the first key is not
997 found. The alternate key uses the same ``regname`` and ``regappend``
1001 found. The alternate key uses the same ``regname`` and ``regappend``
998 semantics of the primary key. The most common use for this key
1002 semantics of the primary key. The most common use for this key
999 is to search for 32bit applications on 64bit operating systems.
1003 is to search for 32bit applications on 64bit operating systems.
1000 Default: None
1004 Default: None
1001
1005
1002 ``regname``
1006 ``regname``
1003 Name of value to read from specified registry key. Defaults to the
1007 Name of value to read from specified registry key. Defaults to the
1004 unnamed (default) value.
1008 unnamed (default) value.
1005
1009
1006 ``regappend``
1010 ``regappend``
1007 String to append to the value read from the registry, typically
1011 String to append to the value read from the registry, typically
1008 the executable name of the tool.
1012 the executable name of the tool.
1009 Default: None
1013 Default: None
1010
1014
1011
1015
1012 ``patch``
1016 ``patch``
1013 ---------
1017 ---------
1014
1018
1015 Settings used when applying patches, for instance through the 'import'
1019 Settings used when applying patches, for instance through the 'import'
1016 command or with Mercurial Queues extension.
1020 command or with Mercurial Queues extension.
1017
1021
1018 ``eol``
1022 ``eol``
1019 When set to 'strict' patch content and patched files end of lines
1023 When set to 'strict' patch content and patched files end of lines
1020 are preserved. When set to ``lf`` or ``crlf``, both files end of
1024 are preserved. When set to ``lf`` or ``crlf``, both files end of
1021 lines are ignored when patching and the result line endings are
1025 lines are ignored when patching and the result line endings are
1022 normalized to either LF (Unix) or CRLF (Windows). When set to
1026 normalized to either LF (Unix) or CRLF (Windows). When set to
1023 ``auto``, end of lines are again ignored while patching but line
1027 ``auto``, end of lines are again ignored while patching but line
1024 endings in patched files are normalized to their original setting
1028 endings in patched files are normalized to their original setting
1025 on a per-file basis. If target file does not exist or has no end
1029 on a per-file basis. If target file does not exist or has no end
1026 of line, patch line endings are preserved.
1030 of line, patch line endings are preserved.
1027 Default: strict.
1031 Default: strict.
1028
1032
1029
1033
1030 ``paths``
1034 ``paths``
1031 ---------
1035 ---------
1032
1036
1033 Assigns symbolic names to repositories. The left side is the
1037 Assigns symbolic names to repositories. The left side is the
1034 symbolic name, and the right gives the directory or URL that is the
1038 symbolic name, and the right gives the directory or URL that is the
1035 location of the repository. Default paths can be declared by setting
1039 location of the repository. Default paths can be declared by setting
1036 the following entries.
1040 the following entries.
1037
1041
1038 ``default``
1042 ``default``
1039 Directory or URL to use when pulling if no source is specified.
1043 Directory or URL to use when pulling if no source is specified.
1040 Default is set to repository from which the current repository was
1044 Default is set to repository from which the current repository was
1041 cloned.
1045 cloned.
1042
1046
1043 ``default-push``
1047 ``default-push``
1044 Optional. Directory or URL to use when pushing if no destination
1048 Optional. Directory or URL to use when pushing if no destination
1045 is specified.
1049 is specified.
1046
1050
1047 Custom paths can be defined by assigning the path to a name that later can be
1051 Custom paths can be defined by assigning the path to a name that later can be
1048 used from the command line. Example::
1052 used from the command line. Example::
1049
1053
1050 [paths]
1054 [paths]
1051 my_path = http://example.com/path
1055 my_path = http://example.com/path
1052
1056
1053 To push to the path defined in ``my_path`` run the command::
1057 To push to the path defined in ``my_path`` run the command::
1054
1058
1055 hg push my_path
1059 hg push my_path
1056
1060
1057
1061
1058 ``phases``
1062 ``phases``
1059 ----------
1063 ----------
1060
1064
1061 Specifies default handling of phases. See :hg:`help phases` for more
1065 Specifies default handling of phases. See :hg:`help phases` for more
1062 information about working with phases.
1066 information about working with phases.
1063
1067
1064 ``publish``
1068 ``publish``
1065 Controls draft phase behavior when working as a server. When true,
1069 Controls draft phase behavior when working as a server. When true,
1066 pushed changesets are set to public in both client and server and
1070 pushed changesets are set to public in both client and server and
1067 pulled or cloned changesets are set to public in the client.
1071 pulled or cloned changesets are set to public in the client.
1068 Default: True
1072 Default: True
1069
1073
1070 ``new-commit``
1074 ``new-commit``
1071 Phase of newly-created commits.
1075 Phase of newly-created commits.
1072 Default: draft
1076 Default: draft
1073
1077
1074 ``checksubrepos``
1078 ``checksubrepos``
1075 Check the phase of the current revision of each subrepository. Allowed
1079 Check the phase of the current revision of each subrepository. Allowed
1076 values are "ignore", "follow" and "abort". For settings other than
1080 values are "ignore", "follow" and "abort". For settings other than
1077 "ignore", the phase of the current revision of each subrepository is
1081 "ignore", the phase of the current revision of each subrepository is
1078 checked before committing the parent repository. If any of those phases is
1082 checked before committing the parent repository. If any of those phases is
1079 greater than the phase of the parent repository (e.g. if a subrepo is in a
1083 greater than the phase of the parent repository (e.g. if a subrepo is in a
1080 "secret" phase while the parent repo is in "draft" phase), the commit is
1084 "secret" phase while the parent repo is in "draft" phase), the commit is
1081 either aborted (if checksubrepos is set to "abort") or the higher phase is
1085 either aborted (if checksubrepos is set to "abort") or the higher phase is
1082 used for the parent repository commit (if set to "follow").
1086 used for the parent repository commit (if set to "follow").
1083 Default: "follow"
1087 Default: "follow"
1084
1088
1085
1089
1086 ``profiling``
1090 ``profiling``
1087 -------------
1091 -------------
1088
1092
1089 Specifies profiling type, format, and file output. Two profilers are
1093 Specifies profiling type, format, and file output. Two profilers are
1090 supported: an instrumenting profiler (named ``ls``), and a sampling
1094 supported: an instrumenting profiler (named ``ls``), and a sampling
1091 profiler (named ``stat``).
1095 profiler (named ``stat``).
1092
1096
1093 In this section description, 'profiling data' stands for the raw data
1097 In this section description, 'profiling data' stands for the raw data
1094 collected during profiling, while 'profiling report' stands for a
1098 collected during profiling, while 'profiling report' stands for a
1095 statistical text report generated from the profiling data. The
1099 statistical text report generated from the profiling data. The
1096 profiling is done using lsprof.
1100 profiling is done using lsprof.
1097
1101
1098 ``type``
1102 ``type``
1099 The type of profiler to use.
1103 The type of profiler to use.
1100 Default: ls.
1104 Default: ls.
1101
1105
1102 ``ls``
1106 ``ls``
1103 Use Python's built-in instrumenting profiler. This profiler
1107 Use Python's built-in instrumenting profiler. This profiler
1104 works on all platforms, but each line number it reports is the
1108 works on all platforms, but each line number it reports is the
1105 first line of a function. This restriction makes it difficult to
1109 first line of a function. This restriction makes it difficult to
1106 identify the expensive parts of a non-trivial function.
1110 identify the expensive parts of a non-trivial function.
1107 ``stat``
1111 ``stat``
1108 Use a third-party statistical profiler, statprof. This profiler
1112 Use a third-party statistical profiler, statprof. This profiler
1109 currently runs only on Unix systems, and is most useful for
1113 currently runs only on Unix systems, and is most useful for
1110 profiling commands that run for longer than about 0.1 seconds.
1114 profiling commands that run for longer than about 0.1 seconds.
1111
1115
1112 ``format``
1116 ``format``
1113 Profiling format. Specific to the ``ls`` instrumenting profiler.
1117 Profiling format. Specific to the ``ls`` instrumenting profiler.
1114 Default: text.
1118 Default: text.
1115
1119
1116 ``text``
1120 ``text``
1117 Generate a profiling report. When saving to a file, it should be
1121 Generate a profiling report. When saving to a file, it should be
1118 noted that only the report is saved, and the profiling data is
1122 noted that only the report is saved, and the profiling data is
1119 not kept.
1123 not kept.
1120 ``kcachegrind``
1124 ``kcachegrind``
1121 Format profiling data for kcachegrind use: when saving to a
1125 Format profiling data for kcachegrind use: when saving to a
1122 file, the generated file can directly be loaded into
1126 file, the generated file can directly be loaded into
1123 kcachegrind.
1127 kcachegrind.
1124
1128
1125 ``frequency``
1129 ``frequency``
1126 Sampling frequency. Specific to the ``stat`` sampling profiler.
1130 Sampling frequency. Specific to the ``stat`` sampling profiler.
1127 Default: 1000.
1131 Default: 1000.
1128
1132
1129 ``output``
1133 ``output``
1130 File path where profiling data or report should be saved. If the
1134 File path where profiling data or report should be saved. If the
1131 file exists, it is replaced. Default: None, data is printed on
1135 file exists, it is replaced. Default: None, data is printed on
1132 stderr
1136 stderr
1133
1137
1134 ``sort``
1138 ``sort``
1135 Sort field. Specific to the ``ls`` instrumenting profiler.
1139 Sort field. Specific to the ``ls`` instrumenting profiler.
1136 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1140 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1137 ``inlinetime``.
1141 ``inlinetime``.
1138 Default: inlinetime.
1142 Default: inlinetime.
1139
1143
1140 ``limit``
1144 ``limit``
1141 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1145 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1142 Default: 30.
1146 Default: 30.
1143
1147
1144 ``nested``
1148 ``nested``
1145 Show at most this number of lines of drill-down info after each main entry.
1149 Show at most this number of lines of drill-down info after each main entry.
1146 This can help explain the difference between Total and Inline.
1150 This can help explain the difference between Total and Inline.
1147 Specific to the ``ls`` instrumenting profiler.
1151 Specific to the ``ls`` instrumenting profiler.
1148 Default: 5.
1152 Default: 5.
1149
1153
1150 ``revsetalias``
1154 ``revsetalias``
1151 ---------------
1155 ---------------
1152
1156
1153 Alias definitions for revsets. See :hg:`help revsets` for details.
1157 Alias definitions for revsets. See :hg:`help revsets` for details.
1154
1158
1155 ``server``
1159 ``server``
1156 ----------
1160 ----------
1157
1161
1158 Controls generic server settings.
1162 Controls generic server settings.
1159
1163
1160 ``uncompressed``
1164 ``uncompressed``
1161 Whether to allow clients to clone a repository using the
1165 Whether to allow clients to clone a repository using the
1162 uncompressed streaming protocol. This transfers about 40% more
1166 uncompressed streaming protocol. This transfers about 40% more
1163 data than a regular clone, but uses less memory and CPU on both
1167 data than a regular clone, but uses less memory and CPU on both
1164 server and client. Over a LAN (100 Mbps or better) or a very fast
1168 server and client. Over a LAN (100 Mbps or better) or a very fast
1165 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1169 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1166 regular clone. Over most WAN connections (anything slower than
1170 regular clone. Over most WAN connections (anything slower than
1167 about 6 Mbps), uncompressed streaming is slower, because of the
1171 about 6 Mbps), uncompressed streaming is slower, because of the
1168 extra data transfer overhead. This mode will also temporarily hold
1172 extra data transfer overhead. This mode will also temporarily hold
1169 the write lock while determining what data to transfer.
1173 the write lock while determining what data to transfer.
1170 Default is True.
1174 Default is True.
1171
1175
1172 ``preferuncompressed``
1176 ``preferuncompressed``
1173 When set, clients will try to use the uncompressed streaming
1177 When set, clients will try to use the uncompressed streaming
1174 protocol. Default is False.
1178 protocol. Default is False.
1175
1179
1176 ``validate``
1180 ``validate``
1177 Whether to validate the completeness of pushed changesets by
1181 Whether to validate the completeness of pushed changesets by
1178 checking that all new file revisions specified in manifests are
1182 checking that all new file revisions specified in manifests are
1179 present. Default is False.
1183 present. Default is False.
1180
1184
1181 ``smtp``
1185 ``smtp``
1182 --------
1186 --------
1183
1187
1184 Configuration for extensions that need to send email messages.
1188 Configuration for extensions that need to send email messages.
1185
1189
1186 ``host``
1190 ``host``
1187 Host name of mail server, e.g. "mail.example.com".
1191 Host name of mail server, e.g. "mail.example.com".
1188
1192
1189 ``port``
1193 ``port``
1190 Optional. Port to connect to on mail server. Default: 465 (if
1194 Optional. Port to connect to on mail server. Default: 465 (if
1191 ``tls`` is smtps) or 25 (otherwise).
1195 ``tls`` is smtps) or 25 (otherwise).
1192
1196
1193 ``tls``
1197 ``tls``
1194 Optional. Method to enable TLS when connecting to mail server: starttls,
1198 Optional. Method to enable TLS when connecting to mail server: starttls,
1195 smtps or none. Default: none.
1199 smtps or none. Default: none.
1196
1200
1197 ``verifycert``
1201 ``verifycert``
1198 Optional. Verification for the certificate of mail server, when
1202 Optional. Verification for the certificate of mail server, when
1199 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1203 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1200 "strict" or "loose", the certificate is verified as same as the
1204 "strict" or "loose", the certificate is verified as same as the
1201 verification for HTTPS connections (see ``[hostfingerprints]`` and
1205 verification for HTTPS connections (see ``[hostfingerprints]`` and
1202 ``[web] cacerts`` also). For "strict", sending email is also
1206 ``[web] cacerts`` also). For "strict", sending email is also
1203 aborted, if there is no configuration for mail server in
1207 aborted, if there is no configuration for mail server in
1204 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1208 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1205 :hg:`email` overwrites this as "loose". Default: "strict".
1209 :hg:`email` overwrites this as "loose". Default: "strict".
1206
1210
1207 ``username``
1211 ``username``
1208 Optional. User name for authenticating with the SMTP server.
1212 Optional. User name for authenticating with the SMTP server.
1209 Default: none.
1213 Default: none.
1210
1214
1211 ``password``
1215 ``password``
1212 Optional. Password for authenticating with the SMTP server. If not
1216 Optional. Password for authenticating with the SMTP server. If not
1213 specified, interactive sessions will prompt the user for a
1217 specified, interactive sessions will prompt the user for a
1214 password; non-interactive sessions will fail. Default: none.
1218 password; non-interactive sessions will fail. Default: none.
1215
1219
1216 ``local_hostname``
1220 ``local_hostname``
1217 Optional. It's the hostname that the sender can use to identify
1221 Optional. It's the hostname that the sender can use to identify
1218 itself to the MTA.
1222 itself to the MTA.
1219
1223
1220
1224
1221 ``subpaths``
1225 ``subpaths``
1222 ------------
1226 ------------
1223
1227
1224 Subrepository source URLs can go stale if a remote server changes name
1228 Subrepository source URLs can go stale if a remote server changes name
1225 or becomes temporarily unavailable. This section lets you define
1229 or becomes temporarily unavailable. This section lets you define
1226 rewrite rules of the form::
1230 rewrite rules of the form::
1227
1231
1228 <pattern> = <replacement>
1232 <pattern> = <replacement>
1229
1233
1230 where ``pattern`` is a regular expression matching a subrepository
1234 where ``pattern`` is a regular expression matching a subrepository
1231 source URL and ``replacement`` is the replacement string used to
1235 source URL and ``replacement`` is the replacement string used to
1232 rewrite it. Groups can be matched in ``pattern`` and referenced in
1236 rewrite it. Groups can be matched in ``pattern`` and referenced in
1233 ``replacements``. For instance::
1237 ``replacements``. For instance::
1234
1238
1235 http://server/(.*)-hg/ = http://hg.server/\1/
1239 http://server/(.*)-hg/ = http://hg.server/\1/
1236
1240
1237 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1241 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1238
1242
1239 Relative subrepository paths are first made absolute, and the
1243 Relative subrepository paths are first made absolute, and the
1240 rewrite rules are then applied on the full (absolute) path. The rules
1244 rewrite rules are then applied on the full (absolute) path. The rules
1241 are applied in definition order.
1245 are applied in definition order.
1242
1246
1243 ``trusted``
1247 ``trusted``
1244 -----------
1248 -----------
1245
1249
1246 Mercurial will not use the settings in the
1250 Mercurial will not use the settings in the
1247 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1251 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1248 user or to a trusted group, as various hgrc features allow arbitrary
1252 user or to a trusted group, as various hgrc features allow arbitrary
1249 commands to be run. This issue is often encountered when configuring
1253 commands to be run. This issue is often encountered when configuring
1250 hooks or extensions for shared repositories or servers. However,
1254 hooks or extensions for shared repositories or servers. However,
1251 the web interface will use some safe settings from the ``[web]``
1255 the web interface will use some safe settings from the ``[web]``
1252 section.
1256 section.
1253
1257
1254 This section specifies what users and groups are trusted. The
1258 This section specifies what users and groups are trusted. The
1255 current user is always trusted. To trust everybody, list a user or a
1259 current user is always trusted. To trust everybody, list a user or a
1256 group with name ``*``. These settings must be placed in an
1260 group with name ``*``. These settings must be placed in an
1257 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1261 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1258 user or service running Mercurial.
1262 user or service running Mercurial.
1259
1263
1260 ``users``
1264 ``users``
1261 Comma-separated list of trusted users.
1265 Comma-separated list of trusted users.
1262
1266
1263 ``groups``
1267 ``groups``
1264 Comma-separated list of trusted groups.
1268 Comma-separated list of trusted groups.
1265
1269
1266
1270
1267 ``ui``
1271 ``ui``
1268 ------
1272 ------
1269
1273
1270 User interface controls.
1274 User interface controls.
1271
1275
1272 ``archivemeta``
1276 ``archivemeta``
1273 Whether to include the .hg_archival.txt file containing meta data
1277 Whether to include the .hg_archival.txt file containing meta data
1274 (hashes for the repository base and for tip) in archives created
1278 (hashes for the repository base and for tip) in archives created
1275 by the :hg:`archive` command or downloaded via hgweb.
1279 by the :hg:`archive` command or downloaded via hgweb.
1276 Default is True.
1280 Default is True.
1277
1281
1278 ``askusername``
1282 ``askusername``
1279 Whether to prompt for a username when committing. If True, and
1283 Whether to prompt for a username when committing. If True, and
1280 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1284 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1281 be prompted to enter a username. If no username is entered, the
1285 be prompted to enter a username. If no username is entered, the
1282 default ``USER@HOST`` is used instead.
1286 default ``USER@HOST`` is used instead.
1283 Default is False.
1287 Default is False.
1284
1288
1285 ``commitsubrepos``
1289 ``commitsubrepos``
1286 Whether to commit modified subrepositories when committing the
1290 Whether to commit modified subrepositories when committing the
1287 parent repository. If False and one subrepository has uncommitted
1291 parent repository. If False and one subrepository has uncommitted
1288 changes, abort the commit.
1292 changes, abort the commit.
1289 Default is False.
1293 Default is False.
1290
1294
1291 ``debug``
1295 ``debug``
1292 Print debugging information. True or False. Default is False.
1296 Print debugging information. True or False. Default is False.
1293
1297
1294 ``editor``
1298 ``editor``
1295 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1299 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1296
1300
1297 ``fallbackencoding``
1301 ``fallbackencoding``
1298 Encoding to try if it's not possible to decode the changelog using
1302 Encoding to try if it's not possible to decode the changelog using
1299 UTF-8. Default is ISO-8859-1.
1303 UTF-8. Default is ISO-8859-1.
1300
1304
1301 ``ignore``
1305 ``ignore``
1302 A file to read per-user ignore patterns from. This file should be
1306 A file to read per-user ignore patterns from. This file should be
1303 in the same format as a repository-wide .hgignore file. This
1307 in the same format as a repository-wide .hgignore file. This
1304 option supports hook syntax, so if you want to specify multiple
1308 option supports hook syntax, so if you want to specify multiple
1305 ignore files, you can do so by setting something like
1309 ignore files, you can do so by setting something like
1306 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1310 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1307 format, see the ``hgignore(5)`` man page.
1311 format, see the ``hgignore(5)`` man page.
1308
1312
1309 ``interactive``
1313 ``interactive``
1310 Allow to prompt the user. True or False. Default is True.
1314 Allow to prompt the user. True or False. Default is True.
1311
1315
1312 ``logtemplate``
1316 ``logtemplate``
1313 Template string for commands that print changesets.
1317 Template string for commands that print changesets.
1314
1318
1315 ``merge``
1319 ``merge``
1316 The conflict resolution program to use during a manual merge.
1320 The conflict resolution program to use during a manual merge.
1317 For more information on merge tools see :hg:`help merge-tools`.
1321 For more information on merge tools see :hg:`help merge-tools`.
1318 For configuring merge tools see the ``[merge-tools]`` section.
1322 For configuring merge tools see the ``[merge-tools]`` section.
1319
1323
1320 ``mergemarkers``
1324 ``mergemarkers``
1321 Sets the merge conflict marker label styling. The ``detailed``
1325 Sets the merge conflict marker label styling. The ``detailed``
1322 style uses the ``mergemarkertemplate`` setting to style the labels.
1326 style uses the ``mergemarkertemplate`` setting to style the labels.
1323 The ``basic`` style just uses 'local' and 'other' as the marker label.
1327 The ``basic`` style just uses 'local' and 'other' as the marker label.
1324 One of ``basic`` or ``detailed``.
1328 One of ``basic`` or ``detailed``.
1325 Default is ``basic``.
1329 Default is ``basic``.
1326
1330
1327 ``mergemarkertemplate``
1331 ``mergemarkertemplate``
1328 The template used to print the commit description next to each conflict
1332 The template used to print the commit description next to each conflict
1329 marker during merge conflicts. See :hg:`help templates` for the template
1333 marker during merge conflicts. See :hg:`help templates` for the template
1330 format.
1334 format.
1331 Defaults to showing the hash, tags, branches, bookmarks, author, and
1335 Defaults to showing the hash, tags, branches, bookmarks, author, and
1332 the first line of the commit description.
1336 the first line of the commit description.
1333 You have to pay attention to encodings of managed files, if you
1337 You have to pay attention to encodings of managed files, if you
1334 use non-ASCII characters in tags, branches, bookmarks, author
1338 use non-ASCII characters in tags, branches, bookmarks, author
1335 and/or commit descriptions. At template expansion, non-ASCII
1339 and/or commit descriptions. At template expansion, non-ASCII
1336 characters use the encoding specified by ``--encoding`` global
1340 characters use the encoding specified by ``--encoding`` global
1337 option, ``HGENCODING`` or other locale setting environment
1341 option, ``HGENCODING`` or other locale setting environment
1338 variables. The difference of encoding between merged file and
1342 variables. The difference of encoding between merged file and
1339 conflict markers causes serious problem.
1343 conflict markers causes serious problem.
1340
1344
1341 ``portablefilenames``
1345 ``portablefilenames``
1342 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1346 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1343 Default is ``warn``.
1347 Default is ``warn``.
1344 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1348 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1345 platforms, if a file with a non-portable filename is added (e.g. a file
1349 platforms, if a file with a non-portable filename is added (e.g. a file
1346 with a name that can't be created on Windows because it contains reserved
1350 with a name that can't be created on Windows because it contains reserved
1347 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1351 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1348 collision with an existing file).
1352 collision with an existing file).
1349 If set to ``ignore`` (or ``false``), no warning is printed.
1353 If set to ``ignore`` (or ``false``), no warning is printed.
1350 If set to ``abort``, the command is aborted.
1354 If set to ``abort``, the command is aborted.
1351 On Windows, this configuration option is ignored and the command aborted.
1355 On Windows, this configuration option is ignored and the command aborted.
1352
1356
1353 ``quiet``
1357 ``quiet``
1354 Reduce the amount of output printed. True or False. Default is False.
1358 Reduce the amount of output printed. True or False. Default is False.
1355
1359
1356 ``remotecmd``
1360 ``remotecmd``
1357 remote command to use for clone/push/pull operations. Default is ``hg``.
1361 remote command to use for clone/push/pull operations. Default is ``hg``.
1358
1362
1359 ``reportoldssl``
1363 ``reportoldssl``
1360 Warn if an SSL certificate is unable to be due to using Python
1364 Warn if an SSL certificate is unable to be due to using Python
1361 2.5 or earlier. True or False. Default is True.
1365 2.5 or earlier. True or False. Default is True.
1362
1366
1363 ``report_untrusted``
1367 ``report_untrusted``
1364 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1368 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1365 trusted user or group. True or False. Default is True.
1369 trusted user or group. True or False. Default is True.
1366
1370
1367 ``slash``
1371 ``slash``
1368 Display paths using a slash (``/``) as the path separator. This
1372 Display paths using a slash (``/``) as the path separator. This
1369 only makes a difference on systems where the default path
1373 only makes a difference on systems where the default path
1370 separator is not the slash character (e.g. Windows uses the
1374 separator is not the slash character (e.g. Windows uses the
1371 backslash character (``\``)).
1375 backslash character (``\``)).
1372 Default is False.
1376 Default is False.
1373
1377
1374 ``ssh``
1378 ``ssh``
1375 command to use for SSH connections. Default is ``ssh``.
1379 command to use for SSH connections. Default is ``ssh``.
1376
1380
1377 ``strict``
1381 ``strict``
1378 Require exact command names, instead of allowing unambiguous
1382 Require exact command names, instead of allowing unambiguous
1379 abbreviations. True or False. Default is False.
1383 abbreviations. True or False. Default is False.
1380
1384
1381 ``style``
1385 ``style``
1382 Name of style to use for command output.
1386 Name of style to use for command output.
1383
1387
1384 ``timeout``
1388 ``timeout``
1385 The timeout used when a lock is held (in seconds), a negative value
1389 The timeout used when a lock is held (in seconds), a negative value
1386 means no timeout. Default is 600.
1390 means no timeout. Default is 600.
1387
1391
1388 ``traceback``
1392 ``traceback``
1389 Mercurial always prints a traceback when an unknown exception
1393 Mercurial always prints a traceback when an unknown exception
1390 occurs. Setting this to True will make Mercurial print a traceback
1394 occurs. Setting this to True will make Mercurial print a traceback
1391 on all exceptions, even those recognized by Mercurial (such as
1395 on all exceptions, even those recognized by Mercurial (such as
1392 IOError or MemoryError). Default is False.
1396 IOError or MemoryError). Default is False.
1393
1397
1394 ``username``
1398 ``username``
1395 The committer of a changeset created when running "commit".
1399 The committer of a changeset created when running "commit".
1396 Typically a person's name and email address, e.g. ``Fred Widget
1400 Typically a person's name and email address, e.g. ``Fred Widget
1397 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1401 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1398 the username in hgrc is empty, it has to be specified manually or
1402 the username in hgrc is empty, it has to be specified manually or
1399 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1403 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1400 ``username =`` in the system hgrc). Environment variables in the
1404 ``username =`` in the system hgrc). Environment variables in the
1401 username are expanded.
1405 username are expanded.
1402
1406
1403 ``verbose``
1407 ``verbose``
1404 Increase the amount of output printed. True or False. Default is False.
1408 Increase the amount of output printed. True or False. Default is False.
1405
1409
1406
1410
1407 ``web``
1411 ``web``
1408 -------
1412 -------
1409
1413
1410 Web interface configuration. The settings in this section apply to
1414 Web interface configuration. The settings in this section apply to
1411 both the builtin webserver (started by :hg:`serve`) and the script you
1415 both the builtin webserver (started by :hg:`serve`) and the script you
1412 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1416 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1413 and WSGI).
1417 and WSGI).
1414
1418
1415 The Mercurial webserver does no authentication (it does not prompt for
1419 The Mercurial webserver does no authentication (it does not prompt for
1416 usernames and passwords to validate *who* users are), but it does do
1420 usernames and passwords to validate *who* users are), but it does do
1417 authorization (it grants or denies access for *authenticated users*
1421 authorization (it grants or denies access for *authenticated users*
1418 based on settings in this section). You must either configure your
1422 based on settings in this section). You must either configure your
1419 webserver to do authentication for you, or disable the authorization
1423 webserver to do authentication for you, or disable the authorization
1420 checks.
1424 checks.
1421
1425
1422 For a quick setup in a trusted environment, e.g., a private LAN, where
1426 For a quick setup in a trusted environment, e.g., a private LAN, where
1423 you want it to accept pushes from anybody, you can use the following
1427 you want it to accept pushes from anybody, you can use the following
1424 command line::
1428 command line::
1425
1429
1426 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1430 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1427
1431
1428 Note that this will allow anybody to push anything to the server and
1432 Note that this will allow anybody to push anything to the server and
1429 that this should not be used for public servers.
1433 that this should not be used for public servers.
1430
1434
1431 The full set of options is:
1435 The full set of options is:
1432
1436
1433 ``accesslog``
1437 ``accesslog``
1434 Where to output the access log. Default is stdout.
1438 Where to output the access log. Default is stdout.
1435
1439
1436 ``address``
1440 ``address``
1437 Interface address to bind to. Default is all.
1441 Interface address to bind to. Default is all.
1438
1442
1439 ``allow_archive``
1443 ``allow_archive``
1440 List of archive format (bz2, gz, zip) allowed for downloading.
1444 List of archive format (bz2, gz, zip) allowed for downloading.
1441 Default is empty.
1445 Default is empty.
1442
1446
1443 ``allowbz2``
1447 ``allowbz2``
1444 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1448 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1445 revisions.
1449 revisions.
1446 Default is False.
1450 Default is False.
1447
1451
1448 ``allowgz``
1452 ``allowgz``
1449 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1453 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1450 revisions.
1454 revisions.
1451 Default is False.
1455 Default is False.
1452
1456
1453 ``allowpull``
1457 ``allowpull``
1454 Whether to allow pulling from the repository. Default is True.
1458 Whether to allow pulling from the repository. Default is True.
1455
1459
1456 ``allow_push``
1460 ``allow_push``
1457 Whether to allow pushing to the repository. If empty or not set,
1461 Whether to allow pushing to the repository. If empty or not set,
1458 push is not allowed. If the special value ``*``, any remote user can
1462 push is not allowed. If the special value ``*``, any remote user can
1459 push, including unauthenticated users. Otherwise, the remote user
1463 push, including unauthenticated users. Otherwise, the remote user
1460 must have been authenticated, and the authenticated user name must
1464 must have been authenticated, and the authenticated user name must
1461 be present in this list. The contents of the allow_push list are
1465 be present in this list. The contents of the allow_push list are
1462 examined after the deny_push list.
1466 examined after the deny_push list.
1463
1467
1464 ``allow_read``
1468 ``allow_read``
1465 If the user has not already been denied repository access due to
1469 If the user has not already been denied repository access due to
1466 the contents of deny_read, this list determines whether to grant
1470 the contents of deny_read, this list determines whether to grant
1467 repository access to the user. If this list is not empty, and the
1471 repository access to the user. If this list is not empty, and the
1468 user is unauthenticated or not present in the list, then access is
1472 user is unauthenticated or not present in the list, then access is
1469 denied for the user. If the list is empty or not set, then access
1473 denied for the user. If the list is empty or not set, then access
1470 is permitted to all users by default. Setting allow_read to the
1474 is permitted to all users by default. Setting allow_read to the
1471 special value ``*`` is equivalent to it not being set (i.e. access
1475 special value ``*`` is equivalent to it not being set (i.e. access
1472 is permitted to all users). The contents of the allow_read list are
1476 is permitted to all users). The contents of the allow_read list are
1473 examined after the deny_read list.
1477 examined after the deny_read list.
1474
1478
1475 ``allowzip``
1479 ``allowzip``
1476 (DEPRECATED) Whether to allow .zip downloading of repository
1480 (DEPRECATED) Whether to allow .zip downloading of repository
1477 revisions. Default is False. This feature creates temporary files.
1481 revisions. Default is False. This feature creates temporary files.
1478
1482
1479 ``archivesubrepos``
1483 ``archivesubrepos``
1480 Whether to recurse into subrepositories when archiving. Default is
1484 Whether to recurse into subrepositories when archiving. Default is
1481 False.
1485 False.
1482
1486
1483 ``baseurl``
1487 ``baseurl``
1484 Base URL to use when publishing URLs in other locations, so
1488 Base URL to use when publishing URLs in other locations, so
1485 third-party tools like email notification hooks can construct
1489 third-party tools like email notification hooks can construct
1486 URLs. Example: ``http://hgserver/repos/``.
1490 URLs. Example: ``http://hgserver/repos/``.
1487
1491
1488 ``cacerts``
1492 ``cacerts``
1489 Path to file containing a list of PEM encoded certificate
1493 Path to file containing a list of PEM encoded certificate
1490 authority certificates. Environment variables and ``~user``
1494 authority certificates. Environment variables and ``~user``
1491 constructs are expanded in the filename. If specified on the
1495 constructs are expanded in the filename. If specified on the
1492 client, then it will verify the identity of remote HTTPS servers
1496 client, then it will verify the identity of remote HTTPS servers
1493 with these certificates.
1497 with these certificates.
1494
1498
1495 This feature is only supported when using Python 2.6 or later. If you wish
1499 This feature is only supported when using Python 2.6 or later. If you wish
1496 to use it with earlier versions of Python, install the backported
1500 to use it with earlier versions of Python, install the backported
1497 version of the ssl library that is available from
1501 version of the ssl library that is available from
1498 ``http://pypi.python.org``.
1502 ``http://pypi.python.org``.
1499
1503
1500 To disable SSL verification temporarily, specify ``--insecure`` from
1504 To disable SSL verification temporarily, specify ``--insecure`` from
1501 command line.
1505 command line.
1502
1506
1503 You can use OpenSSL's CA certificate file if your platform has
1507 You can use OpenSSL's CA certificate file if your platform has
1504 one. On most Linux systems this will be
1508 one. On most Linux systems this will be
1505 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1509 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1506 generate this file manually. The form must be as follows::
1510 generate this file manually. The form must be as follows::
1507
1511
1508 -----BEGIN CERTIFICATE-----
1512 -----BEGIN CERTIFICATE-----
1509 ... (certificate in base64 PEM encoding) ...
1513 ... (certificate in base64 PEM encoding) ...
1510 -----END CERTIFICATE-----
1514 -----END CERTIFICATE-----
1511 -----BEGIN CERTIFICATE-----
1515 -----BEGIN CERTIFICATE-----
1512 ... (certificate in base64 PEM encoding) ...
1516 ... (certificate in base64 PEM encoding) ...
1513 -----END CERTIFICATE-----
1517 -----END CERTIFICATE-----
1514
1518
1515 ``cache``
1519 ``cache``
1516 Whether to support caching in hgweb. Defaults to True.
1520 Whether to support caching in hgweb. Defaults to True.
1517
1521
1518 ``collapse``
1522 ``collapse``
1519 With ``descend`` enabled, repositories in subdirectories are shown at
1523 With ``descend`` enabled, repositories in subdirectories are shown at
1520 a single level alongside repositories in the current path. With
1524 a single level alongside repositories in the current path. With
1521 ``collapse`` also enabled, repositories residing at a deeper level than
1525 ``collapse`` also enabled, repositories residing at a deeper level than
1522 the current path are grouped behind navigable directory entries that
1526 the current path are grouped behind navigable directory entries that
1523 lead to the locations of these repositories. In effect, this setting
1527 lead to the locations of these repositories. In effect, this setting
1524 collapses each collection of repositories found within a subdirectory
1528 collapses each collection of repositories found within a subdirectory
1525 into a single entry for that subdirectory. Default is False.
1529 into a single entry for that subdirectory. Default is False.
1526
1530
1527 ``comparisoncontext``
1531 ``comparisoncontext``
1528 Number of lines of context to show in side-by-side file comparison. If
1532 Number of lines of context to show in side-by-side file comparison. If
1529 negative or the value ``full``, whole files are shown. Default is 5.
1533 negative or the value ``full``, whole files are shown. Default is 5.
1530 This setting can be overridden by a ``context`` request parameter to the
1534 This setting can be overridden by a ``context`` request parameter to the
1531 ``comparison`` command, taking the same values.
1535 ``comparison`` command, taking the same values.
1532
1536
1533 ``contact``
1537 ``contact``
1534 Name or email address of the person in charge of the repository.
1538 Name or email address of the person in charge of the repository.
1535 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1539 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1536
1540
1537 ``deny_push``
1541 ``deny_push``
1538 Whether to deny pushing to the repository. If empty or not set,
1542 Whether to deny pushing to the repository. If empty or not set,
1539 push is not denied. If the special value ``*``, all remote users are
1543 push is not denied. If the special value ``*``, all remote users are
1540 denied push. Otherwise, unauthenticated users are all denied, and
1544 denied push. Otherwise, unauthenticated users are all denied, and
1541 any authenticated user name present in this list is also denied. The
1545 any authenticated user name present in this list is also denied. The
1542 contents of the deny_push list are examined before the allow_push list.
1546 contents of the deny_push list are examined before the allow_push list.
1543
1547
1544 ``deny_read``
1548 ``deny_read``
1545 Whether to deny reading/viewing of the repository. If this list is
1549 Whether to deny reading/viewing of the repository. If this list is
1546 not empty, unauthenticated users are all denied, and any
1550 not empty, unauthenticated users are all denied, and any
1547 authenticated user name present in this list is also denied access to
1551 authenticated user name present in this list is also denied access to
1548 the repository. If set to the special value ``*``, all remote users
1552 the repository. If set to the special value ``*``, all remote users
1549 are denied access (rarely needed ;). If deny_read is empty or not set,
1553 are denied access (rarely needed ;). If deny_read is empty or not set,
1550 the determination of repository access depends on the presence and
1554 the determination of repository access depends on the presence and
1551 content of the allow_read list (see description). If both
1555 content of the allow_read list (see description). If both
1552 deny_read and allow_read are empty or not set, then access is
1556 deny_read and allow_read are empty or not set, then access is
1553 permitted to all users by default. If the repository is being
1557 permitted to all users by default. If the repository is being
1554 served via hgwebdir, denied users will not be able to see it in
1558 served via hgwebdir, denied users will not be able to see it in
1555 the list of repositories. The contents of the deny_read list have
1559 the list of repositories. The contents of the deny_read list have
1556 priority over (are examined before) the contents of the allow_read
1560 priority over (are examined before) the contents of the allow_read
1557 list.
1561 list.
1558
1562
1559 ``descend``
1563 ``descend``
1560 hgwebdir indexes will not descend into subdirectories. Only repositories
1564 hgwebdir indexes will not descend into subdirectories. Only repositories
1561 directly in the current path will be shown (other repositories are still
1565 directly in the current path will be shown (other repositories are still
1562 available from the index corresponding to their containing path).
1566 available from the index corresponding to their containing path).
1563
1567
1564 ``description``
1568 ``description``
1565 Textual description of the repository's purpose or contents.
1569 Textual description of the repository's purpose or contents.
1566 Default is "unknown".
1570 Default is "unknown".
1567
1571
1568 ``encoding``
1572 ``encoding``
1569 Character encoding name. Default is the current locale charset.
1573 Character encoding name. Default is the current locale charset.
1570 Example: "UTF-8"
1574 Example: "UTF-8"
1571
1575
1572 ``errorlog``
1576 ``errorlog``
1573 Where to output the error log. Default is stderr.
1577 Where to output the error log. Default is stderr.
1574
1578
1575 ``guessmime``
1579 ``guessmime``
1576 Control MIME types for raw download of file content.
1580 Control MIME types for raw download of file content.
1577 Set to True to let hgweb guess the content type from the file
1581 Set to True to let hgweb guess the content type from the file
1578 extension. This will serve HTML files as ``text/html`` and might
1582 extension. This will serve HTML files as ``text/html`` and might
1579 allow cross-site scripting attacks when serving untrusted
1583 allow cross-site scripting attacks when serving untrusted
1580 repositories. Default is False.
1584 repositories. Default is False.
1581
1585
1582 ``hidden``
1586 ``hidden``
1583 Whether to hide the repository in the hgwebdir index.
1587 Whether to hide the repository in the hgwebdir index.
1584 Default is False.
1588 Default is False.
1585
1589
1586 ``ipv6``
1590 ``ipv6``
1587 Whether to use IPv6. Default is False.
1591 Whether to use IPv6. Default is False.
1588
1592
1589 ``logoimg``
1593 ``logoimg``
1590 File name of the logo image that some templates display on each page.
1594 File name of the logo image that some templates display on each page.
1591 The file name is relative to ``staticurl``. That is, the full path to
1595 The file name is relative to ``staticurl``. That is, the full path to
1592 the logo image is "staticurl/logoimg".
1596 the logo image is "staticurl/logoimg".
1593 If unset, ``hglogo.png`` will be used.
1597 If unset, ``hglogo.png`` will be used.
1594
1598
1595 ``logourl``
1599 ``logourl``
1596 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1600 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1597 will be used.
1601 will be used.
1598
1602
1599 ``maxchanges``
1603 ``maxchanges``
1600 Maximum number of changes to list on the changelog. Default is 10.
1604 Maximum number of changes to list on the changelog. Default is 10.
1601
1605
1602 ``maxfiles``
1606 ``maxfiles``
1603 Maximum number of files to list per changeset. Default is 10.
1607 Maximum number of files to list per changeset. Default is 10.
1604
1608
1605 ``maxshortchanges``
1609 ``maxshortchanges``
1606 Maximum number of changes to list on the shortlog, graph or filelog
1610 Maximum number of changes to list on the shortlog, graph or filelog
1607 pages. Default is 60.
1611 pages. Default is 60.
1608
1612
1609 ``name``
1613 ``name``
1610 Repository name to use in the web interface. Default is current
1614 Repository name to use in the web interface. Default is current
1611 working directory.
1615 working directory.
1612
1616
1613 ``port``
1617 ``port``
1614 Port to listen on. Default is 8000.
1618 Port to listen on. Default is 8000.
1615
1619
1616 ``prefix``
1620 ``prefix``
1617 Prefix path to serve from. Default is '' (server root).
1621 Prefix path to serve from. Default is '' (server root).
1618
1622
1619 ``push_ssl``
1623 ``push_ssl``
1620 Whether to require that inbound pushes be transported over SSL to
1624 Whether to require that inbound pushes be transported over SSL to
1621 prevent password sniffing. Default is True.
1625 prevent password sniffing. Default is True.
1622
1626
1623 ``staticurl``
1627 ``staticurl``
1624 Base URL to use for static files. If unset, static files (e.g. the
1628 Base URL to use for static files. If unset, static files (e.g. the
1625 hgicon.png favicon) will be served by the CGI script itself. Use
1629 hgicon.png favicon) will be served by the CGI script itself. Use
1626 this setting to serve them directly with the HTTP server.
1630 this setting to serve them directly with the HTTP server.
1627 Example: ``http://hgserver/static/``.
1631 Example: ``http://hgserver/static/``.
1628
1632
1629 ``stripes``
1633 ``stripes``
1630 How many lines a "zebra stripe" should span in multi-line output.
1634 How many lines a "zebra stripe" should span in multi-line output.
1631 Default is 1; set to 0 to disable.
1635 Default is 1; set to 0 to disable.
1632
1636
1633 ``style``
1637 ``style``
1634 Which template map style to use.
1638 Which template map style to use.
1635
1639
1636 ``templates``
1640 ``templates``
1637 Where to find the HTML templates. Default is install path.
1641 Where to find the HTML templates. Default is install path.
1638
1642
1639 ``websub``
1643 ``websub``
1640 ----------
1644 ----------
1641
1645
1642 Web substitution filter definition. You can use this section to
1646 Web substitution filter definition. You can use this section to
1643 define a set of regular expression substitution patterns which
1647 define a set of regular expression substitution patterns which
1644 let you automatically modify the hgweb server output.
1648 let you automatically modify the hgweb server output.
1645
1649
1646 The default hgweb templates only apply these substitution patterns
1650 The default hgweb templates only apply these substitution patterns
1647 on the revision description fields. You can apply them anywhere
1651 on the revision description fields. You can apply them anywhere
1648 you want when you create your own templates by adding calls to the
1652 you want when you create your own templates by adding calls to the
1649 "websub" filter (usually after calling the "escape" filter).
1653 "websub" filter (usually after calling the "escape" filter).
1650
1654
1651 This can be used, for example, to convert issue references to links
1655 This can be used, for example, to convert issue references to links
1652 to your issue tracker, or to convert "markdown-like" syntax into
1656 to your issue tracker, or to convert "markdown-like" syntax into
1653 HTML (see the examples below).
1657 HTML (see the examples below).
1654
1658
1655 Each entry in this section names a substitution filter.
1659 Each entry in this section names a substitution filter.
1656 The value of each entry defines the substitution expression itself.
1660 The value of each entry defines the substitution expression itself.
1657 The websub expressions follow the old interhg extension syntax,
1661 The websub expressions follow the old interhg extension syntax,
1658 which in turn imitates the Unix sed replacement syntax::
1662 which in turn imitates the Unix sed replacement syntax::
1659
1663
1660 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1664 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1661
1665
1662 You can use any separator other than "/". The final "i" is optional
1666 You can use any separator other than "/". The final "i" is optional
1663 and indicates that the search must be case insensitive.
1667 and indicates that the search must be case insensitive.
1664
1668
1665 Examples::
1669 Examples::
1666
1670
1667 [websub]
1671 [websub]
1668 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1672 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1669 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1673 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1670 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1674 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1671
1675
1672 ``worker``
1676 ``worker``
1673 ----------
1677 ----------
1674
1678
1675 Parallel master/worker configuration. We currently perform working
1679 Parallel master/worker configuration. We currently perform working
1676 directory updates in parallel on Unix-like systems, which greatly
1680 directory updates in parallel on Unix-like systems, which greatly
1677 helps performance.
1681 helps performance.
1678
1682
1679 ``numcpus``
1683 ``numcpus``
1680 Number of CPUs to use for parallel operations. Default is 4 or the
1684 Number of CPUs to use for parallel operations. Default is 4 or the
1681 number of CPUs on the system, whichever is larger. A zero or
1685 number of CPUs on the system, whichever is larger. A zero or
1682 negative value is treated as ``use the default``.
1686 negative value is treated as ``use the default``.
@@ -1,851 +1,853 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, scmutil, util, error, formatter
10 import config, scmutil, util, error, formatter
11 from node import hex
11 from node import hex
12
12
13 class ui(object):
13 class ui(object):
14 def __init__(self, src=None):
14 def __init__(self, src=None):
15 # _buffers: used for temporary capture of output
15 # _buffers: used for temporary capture of output
16 self._buffers = []
16 self._buffers = []
17 # _bufferstates: Should the temporary capture includes stderr
17 # _bufferstates: Should the temporary capture includes stderr
18 self._bufferstates = []
18 self._bufferstates = []
19 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
19 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
20 self._reportuntrusted = True
20 self._reportuntrusted = True
21 self._ocfg = config.config() # overlay
21 self._ocfg = config.config() # overlay
22 self._tcfg = config.config() # trusted
22 self._tcfg = config.config() # trusted
23 self._ucfg = config.config() # untrusted
23 self._ucfg = config.config() # untrusted
24 self._trustusers = set()
24 self._trustusers = set()
25 self._trustgroups = set()
25 self._trustgroups = set()
26 self.callhooks = True
26 self.callhooks = True
27
27
28 if src:
28 if src:
29 self.fout = src.fout
29 self.fout = src.fout
30 self.ferr = src.ferr
30 self.ferr = src.ferr
31 self.fin = src.fin
31 self.fin = src.fin
32
32
33 self._tcfg = src._tcfg.copy()
33 self._tcfg = src._tcfg.copy()
34 self._ucfg = src._ucfg.copy()
34 self._ucfg = src._ucfg.copy()
35 self._ocfg = src._ocfg.copy()
35 self._ocfg = src._ocfg.copy()
36 self._trustusers = src._trustusers.copy()
36 self._trustusers = src._trustusers.copy()
37 self._trustgroups = src._trustgroups.copy()
37 self._trustgroups = src._trustgroups.copy()
38 self.environ = src.environ
38 self.environ = src.environ
39 self.callhooks = src.callhooks
39 self.callhooks = src.callhooks
40 self.fixconfig()
40 self.fixconfig()
41 else:
41 else:
42 self.fout = sys.stdout
42 self.fout = sys.stdout
43 self.ferr = sys.stderr
43 self.ferr = sys.stderr
44 self.fin = sys.stdin
44 self.fin = sys.stdin
45
45
46 # shared read-only environment
46 # shared read-only environment
47 self.environ = os.environ
47 self.environ = os.environ
48 # we always trust global config files
48 # we always trust global config files
49 for f in scmutil.rcpath():
49 for f in scmutil.rcpath():
50 self.readconfig(f, trust=True)
50 self.readconfig(f, trust=True)
51
51
52 def copy(self):
52 def copy(self):
53 return self.__class__(self)
53 return self.__class__(self)
54
54
55 def formatter(self, topic, opts):
55 def formatter(self, topic, opts):
56 return formatter.formatter(self, topic, opts)
56 return formatter.formatter(self, topic, opts)
57
57
58 def _trusted(self, fp, f):
58 def _trusted(self, fp, f):
59 st = util.fstat(fp)
59 st = util.fstat(fp)
60 if util.isowner(st):
60 if util.isowner(st):
61 return True
61 return True
62
62
63 tusers, tgroups = self._trustusers, self._trustgroups
63 tusers, tgroups = self._trustusers, self._trustgroups
64 if '*' in tusers or '*' in tgroups:
64 if '*' in tusers or '*' in tgroups:
65 return True
65 return True
66
66
67 user = util.username(st.st_uid)
67 user = util.username(st.st_uid)
68 group = util.groupname(st.st_gid)
68 group = util.groupname(st.st_gid)
69 if user in tusers or group in tgroups or user == util.username():
69 if user in tusers or group in tgroups or user == util.username():
70 return True
70 return True
71
71
72 if self._reportuntrusted:
72 if self._reportuntrusted:
73 self.warn(_('not trusting file %s from untrusted '
73 self.warn(_('not trusting file %s from untrusted '
74 'user %s, group %s\n') % (f, user, group))
74 'user %s, group %s\n') % (f, user, group))
75 return False
75 return False
76
76
77 def readconfig(self, filename, root=None, trust=False,
77 def readconfig(self, filename, root=None, trust=False,
78 sections=None, remap=None):
78 sections=None, remap=None):
79 try:
79 try:
80 fp = open(filename)
80 fp = open(filename)
81 except IOError:
81 except IOError:
82 if not sections: # ignore unless we were looking for something
82 if not sections: # ignore unless we were looking for something
83 return
83 return
84 raise
84 raise
85
85
86 cfg = config.config()
86 cfg = config.config()
87 trusted = sections or trust or self._trusted(fp, filename)
87 trusted = sections or trust or self._trusted(fp, filename)
88
88
89 try:
89 try:
90 cfg.read(filename, fp, sections=sections, remap=remap)
90 cfg.read(filename, fp, sections=sections, remap=remap)
91 fp.close()
91 fp.close()
92 except error.ConfigError, inst:
92 except error.ConfigError, inst:
93 if trusted:
93 if trusted:
94 raise
94 raise
95 self.warn(_("ignored: %s\n") % str(inst))
95 self.warn(_("ignored: %s\n") % str(inst))
96
96
97 if self.plain():
97 if self.plain():
98 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
98 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
99 'logtemplate', 'style',
99 'logtemplate', 'style',
100 'traceback', 'verbose'):
100 'traceback', 'verbose'):
101 if k in cfg['ui']:
101 if k in cfg['ui']:
102 del cfg['ui'][k]
102 del cfg['ui'][k]
103 for k, v in cfg.items('defaults'):
103 for k, v in cfg.items('defaults'):
104 del cfg['defaults'][k]
104 del cfg['defaults'][k]
105 # Don't remove aliases from the configuration if in the exceptionlist
105 # Don't remove aliases from the configuration if in the exceptionlist
106 if self.plain('alias'):
106 if self.plain('alias'):
107 for k, v in cfg.items('alias'):
107 for k, v in cfg.items('alias'):
108 del cfg['alias'][k]
108 del cfg['alias'][k]
109
109
110 if trusted:
110 if trusted:
111 self._tcfg.update(cfg)
111 self._tcfg.update(cfg)
112 self._tcfg.update(self._ocfg)
112 self._tcfg.update(self._ocfg)
113 self._ucfg.update(cfg)
113 self._ucfg.update(cfg)
114 self._ucfg.update(self._ocfg)
114 self._ucfg.update(self._ocfg)
115
115
116 if root is None:
116 if root is None:
117 root = os.path.expanduser('~')
117 root = os.path.expanduser('~')
118 self.fixconfig(root=root)
118 self.fixconfig(root=root)
119
119
120 def fixconfig(self, root=None, section=None):
120 def fixconfig(self, root=None, section=None):
121 if section in (None, 'paths'):
121 if section in (None, 'paths'):
122 # expand vars and ~
122 # expand vars and ~
123 # translate paths relative to root (or home) into absolute paths
123 # translate paths relative to root (or home) into absolute paths
124 root = root or os.getcwd()
124 root = root or os.getcwd()
125 for c in self._tcfg, self._ucfg, self._ocfg:
125 for c in self._tcfg, self._ucfg, self._ocfg:
126 for n, p in c.items('paths'):
126 for n, p in c.items('paths'):
127 if not p:
127 if not p:
128 continue
128 continue
129 if '%%' in p:
129 if '%%' in p:
130 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
130 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
131 % (n, p, self.configsource('paths', n)))
131 % (n, p, self.configsource('paths', n)))
132 p = p.replace('%%', '%')
132 p = p.replace('%%', '%')
133 p = util.expandpath(p)
133 p = util.expandpath(p)
134 if not util.hasscheme(p) and not os.path.isabs(p):
134 if not util.hasscheme(p) and not os.path.isabs(p):
135 p = os.path.normpath(os.path.join(root, p))
135 p = os.path.normpath(os.path.join(root, p))
136 c.set("paths", n, p)
136 c.set("paths", n, p)
137
137
138 if section in (None, 'ui'):
138 if section in (None, 'ui'):
139 # update ui options
139 # update ui options
140 self.debugflag = self.configbool('ui', 'debug')
140 self.debugflag = self.configbool('ui', 'debug')
141 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
141 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
142 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
142 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
143 if self.verbose and self.quiet:
143 if self.verbose and self.quiet:
144 self.quiet = self.verbose = False
144 self.quiet = self.verbose = False
145 self._reportuntrusted = self.debugflag or self.configbool("ui",
145 self._reportuntrusted = self.debugflag or self.configbool("ui",
146 "report_untrusted", True)
146 "report_untrusted", True)
147 self.tracebackflag = self.configbool('ui', 'traceback', False)
147 self.tracebackflag = self.configbool('ui', 'traceback', False)
148
148
149 if section in (None, 'trusted'):
149 if section in (None, 'trusted'):
150 # update trust information
150 # update trust information
151 self._trustusers.update(self.configlist('trusted', 'users'))
151 self._trustusers.update(self.configlist('trusted', 'users'))
152 self._trustgroups.update(self.configlist('trusted', 'groups'))
152 self._trustgroups.update(self.configlist('trusted', 'groups'))
153
153
154 def backupconfig(self, section, item):
154 def backupconfig(self, section, item):
155 return (self._ocfg.backup(section, item),
155 return (self._ocfg.backup(section, item),
156 self._tcfg.backup(section, item),
156 self._tcfg.backup(section, item),
157 self._ucfg.backup(section, item),)
157 self._ucfg.backup(section, item),)
158 def restoreconfig(self, data):
158 def restoreconfig(self, data):
159 self._ocfg.restore(data[0])
159 self._ocfg.restore(data[0])
160 self._tcfg.restore(data[1])
160 self._tcfg.restore(data[1])
161 self._ucfg.restore(data[2])
161 self._ucfg.restore(data[2])
162
162
163 def setconfig(self, section, name, value, source=''):
163 def setconfig(self, section, name, value, source=''):
164 for cfg in (self._ocfg, self._tcfg, self._ucfg):
164 for cfg in (self._ocfg, self._tcfg, self._ucfg):
165 cfg.set(section, name, value, source)
165 cfg.set(section, name, value, source)
166 self.fixconfig(section=section)
166 self.fixconfig(section=section)
167
167
168 def _data(self, untrusted):
168 def _data(self, untrusted):
169 return untrusted and self._ucfg or self._tcfg
169 return untrusted and self._ucfg or self._tcfg
170
170
171 def configsource(self, section, name, untrusted=False):
171 def configsource(self, section, name, untrusted=False):
172 return self._data(untrusted).source(section, name) or 'none'
172 return self._data(untrusted).source(section, name) or 'none'
173
173
174 def config(self, section, name, default=None, untrusted=False):
174 def config(self, section, name, default=None, untrusted=False):
175 if isinstance(name, list):
175 if isinstance(name, list):
176 alternates = name
176 alternates = name
177 else:
177 else:
178 alternates = [name]
178 alternates = [name]
179
179
180 for n in alternates:
180 for n in alternates:
181 value = self._data(untrusted).get(section, n, None)
181 value = self._data(untrusted).get(section, n, None)
182 if value is not None:
182 if value is not None:
183 name = n
183 name = n
184 break
184 break
185 else:
185 else:
186 value = default
186 value = default
187
187
188 if self.debugflag and not untrusted and self._reportuntrusted:
188 if self.debugflag and not untrusted and self._reportuntrusted:
189 for n in alternates:
189 for n in alternates:
190 uvalue = self._ucfg.get(section, n)
190 uvalue = self._ucfg.get(section, n)
191 if uvalue is not None and uvalue != value:
191 if uvalue is not None and uvalue != value:
192 self.debug("ignoring untrusted configuration option "
192 self.debug("ignoring untrusted configuration option "
193 "%s.%s = %s\n" % (section, n, uvalue))
193 "%s.%s = %s\n" % (section, n, uvalue))
194 return value
194 return value
195
195
196 def configpath(self, section, name, default=None, untrusted=False):
196 def configpath(self, section, name, default=None, untrusted=False):
197 'get a path config item, expanded relative to repo root or config file'
197 'get a path config item, expanded relative to repo root or config file'
198 v = self.config(section, name, default, untrusted)
198 v = self.config(section, name, default, untrusted)
199 if v is None:
199 if v is None:
200 return None
200 return None
201 if not os.path.isabs(v) or "://" not in v:
201 if not os.path.isabs(v) or "://" not in v:
202 src = self.configsource(section, name, untrusted)
202 src = self.configsource(section, name, untrusted)
203 if ':' in src:
203 if ':' in src:
204 base = os.path.dirname(src.rsplit(':')[0])
204 base = os.path.dirname(src.rsplit(':')[0])
205 v = os.path.join(base, os.path.expanduser(v))
205 v = os.path.join(base, os.path.expanduser(v))
206 return v
206 return v
207
207
208 def configbool(self, section, name, default=False, untrusted=False):
208 def configbool(self, section, name, default=False, untrusted=False):
209 """parse a configuration element as a boolean
209 """parse a configuration element as a boolean
210
210
211 >>> u = ui(); s = 'foo'
211 >>> u = ui(); s = 'foo'
212 >>> u.setconfig(s, 'true', 'yes')
212 >>> u.setconfig(s, 'true', 'yes')
213 >>> u.configbool(s, 'true')
213 >>> u.configbool(s, 'true')
214 True
214 True
215 >>> u.setconfig(s, 'false', 'no')
215 >>> u.setconfig(s, 'false', 'no')
216 >>> u.configbool(s, 'false')
216 >>> u.configbool(s, 'false')
217 False
217 False
218 >>> u.configbool(s, 'unknown')
218 >>> u.configbool(s, 'unknown')
219 False
219 False
220 >>> u.configbool(s, 'unknown', True)
220 >>> u.configbool(s, 'unknown', True)
221 True
221 True
222 >>> u.setconfig(s, 'invalid', 'somevalue')
222 >>> u.setconfig(s, 'invalid', 'somevalue')
223 >>> u.configbool(s, 'invalid')
223 >>> u.configbool(s, 'invalid')
224 Traceback (most recent call last):
224 Traceback (most recent call last):
225 ...
225 ...
226 ConfigError: foo.invalid is not a boolean ('somevalue')
226 ConfigError: foo.invalid is not a boolean ('somevalue')
227 """
227 """
228
228
229 v = self.config(section, name, None, untrusted)
229 v = self.config(section, name, None, untrusted)
230 if v is None:
230 if v is None:
231 return default
231 return default
232 if isinstance(v, bool):
232 if isinstance(v, bool):
233 return v
233 return v
234 b = util.parsebool(v)
234 b = util.parsebool(v)
235 if b is None:
235 if b is None:
236 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
236 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
237 % (section, name, v))
237 % (section, name, v))
238 return b
238 return b
239
239
240 def configint(self, section, name, default=None, untrusted=False):
240 def configint(self, section, name, default=None, untrusted=False):
241 """parse a configuration element as an integer
241 """parse a configuration element as an integer
242
242
243 >>> u = ui(); s = 'foo'
243 >>> u = ui(); s = 'foo'
244 >>> u.setconfig(s, 'int1', '42')
244 >>> u.setconfig(s, 'int1', '42')
245 >>> u.configint(s, 'int1')
245 >>> u.configint(s, 'int1')
246 42
246 42
247 >>> u.setconfig(s, 'int2', '-42')
247 >>> u.setconfig(s, 'int2', '-42')
248 >>> u.configint(s, 'int2')
248 >>> u.configint(s, 'int2')
249 -42
249 -42
250 >>> u.configint(s, 'unknown', 7)
250 >>> u.configint(s, 'unknown', 7)
251 7
251 7
252 >>> u.setconfig(s, 'invalid', 'somevalue')
252 >>> u.setconfig(s, 'invalid', 'somevalue')
253 >>> u.configint(s, 'invalid')
253 >>> u.configint(s, 'invalid')
254 Traceback (most recent call last):
254 Traceback (most recent call last):
255 ...
255 ...
256 ConfigError: foo.invalid is not an integer ('somevalue')
256 ConfigError: foo.invalid is not an integer ('somevalue')
257 """
257 """
258
258
259 v = self.config(section, name, None, untrusted)
259 v = self.config(section, name, None, untrusted)
260 if v is None:
260 if v is None:
261 return default
261 return default
262 try:
262 try:
263 return int(v)
263 return int(v)
264 except ValueError:
264 except ValueError:
265 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
265 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
266 % (section, name, v))
266 % (section, name, v))
267
267
268 def configbytes(self, section, name, default=0, untrusted=False):
268 def configbytes(self, section, name, default=0, untrusted=False):
269 """parse a configuration element as a quantity in bytes
269 """parse a configuration element as a quantity in bytes
270
270
271 Units can be specified as b (bytes), k or kb (kilobytes), m or
271 Units can be specified as b (bytes), k or kb (kilobytes), m or
272 mb (megabytes), g or gb (gigabytes).
272 mb (megabytes), g or gb (gigabytes).
273
273
274 >>> u = ui(); s = 'foo'
274 >>> u = ui(); s = 'foo'
275 >>> u.setconfig(s, 'val1', '42')
275 >>> u.setconfig(s, 'val1', '42')
276 >>> u.configbytes(s, 'val1')
276 >>> u.configbytes(s, 'val1')
277 42
277 42
278 >>> u.setconfig(s, 'val2', '42.5 kb')
278 >>> u.setconfig(s, 'val2', '42.5 kb')
279 >>> u.configbytes(s, 'val2')
279 >>> u.configbytes(s, 'val2')
280 43520
280 43520
281 >>> u.configbytes(s, 'unknown', '7 MB')
281 >>> u.configbytes(s, 'unknown', '7 MB')
282 7340032
282 7340032
283 >>> u.setconfig(s, 'invalid', 'somevalue')
283 >>> u.setconfig(s, 'invalid', 'somevalue')
284 >>> u.configbytes(s, 'invalid')
284 >>> u.configbytes(s, 'invalid')
285 Traceback (most recent call last):
285 Traceback (most recent call last):
286 ...
286 ...
287 ConfigError: foo.invalid is not a byte quantity ('somevalue')
287 ConfigError: foo.invalid is not a byte quantity ('somevalue')
288 """
288 """
289
289
290 value = self.config(section, name)
290 value = self.config(section, name)
291 if value is None:
291 if value is None:
292 if not isinstance(default, str):
292 if not isinstance(default, str):
293 return default
293 return default
294 value = default
294 value = default
295 try:
295 try:
296 return util.sizetoint(value)
296 return util.sizetoint(value)
297 except error.ParseError:
297 except error.ParseError:
298 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
298 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
299 % (section, name, value))
299 % (section, name, value))
300
300
301 def configlist(self, section, name, default=None, untrusted=False):
301 def configlist(self, section, name, default=None, untrusted=False):
302 """parse a configuration element as a list of comma/space separated
302 """parse a configuration element as a list of comma/space separated
303 strings
303 strings
304
304
305 >>> u = ui(); s = 'foo'
305 >>> u = ui(); s = 'foo'
306 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
306 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
307 >>> u.configlist(s, 'list1')
307 >>> u.configlist(s, 'list1')
308 ['this', 'is', 'a small', 'test']
308 ['this', 'is', 'a small', 'test']
309 """
309 """
310
310
311 def _parse_plain(parts, s, offset):
311 def _parse_plain(parts, s, offset):
312 whitespace = False
312 whitespace = False
313 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
313 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
314 whitespace = True
314 whitespace = True
315 offset += 1
315 offset += 1
316 if offset >= len(s):
316 if offset >= len(s):
317 return None, parts, offset
317 return None, parts, offset
318 if whitespace:
318 if whitespace:
319 parts.append('')
319 parts.append('')
320 if s[offset] == '"' and not parts[-1]:
320 if s[offset] == '"' and not parts[-1]:
321 return _parse_quote, parts, offset + 1
321 return _parse_quote, parts, offset + 1
322 elif s[offset] == '"' and parts[-1][-1] == '\\':
322 elif s[offset] == '"' and parts[-1][-1] == '\\':
323 parts[-1] = parts[-1][:-1] + s[offset]
323 parts[-1] = parts[-1][:-1] + s[offset]
324 return _parse_plain, parts, offset + 1
324 return _parse_plain, parts, offset + 1
325 parts[-1] += s[offset]
325 parts[-1] += s[offset]
326 return _parse_plain, parts, offset + 1
326 return _parse_plain, parts, offset + 1
327
327
328 def _parse_quote(parts, s, offset):
328 def _parse_quote(parts, s, offset):
329 if offset < len(s) and s[offset] == '"': # ""
329 if offset < len(s) and s[offset] == '"': # ""
330 parts.append('')
330 parts.append('')
331 offset += 1
331 offset += 1
332 while offset < len(s) and (s[offset].isspace() or
332 while offset < len(s) and (s[offset].isspace() or
333 s[offset] == ','):
333 s[offset] == ','):
334 offset += 1
334 offset += 1
335 return _parse_plain, parts, offset
335 return _parse_plain, parts, offset
336
336
337 while offset < len(s) and s[offset] != '"':
337 while offset < len(s) and s[offset] != '"':
338 if (s[offset] == '\\' and offset + 1 < len(s)
338 if (s[offset] == '\\' and offset + 1 < len(s)
339 and s[offset + 1] == '"'):
339 and s[offset + 1] == '"'):
340 offset += 1
340 offset += 1
341 parts[-1] += '"'
341 parts[-1] += '"'
342 else:
342 else:
343 parts[-1] += s[offset]
343 parts[-1] += s[offset]
344 offset += 1
344 offset += 1
345
345
346 if offset >= len(s):
346 if offset >= len(s):
347 real_parts = _configlist(parts[-1])
347 real_parts = _configlist(parts[-1])
348 if not real_parts:
348 if not real_parts:
349 parts[-1] = '"'
349 parts[-1] = '"'
350 else:
350 else:
351 real_parts[0] = '"' + real_parts[0]
351 real_parts[0] = '"' + real_parts[0]
352 parts = parts[:-1]
352 parts = parts[:-1]
353 parts.extend(real_parts)
353 parts.extend(real_parts)
354 return None, parts, offset
354 return None, parts, offset
355
355
356 offset += 1
356 offset += 1
357 while offset < len(s) and s[offset] in [' ', ',']:
357 while offset < len(s) and s[offset] in [' ', ',']:
358 offset += 1
358 offset += 1
359
359
360 if offset < len(s):
360 if offset < len(s):
361 if offset + 1 == len(s) and s[offset] == '"':
361 if offset + 1 == len(s) and s[offset] == '"':
362 parts[-1] += '"'
362 parts[-1] += '"'
363 offset += 1
363 offset += 1
364 else:
364 else:
365 parts.append('')
365 parts.append('')
366 else:
366 else:
367 return None, parts, offset
367 return None, parts, offset
368
368
369 return _parse_plain, parts, offset
369 return _parse_plain, parts, offset
370
370
371 def _configlist(s):
371 def _configlist(s):
372 s = s.rstrip(' ,')
372 s = s.rstrip(' ,')
373 if not s:
373 if not s:
374 return []
374 return []
375 parser, parts, offset = _parse_plain, [''], 0
375 parser, parts, offset = _parse_plain, [''], 0
376 while parser:
376 while parser:
377 parser, parts, offset = parser(parts, s, offset)
377 parser, parts, offset = parser(parts, s, offset)
378 return parts
378 return parts
379
379
380 result = self.config(section, name, untrusted=untrusted)
380 result = self.config(section, name, untrusted=untrusted)
381 if result is None:
381 if result is None:
382 result = default or []
382 result = default or []
383 if isinstance(result, basestring):
383 if isinstance(result, basestring):
384 result = _configlist(result.lstrip(' ,\n'))
384 result = _configlist(result.lstrip(' ,\n'))
385 if result is None:
385 if result is None:
386 result = default or []
386 result = default or []
387 return result
387 return result
388
388
389 def has_section(self, section, untrusted=False):
389 def has_section(self, section, untrusted=False):
390 '''tell whether section exists in config.'''
390 '''tell whether section exists in config.'''
391 return section in self._data(untrusted)
391 return section in self._data(untrusted)
392
392
393 def configitems(self, section, untrusted=False):
393 def configitems(self, section, untrusted=False):
394 items = self._data(untrusted).items(section)
394 items = self._data(untrusted).items(section)
395 if self.debugflag and not untrusted and self._reportuntrusted:
395 if self.debugflag and not untrusted and self._reportuntrusted:
396 for k, v in self._ucfg.items(section):
396 for k, v in self._ucfg.items(section):
397 if self._tcfg.get(section, k) != v:
397 if self._tcfg.get(section, k) != v:
398 self.debug("ignoring untrusted configuration option "
398 self.debug("ignoring untrusted configuration option "
399 "%s.%s = %s\n" % (section, k, v))
399 "%s.%s = %s\n" % (section, k, v))
400 return items
400 return items
401
401
402 def walkconfig(self, untrusted=False):
402 def walkconfig(self, untrusted=False):
403 cfg = self._data(untrusted)
403 cfg = self._data(untrusted)
404 for section in cfg.sections():
404 for section in cfg.sections():
405 for name, value in self.configitems(section, untrusted):
405 for name, value in self.configitems(section, untrusted):
406 yield section, name, value
406 yield section, name, value
407
407
408 def plain(self, feature=None):
408 def plain(self, feature=None):
409 '''is plain mode active?
409 '''is plain mode active?
410
410
411 Plain mode means that all configuration variables which affect
411 Plain mode means that all configuration variables which affect
412 the behavior and output of Mercurial should be
412 the behavior and output of Mercurial should be
413 ignored. Additionally, the output should be stable,
413 ignored. Additionally, the output should be stable,
414 reproducible and suitable for use in scripts or applications.
414 reproducible and suitable for use in scripts or applications.
415
415
416 The only way to trigger plain mode is by setting either the
416 The only way to trigger plain mode is by setting either the
417 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
417 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
418
418
419 The return value can either be
419 The return value can either be
420 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
420 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
421 - True otherwise
421 - True otherwise
422 '''
422 '''
423 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
423 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
424 return False
424 return False
425 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
425 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
426 if feature and exceptions:
426 if feature and exceptions:
427 return feature not in exceptions
427 return feature not in exceptions
428 return True
428 return True
429
429
430 def username(self):
430 def username(self):
431 """Return default username to be used in commits.
431 """Return default username to be used in commits.
432
432
433 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
433 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
434 and stop searching if one of these is set.
434 and stop searching if one of these is set.
435 If not found and ui.askusername is True, ask the user, else use
435 If not found and ui.askusername is True, ask the user, else use
436 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
436 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
437 """
437 """
438 user = os.environ.get("HGUSER")
438 user = os.environ.get("HGUSER")
439 if user is None:
439 if user is None:
440 user = self.config("ui", ["username", "user"])
440 user = self.config("ui", ["username", "user"])
441 if user is not None:
441 if user is not None:
442 user = os.path.expandvars(user)
442 user = os.path.expandvars(user)
443 if user is None:
443 if user is None:
444 user = os.environ.get("EMAIL")
444 user = os.environ.get("EMAIL")
445 if user is None and self.configbool("ui", "askusername"):
445 if user is None and self.configbool("ui", "askusername"):
446 user = self.prompt(_("enter a commit username:"), default=None)
446 user = self.prompt(_("enter a commit username:"), default=None)
447 if user is None and not self.interactive():
447 if user is None and not self.interactive():
448 try:
448 try:
449 user = '%s@%s' % (util.getuser(), socket.getfqdn())
449 user = '%s@%s' % (util.getuser(), socket.getfqdn())
450 self.warn(_("no username found, using '%s' instead\n") % user)
450 self.warn(_("no username found, using '%s' instead\n") % user)
451 except KeyError:
451 except KeyError:
452 pass
452 pass
453 if not user:
453 if not user:
454 raise util.Abort(_('no username supplied'),
454 raise util.Abort(_('no username supplied'),
455 hint=_('use "hg config --edit" '
455 hint=_('use "hg config --edit" '
456 'to set your username'))
456 'to set your username'))
457 if "\n" in user:
457 if "\n" in user:
458 raise util.Abort(_("username %s contains a newline\n") % repr(user))
458 raise util.Abort(_("username %s contains a newline\n") % repr(user))
459 return user
459 return user
460
460
461 def shortuser(self, user):
461 def shortuser(self, user):
462 """Return a short representation of a user name or email address."""
462 """Return a short representation of a user name or email address."""
463 if not self.verbose:
463 if not self.verbose:
464 user = util.shortuser(user)
464 user = util.shortuser(user)
465 return user
465 return user
466
466
467 def expandpath(self, loc, default=None):
467 def expandpath(self, loc, default=None):
468 """Return repository location relative to cwd or from [paths]"""
468 """Return repository location relative to cwd or from [paths]"""
469 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
469 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
470 return loc
470 return loc
471
471
472 path = self.config('paths', loc)
472 path = self.config('paths', loc)
473 if not path and default is not None:
473 if not path and default is not None:
474 path = self.config('paths', default)
474 path = self.config('paths', default)
475 return path or loc
475 return path or loc
476
476
477 def pushbuffer(self, error=False):
477 def pushbuffer(self, error=False):
478 """install a buffer to capture standar output of the ui object
478 """install a buffer to capture standar output of the ui object
479
479
480 If error is True, the error output will be captured too."""
480 If error is True, the error output will be captured too."""
481 self._buffers.append([])
481 self._buffers.append([])
482 self._bufferstates.append(error)
482 self._bufferstates.append(error)
483
483
484 def popbuffer(self, labeled=False):
484 def popbuffer(self, labeled=False):
485 '''pop the last buffer and return the buffered output
485 '''pop the last buffer and return the buffered output
486
486
487 If labeled is True, any labels associated with buffered
487 If labeled is True, any labels associated with buffered
488 output will be handled. By default, this has no effect
488 output will be handled. By default, this has no effect
489 on the output returned, but extensions and GUI tools may
489 on the output returned, but extensions and GUI tools may
490 handle this argument and returned styled output. If output
490 handle this argument and returned styled output. If output
491 is being buffered so it can be captured and parsed or
491 is being buffered so it can be captured and parsed or
492 processed, labeled should not be set to True.
492 processed, labeled should not be set to True.
493 '''
493 '''
494 self._bufferstates.pop()
494 self._bufferstates.pop()
495 return "".join(self._buffers.pop())
495 return "".join(self._buffers.pop())
496
496
497 def write(self, *args, **opts):
497 def write(self, *args, **opts):
498 '''write args to output
498 '''write args to output
499
499
500 By default, this method simply writes to the buffer or stdout,
500 By default, this method simply writes to the buffer or stdout,
501 but extensions or GUI tools may override this method,
501 but extensions or GUI tools may override this method,
502 write_err(), popbuffer(), and label() to style output from
502 write_err(), popbuffer(), and label() to style output from
503 various parts of hg.
503 various parts of hg.
504
504
505 An optional keyword argument, "label", can be passed in.
505 An optional keyword argument, "label", can be passed in.
506 This should be a string containing label names separated by
506 This should be a string containing label names separated by
507 space. Label names take the form of "topic.type". For example,
507 space. Label names take the form of "topic.type". For example,
508 ui.debug() issues a label of "ui.debug".
508 ui.debug() issues a label of "ui.debug".
509
509
510 When labeling output for a specific command, a label of
510 When labeling output for a specific command, a label of
511 "cmdname.type" is recommended. For example, status issues
511 "cmdname.type" is recommended. For example, status issues
512 a label of "status.modified" for modified files.
512 a label of "status.modified" for modified files.
513 '''
513 '''
514 if self._buffers:
514 if self._buffers:
515 self._buffers[-1].extend([str(a) for a in args])
515 self._buffers[-1].extend([str(a) for a in args])
516 else:
516 else:
517 for a in args:
517 for a in args:
518 self.fout.write(str(a))
518 self.fout.write(str(a))
519
519
520 def write_err(self, *args, **opts):
520 def write_err(self, *args, **opts):
521 try:
521 try:
522 if self._bufferstates and self._bufferstates[-1]:
522 if self._bufferstates and self._bufferstates[-1]:
523 return self.write(*args, **opts)
523 return self.write(*args, **opts)
524 if not getattr(self.fout, 'closed', False):
524 if not getattr(self.fout, 'closed', False):
525 self.fout.flush()
525 self.fout.flush()
526 for a in args:
526 for a in args:
527 self.ferr.write(str(a))
527 self.ferr.write(str(a))
528 # stderr may be buffered under win32 when redirected to files,
528 # stderr may be buffered under win32 when redirected to files,
529 # including stdout.
529 # including stdout.
530 if not getattr(self.ferr, 'closed', False):
530 if not getattr(self.ferr, 'closed', False):
531 self.ferr.flush()
531 self.ferr.flush()
532 except IOError, inst:
532 except IOError, inst:
533 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
533 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
534 raise
534 raise
535
535
536 def flush(self):
536 def flush(self):
537 try: self.fout.flush()
537 try: self.fout.flush()
538 except (IOError, ValueError): pass
538 except (IOError, ValueError): pass
539 try: self.ferr.flush()
539 try: self.ferr.flush()
540 except (IOError, ValueError): pass
540 except (IOError, ValueError): pass
541
541
542 def _isatty(self, fh):
542 def _isatty(self, fh):
543 if self.configbool('ui', 'nontty', False):
543 if self.configbool('ui', 'nontty', False):
544 return False
544 return False
545 return util.isatty(fh)
545 return util.isatty(fh)
546
546
547 def interactive(self):
547 def interactive(self):
548 '''is interactive input allowed?
548 '''is interactive input allowed?
549
549
550 An interactive session is a session where input can be reasonably read
550 An interactive session is a session where input can be reasonably read
551 from `sys.stdin'. If this function returns false, any attempt to read
551 from `sys.stdin'. If this function returns false, any attempt to read
552 from stdin should fail with an error, unless a sensible default has been
552 from stdin should fail with an error, unless a sensible default has been
553 specified.
553 specified.
554
554
555 Interactiveness is triggered by the value of the `ui.interactive'
555 Interactiveness is triggered by the value of the `ui.interactive'
556 configuration variable or - if it is unset - when `sys.stdin' points
556 configuration variable or - if it is unset - when `sys.stdin' points
557 to a terminal device.
557 to a terminal device.
558
558
559 This function refers to input only; for output, see `ui.formatted()'.
559 This function refers to input only; for output, see `ui.formatted()'.
560 '''
560 '''
561 i = self.configbool("ui", "interactive", None)
561 i = self.configbool("ui", "interactive", None)
562 if i is None:
562 if i is None:
563 # some environments replace stdin without implementing isatty
563 # some environments replace stdin without implementing isatty
564 # usually those are non-interactive
564 # usually those are non-interactive
565 return self._isatty(self.fin)
565 return self._isatty(self.fin)
566
566
567 return i
567 return i
568
568
569 def termwidth(self):
569 def termwidth(self):
570 '''how wide is the terminal in columns?
570 '''how wide is the terminal in columns?
571 '''
571 '''
572 if 'COLUMNS' in os.environ:
572 if 'COLUMNS' in os.environ:
573 try:
573 try:
574 return int(os.environ['COLUMNS'])
574 return int(os.environ['COLUMNS'])
575 except ValueError:
575 except ValueError:
576 pass
576 pass
577 return util.termwidth()
577 return util.termwidth()
578
578
579 def formatted(self):
579 def formatted(self):
580 '''should formatted output be used?
580 '''should formatted output be used?
581
581
582 It is often desirable to format the output to suite the output medium.
582 It is often desirable to format the output to suite the output medium.
583 Examples of this are truncating long lines or colorizing messages.
583 Examples of this are truncating long lines or colorizing messages.
584 However, this is not often not desirable when piping output into other
584 However, this is not often not desirable when piping output into other
585 utilities, e.g. `grep'.
585 utilities, e.g. `grep'.
586
586
587 Formatted output is triggered by the value of the `ui.formatted'
587 Formatted output is triggered by the value of the `ui.formatted'
588 configuration variable or - if it is unset - when `sys.stdout' points
588 configuration variable or - if it is unset - when `sys.stdout' points
589 to a terminal device. Please note that `ui.formatted' should be
589 to a terminal device. Please note that `ui.formatted' should be
590 considered an implementation detail; it is not intended for use outside
590 considered an implementation detail; it is not intended for use outside
591 Mercurial or its extensions.
591 Mercurial or its extensions.
592
592
593 This function refers to output only; for input, see `ui.interactive()'.
593 This function refers to output only; for input, see `ui.interactive()'.
594 This function always returns false when in plain mode, see `ui.plain()'.
594 This function always returns false when in plain mode, see `ui.plain()'.
595 '''
595 '''
596 if self.plain():
596 if self.plain():
597 return False
597 return False
598
598
599 i = self.configbool("ui", "formatted", None)
599 i = self.configbool("ui", "formatted", None)
600 if i is None:
600 if i is None:
601 # some environments replace stdout without implementing isatty
601 # some environments replace stdout without implementing isatty
602 # usually those are non-interactive
602 # usually those are non-interactive
603 return self._isatty(self.fout)
603 return self._isatty(self.fout)
604
604
605 return i
605 return i
606
606
607 def _readline(self, prompt=''):
607 def _readline(self, prompt=''):
608 if self._isatty(self.fin):
608 if self._isatty(self.fin):
609 try:
609 try:
610 # magically add command line editing support, where
610 # magically add command line editing support, where
611 # available
611 # available
612 import readline
612 import readline
613 # force demandimport to really load the module
613 # force demandimport to really load the module
614 readline.read_history_file
614 readline.read_history_file
615 # windows sometimes raises something other than ImportError
615 # windows sometimes raises something other than ImportError
616 except Exception:
616 except Exception:
617 pass
617 pass
618
618
619 # call write() so output goes through subclassed implementation
619 # call write() so output goes through subclassed implementation
620 # e.g. color extension on Windows
620 # e.g. color extension on Windows
621 self.write(prompt)
621 self.write(prompt)
622
622
623 # instead of trying to emulate raw_input, swap (self.fin,
623 # instead of trying to emulate raw_input, swap (self.fin,
624 # self.fout) with (sys.stdin, sys.stdout)
624 # self.fout) with (sys.stdin, sys.stdout)
625 oldin = sys.stdin
625 oldin = sys.stdin
626 oldout = sys.stdout
626 oldout = sys.stdout
627 sys.stdin = self.fin
627 sys.stdin = self.fin
628 sys.stdout = self.fout
628 sys.stdout = self.fout
629 line = raw_input(' ')
629 line = raw_input(' ')
630 sys.stdin = oldin
630 sys.stdin = oldin
631 sys.stdout = oldout
631 sys.stdout = oldout
632
632
633 # When stdin is in binary mode on Windows, it can cause
633 # When stdin is in binary mode on Windows, it can cause
634 # raw_input() to emit an extra trailing carriage return
634 # raw_input() to emit an extra trailing carriage return
635 if os.linesep == '\r\n' and line and line[-1] == '\r':
635 if os.linesep == '\r\n' and line and line[-1] == '\r':
636 line = line[:-1]
636 line = line[:-1]
637 return line
637 return line
638
638
639 def prompt(self, msg, default="y"):
639 def prompt(self, msg, default="y"):
640 """Prompt user with msg, read response.
640 """Prompt user with msg, read response.
641 If ui is not interactive, the default is returned.
641 If ui is not interactive, the default is returned.
642 """
642 """
643 if not self.interactive():
643 if not self.interactive():
644 self.write(msg, ' ', default, "\n")
644 self.write(msg, ' ', default, "\n")
645 return default
645 return default
646 try:
646 try:
647 r = self._readline(self.label(msg, 'ui.prompt'))
647 r = self._readline(self.label(msg, 'ui.prompt'))
648 if not r:
648 if not r:
649 return default
649 return default
650 return r
650 return r
651 except EOFError:
651 except EOFError:
652 raise util.Abort(_('response expected'))
652 raise util.Abort(_('response expected'))
653
653
654 @staticmethod
654 @staticmethod
655 def extractchoices(prompt):
655 def extractchoices(prompt):
656 """Extract prompt message and list of choices from specified prompt.
656 """Extract prompt message and list of choices from specified prompt.
657
657
658 This returns tuple "(message, choices)", and "choices" is the
658 This returns tuple "(message, choices)", and "choices" is the
659 list of tuple "(response character, text without &)".
659 list of tuple "(response character, text without &)".
660 """
660 """
661 parts = prompt.split('$$')
661 parts = prompt.split('$$')
662 msg = parts[0].rstrip(' ')
662 msg = parts[0].rstrip(' ')
663 choices = [p.strip(' ') for p in parts[1:]]
663 choices = [p.strip(' ') for p in parts[1:]]
664 return (msg,
664 return (msg,
665 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
665 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
666 for s in choices])
666 for s in choices])
667
667
668 def promptchoice(self, prompt, default=0):
668 def promptchoice(self, prompt, default=0):
669 """Prompt user with a message, read response, and ensure it matches
669 """Prompt user with a message, read response, and ensure it matches
670 one of the provided choices. The prompt is formatted as follows:
670 one of the provided choices. The prompt is formatted as follows:
671
671
672 "would you like fries with that (Yn)? $$ &Yes $$ &No"
672 "would you like fries with that (Yn)? $$ &Yes $$ &No"
673
673
674 The index of the choice is returned. Responses are case
674 The index of the choice is returned. Responses are case
675 insensitive. If ui is not interactive, the default is
675 insensitive. If ui is not interactive, the default is
676 returned.
676 returned.
677 """
677 """
678
678
679 msg, choices = self.extractchoices(prompt)
679 msg, choices = self.extractchoices(prompt)
680 resps = [r for r, t in choices]
680 resps = [r for r, t in choices]
681 while True:
681 while True:
682 r = self.prompt(msg, resps[default])
682 r = self.prompt(msg, resps[default])
683 if r.lower() in resps:
683 if r.lower() in resps:
684 return resps.index(r.lower())
684 return resps.index(r.lower())
685 self.write(_("unrecognized response\n"))
685 self.write(_("unrecognized response\n"))
686
686
687 def getpass(self, prompt=None, default=None):
687 def getpass(self, prompt=None, default=None):
688 if not self.interactive():
688 if not self.interactive():
689 return default
689 return default
690 try:
690 try:
691 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
691 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
692 # disable getpass() only if explicitly specified. it's still valid
692 # disable getpass() only if explicitly specified. it's still valid
693 # to interact with tty even if fin is not a tty.
693 # to interact with tty even if fin is not a tty.
694 if self.configbool('ui', 'nontty'):
694 if self.configbool('ui', 'nontty'):
695 return self.fin.readline().rstrip('\n')
695 return self.fin.readline().rstrip('\n')
696 else:
696 else:
697 return getpass.getpass('')
697 return getpass.getpass('')
698 except EOFError:
698 except EOFError:
699 raise util.Abort(_('response expected'))
699 raise util.Abort(_('response expected'))
700 def status(self, *msg, **opts):
700 def status(self, *msg, **opts):
701 '''write status message to output (if ui.quiet is False)
701 '''write status message to output (if ui.quiet is False)
702
702
703 This adds an output label of "ui.status".
703 This adds an output label of "ui.status".
704 '''
704 '''
705 if not self.quiet:
705 if not self.quiet:
706 opts['label'] = opts.get('label', '') + ' ui.status'
706 opts['label'] = opts.get('label', '') + ' ui.status'
707 self.write(*msg, **opts)
707 self.write(*msg, **opts)
708 def warn(self, *msg, **opts):
708 def warn(self, *msg, **opts):
709 '''write warning message to output (stderr)
709 '''write warning message to output (stderr)
710
710
711 This adds an output label of "ui.warning".
711 This adds an output label of "ui.warning".
712 '''
712 '''
713 opts['label'] = opts.get('label', '') + ' ui.warning'
713 opts['label'] = opts.get('label', '') + ' ui.warning'
714 self.write_err(*msg, **opts)
714 self.write_err(*msg, **opts)
715 def note(self, *msg, **opts):
715 def note(self, *msg, **opts):
716 '''write note to output (if ui.verbose is True)
716 '''write note to output (if ui.verbose is True)
717
717
718 This adds an output label of "ui.note".
718 This adds an output label of "ui.note".
719 '''
719 '''
720 if self.verbose:
720 if self.verbose:
721 opts['label'] = opts.get('label', '') + ' ui.note'
721 opts['label'] = opts.get('label', '') + ' ui.note'
722 self.write(*msg, **opts)
722 self.write(*msg, **opts)
723 def debug(self, *msg, **opts):
723 def debug(self, *msg, **opts):
724 '''write debug message to output (if ui.debugflag is True)
724 '''write debug message to output (if ui.debugflag is True)
725
725
726 This adds an output label of "ui.debug".
726 This adds an output label of "ui.debug".
727 '''
727 '''
728 if self.debugflag:
728 if self.debugflag:
729 opts['label'] = opts.get('label', '') + ' ui.debug'
729 opts['label'] = opts.get('label', '') + ' ui.debug'
730 self.write(*msg, **opts)
730 self.write(*msg, **opts)
731 def edit(self, text, user, extra={}):
731 def edit(self, text, user, extra={}, editform=None):
732 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
732 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
733 text=True)
733 text=True)
734 try:
734 try:
735 f = os.fdopen(fd, "w")
735 f = os.fdopen(fd, "w")
736 f.write(text)
736 f.write(text)
737 f.close()
737 f.close()
738
738
739 environ = {'HGUSER': user}
739 environ = {'HGUSER': user}
740 if 'transplant_source' in extra:
740 if 'transplant_source' in extra:
741 environ.update({'HGREVISION': hex(extra['transplant_source'])})
741 environ.update({'HGREVISION': hex(extra['transplant_source'])})
742 for label in ('source', 'rebase_source'):
742 for label in ('source', 'rebase_source'):
743 if label in extra:
743 if label in extra:
744 environ.update({'HGREVISION': extra[label]})
744 environ.update({'HGREVISION': extra[label]})
745 break
745 break
746 if editform:
747 environ.update({'HGEDITFORM': editform})
746
748
747 editor = self.geteditor()
749 editor = self.geteditor()
748
750
749 util.system("%s \"%s\"" % (editor, name),
751 util.system("%s \"%s\"" % (editor, name),
750 environ=environ,
752 environ=environ,
751 onerr=util.Abort, errprefix=_("edit failed"),
753 onerr=util.Abort, errprefix=_("edit failed"),
752 out=self.fout)
754 out=self.fout)
753
755
754 f = open(name)
756 f = open(name)
755 t = f.read()
757 t = f.read()
756 f.close()
758 f.close()
757 finally:
759 finally:
758 os.unlink(name)
760 os.unlink(name)
759
761
760 return t
762 return t
761
763
762 def traceback(self, exc=None, force=False):
764 def traceback(self, exc=None, force=False):
763 '''print exception traceback if traceback printing enabled or forced.
765 '''print exception traceback if traceback printing enabled or forced.
764 only to call in exception handler. returns true if traceback
766 only to call in exception handler. returns true if traceback
765 printed.'''
767 printed.'''
766 if self.tracebackflag or force:
768 if self.tracebackflag or force:
767 if exc is None:
769 if exc is None:
768 exc = sys.exc_info()
770 exc = sys.exc_info()
769 cause = getattr(exc[1], 'cause', None)
771 cause = getattr(exc[1], 'cause', None)
770
772
771 if cause is not None:
773 if cause is not None:
772 causetb = traceback.format_tb(cause[2])
774 causetb = traceback.format_tb(cause[2])
773 exctb = traceback.format_tb(exc[2])
775 exctb = traceback.format_tb(exc[2])
774 exconly = traceback.format_exception_only(cause[0], cause[1])
776 exconly = traceback.format_exception_only(cause[0], cause[1])
775
777
776 # exclude frame where 'exc' was chained and rethrown from exctb
778 # exclude frame where 'exc' was chained and rethrown from exctb
777 self.write_err('Traceback (most recent call last):\n',
779 self.write_err('Traceback (most recent call last):\n',
778 ''.join(exctb[:-1]),
780 ''.join(exctb[:-1]),
779 ''.join(causetb),
781 ''.join(causetb),
780 ''.join(exconly))
782 ''.join(exconly))
781 else:
783 else:
782 traceback.print_exception(exc[0], exc[1], exc[2],
784 traceback.print_exception(exc[0], exc[1], exc[2],
783 file=self.ferr)
785 file=self.ferr)
784 return self.tracebackflag or force
786 return self.tracebackflag or force
785
787
786 def geteditor(self):
788 def geteditor(self):
787 '''return editor to use'''
789 '''return editor to use'''
788 if sys.platform == 'plan9':
790 if sys.platform == 'plan9':
789 # vi is the MIPS instruction simulator on Plan 9. We
791 # vi is the MIPS instruction simulator on Plan 9. We
790 # instead default to E to plumb commit messages to
792 # instead default to E to plumb commit messages to
791 # avoid confusion.
793 # avoid confusion.
792 editor = 'E'
794 editor = 'E'
793 else:
795 else:
794 editor = 'vi'
796 editor = 'vi'
795 return (os.environ.get("HGEDITOR") or
797 return (os.environ.get("HGEDITOR") or
796 self.config("ui", "editor") or
798 self.config("ui", "editor") or
797 os.environ.get("VISUAL") or
799 os.environ.get("VISUAL") or
798 os.environ.get("EDITOR", editor))
800 os.environ.get("EDITOR", editor))
799
801
800 def progress(self, topic, pos, item="", unit="", total=None):
802 def progress(self, topic, pos, item="", unit="", total=None):
801 '''show a progress message
803 '''show a progress message
802
804
803 With stock hg, this is simply a debug message that is hidden
805 With stock hg, this is simply a debug message that is hidden
804 by default, but with extensions or GUI tools it may be
806 by default, but with extensions or GUI tools it may be
805 visible. 'topic' is the current operation, 'item' is a
807 visible. 'topic' is the current operation, 'item' is a
806 non-numeric marker of the current position (i.e. the currently
808 non-numeric marker of the current position (i.e. the currently
807 in-process file), 'pos' is the current numeric position (i.e.
809 in-process file), 'pos' is the current numeric position (i.e.
808 revision, bytes, etc.), unit is a corresponding unit label,
810 revision, bytes, etc.), unit is a corresponding unit label,
809 and total is the highest expected pos.
811 and total is the highest expected pos.
810
812
811 Multiple nested topics may be active at a time.
813 Multiple nested topics may be active at a time.
812
814
813 All topics should be marked closed by setting pos to None at
815 All topics should be marked closed by setting pos to None at
814 termination.
816 termination.
815 '''
817 '''
816
818
817 if pos is None or not self.debugflag:
819 if pos is None or not self.debugflag:
818 return
820 return
819
821
820 if unit:
822 if unit:
821 unit = ' ' + unit
823 unit = ' ' + unit
822 if item:
824 if item:
823 item = ' ' + item
825 item = ' ' + item
824
826
825 if total:
827 if total:
826 pct = 100.0 * pos / total
828 pct = 100.0 * pos / total
827 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
829 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
828 % (topic, item, pos, total, unit, pct))
830 % (topic, item, pos, total, unit, pct))
829 else:
831 else:
830 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
832 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
831
833
832 def log(self, service, *msg, **opts):
834 def log(self, service, *msg, **opts):
833 '''hook for logging facility extensions
835 '''hook for logging facility extensions
834
836
835 service should be a readily-identifiable subsystem, which will
837 service should be a readily-identifiable subsystem, which will
836 allow filtering.
838 allow filtering.
837 message should be a newline-terminated string to log.
839 message should be a newline-terminated string to log.
838 '''
840 '''
839 pass
841 pass
840
842
841 def label(self, msg, label):
843 def label(self, msg, label):
842 '''style msg based on supplied label
844 '''style msg based on supplied label
843
845
844 Like ui.write(), this just returns msg unchanged, but extensions
846 Like ui.write(), this just returns msg unchanged, but extensions
845 and GUI tools can override it to allow styling output without
847 and GUI tools can override it to allow styling output without
846 writing it.
848 writing it.
847
849
848 ui.write(s, 'label') is equivalent to
850 ui.write(s, 'label') is equivalent to
849 ui.write(ui.label(s, 'label')).
851 ui.write(ui.label(s, 'label')).
850 '''
852 '''
851 return msg
853 return msg
@@ -1,454 +1,459 b''
1 commit date test
1 commit date test
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo foo > foo
5 $ echo foo > foo
6 $ hg add foo
6 $ hg add foo
7 $ HGEDITOR=true hg commit -m ""
7 $ cat > $TESTTMP/checkeditform.sh <<EOF
8 > env | grep HGEDITFORM
9 > true
10 > EOF
11 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg commit -m ""
12 HGEDITFORM=commit.normal
8 abort: empty commit message
13 abort: empty commit message
9 [255]
14 [255]
10 $ hg commit -d '0 0' -m commit-1
15 $ hg commit -d '0 0' -m commit-1
11 $ echo foo >> foo
16 $ echo foo >> foo
12 $ hg commit -d '1 4444444' -m commit-3
17 $ hg commit -d '1 4444444' -m commit-3
13 abort: impossible time zone offset: 4444444
18 abort: impossible time zone offset: 4444444
14 [255]
19 [255]
15 $ hg commit -d '1 15.1' -m commit-4
20 $ hg commit -d '1 15.1' -m commit-4
16 abort: invalid date: '1\t15.1'
21 abort: invalid date: '1\t15.1'
17 [255]
22 [255]
18 $ hg commit -d 'foo bar' -m commit-5
23 $ hg commit -d 'foo bar' -m commit-5
19 abort: invalid date: 'foo bar'
24 abort: invalid date: 'foo bar'
20 [255]
25 [255]
21 $ hg commit -d ' 1 4444' -m commit-6
26 $ hg commit -d ' 1 4444' -m commit-6
22 $ hg commit -d '111111111111 0' -m commit-7
27 $ hg commit -d '111111111111 0' -m commit-7
23 abort: date exceeds 32 bits: 111111111111
28 abort: date exceeds 32 bits: 111111111111
24 [255]
29 [255]
25 $ hg commit -d '-7654321 3600' -m commit-7
30 $ hg commit -d '-7654321 3600' -m commit-7
26 abort: negative date value: -7654321
31 abort: negative date value: -7654321
27 [255]
32 [255]
28
33
29 commit added file that has been deleted
34 commit added file that has been deleted
30
35
31 $ echo bar > bar
36 $ echo bar > bar
32 $ hg add bar
37 $ hg add bar
33 $ rm bar
38 $ rm bar
34 $ hg commit -m commit-8
39 $ hg commit -m commit-8
35 nothing changed (1 missing files, see 'hg status')
40 nothing changed (1 missing files, see 'hg status')
36 [1]
41 [1]
37 $ hg commit -m commit-8-2 bar
42 $ hg commit -m commit-8-2 bar
38 abort: bar: file not found!
43 abort: bar: file not found!
39 [255]
44 [255]
40
45
41 $ hg -q revert -a --no-backup
46 $ hg -q revert -a --no-backup
42
47
43 $ mkdir dir
48 $ mkdir dir
44 $ echo boo > dir/file
49 $ echo boo > dir/file
45 $ hg add
50 $ hg add
46 adding dir/file (glob)
51 adding dir/file (glob)
47 $ hg -v commit -m commit-9 dir
52 $ hg -v commit -m commit-9 dir
48 dir/file
53 dir/file
49 committed changeset 2:d2a76177cb42
54 committed changeset 2:d2a76177cb42
50
55
51 $ echo > dir.file
56 $ echo > dir.file
52 $ hg add
57 $ hg add
53 adding dir.file
58 adding dir.file
54 $ hg commit -m commit-10 dir dir.file
59 $ hg commit -m commit-10 dir dir.file
55 abort: dir: no match under directory!
60 abort: dir: no match under directory!
56 [255]
61 [255]
57
62
58 $ echo >> dir/file
63 $ echo >> dir/file
59 $ mkdir bleh
64 $ mkdir bleh
60 $ mkdir dir2
65 $ mkdir dir2
61 $ cd bleh
66 $ cd bleh
62 $ hg commit -m commit-11 .
67 $ hg commit -m commit-11 .
63 abort: bleh: no match under directory!
68 abort: bleh: no match under directory!
64 [255]
69 [255]
65 $ hg commit -m commit-12 ../dir ../dir2
70 $ hg commit -m commit-12 ../dir ../dir2
66 abort: dir2: no match under directory!
71 abort: dir2: no match under directory!
67 [255]
72 [255]
68 $ hg -v commit -m commit-13 ../dir
73 $ hg -v commit -m commit-13 ../dir
69 dir/file
74 dir/file
70 committed changeset 3:1cd62a2d8db5
75 committed changeset 3:1cd62a2d8db5
71 $ cd ..
76 $ cd ..
72
77
73 $ hg commit -m commit-14 does-not-exist
78 $ hg commit -m commit-14 does-not-exist
74 abort: does-not-exist: * (glob)
79 abort: does-not-exist: * (glob)
75 [255]
80 [255]
76
81
77 #if symlink
82 #if symlink
78 $ ln -s foo baz
83 $ ln -s foo baz
79 $ hg commit -m commit-15 baz
84 $ hg commit -m commit-15 baz
80 abort: baz: file not tracked!
85 abort: baz: file not tracked!
81 [255]
86 [255]
82 #endif
87 #endif
83
88
84 $ touch quux
89 $ touch quux
85 $ hg commit -m commit-16 quux
90 $ hg commit -m commit-16 quux
86 abort: quux: file not tracked!
91 abort: quux: file not tracked!
87 [255]
92 [255]
88 $ echo >> dir/file
93 $ echo >> dir/file
89 $ hg -v commit -m commit-17 dir/file
94 $ hg -v commit -m commit-17 dir/file
90 dir/file
95 dir/file
91 committed changeset 4:49176991390e
96 committed changeset 4:49176991390e
92
97
93 An empty date was interpreted as epoch origin
98 An empty date was interpreted as epoch origin
94
99
95 $ echo foo >> foo
100 $ echo foo >> foo
96 $ hg commit -d '' -m commit-no-date
101 $ hg commit -d '' -m commit-no-date
97 $ hg tip --template '{date|isodate}\n' | grep '1970'
102 $ hg tip --template '{date|isodate}\n' | grep '1970'
98 [1]
103 [1]
99
104
100 Make sure we do not obscure unknown requires file entries (issue2649)
105 Make sure we do not obscure unknown requires file entries (issue2649)
101
106
102 $ echo foo >> foo
107 $ echo foo >> foo
103 $ echo fake >> .hg/requires
108 $ echo fake >> .hg/requires
104 $ hg commit -m bla
109 $ hg commit -m bla
105 abort: repository requires features unknown to this Mercurial: fake!
110 abort: repository requires features unknown to this Mercurial: fake!
106 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
111 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
107 [255]
112 [255]
108
113
109 $ cd ..
114 $ cd ..
110
115
111
116
112 partial subdir commit test
117 partial subdir commit test
113
118
114 $ hg init test2
119 $ hg init test2
115 $ cd test2
120 $ cd test2
116 $ mkdir foo
121 $ mkdir foo
117 $ echo foo > foo/foo
122 $ echo foo > foo/foo
118 $ mkdir bar
123 $ mkdir bar
119 $ echo bar > bar/bar
124 $ echo bar > bar/bar
120 $ hg add
125 $ hg add
121 adding bar/bar (glob)
126 adding bar/bar (glob)
122 adding foo/foo (glob)
127 adding foo/foo (glob)
123 $ HGEDITOR=cat hg ci -e -m commit-subdir-1 foo
128 $ HGEDITOR=cat hg ci -e -m commit-subdir-1 foo
124 commit-subdir-1
129 commit-subdir-1
125
130
126
131
127 HG: Enter commit message. Lines beginning with 'HG:' are removed.
132 HG: Enter commit message. Lines beginning with 'HG:' are removed.
128 HG: Leave message empty to abort commit.
133 HG: Leave message empty to abort commit.
129 HG: --
134 HG: --
130 HG: user: test
135 HG: user: test
131 HG: branch 'default'
136 HG: branch 'default'
132 HG: added foo/foo
137 HG: added foo/foo
133
138
134
139
135 $ hg ci -m commit-subdir-2 bar
140 $ hg ci -m commit-subdir-2 bar
136
141
137 subdir log 1
142 subdir log 1
138
143
139 $ hg log -v foo
144 $ hg log -v foo
140 changeset: 0:f97e73a25882
145 changeset: 0:f97e73a25882
141 user: test
146 user: test
142 date: Thu Jan 01 00:00:00 1970 +0000
147 date: Thu Jan 01 00:00:00 1970 +0000
143 files: foo/foo
148 files: foo/foo
144 description:
149 description:
145 commit-subdir-1
150 commit-subdir-1
146
151
147
152
148
153
149 subdir log 2
154 subdir log 2
150
155
151 $ hg log -v bar
156 $ hg log -v bar
152 changeset: 1:aa809156d50d
157 changeset: 1:aa809156d50d
153 tag: tip
158 tag: tip
154 user: test
159 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
160 date: Thu Jan 01 00:00:00 1970 +0000
156 files: bar/bar
161 files: bar/bar
157 description:
162 description:
158 commit-subdir-2
163 commit-subdir-2
159
164
160
165
161
166
162 full log
167 full log
163
168
164 $ hg log -v
169 $ hg log -v
165 changeset: 1:aa809156d50d
170 changeset: 1:aa809156d50d
166 tag: tip
171 tag: tip
167 user: test
172 user: test
168 date: Thu Jan 01 00:00:00 1970 +0000
173 date: Thu Jan 01 00:00:00 1970 +0000
169 files: bar/bar
174 files: bar/bar
170 description:
175 description:
171 commit-subdir-2
176 commit-subdir-2
172
177
173
178
174 changeset: 0:f97e73a25882
179 changeset: 0:f97e73a25882
175 user: test
180 user: test
176 date: Thu Jan 01 00:00:00 1970 +0000
181 date: Thu Jan 01 00:00:00 1970 +0000
177 files: foo/foo
182 files: foo/foo
178 description:
183 description:
179 commit-subdir-1
184 commit-subdir-1
180
185
181
186
182 $ cd ..
187 $ cd ..
183
188
184
189
185 dot and subdir commit test
190 dot and subdir commit test
186
191
187 $ hg init test3
192 $ hg init test3
188 $ echo commit-foo-subdir > commit-log-test
193 $ echo commit-foo-subdir > commit-log-test
189 $ cd test3
194 $ cd test3
190 $ mkdir foo
195 $ mkdir foo
191 $ echo foo content > foo/plain-file
196 $ echo foo content > foo/plain-file
192 $ hg add foo/plain-file
197 $ hg add foo/plain-file
193 $ HGEDITOR=cat hg ci --edit -l ../commit-log-test foo
198 $ HGEDITOR=cat hg ci --edit -l ../commit-log-test foo
194 commit-foo-subdir
199 commit-foo-subdir
195
200
196
201
197 HG: Enter commit message. Lines beginning with 'HG:' are removed.
202 HG: Enter commit message. Lines beginning with 'HG:' are removed.
198 HG: Leave message empty to abort commit.
203 HG: Leave message empty to abort commit.
199 HG: --
204 HG: --
200 HG: user: test
205 HG: user: test
201 HG: branch 'default'
206 HG: branch 'default'
202 HG: added foo/plain-file
207 HG: added foo/plain-file
203
208
204
209
205 $ echo modified foo content > foo/plain-file
210 $ echo modified foo content > foo/plain-file
206 $ hg ci -m commit-foo-dot .
211 $ hg ci -m commit-foo-dot .
207
212
208 full log
213 full log
209
214
210 $ hg log -v
215 $ hg log -v
211 changeset: 1:95b38e3a5b2e
216 changeset: 1:95b38e3a5b2e
212 tag: tip
217 tag: tip
213 user: test
218 user: test
214 date: Thu Jan 01 00:00:00 1970 +0000
219 date: Thu Jan 01 00:00:00 1970 +0000
215 files: foo/plain-file
220 files: foo/plain-file
216 description:
221 description:
217 commit-foo-dot
222 commit-foo-dot
218
223
219
224
220 changeset: 0:65d4e9386227
225 changeset: 0:65d4e9386227
221 user: test
226 user: test
222 date: Thu Jan 01 00:00:00 1970 +0000
227 date: Thu Jan 01 00:00:00 1970 +0000
223 files: foo/plain-file
228 files: foo/plain-file
224 description:
229 description:
225 commit-foo-subdir
230 commit-foo-subdir
226
231
227
232
228
233
229 subdir log
234 subdir log
230
235
231 $ cd foo
236 $ cd foo
232 $ hg log .
237 $ hg log .
233 changeset: 1:95b38e3a5b2e
238 changeset: 1:95b38e3a5b2e
234 tag: tip
239 tag: tip
235 user: test
240 user: test
236 date: Thu Jan 01 00:00:00 1970 +0000
241 date: Thu Jan 01 00:00:00 1970 +0000
237 summary: commit-foo-dot
242 summary: commit-foo-dot
238
243
239 changeset: 0:65d4e9386227
244 changeset: 0:65d4e9386227
240 user: test
245 user: test
241 date: Thu Jan 01 00:00:00 1970 +0000
246 date: Thu Jan 01 00:00:00 1970 +0000
242 summary: commit-foo-subdir
247 summary: commit-foo-subdir
243
248
244 $ cd ..
249 $ cd ..
245 $ cd ..
250 $ cd ..
246
251
247 Issue1049: Hg permits partial commit of merge without warning
252 Issue1049: Hg permits partial commit of merge without warning
248
253
249 $ hg init issue1049
254 $ hg init issue1049
250 $ cd issue1049
255 $ cd issue1049
251 $ echo a > a
256 $ echo a > a
252 $ hg ci -Ama
257 $ hg ci -Ama
253 adding a
258 adding a
254 $ echo a >> a
259 $ echo a >> a
255 $ hg ci -mb
260 $ hg ci -mb
256 $ hg up 0
261 $ hg up 0
257 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 $ echo b >> a
263 $ echo b >> a
259 $ hg ci -mc
264 $ hg ci -mc
260 created new head
265 created new head
261 $ HGMERGE=true hg merge
266 $ HGMERGE=true hg merge
262 merging a
267 merging a
263 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
268 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
264 (branch merge, don't forget to commit)
269 (branch merge, don't forget to commit)
265
270
266 should fail because we are specifying a file name
271 should fail because we are specifying a file name
267
272
268 $ hg ci -mmerge a
273 $ hg ci -mmerge a
269 abort: cannot partially commit a merge (do not specify files or patterns)
274 abort: cannot partially commit a merge (do not specify files or patterns)
270 [255]
275 [255]
271
276
272 should fail because we are specifying a pattern
277 should fail because we are specifying a pattern
273
278
274 $ hg ci -mmerge -I a
279 $ hg ci -mmerge -I a
275 abort: cannot partially commit a merge (do not specify files or patterns)
280 abort: cannot partially commit a merge (do not specify files or patterns)
276 [255]
281 [255]
277
282
278 should succeed
283 should succeed
279
284
280 $ hg ci -mmerge
285 $ hg ci -mmerge
281 $ cd ..
286 $ cd ..
282
287
283
288
284 test commit message content
289 test commit message content
285
290
286 $ hg init commitmsg
291 $ hg init commitmsg
287 $ cd commitmsg
292 $ cd commitmsg
288 $ echo changed > changed
293 $ echo changed > changed
289 $ echo removed > removed
294 $ echo removed > removed
290 $ hg book currentbookmark
295 $ hg book currentbookmark
291 $ hg ci -qAm init
296 $ hg ci -qAm init
292
297
293 $ hg rm removed
298 $ hg rm removed
294 $ echo changed >> changed
299 $ echo changed >> changed
295 $ echo added > added
300 $ echo added > added
296 $ hg add added
301 $ hg add added
297 $ HGEDITOR=cat hg ci -A
302 $ HGEDITOR=cat hg ci -A
298
303
299
304
300 HG: Enter commit message. Lines beginning with 'HG:' are removed.
305 HG: Enter commit message. Lines beginning with 'HG:' are removed.
301 HG: Leave message empty to abort commit.
306 HG: Leave message empty to abort commit.
302 HG: --
307 HG: --
303 HG: user: test
308 HG: user: test
304 HG: branch 'default'
309 HG: branch 'default'
305 HG: bookmark 'currentbookmark'
310 HG: bookmark 'currentbookmark'
306 HG: added added
311 HG: added added
307 HG: changed changed
312 HG: changed changed
308 HG: removed removed
313 HG: removed removed
309 abort: empty commit message
314 abort: empty commit message
310 [255]
315 [255]
311
316
312 test saving last-message.txt
317 test saving last-message.txt
313
318
314 $ hg init sub
319 $ hg init sub
315 $ echo a > sub/a
320 $ echo a > sub/a
316 $ hg -R sub add sub/a
321 $ hg -R sub add sub/a
317 $ cat > sub/.hg/hgrc <<EOF
322 $ cat > sub/.hg/hgrc <<EOF
318 > [hooks]
323 > [hooks]
319 > precommit.test-saving-last-message = false
324 > precommit.test-saving-last-message = false
320 > EOF
325 > EOF
321
326
322 $ echo 'sub = sub' > .hgsub
327 $ echo 'sub = sub' > .hgsub
323 $ hg add .hgsub
328 $ hg add .hgsub
324
329
325 $ cat > $TESTTMP/editor.sh <<EOF
330 $ cat > $TESTTMP/editor.sh <<EOF
326 > echo "==== before editing:"
331 > echo "==== before editing:"
327 > cat \$1
332 > cat \$1
328 > echo "===="
333 > echo "===="
329 > echo "test saving last-message.txt" >> \$1
334 > echo "test saving last-message.txt" >> \$1
330 > EOF
335 > EOF
331
336
332 $ rm -f .hg/last-message.txt
337 $ rm -f .hg/last-message.txt
333 $ HGEDITOR="sh $TESTTMP/editor.sh" hg commit -S -q
338 $ HGEDITOR="sh $TESTTMP/editor.sh" hg commit -S -q
334 ==== before editing:
339 ==== before editing:
335
340
336
341
337 HG: Enter commit message. Lines beginning with 'HG:' are removed.
342 HG: Enter commit message. Lines beginning with 'HG:' are removed.
338 HG: Leave message empty to abort commit.
343 HG: Leave message empty to abort commit.
339 HG: --
344 HG: --
340 HG: user: test
345 HG: user: test
341 HG: branch 'default'
346 HG: branch 'default'
342 HG: bookmark 'currentbookmark'
347 HG: bookmark 'currentbookmark'
343 HG: subrepo sub
348 HG: subrepo sub
344 HG: added .hgsub
349 HG: added .hgsub
345 HG: added added
350 HG: added added
346 HG: changed .hgsubstate
351 HG: changed .hgsubstate
347 HG: changed changed
352 HG: changed changed
348 HG: removed removed
353 HG: removed removed
349 ====
354 ====
350 abort: precommit.test-saving-last-message hook exited with status 1 (in subrepo sub)
355 abort: precommit.test-saving-last-message hook exited with status 1 (in subrepo sub)
351 [255]
356 [255]
352 $ cat .hg/last-message.txt
357 $ cat .hg/last-message.txt
353
358
354
359
355 test saving last-message.txt
360 test saving last-message.txt
356
361
357 test that '[committemplate] changeset' definition and commit log
362 test that '[committemplate] changeset' definition and commit log
358 specific template keywords work well
363 specific template keywords work well
359
364
360 $ cat >> .hg/hgrc <<EOF
365 $ cat >> .hg/hgrc <<EOF
361 > [committemplate]
366 > [committemplate]
362 > changeset.commit.normal = HG: this is "commit.normal" template
367 > changeset.commit.normal = HG: this is "commit.normal" template
363 > HG: {extramsg}
368 > HG: {extramsg}
364 > {if(currentbookmark,
369 > {if(currentbookmark,
365 > "HG: bookmark '{currentbookmark}' is activated\n",
370 > "HG: bookmark '{currentbookmark}' is activated\n",
366 > "HG: no bookmark is activated\n")}{subrepos %
371 > "HG: no bookmark is activated\n")}{subrepos %
367 > "HG: subrepo '{subrepo}' is changed\n"}
372 > "HG: subrepo '{subrepo}' is changed\n"}
368 >
373 >
369 > changeset.commit = HG: this is "commit" template
374 > changeset.commit = HG: this is "commit" template
370 > HG: {extramsg}
375 > HG: {extramsg}
371 > {if(currentbookmark,
376 > {if(currentbookmark,
372 > "HG: bookmark '{currentbookmark}' is activated\n",
377 > "HG: bookmark '{currentbookmark}' is activated\n",
373 > "HG: no bookmark is activated\n")}{subrepos %
378 > "HG: no bookmark is activated\n")}{subrepos %
374 > "HG: subrepo '{subrepo}' is changed\n"}
379 > "HG: subrepo '{subrepo}' is changed\n"}
375 >
380 >
376 > changeset = HG: this is customized commit template
381 > changeset = HG: this is customized commit template
377 > HG: {extramsg}
382 > HG: {extramsg}
378 > {if(currentbookmark,
383 > {if(currentbookmark,
379 > "HG: bookmark '{currentbookmark}' is activated\n",
384 > "HG: bookmark '{currentbookmark}' is activated\n",
380 > "HG: no bookmark is activated\n")}{subrepos %
385 > "HG: no bookmark is activated\n")}{subrepos %
381 > "HG: subrepo '{subrepo}' is changed\n"}
386 > "HG: subrepo '{subrepo}' is changed\n"}
382 > EOF
387 > EOF
383
388
384 $ hg init sub2
389 $ hg init sub2
385 $ echo a > sub2/a
390 $ echo a > sub2/a
386 $ hg -R sub2 add sub2/a
391 $ hg -R sub2 add sub2/a
387 $ echo 'sub2 = sub2' >> .hgsub
392 $ echo 'sub2 = sub2' >> .hgsub
388
393
389 $ HGEDITOR=cat hg commit -S -q
394 $ HGEDITOR=cat hg commit -S -q
390 HG: this is "commit.normal" template
395 HG: this is "commit.normal" template
391 HG: Leave message empty to abort commit.
396 HG: Leave message empty to abort commit.
392 HG: bookmark 'currentbookmark' is activated
397 HG: bookmark 'currentbookmark' is activated
393 HG: subrepo 'sub' is changed
398 HG: subrepo 'sub' is changed
394 HG: subrepo 'sub2' is changed
399 HG: subrepo 'sub2' is changed
395 abort: empty commit message
400 abort: empty commit message
396 [255]
401 [255]
397
402
398 $ cat >> .hg/hgrc <<EOF
403 $ cat >> .hg/hgrc <<EOF
399 > [committemplate]
404 > [committemplate]
400 > changeset.commit.normal =
405 > changeset.commit.normal =
401 > # now, "changeset.commit" should be chosen for "hg commit"
406 > # now, "changeset.commit" should be chosen for "hg commit"
402 > EOF
407 > EOF
403
408
404 $ hg bookmark --inactive currentbookmark
409 $ hg bookmark --inactive currentbookmark
405 $ hg forget .hgsub
410 $ hg forget .hgsub
406 $ HGEDITOR=cat hg commit -q
411 $ HGEDITOR=cat hg commit -q
407 HG: this is "commit" template
412 HG: this is "commit" template
408 HG: Leave message empty to abort commit.
413 HG: Leave message empty to abort commit.
409 HG: no bookmark is activated
414 HG: no bookmark is activated
410 abort: empty commit message
415 abort: empty commit message
411 [255]
416 [255]
412
417
413 $ cat >> .hg/hgrc <<EOF
418 $ cat >> .hg/hgrc <<EOF
414 > [committemplate]
419 > [committemplate]
415 > changeset.commit =
420 > changeset.commit =
416 > # now, "changeset" should be chosen for "hg commit"
421 > # now, "changeset" should be chosen for "hg commit"
417 > EOF
422 > EOF
418
423
419 $ HGEDITOR=cat hg commit -q
424 $ HGEDITOR=cat hg commit -q
420 HG: this is customized commit template
425 HG: this is customized commit template
421 HG: Leave message empty to abort commit.
426 HG: Leave message empty to abort commit.
422 HG: no bookmark is activated
427 HG: no bookmark is activated
423 abort: empty commit message
428 abort: empty commit message
424 [255]
429 [255]
425
430
426 $ cat >> .hg/hgrc <<EOF
431 $ cat >> .hg/hgrc <<EOF
427 > # disable customizing for subsequent tests
432 > # disable customizing for subsequent tests
428 > [committemplate]
433 > [committemplate]
429 > changeset =
434 > changeset =
430 > EOF
435 > EOF
431
436
432 $ cd ..
437 $ cd ..
433
438
434
439
435 commit copy
440 commit copy
436
441
437 $ hg init dir2
442 $ hg init dir2
438 $ cd dir2
443 $ cd dir2
439 $ echo bleh > bar
444 $ echo bleh > bar
440 $ hg add bar
445 $ hg add bar
441 $ hg ci -m 'add bar'
446 $ hg ci -m 'add bar'
442
447
443 $ hg cp bar foo
448 $ hg cp bar foo
444 $ echo >> bar
449 $ echo >> bar
445 $ hg ci -m 'cp bar foo; change bar'
450 $ hg ci -m 'cp bar foo; change bar'
446
451
447 $ hg debugrename foo
452 $ hg debugrename foo
448 foo renamed from bar:26d3ca0dfd18e44d796b564e38dd173c9668d3a9
453 foo renamed from bar:26d3ca0dfd18e44d796b564e38dd173c9668d3a9
449 $ hg debugindex bar
454 $ hg debugindex bar
450 rev offset length ..... linkrev nodeid p1 p2 (re)
455 rev offset length ..... linkrev nodeid p1 p2 (re)
451 0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re)
456 0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re)
452 1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re)
457 1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re)
453
458
454 $ cd ..
459 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now