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