##// END OF EJS Templates
move walk and matchpats from commands to cmdutil.
Vadim Gelfer -
r2882:cf98cd70 default
parent child Browse files
Show More
@@ -1,68 +1,92 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import demandload
9 9 from node import *
10 10 from i18n import gettext as _
11 demandload(globals(), 'util')
11 12 demandload(globals(), 'os sys')
12 13
13 14 def make_filename(repo, pat, node,
14 15 total=None, seqno=None, revwidth=None, pathname=None):
15 16 node_expander = {
16 17 'H': lambda: hex(node),
17 18 'R': lambda: str(repo.changelog.rev(node)),
18 19 'h': lambda: short(node),
19 20 }
20 21 expander = {
21 22 '%': lambda: '%',
22 23 'b': lambda: os.path.basename(repo.root),
23 24 }
24 25
25 26 try:
26 27 if node:
27 28 expander.update(node_expander)
28 29 if node and revwidth is not None:
29 30 expander['r'] = (lambda:
30 31 str(repo.changelog.rev(node)).zfill(revwidth))
31 32 if total is not None:
32 33 expander['N'] = lambda: str(total)
33 34 if seqno is not None:
34 35 expander['n'] = lambda: str(seqno)
35 36 if total is not None and seqno is not None:
36 37 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
37 38 if pathname is not None:
38 39 expander['s'] = lambda: os.path.basename(pathname)
39 40 expander['d'] = lambda: os.path.dirname(pathname) or '.'
40 41 expander['p'] = lambda: pathname
41 42
42 43 newname = []
43 44 patlen = len(pat)
44 45 i = 0
45 46 while i < patlen:
46 47 c = pat[i]
47 48 if c == '%':
48 49 i += 1
49 50 c = pat[i]
50 51 c = expander[c]()
51 52 newname.append(c)
52 53 i += 1
53 54 return ''.join(newname)
54 55 except KeyError, inst:
55 56 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
56 57 inst.args[0])
57 58
58 59 def make_file(repo, pat, node=None,
59 60 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
60 61 if not pat or pat == '-':
61 62 return 'w' in mode and sys.stdout or sys.stdin
62 63 if hasattr(pat, 'write') and 'w' in mode:
63 64 return pat
64 65 if hasattr(pat, 'read') and 'r' in mode:
65 66 return pat
66 67 return open(make_filename(repo, pat, node, total, seqno, revwidth,
67 68 pathname),
68 69 mode)
70
71 def matchpats(repo, pats=[], opts={}, head=''):
72 cwd = repo.getcwd()
73 if not pats and cwd:
74 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
75 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
76 cwd = ''
77 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
78 opts.get('exclude'), head)
79
80 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
81 files, matchfn, anypats = matchpats(repo, pats, opts, head)
82 exact = dict(zip(files, files))
83 def walk():
84 for src, fn in repo.walk(node=node, files=files, match=matchfn,
85 badmatch=badmatch):
86 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
87 return files, matchfn, walk()
88
89 def walk(repo, pats, opts, node=None, head='', badmatch=None):
90 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
91 for r in results:
92 yield r
@@ -1,3524 +1,3504 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import demandload
9 9 from node import *
10 10 from i18n import gettext as _
11 11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
14 14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 15 demandload(globals(), "archival cStringIO changegroup")
16 16 demandload(globals(), "cmdutil hgweb.server sshserver")
17 17
18 18 class UnknownCommand(Exception):
19 19 """Exception raised if command is not in the command table."""
20 20 class AmbiguousCommand(Exception):
21 21 """Exception raised if command shortcut matches more than one command."""
22 22
23 23 def bail_if_changed(repo):
24 24 modified, added, removed, deleted = repo.status()[:4]
25 25 if modified or added or removed or deleted:
26 26 raise util.Abort(_("outstanding uncommitted changes"))
27 27
28 28 def relpath(repo, args):
29 29 cwd = repo.getcwd()
30 30 if cwd:
31 31 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 32 return args
33 33
34 34 def logmessage(opts):
35 35 """ get the log message according to -m and -l option """
36 36 message = opts['message']
37 37 logfile = opts['logfile']
38 38
39 39 if message and logfile:
40 40 raise util.Abort(_('options --message and --logfile are mutually '
41 41 'exclusive'))
42 42 if not message and logfile:
43 43 try:
44 44 if logfile == '-':
45 45 message = sys.stdin.read()
46 46 else:
47 47 message = open(logfile).read()
48 48 except IOError, inst:
49 49 raise util.Abort(_("can't read commit message '%s': %s") %
50 50 (logfile, inst.strerror))
51 51 return message
52 52
53 def matchpats(repo, pats=[], opts={}, head=''):
54 cwd = repo.getcwd()
55 if not pats and cwd:
56 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
57 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
58 cwd = ''
59 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
60 opts.get('exclude'), head)
61
62 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
63 files, matchfn, anypats = matchpats(repo, pats, opts, head)
64 exact = dict(zip(files, files))
65 def walk():
66 for src, fn in repo.walk(node=node, files=files, match=matchfn,
67 badmatch=badmatch):
68 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
69 return files, matchfn, walk()
70
71 def walk(repo, pats, opts, node=None, head='', badmatch=None):
72 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
73 for r in results:
74 yield r
75
76 53 def walkchangerevs(ui, repo, pats, opts):
77 54 '''Iterate over files and the revs they changed in.
78 55
79 56 Callers most commonly need to iterate backwards over the history
80 57 it is interested in. Doing so has awful (quadratic-looking)
81 58 performance, so we use iterators in a "windowed" way.
82 59
83 60 We walk a window of revisions in the desired order. Within the
84 61 window, we first walk forwards to gather data, then in the desired
85 62 order (usually backwards) to display it.
86 63
87 64 This function returns an (iterator, getchange, matchfn) tuple. The
88 65 getchange function returns the changelog entry for a numeric
89 66 revision. The iterator yields 3-tuples. They will be of one of
90 67 the following forms:
91 68
92 69 "window", incrementing, lastrev: stepping through a window,
93 70 positive if walking forwards through revs, last rev in the
94 71 sequence iterated over - use to reset state for the current window
95 72
96 73 "add", rev, fns: out-of-order traversal of the given file names
97 74 fns, which changed during revision rev - use to gather data for
98 75 possible display
99 76
100 77 "iter", rev, None: in-order traversal of the revs earlier iterated
101 78 over with "add" - use to display data'''
102 79
103 80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
104 81 if start < end:
105 82 while start < end:
106 83 yield start, min(windowsize, end-start)
107 84 start += windowsize
108 85 if windowsize < sizelimit:
109 86 windowsize *= 2
110 87 else:
111 88 while start > end:
112 89 yield start, min(windowsize, start-end-1)
113 90 start -= windowsize
114 91 if windowsize < sizelimit:
115 92 windowsize *= 2
116 93
117 94
118 files, matchfn, anypats = matchpats(repo, pats, opts)
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
119 96 follow = opts.get('follow') or opts.get('follow_first')
120 97
121 98 if repo.changelog.count() == 0:
122 99 return [], False, matchfn
123 100
124 101 if follow:
125 102 p = repo.dirstate.parents()[0]
126 103 if p == nullid:
127 104 ui.warn(_('No working directory revision; defaulting to tip\n'))
128 105 start = 'tip'
129 106 else:
130 107 start = repo.changelog.rev(p)
131 108 defrange = '%s:0' % start
132 109 else:
133 110 defrange = 'tip:0'
134 111 revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
135 112 wanted = {}
136 113 slowpath = anypats
137 114 fncache = {}
138 115
139 116 chcache = {}
140 117 def getchange(rev):
141 118 ch = chcache.get(rev)
142 119 if ch is None:
143 120 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
144 121 return ch
145 122
146 123 if not slowpath and not files:
147 124 # No files, no patterns. Display all revs.
148 125 wanted = dict(zip(revs, revs))
149 126 copies = []
150 127 if not slowpath:
151 128 # Only files, no patterns. Check the history of each file.
152 129 def filerevgen(filelog, node):
153 130 cl_count = repo.changelog.count()
154 131 if node is None:
155 132 last = filelog.count() - 1
156 133 else:
157 134 last = filelog.rev(node)
158 135 for i, window in increasing_windows(last, -1):
159 136 revs = []
160 137 for j in xrange(i - window, i + 1):
161 138 n = filelog.node(j)
162 139 revs.append((filelog.linkrev(n),
163 140 follow and filelog.renamed(n)))
164 141 revs.reverse()
165 142 for rev in revs:
166 143 # only yield rev for which we have the changelog, it can
167 144 # happen while doing "hg log" during a pull or commit
168 145 if rev[0] < cl_count:
169 146 yield rev
170 147 def iterfiles():
171 148 for filename in files:
172 149 yield filename, None
173 150 for filename_node in copies:
174 151 yield filename_node
175 152 minrev, maxrev = min(revs), max(revs)
176 153 for file_, node in iterfiles():
177 154 filelog = repo.file(file_)
178 155 # A zero count may be a directory or deleted file, so
179 156 # try to find matching entries on the slow path.
180 157 if filelog.count() == 0:
181 158 slowpath = True
182 159 break
183 160 for rev, copied in filerevgen(filelog, node):
184 161 if rev <= maxrev:
185 162 if rev < minrev:
186 163 break
187 164 fncache.setdefault(rev, [])
188 165 fncache[rev].append(file_)
189 166 wanted[rev] = 1
190 167 if follow and copied:
191 168 copies.append(copied)
192 169 if slowpath:
193 170 if follow:
194 171 raise util.Abort(_('can only follow copies/renames for explicit '
195 172 'file names'))
196 173
197 174 # The slow path checks files modified in every changeset.
198 175 def changerevgen():
199 176 for i, window in increasing_windows(repo.changelog.count()-1, -1):
200 177 for j in xrange(i - window, i + 1):
201 178 yield j, getchange(j)[3]
202 179
203 180 for rev, changefiles in changerevgen():
204 181 matches = filter(matchfn, changefiles)
205 182 if matches:
206 183 fncache[rev] = matches
207 184 wanted[rev] = 1
208 185
209 186 def iterate():
210 187 class followfilter:
211 188 def __init__(self, onlyfirst=False):
212 189 self.startrev = -1
213 190 self.roots = []
214 191 self.onlyfirst = onlyfirst
215 192
216 193 def match(self, rev):
217 194 def realparents(rev):
218 195 if self.onlyfirst:
219 196 return repo.changelog.parentrevs(rev)[0:1]
220 197 else:
221 198 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
222 199
223 200 if self.startrev == -1:
224 201 self.startrev = rev
225 202 return True
226 203
227 204 if rev > self.startrev:
228 205 # forward: all descendants
229 206 if not self.roots:
230 207 self.roots.append(self.startrev)
231 208 for parent in realparents(rev):
232 209 if parent in self.roots:
233 210 self.roots.append(rev)
234 211 return True
235 212 else:
236 213 # backwards: all parents
237 214 if not self.roots:
238 215 self.roots.extend(realparents(self.startrev))
239 216 if rev in self.roots:
240 217 self.roots.remove(rev)
241 218 self.roots.extend(realparents(rev))
242 219 return True
243 220
244 221 return False
245 222
246 223 if follow and not files:
247 224 ff = followfilter(onlyfirst=opts.get('follow_first'))
248 225 def want(rev):
249 226 if rev not in wanted:
250 227 return False
251 228 return ff.match(rev)
252 229 else:
253 230 def want(rev):
254 231 return rev in wanted
255 232
256 233 for i, window in increasing_windows(0, len(revs)):
257 234 yield 'window', revs[0] < revs[-1], revs[-1]
258 235 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
259 236 srevs = list(nrevs)
260 237 srevs.sort()
261 238 for rev in srevs:
262 239 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
263 240 yield 'add', rev, fns
264 241 for rev in nrevs:
265 242 yield 'iter', rev, None
266 243 return iterate(), getchange, matchfn
267 244
268 245 revrangesep = ':'
269 246
270 247 def revfix(repo, val, defval):
271 248 '''turn user-level id of changeset into rev number.
272 249 user-level id can be tag, changeset, rev number, or negative rev
273 250 number relative to number of revs (-1 is tip, etc).'''
274 251 if not val:
275 252 return defval
276 253 try:
277 254 num = int(val)
278 255 if str(num) != val:
279 256 raise ValueError
280 257 if num < 0:
281 258 num += repo.changelog.count()
282 259 if num < 0:
283 260 num = 0
284 261 elif num >= repo.changelog.count():
285 262 raise ValueError
286 263 except ValueError:
287 264 try:
288 265 num = repo.changelog.rev(repo.lookup(val))
289 266 except KeyError:
290 267 raise util.Abort(_('invalid revision identifier %s'), val)
291 268 return num
292 269
293 270 def revpair(ui, repo, revs):
294 271 '''return pair of nodes, given list of revisions. second item can
295 272 be None, meaning use working dir.'''
296 273 if not revs:
297 274 return repo.dirstate.parents()[0], None
298 275 end = None
299 276 if len(revs) == 1:
300 277 start = revs[0]
301 278 if revrangesep in start:
302 279 start, end = start.split(revrangesep, 1)
303 280 start = revfix(repo, start, 0)
304 281 end = revfix(repo, end, repo.changelog.count() - 1)
305 282 else:
306 283 start = revfix(repo, start, None)
307 284 elif len(revs) == 2:
308 285 if revrangesep in revs[0] or revrangesep in revs[1]:
309 286 raise util.Abort(_('too many revisions specified'))
310 287 start = revfix(repo, revs[0], None)
311 288 end = revfix(repo, revs[1], None)
312 289 else:
313 290 raise util.Abort(_('too many revisions specified'))
314 291 if end is not None: end = repo.lookup(str(end))
315 292 return repo.lookup(str(start)), end
316 293
317 294 def revrange(ui, repo, revs):
318 295 """Yield revision as strings from a list of revision specifications."""
319 296 seen = {}
320 297 for spec in revs:
321 298 if revrangesep in spec:
322 299 start, end = spec.split(revrangesep, 1)
323 300 start = revfix(repo, start, 0)
324 301 end = revfix(repo, end, repo.changelog.count() - 1)
325 302 step = start > end and -1 or 1
326 303 for rev in xrange(start, end+step, step):
327 304 if rev in seen:
328 305 continue
329 306 seen[rev] = 1
330 307 yield str(rev)
331 308 else:
332 309 rev = revfix(repo, spec, None)
333 310 if rev in seen:
334 311 continue
335 312 seen[rev] = 1
336 313 yield str(rev)
337 314
338 315 def write_bundle(cg, filename=None, compress=True):
339 316 """Write a bundle file and return its filename.
340 317
341 318 Existing files will not be overwritten.
342 319 If no filename is specified, a temporary file is created.
343 320 bz2 compression can be turned off.
344 321 The bundle file will be deleted in case of errors.
345 322 """
346 323 class nocompress(object):
347 324 def compress(self, x):
348 325 return x
349 326 def flush(self):
350 327 return ""
351 328
352 329 fh = None
353 330 cleanup = None
354 331 try:
355 332 if filename:
356 333 if os.path.exists(filename):
357 334 raise util.Abort(_("file '%s' already exists"), filename)
358 335 fh = open(filename, "wb")
359 336 else:
360 337 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
361 338 fh = os.fdopen(fd, "wb")
362 339 cleanup = filename
363 340
364 341 if compress:
365 342 fh.write("HG10")
366 343 z = bz2.BZ2Compressor(9)
367 344 else:
368 345 fh.write("HG10UN")
369 346 z = nocompress()
370 347 # parse the changegroup data, otherwise we will block
371 348 # in case of sshrepo because we don't know the end of the stream
372 349
373 350 # an empty chunkiter is the end of the changegroup
374 351 empty = False
375 352 while not empty:
376 353 empty = True
377 354 for chunk in changegroup.chunkiter(cg):
378 355 empty = False
379 356 fh.write(z.compress(changegroup.genchunk(chunk)))
380 357 fh.write(z.compress(changegroup.closechunk()))
381 358 fh.write(z.flush())
382 359 cleanup = None
383 360 return filename
384 361 finally:
385 362 if fh is not None:
386 363 fh.close()
387 364 if cleanup is not None:
388 365 os.unlink(cleanup)
389 366
390 367 def trimuser(ui, name, rev, revcache):
391 368 """trim the name of the user who committed a change"""
392 369 user = revcache.get(rev)
393 370 if user is None:
394 371 user = revcache[rev] = ui.shortuser(name)
395 372 return user
396 373
397 374 class changeset_printer(object):
398 375 '''show changeset information when templating not requested.'''
399 376
400 377 def __init__(self, ui, repo):
401 378 self.ui = ui
402 379 self.repo = repo
403 380
404 381 def show(self, rev=0, changenode=None, brinfo=None):
405 382 '''show a single changeset or file revision'''
406 383 log = self.repo.changelog
407 384 if changenode is None:
408 385 changenode = log.node(rev)
409 386 elif not rev:
410 387 rev = log.rev(changenode)
411 388
412 389 if self.ui.quiet:
413 390 self.ui.write("%d:%s\n" % (rev, short(changenode)))
414 391 return
415 392
416 393 changes = log.read(changenode)
417 394 date = util.datestr(changes[2])
418 395
419 396 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
420 397 for p in log.parents(changenode)
421 398 if self.ui.debugflag or p != nullid]
422 399 if (not self.ui.debugflag and len(parents) == 1 and
423 400 parents[0][0] == rev-1):
424 401 parents = []
425 402
426 403 if self.ui.verbose:
427 404 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
428 405 else:
429 406 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
430 407
431 408 for tag in self.repo.nodetags(changenode):
432 409 self.ui.status(_("tag: %s\n") % tag)
433 410 for parent in parents:
434 411 self.ui.write(_("parent: %d:%s\n") % parent)
435 412
436 413 if brinfo and changenode in brinfo:
437 414 br = brinfo[changenode]
438 415 self.ui.write(_("branch: %s\n") % " ".join(br))
439 416
440 417 self.ui.debug(_("manifest: %d:%s\n") %
441 418 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
442 419 self.ui.status(_("user: %s\n") % changes[1])
443 420 self.ui.status(_("date: %s\n") % date)
444 421
445 422 if self.ui.debugflag:
446 423 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
447 424 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
448 425 files):
449 426 if value:
450 427 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
451 428 else:
452 429 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
453 430
454 431 description = changes[4].strip()
455 432 if description:
456 433 if self.ui.verbose:
457 434 self.ui.status(_("description:\n"))
458 435 self.ui.status(description)
459 436 self.ui.status("\n\n")
460 437 else:
461 438 self.ui.status(_("summary: %s\n") %
462 439 description.splitlines()[0])
463 440 self.ui.status("\n")
464 441
465 442 def show_changeset(ui, repo, opts):
466 443 '''show one changeset. uses template or regular display. caller
467 444 can pass in 'style' and 'template' options in opts.'''
468 445
469 446 tmpl = opts.get('template')
470 447 if tmpl:
471 448 tmpl = templater.parsestring(tmpl, quoted=False)
472 449 else:
473 450 tmpl = ui.config('ui', 'logtemplate')
474 451 if tmpl: tmpl = templater.parsestring(tmpl)
475 452 mapfile = opts.get('style') or ui.config('ui', 'style')
476 453 if tmpl or mapfile:
477 454 if mapfile:
478 455 if not os.path.isfile(mapfile):
479 456 mapname = templater.templatepath('map-cmdline.' + mapfile)
480 457 if not mapname: mapname = templater.templatepath(mapfile)
481 458 if mapname: mapfile = mapname
482 459 try:
483 460 t = templater.changeset_templater(ui, repo, mapfile)
484 461 except SyntaxError, inst:
485 462 raise util.Abort(inst.args[0])
486 463 if tmpl: t.use_template(tmpl)
487 464 return t
488 465 return changeset_printer(ui, repo)
489 466
490 467 def setremoteconfig(ui, opts):
491 468 "copy remote options to ui tree"
492 469 if opts.get('ssh'):
493 470 ui.setconfig("ui", "ssh", opts['ssh'])
494 471 if opts.get('remotecmd'):
495 472 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
496 473
497 474 def show_version(ui):
498 475 """output version and copyright information"""
499 476 ui.write(_("Mercurial Distributed SCM (version %s)\n")
500 477 % version.get_version())
501 478 ui.status(_(
502 479 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
503 480 "This is free software; see the source for copying conditions. "
504 481 "There is NO\nwarranty; "
505 482 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
506 483 ))
507 484
508 485 def help_(ui, name=None, with_version=False):
509 486 """show help for a command, extension, or list of commands
510 487
511 488 With no arguments, print a list of commands and short help.
512 489
513 490 Given a command name, print help for that command.
514 491
515 492 Given an extension name, print help for that extension, and the
516 493 commands it provides."""
517 494 option_lists = []
518 495
519 496 def helpcmd(name):
520 497 if with_version:
521 498 show_version(ui)
522 499 ui.write('\n')
523 500 aliases, i = findcmd(name)
524 501 # synopsis
525 502 ui.write("%s\n\n" % i[2])
526 503
527 504 # description
528 505 doc = i[0].__doc__
529 506 if not doc:
530 507 doc = _("(No help text available)")
531 508 if ui.quiet:
532 509 doc = doc.splitlines(0)[0]
533 510 ui.write("%s\n" % doc.rstrip())
534 511
535 512 if not ui.quiet:
536 513 # aliases
537 514 if len(aliases) > 1:
538 515 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
539 516
540 517 # options
541 518 if i[1]:
542 519 option_lists.append(("options", i[1]))
543 520
544 521 def helplist(select=None):
545 522 h = {}
546 523 cmds = {}
547 524 for c, e in table.items():
548 525 f = c.split("|", 1)[0]
549 526 if select and not select(f):
550 527 continue
551 528 if name == "shortlist" and not f.startswith("^"):
552 529 continue
553 530 f = f.lstrip("^")
554 531 if not ui.debugflag and f.startswith("debug"):
555 532 continue
556 533 doc = e[0].__doc__
557 534 if not doc:
558 535 doc = _("(No help text available)")
559 536 h[f] = doc.splitlines(0)[0].rstrip()
560 537 cmds[f] = c.lstrip("^")
561 538
562 539 fns = h.keys()
563 540 fns.sort()
564 541 m = max(map(len, fns))
565 542 for f in fns:
566 543 if ui.verbose:
567 544 commands = cmds[f].replace("|",", ")
568 545 ui.write(" %s:\n %s\n"%(commands, h[f]))
569 546 else:
570 547 ui.write(' %-*s %s\n' % (m, f, h[f]))
571 548
572 549 def helpext(name):
573 550 try:
574 551 mod = findext(name)
575 552 except KeyError:
576 553 raise UnknownCommand(name)
577 554
578 555 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
579 556 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
580 557 for d in doc[1:]:
581 558 ui.write(d, '\n')
582 559
583 560 ui.status('\n')
584 561 if ui.verbose:
585 562 ui.status(_('list of commands:\n\n'))
586 563 else:
587 564 ui.status(_('list of commands (use "hg help -v %s" '
588 565 'to show aliases and global options):\n\n') % name)
589 566
590 567 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
591 568 helplist(modcmds.has_key)
592 569
593 570 if name and name != 'shortlist':
594 571 try:
595 572 helpcmd(name)
596 573 except UnknownCommand:
597 574 helpext(name)
598 575
599 576 else:
600 577 # program name
601 578 if ui.verbose or with_version:
602 579 show_version(ui)
603 580 else:
604 581 ui.status(_("Mercurial Distributed SCM\n"))
605 582 ui.status('\n')
606 583
607 584 # list of commands
608 585 if name == "shortlist":
609 586 ui.status(_('basic commands (use "hg help" '
610 587 'for the full list or option "-v" for details):\n\n'))
611 588 elif ui.verbose:
612 589 ui.status(_('list of commands:\n\n'))
613 590 else:
614 591 ui.status(_('list of commands (use "hg help -v" '
615 592 'to show aliases and global options):\n\n'))
616 593
617 594 helplist()
618 595
619 596 # global options
620 597 if ui.verbose:
621 598 option_lists.append(("global options", globalopts))
622 599
623 600 # list all option lists
624 601 opt_output = []
625 602 for title, options in option_lists:
626 603 opt_output.append(("\n%s:\n" % title, None))
627 604 for shortopt, longopt, default, desc in options:
628 605 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
629 606 longopt and " --%s" % longopt),
630 607 "%s%s" % (desc,
631 608 default
632 609 and _(" (default: %s)") % default
633 610 or "")))
634 611
635 612 if opt_output:
636 613 opts_len = max([len(line[0]) for line in opt_output if line[1]])
637 614 for first, second in opt_output:
638 615 if second:
639 616 ui.write(" %-*s %s\n" % (opts_len, first, second))
640 617 else:
641 618 ui.write("%s\n" % first)
642 619
643 620 # Commands start here, listed alphabetically
644 621
645 622 def add(ui, repo, *pats, **opts):
646 623 """add the specified files on the next commit
647 624
648 625 Schedule files to be version controlled and added to the repository.
649 626
650 627 The files will be added to the repository at the next commit.
651 628
652 629 If no names are given, add all files in the repository.
653 630 """
654 631
655 632 names = []
656 for src, abs, rel, exact in walk(repo, pats, opts):
633 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
657 634 if exact:
658 635 if ui.verbose:
659 636 ui.status(_('adding %s\n') % rel)
660 637 names.append(abs)
661 638 elif repo.dirstate.state(abs) == '?':
662 639 ui.status(_('adding %s\n') % rel)
663 640 names.append(abs)
664 641 if not opts.get('dry_run'):
665 642 repo.add(names)
666 643
667 644 def addremove(ui, repo, *pats, **opts):
668 645 """add all new files, delete all missing files (DEPRECATED)
669 646
670 647 (DEPRECATED)
671 648 Add all new files and remove all missing files from the repository.
672 649
673 650 New files are ignored if they match any of the patterns in .hgignore. As
674 651 with add, these changes take effect at the next commit.
675 652
676 653 This command is now deprecated and will be removed in a future
677 654 release. Please use add and remove --after instead.
678 655 """
679 656 ui.warn(_('(the addremove command is deprecated; use add and remove '
680 657 '--after instead)\n'))
681 658 return addremove_lock(ui, repo, pats, opts)
682 659
683 660 def addremove_lock(ui, repo, pats, opts, wlock=None):
684 661 add, remove = [], []
685 for src, abs, rel, exact in walk(repo, pats, opts):
662 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
686 663 if src == 'f' and repo.dirstate.state(abs) == '?':
687 664 add.append(abs)
688 665 if ui.verbose or not exact:
689 666 ui.status(_('adding %s\n') % ((pats and rel) or abs))
690 667 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
691 668 remove.append(abs)
692 669 if ui.verbose or not exact:
693 670 ui.status(_('removing %s\n') % ((pats and rel) or abs))
694 671 if not opts.get('dry_run'):
695 672 repo.add(add, wlock=wlock)
696 673 repo.remove(remove, wlock=wlock)
697 674
698 675 def annotate(ui, repo, *pats, **opts):
699 676 """show changeset information per file line
700 677
701 678 List changes in files, showing the revision id responsible for each line
702 679
703 680 This command is useful to discover who did a change or when a change took
704 681 place.
705 682
706 683 Without the -a option, annotate will avoid processing files it
707 684 detects as binary. With -a, annotate will generate an annotation
708 685 anyway, probably with undesirable results.
709 686 """
710 687 def getnode(rev):
711 688 return short(repo.changelog.node(rev))
712 689
713 690 ucache = {}
714 691 def getname(rev):
715 692 try:
716 693 return ucache[rev]
717 694 except:
718 695 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
719 696 ucache[rev] = u
720 697 return u
721 698
722 699 dcache = {}
723 700 def getdate(rev):
724 701 datestr = dcache.get(rev)
725 702 if datestr is None:
726 703 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
727 704 return datestr
728 705
729 706 if not pats:
730 707 raise util.Abort(_('at least one file name or pattern required'))
731 708
732 709 opmap = [['user', getname], ['number', str], ['changeset', getnode],
733 710 ['date', getdate]]
734 711 if not opts['user'] and not opts['changeset'] and not opts['date']:
735 712 opts['number'] = 1
736 713
737 714 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
738 715
739 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
716 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
717 node=ctx.node()):
740 718 fctx = ctx.filectx(abs)
741 719 if not opts['text'] and util.binary(fctx.data()):
742 720 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
743 721 continue
744 722
745 723 lines = fctx.annotate()
746 724 pieces = []
747 725
748 726 for o, f in opmap:
749 727 if opts[o]:
750 728 l = [f(n) for n, dummy in lines]
751 729 if l:
752 730 m = max(map(len, l))
753 731 pieces.append(["%*s" % (m, x) for x in l])
754 732
755 733 if pieces:
756 734 for p, l in zip(zip(*pieces), lines):
757 735 ui.write("%s: %s" % (" ".join(p), l[1]))
758 736
759 737 def archive(ui, repo, dest, **opts):
760 738 '''create unversioned archive of a repository revision
761 739
762 740 By default, the revision used is the parent of the working
763 741 directory; use "-r" to specify a different revision.
764 742
765 743 To specify the type of archive to create, use "-t". Valid
766 744 types are:
767 745
768 746 "files" (default): a directory full of files
769 747 "tar": tar archive, uncompressed
770 748 "tbz2": tar archive, compressed using bzip2
771 749 "tgz": tar archive, compressed using gzip
772 750 "uzip": zip archive, uncompressed
773 751 "zip": zip archive, compressed using deflate
774 752
775 753 The exact name of the destination archive or directory is given
776 754 using a format string; see "hg help export" for details.
777 755
778 756 Each member added to an archive file has a directory prefix
779 757 prepended. Use "-p" to specify a format string for the prefix.
780 758 The default is the basename of the archive, with suffixes removed.
781 759 '''
782 760
783 761 if opts['rev']:
784 762 node = repo.lookup(opts['rev'])
785 763 else:
786 764 node, p2 = repo.dirstate.parents()
787 765 if p2 != nullid:
788 766 raise util.Abort(_('uncommitted merge - please provide a '
789 767 'specific revision'))
790 768
791 769 dest = cmdutil.make_filename(repo, dest, node)
792 770 if os.path.realpath(dest) == repo.root:
793 771 raise util.Abort(_('repository root cannot be destination'))
794 dummy, matchfn, dummy = matchpats(repo, [], opts)
772 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
795 773 kind = opts.get('type') or 'files'
796 774 prefix = opts['prefix']
797 775 if dest == '-':
798 776 if kind == 'files':
799 777 raise util.Abort(_('cannot archive plain files to stdout'))
800 778 dest = sys.stdout
801 779 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
802 780 prefix = cmdutil.make_filename(repo, prefix, node)
803 781 archival.archive(repo, dest, node, kind, not opts['no_decode'],
804 782 matchfn, prefix)
805 783
806 784 def backout(ui, repo, rev, **opts):
807 785 '''reverse effect of earlier changeset
808 786
809 787 Commit the backed out changes as a new changeset. The new
810 788 changeset is a child of the backed out changeset.
811 789
812 790 If you back out a changeset other than the tip, a new head is
813 791 created. This head is the parent of the working directory. If
814 792 you back out an old changeset, your working directory will appear
815 793 old after the backout. You should merge the backout changeset
816 794 with another head.
817 795
818 796 The --merge option remembers the parent of the working directory
819 797 before starting the backout, then merges the new head with that
820 798 changeset afterwards. This saves you from doing the merge by
821 799 hand. The result of this merge is not committed, as for a normal
822 800 merge.'''
823 801
824 802 bail_if_changed(repo)
825 803 op1, op2 = repo.dirstate.parents()
826 804 if op2 != nullid:
827 805 raise util.Abort(_('outstanding uncommitted merge'))
828 806 node = repo.lookup(rev)
829 807 p1, p2 = repo.changelog.parents(node)
830 808 if p1 == nullid:
831 809 raise util.Abort(_('cannot back out a change with no parents'))
832 810 if p2 != nullid:
833 811 if not opts['parent']:
834 812 raise util.Abort(_('cannot back out a merge changeset without '
835 813 '--parent'))
836 814 p = repo.lookup(opts['parent'])
837 815 if p not in (p1, p2):
838 816 raise util.Abort(_('%s is not a parent of %s' %
839 817 (short(p), short(node))))
840 818 parent = p
841 819 else:
842 820 if opts['parent']:
843 821 raise util.Abort(_('cannot use --parent on non-merge changeset'))
844 822 parent = p1
845 823 hg.clean(repo, node, show_stats=False)
846 824 revert_opts = opts.copy()
847 825 revert_opts['rev'] = hex(parent)
848 826 revert(ui, repo, **revert_opts)
849 827 commit_opts = opts.copy()
850 828 commit_opts['addremove'] = False
851 829 if not commit_opts['message'] and not commit_opts['logfile']:
852 830 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
853 831 commit_opts['force_editor'] = True
854 832 commit(ui, repo, **commit_opts)
855 833 def nice(node):
856 834 return '%d:%s' % (repo.changelog.rev(node), short(node))
857 835 ui.status(_('changeset %s backs out changeset %s\n') %
858 836 (nice(repo.changelog.tip()), nice(node)))
859 837 if op1 != node:
860 838 if opts['merge']:
861 839 ui.status(_('merging with changeset %s\n') % nice(op1))
862 840 n = _lookup(repo, hex(op1))
863 841 hg.merge(repo, n)
864 842 else:
865 843 ui.status(_('the backout changeset is a new head - '
866 844 'do not forget to merge\n'))
867 845 ui.status(_('(use "backout --merge" '
868 846 'if you want to auto-merge)\n'))
869 847
870 848 def bundle(ui, repo, fname, dest=None, **opts):
871 849 """create a changegroup file
872 850
873 851 Generate a compressed changegroup file collecting all changesets
874 852 not found in the other repository.
875 853
876 854 This file can then be transferred using conventional means and
877 855 applied to another repository with the unbundle command. This is
878 856 useful when native push and pull are not available or when
879 857 exporting an entire repository is undesirable. The standard file
880 858 extension is ".hg".
881 859
882 860 Unlike import/export, this exactly preserves all changeset
883 861 contents including permissions, rename data, and revision history.
884 862 """
885 863 dest = ui.expandpath(dest or 'default-push', dest or 'default')
886 864 other = hg.repository(ui, dest)
887 865 o = repo.findoutgoing(other, force=opts['force'])
888 866 cg = repo.changegroup(o, 'bundle')
889 867 write_bundle(cg, fname)
890 868
891 869 def cat(ui, repo, file1, *pats, **opts):
892 870 """output the latest or given revisions of files
893 871
894 872 Print the specified files as they were at the given revision.
895 873 If no revision is given then the tip is used.
896 874
897 875 Output may be to a file, in which case the name of the file is
898 876 given using a format string. The formatting rules are the same as
899 877 for the export command, with the following additions:
900 878
901 879 %s basename of file being printed
902 880 %d dirname of file being printed, or '.' if in repo root
903 881 %p root-relative path name of file being printed
904 882 """
905 883 ctx = repo.changectx(opts['rev'] or "-1")
906 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
884 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
885 ctx.node()):
907 886 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
908 887 fp.write(ctx.filectx(abs).data())
909 888
910 889 def clone(ui, source, dest=None, **opts):
911 890 """make a copy of an existing repository
912 891
913 892 Create a copy of an existing repository in a new directory.
914 893
915 894 If no destination directory name is specified, it defaults to the
916 895 basename of the source.
917 896
918 897 The location of the source is added to the new repository's
919 898 .hg/hgrc file, as the default to be used for future pulls.
920 899
921 900 For efficiency, hardlinks are used for cloning whenever the source
922 901 and destination are on the same filesystem (note this applies only
923 902 to the repository data, not to the checked out files). Some
924 903 filesystems, such as AFS, implement hardlinking incorrectly, but
925 904 do not report errors. In these cases, use the --pull option to
926 905 avoid hardlinking.
927 906
928 907 You can safely clone repositories and checked out files using full
929 908 hardlinks with
930 909
931 910 $ cp -al REPO REPOCLONE
932 911
933 912 which is the fastest way to clone. However, the operation is not
934 913 atomic (making sure REPO is not modified during the operation is
935 914 up to you) and you have to make sure your editor breaks hardlinks
936 915 (Emacs and most Linux Kernel tools do so).
937 916
938 917 If you use the -r option to clone up to a specific revision, no
939 918 subsequent revisions will be present in the cloned repository.
940 919 This option implies --pull, even on local repositories.
941 920
942 921 See pull for valid source format details.
943 922
944 923 It is possible to specify an ssh:// URL as the destination, but no
945 924 .hg/hgrc will be created on the remote side. Look at the help text
946 925 for the pull command for important details about ssh:// URLs.
947 926 """
948 927 setremoteconfig(ui, opts)
949 928 hg.clone(ui, ui.expandpath(source), dest,
950 929 pull=opts['pull'],
951 930 stream=opts['uncompressed'],
952 931 rev=opts['rev'],
953 932 update=not opts['noupdate'])
954 933
955 934 def commit(ui, repo, *pats, **opts):
956 935 """commit the specified files or all outstanding changes
957 936
958 937 Commit changes to the given files into the repository.
959 938
960 939 If a list of files is omitted, all changes reported by "hg status"
961 940 will be committed.
962 941
963 942 If no commit message is specified, the editor configured in your hgrc
964 943 or in the EDITOR environment variable is started to enter a message.
965 944 """
966 945 message = logmessage(opts)
967 946
968 947 if opts['addremove']:
969 948 addremove_lock(ui, repo, pats, opts)
970 fns, match, anypats = matchpats(repo, pats, opts)
949 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
971 950 if pats:
972 951 modified, added, removed = repo.status(files=fns, match=match)[:3]
973 952 files = modified + added + removed
974 953 else:
975 954 files = []
976 955 try:
977 956 repo.commit(files, message, opts['user'], opts['date'], match,
978 957 force_editor=opts.get('force_editor'))
979 958 except ValueError, inst:
980 959 raise util.Abort(str(inst))
981 960
982 961 def docopy(ui, repo, pats, opts, wlock):
983 962 # called with the repo lock held
984 963 cwd = repo.getcwd()
985 964 errors = 0
986 965 copied = []
987 966 targets = {}
988 967
989 968 def okaytocopy(abs, rel, exact):
990 969 reasons = {'?': _('is not managed'),
991 970 'a': _('has been marked for add'),
992 971 'r': _('has been marked for remove')}
993 972 state = repo.dirstate.state(abs)
994 973 reason = reasons.get(state)
995 974 if reason:
996 975 if state == 'a':
997 976 origsrc = repo.dirstate.copied(abs)
998 977 if origsrc is not None:
999 978 return origsrc
1000 979 if exact:
1001 980 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
1002 981 else:
1003 982 return abs
1004 983
1005 984 def copy(origsrc, abssrc, relsrc, target, exact):
1006 985 abstarget = util.canonpath(repo.root, cwd, target)
1007 986 reltarget = util.pathto(cwd, abstarget)
1008 987 prevsrc = targets.get(abstarget)
1009 988 if prevsrc is not None:
1010 989 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1011 990 (reltarget, abssrc, prevsrc))
1012 991 return
1013 992 if (not opts['after'] and os.path.exists(reltarget) or
1014 993 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
1015 994 if not opts['force']:
1016 995 ui.warn(_('%s: not overwriting - file exists\n') %
1017 996 reltarget)
1018 997 return
1019 998 if not opts['after'] and not opts.get('dry_run'):
1020 999 os.unlink(reltarget)
1021 1000 if opts['after']:
1022 1001 if not os.path.exists(reltarget):
1023 1002 return
1024 1003 else:
1025 1004 targetdir = os.path.dirname(reltarget) or '.'
1026 1005 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1027 1006 os.makedirs(targetdir)
1028 1007 try:
1029 1008 restore = repo.dirstate.state(abstarget) == 'r'
1030 1009 if restore and not opts.get('dry_run'):
1031 1010 repo.undelete([abstarget], wlock)
1032 1011 try:
1033 1012 if not opts.get('dry_run'):
1034 1013 shutil.copyfile(relsrc, reltarget)
1035 1014 shutil.copymode(relsrc, reltarget)
1036 1015 restore = False
1037 1016 finally:
1038 1017 if restore:
1039 1018 repo.remove([abstarget], wlock)
1040 1019 except shutil.Error, inst:
1041 1020 raise util.Abort(str(inst))
1042 1021 except IOError, inst:
1043 1022 if inst.errno == errno.ENOENT:
1044 1023 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1045 1024 else:
1046 1025 ui.warn(_('%s: cannot copy - %s\n') %
1047 1026 (relsrc, inst.strerror))
1048 1027 errors += 1
1049 1028 return
1050 1029 if ui.verbose or not exact:
1051 1030 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1052 1031 targets[abstarget] = abssrc
1053 1032 if abstarget != origsrc and not opts.get('dry_run'):
1054 1033 repo.copy(origsrc, abstarget, wlock)
1055 1034 copied.append((abssrc, relsrc, exact))
1056 1035
1057 1036 def targetpathfn(pat, dest, srcs):
1058 1037 if os.path.isdir(pat):
1059 1038 abspfx = util.canonpath(repo.root, cwd, pat)
1060 1039 if destdirexists:
1061 1040 striplen = len(os.path.split(abspfx)[0])
1062 1041 else:
1063 1042 striplen = len(abspfx)
1064 1043 if striplen:
1065 1044 striplen += len(os.sep)
1066 1045 res = lambda p: os.path.join(dest, p[striplen:])
1067 1046 elif destdirexists:
1068 1047 res = lambda p: os.path.join(dest, os.path.basename(p))
1069 1048 else:
1070 1049 res = lambda p: dest
1071 1050 return res
1072 1051
1073 1052 def targetpathafterfn(pat, dest, srcs):
1074 1053 if util.patkind(pat, None)[0]:
1075 1054 # a mercurial pattern
1076 1055 res = lambda p: os.path.join(dest, os.path.basename(p))
1077 1056 else:
1078 1057 abspfx = util.canonpath(repo.root, cwd, pat)
1079 1058 if len(abspfx) < len(srcs[0][0]):
1080 1059 # A directory. Either the target path contains the last
1081 1060 # component of the source path or it does not.
1082 1061 def evalpath(striplen):
1083 1062 score = 0
1084 1063 for s in srcs:
1085 1064 t = os.path.join(dest, s[0][striplen:])
1086 1065 if os.path.exists(t):
1087 1066 score += 1
1088 1067 return score
1089 1068
1090 1069 striplen = len(abspfx)
1091 1070 if striplen:
1092 1071 striplen += len(os.sep)
1093 1072 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1094 1073 score = evalpath(striplen)
1095 1074 striplen1 = len(os.path.split(abspfx)[0])
1096 1075 if striplen1:
1097 1076 striplen1 += len(os.sep)
1098 1077 if evalpath(striplen1) > score:
1099 1078 striplen = striplen1
1100 1079 res = lambda p: os.path.join(dest, p[striplen:])
1101 1080 else:
1102 1081 # a file
1103 1082 if destdirexists:
1104 1083 res = lambda p: os.path.join(dest, os.path.basename(p))
1105 1084 else:
1106 1085 res = lambda p: dest
1107 1086 return res
1108 1087
1109 1088
1110 1089 pats = list(pats)
1111 1090 if not pats:
1112 1091 raise util.Abort(_('no source or destination specified'))
1113 1092 if len(pats) == 1:
1114 1093 raise util.Abort(_('no destination specified'))
1115 1094 dest = pats.pop()
1116 1095 destdirexists = os.path.isdir(dest)
1117 1096 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1118 1097 raise util.Abort(_('with multiple sources, destination must be an '
1119 1098 'existing directory'))
1120 1099 if opts['after']:
1121 1100 tfn = targetpathafterfn
1122 1101 else:
1123 1102 tfn = targetpathfn
1124 1103 copylist = []
1125 1104 for pat in pats:
1126 1105 srcs = []
1127 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1106 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1128 1107 origsrc = okaytocopy(abssrc, relsrc, exact)
1129 1108 if origsrc:
1130 1109 srcs.append((origsrc, abssrc, relsrc, exact))
1131 1110 if not srcs:
1132 1111 continue
1133 1112 copylist.append((tfn(pat, dest, srcs), srcs))
1134 1113 if not copylist:
1135 1114 raise util.Abort(_('no files to copy'))
1136 1115
1137 1116 for targetpath, srcs in copylist:
1138 1117 for origsrc, abssrc, relsrc, exact in srcs:
1139 1118 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1140 1119
1141 1120 if errors:
1142 1121 ui.warn(_('(consider using --after)\n'))
1143 1122 return errors, copied
1144 1123
1145 1124 def copy(ui, repo, *pats, **opts):
1146 1125 """mark files as copied for the next commit
1147 1126
1148 1127 Mark dest as having copies of source files. If dest is a
1149 1128 directory, copies are put in that directory. If dest is a file,
1150 1129 there can only be one source.
1151 1130
1152 1131 By default, this command copies the contents of files as they
1153 1132 stand in the working directory. If invoked with --after, the
1154 1133 operation is recorded, but no copying is performed.
1155 1134
1156 1135 This command takes effect in the next commit.
1157 1136
1158 1137 NOTE: This command should be treated as experimental. While it
1159 1138 should properly record copied files, this information is not yet
1160 1139 fully used by merge, nor fully reported by log.
1161 1140 """
1162 1141 wlock = repo.wlock(0)
1163 1142 errs, copied = docopy(ui, repo, pats, opts, wlock)
1164 1143 return errs
1165 1144
1166 1145 def debugancestor(ui, index, rev1, rev2):
1167 1146 """find the ancestor revision of two revisions in a given index"""
1168 1147 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1169 1148 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1170 1149 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1171 1150
1172 1151 def debugcomplete(ui, cmd='', **opts):
1173 1152 """returns the completion list associated with the given command"""
1174 1153
1175 1154 if opts['options']:
1176 1155 options = []
1177 1156 otables = [globalopts]
1178 1157 if cmd:
1179 1158 aliases, entry = findcmd(cmd)
1180 1159 otables.append(entry[1])
1181 1160 for t in otables:
1182 1161 for o in t:
1183 1162 if o[0]:
1184 1163 options.append('-%s' % o[0])
1185 1164 options.append('--%s' % o[1])
1186 1165 ui.write("%s\n" % "\n".join(options))
1187 1166 return
1188 1167
1189 1168 clist = findpossible(cmd).keys()
1190 1169 clist.sort()
1191 1170 ui.write("%s\n" % "\n".join(clist))
1192 1171
1193 1172 def debugrebuildstate(ui, repo, rev=None):
1194 1173 """rebuild the dirstate as it would look like for the given revision"""
1195 1174 if not rev:
1196 1175 rev = repo.changelog.tip()
1197 1176 else:
1198 1177 rev = repo.lookup(rev)
1199 1178 change = repo.changelog.read(rev)
1200 1179 n = change[0]
1201 1180 files = repo.manifest.read(n)
1202 1181 wlock = repo.wlock()
1203 1182 repo.dirstate.rebuild(rev, files)
1204 1183
1205 1184 def debugcheckstate(ui, repo):
1206 1185 """validate the correctness of the current dirstate"""
1207 1186 parent1, parent2 = repo.dirstate.parents()
1208 1187 repo.dirstate.read()
1209 1188 dc = repo.dirstate.map
1210 1189 keys = dc.keys()
1211 1190 keys.sort()
1212 1191 m1n = repo.changelog.read(parent1)[0]
1213 1192 m2n = repo.changelog.read(parent2)[0]
1214 1193 m1 = repo.manifest.read(m1n)
1215 1194 m2 = repo.manifest.read(m2n)
1216 1195 errors = 0
1217 1196 for f in dc:
1218 1197 state = repo.dirstate.state(f)
1219 1198 if state in "nr" and f not in m1:
1220 1199 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1221 1200 errors += 1
1222 1201 if state in "a" and f in m1:
1223 1202 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1224 1203 errors += 1
1225 1204 if state in "m" and f not in m1 and f not in m2:
1226 1205 ui.warn(_("%s in state %s, but not in either manifest\n") %
1227 1206 (f, state))
1228 1207 errors += 1
1229 1208 for f in m1:
1230 1209 state = repo.dirstate.state(f)
1231 1210 if state not in "nrm":
1232 1211 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1233 1212 errors += 1
1234 1213 if errors:
1235 1214 error = _(".hg/dirstate inconsistent with current parent's manifest")
1236 1215 raise util.Abort(error)
1237 1216
1238 1217 def debugconfig(ui, repo, *values):
1239 1218 """show combined config settings from all hgrc files
1240 1219
1241 1220 With no args, print names and values of all config items.
1242 1221
1243 1222 With one arg of the form section.name, print just the value of
1244 1223 that config item.
1245 1224
1246 1225 With multiple args, print names and values of all config items
1247 1226 with matching section names."""
1248 1227
1249 1228 if values:
1250 1229 if len([v for v in values if '.' in v]) > 1:
1251 1230 raise util.Abort(_('only one config item permitted'))
1252 1231 for section, name, value in ui.walkconfig():
1253 1232 sectname = section + '.' + name
1254 1233 if values:
1255 1234 for v in values:
1256 1235 if v == section:
1257 1236 ui.write('%s=%s\n' % (sectname, value))
1258 1237 elif v == sectname:
1259 1238 ui.write(value, '\n')
1260 1239 else:
1261 1240 ui.write('%s=%s\n' % (sectname, value))
1262 1241
1263 1242 def debugsetparents(ui, repo, rev1, rev2=None):
1264 1243 """manually set the parents of the current working directory
1265 1244
1266 1245 This is useful for writing repository conversion tools, but should
1267 1246 be used with care.
1268 1247 """
1269 1248
1270 1249 if not rev2:
1271 1250 rev2 = hex(nullid)
1272 1251
1273 1252 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1274 1253
1275 1254 def debugstate(ui, repo):
1276 1255 """show the contents of the current dirstate"""
1277 1256 repo.dirstate.read()
1278 1257 dc = repo.dirstate.map
1279 1258 keys = dc.keys()
1280 1259 keys.sort()
1281 1260 for file_ in keys:
1282 1261 ui.write("%c %3o %10d %s %s\n"
1283 1262 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1284 1263 time.strftime("%x %X",
1285 1264 time.localtime(dc[file_][3])), file_))
1286 1265 for f in repo.dirstate.copies:
1287 1266 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1288 1267
1289 1268 def debugdata(ui, file_, rev):
1290 1269 """dump the contents of an data file revision"""
1291 1270 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1292 1271 file_[:-2] + ".i", file_, 0)
1293 1272 try:
1294 1273 ui.write(r.revision(r.lookup(rev)))
1295 1274 except KeyError:
1296 1275 raise util.Abort(_('invalid revision identifier %s'), rev)
1297 1276
1298 1277 def debugindex(ui, file_):
1299 1278 """dump the contents of an index file"""
1300 1279 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1301 1280 ui.write(" rev offset length base linkrev" +
1302 1281 " nodeid p1 p2\n")
1303 1282 for i in range(r.count()):
1304 1283 node = r.node(i)
1305 1284 pp = r.parents(node)
1306 1285 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1307 1286 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1308 1287 short(node), short(pp[0]), short(pp[1])))
1309 1288
1310 1289 def debugindexdot(ui, file_):
1311 1290 """dump an index DAG as a .dot file"""
1312 1291 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1313 1292 ui.write("digraph G {\n")
1314 1293 for i in range(r.count()):
1315 1294 node = r.node(i)
1316 1295 pp = r.parents(node)
1317 1296 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1318 1297 if pp[1] != nullid:
1319 1298 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1320 1299 ui.write("}\n")
1321 1300
1322 1301 def debugrename(ui, repo, file, rev=None):
1323 1302 """dump rename information"""
1324 1303 r = repo.file(relpath(repo, [file])[0])
1325 1304 if rev:
1326 1305 try:
1327 1306 # assume all revision numbers are for changesets
1328 1307 n = repo.lookup(rev)
1329 1308 change = repo.changelog.read(n)
1330 1309 m = repo.manifest.read(change[0])
1331 1310 n = m[relpath(repo, [file])[0]]
1332 1311 except (hg.RepoError, KeyError):
1333 1312 n = r.lookup(rev)
1334 1313 else:
1335 1314 n = r.tip()
1336 1315 m = r.renamed(n)
1337 1316 if m:
1338 1317 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1339 1318 else:
1340 1319 ui.write(_("not renamed\n"))
1341 1320
1342 1321 def debugwalk(ui, repo, *pats, **opts):
1343 1322 """show how files match on given patterns"""
1344 items = list(walk(repo, pats, opts))
1323 items = list(cmdutil.walk(repo, pats, opts))
1345 1324 if not items:
1346 1325 return
1347 1326 fmt = '%%s %%-%ds %%-%ds %%s' % (
1348 1327 max([len(abs) for (src, abs, rel, exact) in items]),
1349 1328 max([len(rel) for (src, abs, rel, exact) in items]))
1350 1329 for src, abs, rel, exact in items:
1351 1330 line = fmt % (src, abs, rel, exact and 'exact' or '')
1352 1331 ui.write("%s\n" % line.rstrip())
1353 1332
1354 1333 def diff(ui, repo, *pats, **opts):
1355 1334 """diff repository (or selected files)
1356 1335
1357 1336 Show differences between revisions for the specified files.
1358 1337
1359 1338 Differences between files are shown using the unified diff format.
1360 1339
1361 1340 When two revision arguments are given, then changes are shown
1362 1341 between those revisions. If only one revision is specified then
1363 1342 that revision is compared to the working directory, and, when no
1364 1343 revisions are specified, the working directory files are compared
1365 1344 to its parent.
1366 1345
1367 1346 Without the -a option, diff will avoid generating diffs of files
1368 1347 it detects as binary. With -a, diff will generate a diff anyway,
1369 1348 probably with undesirable results.
1370 1349 """
1371 1350 node1, node2 = revpair(ui, repo, opts['rev'])
1372 1351
1373 fns, matchfn, anypats = matchpats(repo, pats, opts)
1352 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1374 1353
1375 1354 patch.diff(repo, node1, node2, fns, match=matchfn,
1376 1355 opts=ui.diffopts(opts))
1377 1356
1378 1357 def export(ui, repo, *changesets, **opts):
1379 1358 """dump the header and diffs for one or more changesets
1380 1359
1381 1360 Print the changeset header and diffs for one or more revisions.
1382 1361
1383 1362 The information shown in the changeset header is: author,
1384 1363 changeset hash, parent and commit comment.
1385 1364
1386 1365 Output may be to a file, in which case the name of the file is
1387 1366 given using a format string. The formatting rules are as follows:
1388 1367
1389 1368 %% literal "%" character
1390 1369 %H changeset hash (40 bytes of hexadecimal)
1391 1370 %N number of patches being generated
1392 1371 %R changeset revision number
1393 1372 %b basename of the exporting repository
1394 1373 %h short-form changeset hash (12 bytes of hexadecimal)
1395 1374 %n zero-padded sequence number, starting at 1
1396 1375 %r zero-padded changeset revision number
1397 1376
1398 1377 Without the -a option, export will avoid generating diffs of files
1399 1378 it detects as binary. With -a, export will generate a diff anyway,
1400 1379 probably with undesirable results.
1401 1380
1402 1381 With the --switch-parent option, the diff will be against the second
1403 1382 parent. It can be useful to review a merge.
1404 1383 """
1405 1384 if not changesets:
1406 1385 raise util.Abort(_("export requires at least one changeset"))
1407 1386 revs = list(revrange(ui, repo, changesets))
1408 1387 if len(revs) > 1:
1409 1388 ui.note(_('exporting patches:\n'))
1410 1389 else:
1411 1390 ui.note(_('exporting patch:\n'))
1412 1391 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1413 1392 switch_parent=opts['switch_parent'], opts=ui.diffopts(opts))
1414 1393
1415 1394 def forget(ui, repo, *pats, **opts):
1416 1395 """don't add the specified files on the next commit (DEPRECATED)
1417 1396
1418 1397 (DEPRECATED)
1419 1398 Undo an 'hg add' scheduled for the next commit.
1420 1399
1421 1400 This command is now deprecated and will be removed in a future
1422 1401 release. Please use revert instead.
1423 1402 """
1424 1403 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1425 1404 forget = []
1426 for src, abs, rel, exact in walk(repo, pats, opts):
1405 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1427 1406 if repo.dirstate.state(abs) == 'a':
1428 1407 forget.append(abs)
1429 1408 if ui.verbose or not exact:
1430 1409 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1431 1410 repo.forget(forget)
1432 1411
1433 1412 def grep(ui, repo, pattern, *pats, **opts):
1434 1413 """search for a pattern in specified files and revisions
1435 1414
1436 1415 Search revisions of files for a regular expression.
1437 1416
1438 1417 This command behaves differently than Unix grep. It only accepts
1439 1418 Python/Perl regexps. It searches repository history, not the
1440 1419 working directory. It always prints the revision number in which
1441 1420 a match appears.
1442 1421
1443 1422 By default, grep only prints output for the first revision of a
1444 1423 file in which it finds a match. To get it to print every revision
1445 1424 that contains a change in match status ("-" for a match that
1446 1425 becomes a non-match, or "+" for a non-match that becomes a match),
1447 1426 use the --all flag.
1448 1427 """
1449 1428 reflags = 0
1450 1429 if opts['ignore_case']:
1451 1430 reflags |= re.I
1452 1431 regexp = re.compile(pattern, reflags)
1453 1432 sep, eol = ':', '\n'
1454 1433 if opts['print0']:
1455 1434 sep = eol = '\0'
1456 1435
1457 1436 fcache = {}
1458 1437 def getfile(fn):
1459 1438 if fn not in fcache:
1460 1439 fcache[fn] = repo.file(fn)
1461 1440 return fcache[fn]
1462 1441
1463 1442 def matchlines(body):
1464 1443 begin = 0
1465 1444 linenum = 0
1466 1445 while True:
1467 1446 match = regexp.search(body, begin)
1468 1447 if not match:
1469 1448 break
1470 1449 mstart, mend = match.span()
1471 1450 linenum += body.count('\n', begin, mstart) + 1
1472 1451 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1473 1452 lend = body.find('\n', mend)
1474 1453 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1475 1454 begin = lend + 1
1476 1455
1477 1456 class linestate(object):
1478 1457 def __init__(self, line, linenum, colstart, colend):
1479 1458 self.line = line
1480 1459 self.linenum = linenum
1481 1460 self.colstart = colstart
1482 1461 self.colend = colend
1483 1462
1484 1463 def __eq__(self, other):
1485 1464 return self.line == other.line
1486 1465
1487 1466 matches = {}
1488 1467 copies = {}
1489 1468 def grepbody(fn, rev, body):
1490 1469 matches[rev].setdefault(fn, [])
1491 1470 m = matches[rev][fn]
1492 1471 for lnum, cstart, cend, line in matchlines(body):
1493 1472 s = linestate(line, lnum, cstart, cend)
1494 1473 m.append(s)
1495 1474
1496 1475 def difflinestates(a, b):
1497 1476 sm = difflib.SequenceMatcher(None, a, b)
1498 1477 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1499 1478 if tag == 'insert':
1500 1479 for i in range(blo, bhi):
1501 1480 yield ('+', b[i])
1502 1481 elif tag == 'delete':
1503 1482 for i in range(alo, ahi):
1504 1483 yield ('-', a[i])
1505 1484 elif tag == 'replace':
1506 1485 for i in range(alo, ahi):
1507 1486 yield ('-', a[i])
1508 1487 for i in range(blo, bhi):
1509 1488 yield ('+', b[i])
1510 1489
1511 1490 prev = {}
1512 1491 ucache = {}
1513 1492 def display(fn, rev, states, prevstates):
1514 1493 counts = {'-': 0, '+': 0}
1515 1494 filerevmatches = {}
1516 1495 if incrementing or not opts['all']:
1517 1496 a, b = prevstates, states
1518 1497 else:
1519 1498 a, b = states, prevstates
1520 1499 for change, l in difflinestates(a, b):
1521 1500 if incrementing or not opts['all']:
1522 1501 r = rev
1523 1502 else:
1524 1503 r = prev[fn]
1525 1504 cols = [fn, str(r)]
1526 1505 if opts['line_number']:
1527 1506 cols.append(str(l.linenum))
1528 1507 if opts['all']:
1529 1508 cols.append(change)
1530 1509 if opts['user']:
1531 1510 cols.append(trimuser(ui, getchange(r)[1], rev,
1532 1511 ucache))
1533 1512 if opts['files_with_matches']:
1534 1513 c = (fn, rev)
1535 1514 if c in filerevmatches:
1536 1515 continue
1537 1516 filerevmatches[c] = 1
1538 1517 else:
1539 1518 cols.append(l.line)
1540 1519 ui.write(sep.join(cols), eol)
1541 1520 counts[change] += 1
1542 1521 return counts['+'], counts['-']
1543 1522
1544 1523 fstate = {}
1545 1524 skip = {}
1546 1525 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1547 1526 count = 0
1548 1527 incrementing = False
1549 1528 follow = opts.get('follow')
1550 1529 for st, rev, fns in changeiter:
1551 1530 if st == 'window':
1552 1531 incrementing = rev
1553 1532 matches.clear()
1554 1533 copies.clear()
1555 1534 elif st == 'add':
1556 1535 change = repo.changelog.read(repo.lookup(str(rev)))
1557 1536 mf = repo.manifest.read(change[0])
1558 1537 matches[rev] = {}
1559 1538 for fn in fns:
1560 1539 if fn in skip:
1561 1540 continue
1562 1541 fstate.setdefault(fn, {})
1563 1542 copies.setdefault(rev, {})
1564 1543 try:
1565 1544 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1566 1545 if follow:
1567 1546 copied = getfile(fn).renamed(mf[fn])
1568 1547 if copied:
1569 1548 copies[rev][fn] = copied[0]
1570 1549 except KeyError:
1571 1550 pass
1572 1551 elif st == 'iter':
1573 1552 states = matches[rev].items()
1574 1553 states.sort()
1575 1554 for fn, m in states:
1576 1555 copy = copies[rev].get(fn)
1577 1556 if fn in skip:
1578 1557 if copy:
1579 1558 skip[copy] = True
1580 1559 continue
1581 1560 if incrementing or not opts['all'] or fstate[fn]:
1582 1561 pos, neg = display(fn, rev, m, fstate[fn])
1583 1562 count += pos + neg
1584 1563 if pos and not opts['all']:
1585 1564 skip[fn] = True
1586 1565 if copy:
1587 1566 skip[copy] = True
1588 1567 fstate[fn] = m
1589 1568 if copy:
1590 1569 fstate[copy] = m
1591 1570 prev[fn] = rev
1592 1571
1593 1572 if not incrementing:
1594 1573 fstate = fstate.items()
1595 1574 fstate.sort()
1596 1575 for fn, state in fstate:
1597 1576 if fn in skip:
1598 1577 continue
1599 1578 if fn not in copies[prev[fn]]:
1600 1579 display(fn, rev, {}, state)
1601 1580 return (count == 0 and 1) or 0
1602 1581
1603 1582 def heads(ui, repo, **opts):
1604 1583 """show current repository heads
1605 1584
1606 1585 Show all repository head changesets.
1607 1586
1608 1587 Repository "heads" are changesets that don't have children
1609 1588 changesets. They are where development generally takes place and
1610 1589 are the usual targets for update and merge operations.
1611 1590 """
1612 1591 if opts['rev']:
1613 1592 heads = repo.heads(repo.lookup(opts['rev']))
1614 1593 else:
1615 1594 heads = repo.heads()
1616 1595 br = None
1617 1596 if opts['branches']:
1618 1597 br = repo.branchlookup(heads)
1619 1598 displayer = show_changeset(ui, repo, opts)
1620 1599 for n in heads:
1621 1600 displayer.show(changenode=n, brinfo=br)
1622 1601
1623 1602 def identify(ui, repo):
1624 1603 """print information about the working copy
1625 1604
1626 1605 Print a short summary of the current state of the repo.
1627 1606
1628 1607 This summary identifies the repository state using one or two parent
1629 1608 hash identifiers, followed by a "+" if there are uncommitted changes
1630 1609 in the working directory, followed by a list of tags for this revision.
1631 1610 """
1632 1611 parents = [p for p in repo.dirstate.parents() if p != nullid]
1633 1612 if not parents:
1634 1613 ui.write(_("unknown\n"))
1635 1614 return
1636 1615
1637 1616 hexfunc = ui.verbose and hex or short
1638 1617 modified, added, removed, deleted = repo.status()[:4]
1639 1618 output = ["%s%s" %
1640 1619 ('+'.join([hexfunc(parent) for parent in parents]),
1641 1620 (modified or added or removed or deleted) and "+" or "")]
1642 1621
1643 1622 if not ui.quiet:
1644 1623 # multiple tags for a single parent separated by '/'
1645 1624 parenttags = ['/'.join(tags)
1646 1625 for tags in map(repo.nodetags, parents) if tags]
1647 1626 # tags for multiple parents separated by ' + '
1648 1627 if parenttags:
1649 1628 output.append(' + '.join(parenttags))
1650 1629
1651 1630 ui.write("%s\n" % ' '.join(output))
1652 1631
1653 1632 def import_(ui, repo, patch1, *patches, **opts):
1654 1633 """import an ordered set of patches
1655 1634
1656 1635 Import a list of patches and commit them individually.
1657 1636
1658 1637 If there are outstanding changes in the working directory, import
1659 1638 will abort unless given the -f flag.
1660 1639
1661 1640 You can import a patch straight from a mail message. Even patches
1662 1641 as attachments work (body part must be type text/plain or
1663 1642 text/x-patch to be used). From and Subject headers of email
1664 1643 message are used as default committer and commit message. All
1665 1644 text/plain body parts before first diff are added to commit
1666 1645 message.
1667 1646
1668 1647 If imported patch was generated by hg export, user and description
1669 1648 from patch override values from message headers and body. Values
1670 1649 given on command line with -m and -u override these.
1671 1650
1672 1651 To read a patch from standard input, use patch name "-".
1673 1652 """
1674 1653 patches = (patch1,) + patches
1675 1654
1676 1655 if not opts['force']:
1677 1656 bail_if_changed(repo)
1678 1657
1679 1658 d = opts["base"]
1680 1659 strip = opts["strip"]
1681 1660
1682 1661 wlock = repo.wlock()
1683 1662 lock = repo.lock()
1684 1663
1685 1664 for p in patches:
1686 1665 pf = os.path.join(d, p)
1687 1666
1688 1667 if pf == '-':
1689 1668 ui.status(_("applying patch from stdin\n"))
1690 1669 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1691 1670 else:
1692 1671 ui.status(_("applying %s\n") % p)
1693 1672 tmpname, message, user, date = patch.extract(ui, file(pf))
1694 1673
1695 1674 if tmpname is None:
1696 1675 raise util.Abort(_('no diffs found'))
1697 1676
1698 1677 try:
1699 1678 if opts['message']:
1700 1679 # pickup the cmdline msg
1701 1680 message = opts['message']
1702 1681 elif message:
1703 1682 # pickup the patch msg
1704 1683 message = message.strip()
1705 1684 else:
1706 1685 # launch the editor
1707 1686 message = None
1708 1687 ui.debug(_('message:\n%s\n') % message)
1709 1688
1710 1689 files = patch.patch(strip, tmpname, ui, cwd=repo.root)
1711 1690 removes = []
1712 1691 if len(files) > 0:
1713 1692 cfiles = files.keys()
1714 1693 copies = []
1715 1694 copts = {'after': False, 'force': False}
1716 1695 cwd = repo.getcwd()
1717 1696 if cwd:
1718 1697 cfiles = [util.pathto(cwd, f) for f in files.keys()]
1719 1698 for f in files:
1720 1699 ctype, gp = files[f]
1721 1700 if ctype == 'RENAME':
1722 1701 copies.append((gp.oldpath, gp.path, gp.copymod))
1723 1702 removes.append(gp.oldpath)
1724 1703 elif ctype == 'COPY':
1725 1704 copies.append((gp.oldpath, gp.path, gp.copymod))
1726 1705 elif ctype == 'DELETE':
1727 1706 removes.append(gp.path)
1728 1707 for src, dst, after in copies:
1729 1708 absdst = os.path.join(repo.root, dst)
1730 1709 if not after and os.path.exists(absdst):
1731 1710 raise util.Abort(_('patch creates existing file %s') % dst)
1732 1711 if cwd:
1733 1712 src, dst = [util.pathto(cwd, f) for f in (src, dst)]
1734 1713 copts['after'] = after
1735 1714 errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock)
1736 1715 if errs:
1737 1716 raise util.Abort(errs)
1738 1717 if removes:
1739 1718 repo.remove(removes, True, wlock=wlock)
1740 1719 for f in files:
1741 1720 ctype, gp = files[f]
1742 1721 if gp and gp.mode:
1743 1722 x = gp.mode & 0100 != 0
1744 1723 dst = os.path.join(repo.root, gp.path)
1745 1724 util.set_exec(dst, x)
1746 1725 addremove_lock(ui, repo, cfiles, {}, wlock=wlock)
1747 1726 files = files.keys()
1748 1727 files.extend([r for r in removes if r not in files])
1749 1728 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1750 1729 finally:
1751 1730 os.unlink(tmpname)
1752 1731
1753 1732 def incoming(ui, repo, source="default", **opts):
1754 1733 """show new changesets found in source
1755 1734
1756 1735 Show new changesets found in the specified path/URL or the default
1757 1736 pull location. These are the changesets that would be pulled if a pull
1758 1737 was requested.
1759 1738
1760 1739 For remote repository, using --bundle avoids downloading the changesets
1761 1740 twice if the incoming is followed by a pull.
1762 1741
1763 1742 See pull for valid source format details.
1764 1743 """
1765 1744 source = ui.expandpath(source)
1766 1745 setremoteconfig(ui, opts)
1767 1746
1768 1747 other = hg.repository(ui, source)
1769 1748 incoming = repo.findincoming(other, force=opts["force"])
1770 1749 if not incoming:
1771 1750 ui.status(_("no changes found\n"))
1772 1751 return
1773 1752
1774 1753 cleanup = None
1775 1754 try:
1776 1755 fname = opts["bundle"]
1777 1756 if fname or not other.local():
1778 1757 # create a bundle (uncompressed if other repo is not local)
1779 1758 cg = other.changegroup(incoming, "incoming")
1780 1759 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1781 1760 # keep written bundle?
1782 1761 if opts["bundle"]:
1783 1762 cleanup = None
1784 1763 if not other.local():
1785 1764 # use the created uncompressed bundlerepo
1786 1765 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1787 1766
1788 1767 revs = None
1789 1768 if opts['rev']:
1790 1769 revs = [other.lookup(rev) for rev in opts['rev']]
1791 1770 o = other.changelog.nodesbetween(incoming, revs)[0]
1792 1771 if opts['newest_first']:
1793 1772 o.reverse()
1794 1773 displayer = show_changeset(ui, other, opts)
1795 1774 for n in o:
1796 1775 parents = [p for p in other.changelog.parents(n) if p != nullid]
1797 1776 if opts['no_merges'] and len(parents) == 2:
1798 1777 continue
1799 1778 displayer.show(changenode=n)
1800 1779 if opts['patch']:
1801 1780 prev = (parents and parents[0]) or nullid
1802 1781 patch.diff(repo, other, prev, n)
1803 1782 ui.write("\n")
1804 1783 finally:
1805 1784 if hasattr(other, 'close'):
1806 1785 other.close()
1807 1786 if cleanup:
1808 1787 os.unlink(cleanup)
1809 1788
1810 1789 def init(ui, dest=".", **opts):
1811 1790 """create a new repository in the given directory
1812 1791
1813 1792 Initialize a new repository in the given directory. If the given
1814 1793 directory does not exist, it is created.
1815 1794
1816 1795 If no directory is given, the current directory is used.
1817 1796
1818 1797 It is possible to specify an ssh:// URL as the destination.
1819 1798 Look at the help text for the pull command for important details
1820 1799 about ssh:// URLs.
1821 1800 """
1822 1801 setremoteconfig(ui, opts)
1823 1802 hg.repository(ui, dest, create=1)
1824 1803
1825 1804 def locate(ui, repo, *pats, **opts):
1826 1805 """locate files matching specific patterns
1827 1806
1828 1807 Print all files under Mercurial control whose names match the
1829 1808 given patterns.
1830 1809
1831 1810 This command searches the current directory and its
1832 1811 subdirectories. To search an entire repository, move to the root
1833 1812 of the repository.
1834 1813
1835 1814 If no patterns are given to match, this command prints all file
1836 1815 names.
1837 1816
1838 1817 If you want to feed the output of this command into the "xargs"
1839 1818 command, use the "-0" option to both this command and "xargs".
1840 1819 This will avoid the problem of "xargs" treating single filenames
1841 1820 that contain white space as multiple filenames.
1842 1821 """
1843 1822 end = opts['print0'] and '\0' or '\n'
1844 1823 rev = opts['rev']
1845 1824 if rev:
1846 1825 node = repo.lookup(rev)
1847 1826 else:
1848 1827 node = None
1849 1828
1850 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1851 head='(?:.*/|)'):
1829 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1830 head='(?:.*/|)'):
1852 1831 if not node and repo.dirstate.state(abs) == '?':
1853 1832 continue
1854 1833 if opts['fullpath']:
1855 1834 ui.write(os.path.join(repo.root, abs), end)
1856 1835 else:
1857 1836 ui.write(((pats and rel) or abs), end)
1858 1837
1859 1838 def log(ui, repo, *pats, **opts):
1860 1839 """show revision history of entire repository or files
1861 1840
1862 1841 Print the revision history of the specified files or the entire
1863 1842 project.
1864 1843
1865 1844 File history is shown without following rename or copy history of
1866 1845 files. Use -f/--follow with a file name to follow history across
1867 1846 renames and copies. --follow without a file name will only show
1868 1847 ancestors or descendants of the starting revision. --follow-first
1869 1848 only follows the first parent of merge revisions.
1870 1849
1871 1850 If no revision range is specified, the default is tip:0 unless
1872 1851 --follow is set, in which case the working directory parent is
1873 1852 used as the starting revision.
1874 1853
1875 1854 By default this command outputs: changeset id and hash, tags,
1876 1855 non-trivial parents, user, date and time, and a summary for each
1877 1856 commit. When the -v/--verbose switch is used, the list of changed
1878 1857 files and full commit message is shown.
1879 1858 """
1880 1859 class dui(object):
1881 1860 # Implement and delegate some ui protocol. Save hunks of
1882 1861 # output for later display in the desired order.
1883 1862 def __init__(self, ui):
1884 1863 self.ui = ui
1885 1864 self.hunk = {}
1886 1865 self.header = {}
1887 1866 def bump(self, rev):
1888 1867 self.rev = rev
1889 1868 self.hunk[rev] = []
1890 1869 self.header[rev] = []
1891 1870 def note(self, *args):
1892 1871 if self.verbose:
1893 1872 self.write(*args)
1894 1873 def status(self, *args):
1895 1874 if not self.quiet:
1896 1875 self.write(*args)
1897 1876 def write(self, *args):
1898 1877 self.hunk[self.rev].append(args)
1899 1878 def write_header(self, *args):
1900 1879 self.header[self.rev].append(args)
1901 1880 def debug(self, *args):
1902 1881 if self.debugflag:
1903 1882 self.write(*args)
1904 1883 def __getattr__(self, key):
1905 1884 return getattr(self.ui, key)
1906 1885
1907 1886 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1908 1887
1909 1888 if opts['limit']:
1910 1889 try:
1911 1890 limit = int(opts['limit'])
1912 1891 except ValueError:
1913 1892 raise util.Abort(_('limit must be a positive integer'))
1914 1893 if limit <= 0: raise util.Abort(_('limit must be positive'))
1915 1894 else:
1916 1895 limit = sys.maxint
1917 1896 count = 0
1918 1897
1919 1898 displayer = show_changeset(ui, repo, opts)
1920 1899 for st, rev, fns in changeiter:
1921 1900 if st == 'window':
1922 1901 du = dui(ui)
1923 1902 displayer.ui = du
1924 1903 elif st == 'add':
1925 1904 du.bump(rev)
1926 1905 changenode = repo.changelog.node(rev)
1927 1906 parents = [p for p in repo.changelog.parents(changenode)
1928 1907 if p != nullid]
1929 1908 if opts['no_merges'] and len(parents) == 2:
1930 1909 continue
1931 1910 if opts['only_merges'] and len(parents) != 2:
1932 1911 continue
1933 1912
1934 1913 if opts['keyword']:
1935 1914 changes = getchange(rev)
1936 1915 miss = 0
1937 1916 for k in [kw.lower() for kw in opts['keyword']]:
1938 1917 if not (k in changes[1].lower() or
1939 1918 k in changes[4].lower() or
1940 1919 k in " ".join(changes[3][:20]).lower()):
1941 1920 miss = 1
1942 1921 break
1943 1922 if miss:
1944 1923 continue
1945 1924
1946 1925 br = None
1947 1926 if opts['branches']:
1948 1927 br = repo.branchlookup([repo.changelog.node(rev)])
1949 1928
1950 1929 displayer.show(rev, brinfo=br)
1951 1930 if opts['patch']:
1952 1931 prev = (parents and parents[0]) or nullid
1953 1932 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1954 1933 du.write("\n\n")
1955 1934 elif st == 'iter':
1956 1935 if count == limit: break
1957 1936 if du.header[rev]:
1958 1937 for args in du.header[rev]:
1959 1938 ui.write_header(*args)
1960 1939 if du.hunk[rev]:
1961 1940 count += 1
1962 1941 for args in du.hunk[rev]:
1963 1942 ui.write(*args)
1964 1943
1965 1944 def manifest(ui, repo, rev=None):
1966 1945 """output the latest or given revision of the project manifest
1967 1946
1968 1947 Print a list of version controlled files for the given revision.
1969 1948
1970 1949 The manifest is the list of files being version controlled. If no revision
1971 1950 is given then the tip is used.
1972 1951 """
1973 1952 if rev:
1974 1953 try:
1975 1954 # assume all revision numbers are for changesets
1976 1955 n = repo.lookup(rev)
1977 1956 change = repo.changelog.read(n)
1978 1957 n = change[0]
1979 1958 except hg.RepoError:
1980 1959 n = repo.manifest.lookup(rev)
1981 1960 else:
1982 1961 n = repo.manifest.tip()
1983 1962 m = repo.manifest.read(n)
1984 1963 files = m.keys()
1985 1964 files.sort()
1986 1965
1987 1966 for f in files:
1988 1967 ui.write("%40s %3s %s\n" % (hex(m[f]),
1989 1968 m.execf(f) and "755" or "644", f))
1990 1969
1991 1970 def merge(ui, repo, node=None, force=None, branch=None):
1992 1971 """Merge working directory with another revision
1993 1972
1994 1973 Merge the contents of the current working directory and the
1995 1974 requested revision. Files that changed between either parent are
1996 1975 marked as changed for the next commit and a commit must be
1997 1976 performed before any further updates are allowed.
1998 1977 """
1999 1978
2000 1979 node = _lookup(repo, node, branch)
2001 1980 return hg.merge(repo, node, force=force)
2002 1981
2003 1982 def outgoing(ui, repo, dest=None, **opts):
2004 1983 """show changesets not found in destination
2005 1984
2006 1985 Show changesets not found in the specified destination repository or
2007 1986 the default push location. These are the changesets that would be pushed
2008 1987 if a push was requested.
2009 1988
2010 1989 See pull for valid destination format details.
2011 1990 """
2012 1991 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2013 1992 setremoteconfig(ui, opts)
2014 1993 revs = None
2015 1994 if opts['rev']:
2016 1995 revs = [repo.lookup(rev) for rev in opts['rev']]
2017 1996
2018 1997 other = hg.repository(ui, dest)
2019 1998 o = repo.findoutgoing(other, force=opts['force'])
2020 1999 if not o:
2021 2000 ui.status(_("no changes found\n"))
2022 2001 return
2023 2002 o = repo.changelog.nodesbetween(o, revs)[0]
2024 2003 if opts['newest_first']:
2025 2004 o.reverse()
2026 2005 displayer = show_changeset(ui, repo, opts)
2027 2006 for n in o:
2028 2007 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2029 2008 if opts['no_merges'] and len(parents) == 2:
2030 2009 continue
2031 2010 displayer.show(changenode=n)
2032 2011 if opts['patch']:
2033 2012 prev = (parents and parents[0]) or nullid
2034 2013 patch.diff(repo, prev, n)
2035 2014 ui.write("\n")
2036 2015
2037 2016 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
2038 2017 """show the parents of the working dir or revision
2039 2018
2040 2019 Print the working directory's parent revisions.
2041 2020 """
2042 2021 # legacy
2043 2022 if file_ and not rev:
2044 2023 try:
2045 2024 rev = repo.lookup(file_)
2046 2025 file_ = None
2047 2026 except hg.RepoError:
2048 2027 pass
2049 2028 else:
2050 2029 ui.warn(_("'hg parent REV' is deprecated, "
2051 2030 "please use 'hg parents -r REV instead\n"))
2052 2031
2053 2032 if rev:
2054 2033 if file_:
2055 2034 ctx = repo.filectx(file_, changeid=rev)
2056 2035 else:
2057 2036 ctx = repo.changectx(rev)
2058 2037 p = [cp.node() for cp in ctx.parents()]
2059 2038 else:
2060 2039 p = repo.dirstate.parents()
2061 2040
2062 2041 br = None
2063 2042 if branches is not None:
2064 2043 br = repo.branchlookup(p)
2065 2044 displayer = show_changeset(ui, repo, opts)
2066 2045 for n in p:
2067 2046 if n != nullid:
2068 2047 displayer.show(changenode=n, brinfo=br)
2069 2048
2070 2049 def paths(ui, repo, search=None):
2071 2050 """show definition of symbolic path names
2072 2051
2073 2052 Show definition of symbolic path name NAME. If no name is given, show
2074 2053 definition of available names.
2075 2054
2076 2055 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2077 2056 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2078 2057 """
2079 2058 if search:
2080 2059 for name, path in ui.configitems("paths"):
2081 2060 if name == search:
2082 2061 ui.write("%s\n" % path)
2083 2062 return
2084 2063 ui.warn(_("not found!\n"))
2085 2064 return 1
2086 2065 else:
2087 2066 for name, path in ui.configitems("paths"):
2088 2067 ui.write("%s = %s\n" % (name, path))
2089 2068
2090 2069 def postincoming(ui, repo, modheads, optupdate):
2091 2070 if modheads == 0:
2092 2071 return
2093 2072 if optupdate:
2094 2073 if modheads == 1:
2095 2074 return hg.update(repo, repo.changelog.tip()) # update
2096 2075 else:
2097 2076 ui.status(_("not updating, since new heads added\n"))
2098 2077 if modheads > 1:
2099 2078 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2100 2079 else:
2101 2080 ui.status(_("(run 'hg update' to get a working copy)\n"))
2102 2081
2103 2082 def pull(ui, repo, source="default", **opts):
2104 2083 """pull changes from the specified source
2105 2084
2106 2085 Pull changes from a remote repository to a local one.
2107 2086
2108 2087 This finds all changes from the repository at the specified path
2109 2088 or URL and adds them to the local repository. By default, this
2110 2089 does not update the copy of the project in the working directory.
2111 2090
2112 2091 Valid URLs are of the form:
2113 2092
2114 2093 local/filesystem/path
2115 2094 http://[user@]host[:port]/[path]
2116 2095 https://[user@]host[:port]/[path]
2117 2096 ssh://[user@]host[:port]/[path]
2118 2097
2119 2098 Some notes about using SSH with Mercurial:
2120 2099 - SSH requires an accessible shell account on the destination machine
2121 2100 and a copy of hg in the remote path or specified with as remotecmd.
2122 2101 - path is relative to the remote user's home directory by default.
2123 2102 Use an extra slash at the start of a path to specify an absolute path:
2124 2103 ssh://example.com//tmp/repository
2125 2104 - Mercurial doesn't use its own compression via SSH; the right thing
2126 2105 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2127 2106 Host *.mylocalnetwork.example.com
2128 2107 Compression off
2129 2108 Host *
2130 2109 Compression on
2131 2110 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2132 2111 with the --ssh command line option.
2133 2112 """
2134 2113 source = ui.expandpath(source)
2135 2114 setremoteconfig(ui, opts)
2136 2115
2137 2116 other = hg.repository(ui, source)
2138 2117 ui.status(_('pulling from %s\n') % (source))
2139 2118 revs = None
2140 2119 if opts['rev'] and not other.local():
2141 2120 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2142 2121 elif opts['rev']:
2143 2122 revs = [other.lookup(rev) for rev in opts['rev']]
2144 2123 modheads = repo.pull(other, heads=revs, force=opts['force'])
2145 2124 return postincoming(ui, repo, modheads, opts['update'])
2146 2125
2147 2126 def push(ui, repo, dest=None, **opts):
2148 2127 """push changes to the specified destination
2149 2128
2150 2129 Push changes from the local repository to the given destination.
2151 2130
2152 2131 This is the symmetrical operation for pull. It helps to move
2153 2132 changes from the current repository to a different one. If the
2154 2133 destination is local this is identical to a pull in that directory
2155 2134 from the current one.
2156 2135
2157 2136 By default, push will refuse to run if it detects the result would
2158 2137 increase the number of remote heads. This generally indicates the
2159 2138 the client has forgotten to sync and merge before pushing.
2160 2139
2161 2140 Valid URLs are of the form:
2162 2141
2163 2142 local/filesystem/path
2164 2143 ssh://[user@]host[:port]/[path]
2165 2144
2166 2145 Look at the help text for the pull command for important details
2167 2146 about ssh:// URLs.
2168 2147
2169 2148 Pushing to http:// and https:// URLs is possible, too, if this
2170 2149 feature is enabled on the remote Mercurial server.
2171 2150 """
2172 2151 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2173 2152 setremoteconfig(ui, opts)
2174 2153
2175 2154 other = hg.repository(ui, dest)
2176 2155 ui.status('pushing to %s\n' % (dest))
2177 2156 revs = None
2178 2157 if opts['rev']:
2179 2158 revs = [repo.lookup(rev) for rev in opts['rev']]
2180 2159 r = repo.push(other, opts['force'], revs=revs)
2181 2160 return r == 0
2182 2161
2183 2162 def rawcommit(ui, repo, *flist, **rc):
2184 2163 """raw commit interface (DEPRECATED)
2185 2164
2186 2165 (DEPRECATED)
2187 2166 Lowlevel commit, for use in helper scripts.
2188 2167
2189 2168 This command is not intended to be used by normal users, as it is
2190 2169 primarily useful for importing from other SCMs.
2191 2170
2192 2171 This command is now deprecated and will be removed in a future
2193 2172 release, please use debugsetparents and commit instead.
2194 2173 """
2195 2174
2196 2175 ui.warn(_("(the rawcommit command is deprecated)\n"))
2197 2176
2198 2177 message = rc['message']
2199 2178 if not message and rc['logfile']:
2200 2179 try:
2201 2180 message = open(rc['logfile']).read()
2202 2181 except IOError:
2203 2182 pass
2204 2183 if not message and not rc['logfile']:
2205 2184 raise util.Abort(_("missing commit message"))
2206 2185
2207 2186 files = relpath(repo, list(flist))
2208 2187 if rc['files']:
2209 2188 files += open(rc['files']).read().splitlines()
2210 2189
2211 2190 rc['parent'] = map(repo.lookup, rc['parent'])
2212 2191
2213 2192 try:
2214 2193 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2215 2194 except ValueError, inst:
2216 2195 raise util.Abort(str(inst))
2217 2196
2218 2197 def recover(ui, repo):
2219 2198 """roll back an interrupted transaction
2220 2199
2221 2200 Recover from an interrupted commit or pull.
2222 2201
2223 2202 This command tries to fix the repository status after an interrupted
2224 2203 operation. It should only be necessary when Mercurial suggests it.
2225 2204 """
2226 2205 if repo.recover():
2227 2206 return hg.verify(repo)
2228 2207 return 1
2229 2208
2230 2209 def remove(ui, repo, *pats, **opts):
2231 2210 """remove the specified files on the next commit
2232 2211
2233 2212 Schedule the indicated files for removal from the repository.
2234 2213
2235 2214 This command schedules the files to be removed at the next commit.
2236 2215 This only removes files from the current branch, not from the
2237 2216 entire project history. If the files still exist in the working
2238 2217 directory, they will be deleted from it. If invoked with --after,
2239 2218 files that have been manually deleted are marked as removed.
2240 2219
2241 2220 Modified files and added files are not removed by default. To
2242 2221 remove them, use the -f/--force option.
2243 2222 """
2244 2223 names = []
2245 2224 if not opts['after'] and not pats:
2246 2225 raise util.Abort(_('no files specified'))
2247 files, matchfn, anypats = matchpats(repo, pats, opts)
2226 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2248 2227 exact = dict.fromkeys(files)
2249 2228 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2250 2229 modified, added, removed, deleted, unknown = mardu
2251 2230 remove, forget = [], []
2252 for src, abs, rel, exact in walk(repo, pats, opts):
2231 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2253 2232 reason = None
2254 2233 if abs not in deleted and opts['after']:
2255 2234 reason = _('is still present')
2256 2235 elif abs in modified and not opts['force']:
2257 2236 reason = _('is modified (use -f to force removal)')
2258 2237 elif abs in added:
2259 2238 if opts['force']:
2260 2239 forget.append(abs)
2261 2240 continue
2262 2241 reason = _('has been marked for add (use -f to force removal)')
2263 2242 elif abs in unknown:
2264 2243 reason = _('is not managed')
2265 2244 elif abs in removed:
2266 2245 continue
2267 2246 if reason:
2268 2247 if exact:
2269 2248 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2270 2249 else:
2271 2250 if ui.verbose or not exact:
2272 2251 ui.status(_('removing %s\n') % rel)
2273 2252 remove.append(abs)
2274 2253 repo.forget(forget)
2275 2254 repo.remove(remove, unlink=not opts['after'])
2276 2255
2277 2256 def rename(ui, repo, *pats, **opts):
2278 2257 """rename files; equivalent of copy + remove
2279 2258
2280 2259 Mark dest as copies of sources; mark sources for deletion. If
2281 2260 dest is a directory, copies are put in that directory. If dest is
2282 2261 a file, there can only be one source.
2283 2262
2284 2263 By default, this command copies the contents of files as they
2285 2264 stand in the working directory. If invoked with --after, the
2286 2265 operation is recorded, but no copying is performed.
2287 2266
2288 2267 This command takes effect in the next commit.
2289 2268
2290 2269 NOTE: This command should be treated as experimental. While it
2291 2270 should properly record rename files, this information is not yet
2292 2271 fully used by merge, nor fully reported by log.
2293 2272 """
2294 2273 wlock = repo.wlock(0)
2295 2274 errs, copied = docopy(ui, repo, pats, opts, wlock)
2296 2275 names = []
2297 2276 for abs, rel, exact in copied:
2298 2277 if ui.verbose or not exact:
2299 2278 ui.status(_('removing %s\n') % rel)
2300 2279 names.append(abs)
2301 2280 if not opts.get('dry_run'):
2302 2281 repo.remove(names, True, wlock)
2303 2282 return errs
2304 2283
2305 2284 def revert(ui, repo, *pats, **opts):
2306 2285 """revert files or dirs to their states as of some revision
2307 2286
2308 2287 With no revision specified, revert the named files or directories
2309 2288 to the contents they had in the parent of the working directory.
2310 2289 This restores the contents of the affected files to an unmodified
2311 2290 state. If the working directory has two parents, you must
2312 2291 explicitly specify the revision to revert to.
2313 2292
2314 2293 Modified files are saved with a .orig suffix before reverting.
2315 2294 To disable these backups, use --no-backup.
2316 2295
2317 2296 Using the -r option, revert the given files or directories to
2318 2297 their contents as of a specific revision. This can be helpful to"roll
2319 2298 back" some or all of a change that should not have been committed.
2320 2299
2321 2300 Revert modifies the working directory. It does not commit any
2322 2301 changes, or change the parent of the working directory. If you
2323 2302 revert to a revision other than the parent of the working
2324 2303 directory, the reverted files will thus appear modified
2325 2304 afterwards.
2326 2305
2327 2306 If a file has been deleted, it is recreated. If the executable
2328 2307 mode of a file was changed, it is reset.
2329 2308
2330 2309 If names are given, all files matching the names are reverted.
2331 2310
2332 2311 If no arguments are given, all files in the repository are reverted.
2333 2312 """
2334 2313 parent, p2 = repo.dirstate.parents()
2335 2314 if opts['rev']:
2336 2315 node = repo.lookup(opts['rev'])
2337 2316 elif p2 != nullid:
2338 2317 raise util.Abort(_('working dir has two parents; '
2339 2318 'you must specify the revision to revert to'))
2340 2319 else:
2341 2320 node = parent
2342 2321 mf = repo.manifest.read(repo.changelog.read(node)[0])
2343 2322 if node == parent:
2344 2323 pmf = mf
2345 2324 else:
2346 2325 pmf = None
2347 2326
2348 2327 wlock = repo.wlock()
2349 2328
2350 2329 # need all matching names in dirstate and manifest of target rev,
2351 2330 # so have to walk both. do not print errors if files exist in one
2352 2331 # but not other.
2353 2332
2354 2333 names = {}
2355 2334 target_only = {}
2356 2335
2357 2336 # walk dirstate.
2358 2337
2359 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2338 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2339 badmatch=mf.has_key):
2360 2340 names[abs] = (rel, exact)
2361 2341 if src == 'b':
2362 2342 target_only[abs] = True
2363 2343
2364 2344 # walk target manifest.
2365 2345
2366 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2367 badmatch=names.has_key):
2346 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2347 badmatch=names.has_key):
2368 2348 if abs in names: continue
2369 2349 names[abs] = (rel, exact)
2370 2350 target_only[abs] = True
2371 2351
2372 2352 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2373 2353 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2374 2354
2375 2355 revert = ([], _('reverting %s\n'))
2376 2356 add = ([], _('adding %s\n'))
2377 2357 remove = ([], _('removing %s\n'))
2378 2358 forget = ([], _('forgetting %s\n'))
2379 2359 undelete = ([], _('undeleting %s\n'))
2380 2360 update = {}
2381 2361
2382 2362 disptable = (
2383 2363 # dispatch table:
2384 2364 # file state
2385 2365 # action if in target manifest
2386 2366 # action if not in target manifest
2387 2367 # make backup if in target manifest
2388 2368 # make backup if not in target manifest
2389 2369 (modified, revert, remove, True, True),
2390 2370 (added, revert, forget, True, False),
2391 2371 (removed, undelete, None, False, False),
2392 2372 (deleted, revert, remove, False, False),
2393 2373 (unknown, add, None, True, False),
2394 2374 (target_only, add, None, False, False),
2395 2375 )
2396 2376
2397 2377 entries = names.items()
2398 2378 entries.sort()
2399 2379
2400 2380 for abs, (rel, exact) in entries:
2401 2381 mfentry = mf.get(abs)
2402 2382 def handle(xlist, dobackup):
2403 2383 xlist[0].append(abs)
2404 2384 update[abs] = 1
2405 2385 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2406 2386 bakname = "%s.orig" % rel
2407 2387 ui.note(_('saving current version of %s as %s\n') %
2408 2388 (rel, bakname))
2409 2389 if not opts.get('dry_run'):
2410 2390 shutil.copyfile(rel, bakname)
2411 2391 shutil.copymode(rel, bakname)
2412 2392 if ui.verbose or not exact:
2413 2393 ui.status(xlist[1] % rel)
2414 2394 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2415 2395 if abs not in table: continue
2416 2396 # file has changed in dirstate
2417 2397 if mfentry:
2418 2398 handle(hitlist, backuphit)
2419 2399 elif misslist is not None:
2420 2400 handle(misslist, backupmiss)
2421 2401 else:
2422 2402 if exact: ui.warn(_('file not managed: %s\n' % rel))
2423 2403 break
2424 2404 else:
2425 2405 # file has not changed in dirstate
2426 2406 if node == parent:
2427 2407 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2428 2408 continue
2429 2409 if pmf is None:
2430 2410 # only need parent manifest in this unlikely case,
2431 2411 # so do not read by default
2432 2412 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2433 2413 if abs in pmf:
2434 2414 if mfentry:
2435 2415 # if version of file is same in parent and target
2436 2416 # manifests, do nothing
2437 2417 if pmf[abs] != mfentry:
2438 2418 handle(revert, False)
2439 2419 else:
2440 2420 handle(remove, False)
2441 2421
2442 2422 if not opts.get('dry_run'):
2443 2423 repo.dirstate.forget(forget[0])
2444 2424 r = hg.revert(repo, node, update.has_key, wlock)
2445 2425 repo.dirstate.update(add[0], 'a')
2446 2426 repo.dirstate.update(undelete[0], 'n')
2447 2427 repo.dirstate.update(remove[0], 'r')
2448 2428 return r
2449 2429
2450 2430 def rollback(ui, repo):
2451 2431 """roll back the last transaction in this repository
2452 2432
2453 2433 Roll back the last transaction in this repository, restoring the
2454 2434 project to its state prior to the transaction.
2455 2435
2456 2436 Transactions are used to encapsulate the effects of all commands
2457 2437 that create new changesets or propagate existing changesets into a
2458 2438 repository. For example, the following commands are transactional,
2459 2439 and their effects can be rolled back:
2460 2440
2461 2441 commit
2462 2442 import
2463 2443 pull
2464 2444 push (with this repository as destination)
2465 2445 unbundle
2466 2446
2467 2447 This command should be used with care. There is only one level of
2468 2448 rollback, and there is no way to undo a rollback.
2469 2449
2470 2450 This command is not intended for use on public repositories. Once
2471 2451 changes are visible for pull by other users, rolling a transaction
2472 2452 back locally is ineffective (someone else may already have pulled
2473 2453 the changes). Furthermore, a race is possible with readers of the
2474 2454 repository; for example an in-progress pull from the repository
2475 2455 may fail if a rollback is performed.
2476 2456 """
2477 2457 repo.rollback()
2478 2458
2479 2459 def root(ui, repo):
2480 2460 """print the root (top) of the current working dir
2481 2461
2482 2462 Print the root directory of the current repository.
2483 2463 """
2484 2464 ui.write(repo.root + "\n")
2485 2465
2486 2466 def serve(ui, repo, **opts):
2487 2467 """export the repository via HTTP
2488 2468
2489 2469 Start a local HTTP repository browser and pull server.
2490 2470
2491 2471 By default, the server logs accesses to stdout and errors to
2492 2472 stderr. Use the "-A" and "-E" options to log to files.
2493 2473 """
2494 2474
2495 2475 if opts["stdio"]:
2496 2476 if repo is None:
2497 2477 raise hg.RepoError(_('no repo found'))
2498 2478 s = sshserver.sshserver(ui, repo)
2499 2479 s.serve_forever()
2500 2480
2501 2481 optlist = ("name templates style address port ipv6"
2502 2482 " accesslog errorlog webdir_conf")
2503 2483 for o in optlist.split():
2504 2484 if opts[o]:
2505 2485 ui.setconfig("web", o, opts[o])
2506 2486
2507 2487 if repo is None and not ui.config("web", "webdir_conf"):
2508 2488 raise hg.RepoError(_('no repo found'))
2509 2489
2510 2490 if opts['daemon'] and not opts['daemon_pipefds']:
2511 2491 rfd, wfd = os.pipe()
2512 2492 args = sys.argv[:]
2513 2493 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2514 2494 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2515 2495 args[0], args)
2516 2496 os.close(wfd)
2517 2497 os.read(rfd, 1)
2518 2498 os._exit(0)
2519 2499
2520 2500 try:
2521 2501 httpd = hgweb.server.create_server(ui, repo)
2522 2502 except socket.error, inst:
2523 2503 raise util.Abort(_('cannot start server: ') + inst.args[1])
2524 2504
2525 2505 if ui.verbose:
2526 2506 addr, port = httpd.socket.getsockname()
2527 2507 if addr == '0.0.0.0':
2528 2508 addr = socket.gethostname()
2529 2509 else:
2530 2510 try:
2531 2511 addr = socket.gethostbyaddr(addr)[0]
2532 2512 except socket.error:
2533 2513 pass
2534 2514 if port != 80:
2535 2515 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2536 2516 else:
2537 2517 ui.status(_('listening at http://%s/\n') % addr)
2538 2518
2539 2519 if opts['pid_file']:
2540 2520 fp = open(opts['pid_file'], 'w')
2541 2521 fp.write(str(os.getpid()) + '\n')
2542 2522 fp.close()
2543 2523
2544 2524 if opts['daemon_pipefds']:
2545 2525 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2546 2526 os.close(rfd)
2547 2527 os.write(wfd, 'y')
2548 2528 os.close(wfd)
2549 2529 sys.stdout.flush()
2550 2530 sys.stderr.flush()
2551 2531 fd = os.open(util.nulldev, os.O_RDWR)
2552 2532 if fd != 0: os.dup2(fd, 0)
2553 2533 if fd != 1: os.dup2(fd, 1)
2554 2534 if fd != 2: os.dup2(fd, 2)
2555 2535 if fd not in (0, 1, 2): os.close(fd)
2556 2536
2557 2537 httpd.serve_forever()
2558 2538
2559 2539 def status(ui, repo, *pats, **opts):
2560 2540 """show changed files in the working directory
2561 2541
2562 2542 Show status of files in the repository. If names are given, only
2563 2543 files that match are shown. Files that are clean or ignored, are
2564 2544 not listed unless -c (clean), -i (ignored) or -A is given.
2565 2545
2566 2546 The codes used to show the status of files are:
2567 2547 M = modified
2568 2548 A = added
2569 2549 R = removed
2570 2550 C = clean
2571 2551 ! = deleted, but still tracked
2572 2552 ? = not tracked
2573 2553 I = ignored (not shown by default)
2574 2554 = the previous added file was copied from here
2575 2555 """
2576 2556
2577 2557 all = opts['all']
2578 2558
2579 files, matchfn, anypats = matchpats(repo, pats, opts)
2559 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2580 2560 cwd = (pats and repo.getcwd()) or ''
2581 2561 modified, added, removed, deleted, unknown, ignored, clean = [
2582 2562 [util.pathto(cwd, x) for x in n]
2583 2563 for n in repo.status(files=files, match=matchfn,
2584 2564 list_ignored=all or opts['ignored'],
2585 2565 list_clean=all or opts['clean'])]
2586 2566
2587 2567 changetypes = (('modified', 'M', modified),
2588 2568 ('added', 'A', added),
2589 2569 ('removed', 'R', removed),
2590 2570 ('deleted', '!', deleted),
2591 2571 ('unknown', '?', unknown),
2592 2572 ('ignored', 'I', ignored))
2593 2573
2594 2574 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2595 2575
2596 2576 end = opts['print0'] and '\0' or '\n'
2597 2577
2598 2578 for opt, char, changes in ([ct for ct in explicit_changetypes
2599 2579 if all or opts[ct[0]]]
2600 2580 or changetypes):
2601 2581 if opts['no_status']:
2602 2582 format = "%%s%s" % end
2603 2583 else:
2604 2584 format = "%s %%s%s" % (char, end)
2605 2585
2606 2586 for f in changes:
2607 2587 ui.write(format % f)
2608 2588 if ((all or opts.get('copies')) and not opts.get('no_status')
2609 2589 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2610 2590 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2611 2591
2612 2592 def tag(ui, repo, name, rev_=None, **opts):
2613 2593 """add a tag for the current tip or a given revision
2614 2594
2615 2595 Name a particular revision using <name>.
2616 2596
2617 2597 Tags are used to name particular revisions of the repository and are
2618 2598 very useful to compare different revision, to go back to significant
2619 2599 earlier versions or to mark branch points as releases, etc.
2620 2600
2621 2601 If no revision is given, the parent of the working directory is used.
2622 2602
2623 2603 To facilitate version control, distribution, and merging of tags,
2624 2604 they are stored as a file named ".hgtags" which is managed
2625 2605 similarly to other project files and can be hand-edited if
2626 2606 necessary. The file '.hg/localtags' is used for local tags (not
2627 2607 shared among repositories).
2628 2608 """
2629 2609 if name in ['tip', '.']:
2630 2610 raise util.Abort(_("the name '%s' is reserved") % name)
2631 2611 if rev_ is not None:
2632 2612 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2633 2613 "please use 'hg tag [-r REV] NAME' instead\n"))
2634 2614 if opts['rev']:
2635 2615 raise util.Abort(_("use only one form to specify the revision"))
2636 2616 if opts['rev']:
2637 2617 rev_ = opts['rev']
2638 2618 if rev_:
2639 2619 r = hex(repo.lookup(rev_))
2640 2620 else:
2641 2621 p1, p2 = repo.dirstate.parents()
2642 2622 if p1 == nullid:
2643 2623 raise util.Abort(_('no revision to tag'))
2644 2624 if p2 != nullid:
2645 2625 raise util.Abort(_('outstanding uncommitted merges'))
2646 2626 r = hex(p1)
2647 2627
2648 2628 repo.tag(name, r, opts['local'], opts['message'], opts['user'],
2649 2629 opts['date'])
2650 2630
2651 2631 def tags(ui, repo):
2652 2632 """list repository tags
2653 2633
2654 2634 List the repository tags.
2655 2635
2656 2636 This lists both regular and local tags.
2657 2637 """
2658 2638
2659 2639 l = repo.tagslist()
2660 2640 l.reverse()
2661 2641 for t, n in l:
2662 2642 try:
2663 2643 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2664 2644 except KeyError:
2665 2645 r = " ?:?"
2666 2646 if ui.quiet:
2667 2647 ui.write("%s\n" % t)
2668 2648 else:
2669 2649 ui.write("%-30s %s\n" % (t, r))
2670 2650
2671 2651 def tip(ui, repo, **opts):
2672 2652 """show the tip revision
2673 2653
2674 2654 Show the tip revision.
2675 2655 """
2676 2656 n = repo.changelog.tip()
2677 2657 br = None
2678 2658 if opts['branches']:
2679 2659 br = repo.branchlookup([n])
2680 2660 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2681 2661 if opts['patch']:
2682 2662 patch.diff(repo, repo.changelog.parents(n)[0], n)
2683 2663
2684 2664 def unbundle(ui, repo, fname, **opts):
2685 2665 """apply a changegroup file
2686 2666
2687 2667 Apply a compressed changegroup file generated by the bundle
2688 2668 command.
2689 2669 """
2690 2670 f = urllib.urlopen(fname)
2691 2671
2692 2672 header = f.read(6)
2693 2673 if not header.startswith("HG"):
2694 2674 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2695 2675 elif not header.startswith("HG10"):
2696 2676 raise util.Abort(_("%s: unknown bundle version") % fname)
2697 2677 elif header == "HG10BZ":
2698 2678 def generator(f):
2699 2679 zd = bz2.BZ2Decompressor()
2700 2680 zd.decompress("BZ")
2701 2681 for chunk in f:
2702 2682 yield zd.decompress(chunk)
2703 2683 elif header == "HG10UN":
2704 2684 def generator(f):
2705 2685 for chunk in f:
2706 2686 yield chunk
2707 2687 else:
2708 2688 raise util.Abort(_("%s: unknown bundle compression type")
2709 2689 % fname)
2710 2690 gen = generator(util.filechunkiter(f, 4096))
2711 2691 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2712 2692 'bundle:' + fname)
2713 2693 return postincoming(ui, repo, modheads, opts['update'])
2714 2694
2715 2695 def undo(ui, repo):
2716 2696 """undo the last commit or pull (DEPRECATED)
2717 2697
2718 2698 (DEPRECATED)
2719 2699 This command is now deprecated and will be removed in a future
2720 2700 release. Please use the rollback command instead. For usage
2721 2701 instructions, see the rollback command.
2722 2702 """
2723 2703 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2724 2704 repo.rollback()
2725 2705
2726 2706 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2727 2707 branch=None):
2728 2708 """update or merge working directory
2729 2709
2730 2710 Update the working directory to the specified revision.
2731 2711
2732 2712 If there are no outstanding changes in the working directory and
2733 2713 there is a linear relationship between the current version and the
2734 2714 requested version, the result is the requested version.
2735 2715
2736 2716 To merge the working directory with another revision, use the
2737 2717 merge command.
2738 2718
2739 2719 By default, update will refuse to run if doing so would require
2740 2720 merging or discarding local changes.
2741 2721 """
2742 2722 node = _lookup(repo, node, branch)
2743 2723 if merge:
2744 2724 ui.warn(_('(the -m/--merge option is deprecated; '
2745 2725 'use the merge command instead)\n'))
2746 2726 return hg.merge(repo, node, force=force)
2747 2727 elif clean:
2748 2728 return hg.clean(repo, node)
2749 2729 else:
2750 2730 return hg.update(repo, node)
2751 2731
2752 2732 def _lookup(repo, node, branch=None):
2753 2733 if branch:
2754 2734 br = repo.branchlookup(branch=branch)
2755 2735 found = []
2756 2736 for x in br:
2757 2737 if branch in br[x]:
2758 2738 found.append(x)
2759 2739 if len(found) > 1:
2760 2740 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2761 2741 for x in found:
2762 2742 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2763 2743 raise util.Abort("")
2764 2744 if len(found) == 1:
2765 2745 node = found[0]
2766 2746 repo.ui.warn(_("Using head %s for branch %s\n")
2767 2747 % (short(node), branch))
2768 2748 else:
2769 2749 raise util.Abort(_("branch %s not found\n") % (branch))
2770 2750 else:
2771 2751 node = node and repo.lookup(node) or repo.changelog.tip()
2772 2752 return node
2773 2753
2774 2754 def verify(ui, repo):
2775 2755 """verify the integrity of the repository
2776 2756
2777 2757 Verify the integrity of the current repository.
2778 2758
2779 2759 This will perform an extensive check of the repository's
2780 2760 integrity, validating the hashes and checksums of each entry in
2781 2761 the changelog, manifest, and tracked files, as well as the
2782 2762 integrity of their crosslinks and indices.
2783 2763 """
2784 2764 return hg.verify(repo)
2785 2765
2786 2766 # Command options and aliases are listed here, alphabetically
2787 2767
2788 2768 table = {
2789 2769 "^add":
2790 2770 (add,
2791 2771 [('I', 'include', [], _('include names matching the given patterns')),
2792 2772 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2793 2773 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2794 2774 _('hg add [OPTION]... [FILE]...')),
2795 2775 "debugaddremove|addremove":
2796 2776 (addremove,
2797 2777 [('I', 'include', [], _('include names matching the given patterns')),
2798 2778 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2799 2779 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2800 2780 _('hg addremove [OPTION]... [FILE]...')),
2801 2781 "^annotate":
2802 2782 (annotate,
2803 2783 [('r', 'rev', '', _('annotate the specified revision')),
2804 2784 ('a', 'text', None, _('treat all files as text')),
2805 2785 ('u', 'user', None, _('list the author')),
2806 2786 ('d', 'date', None, _('list the date')),
2807 2787 ('n', 'number', None, _('list the revision number (default)')),
2808 2788 ('c', 'changeset', None, _('list the changeset')),
2809 2789 ('I', 'include', [], _('include names matching the given patterns')),
2810 2790 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2811 2791 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2812 2792 "archive":
2813 2793 (archive,
2814 2794 [('', 'no-decode', None, _('do not pass files through decoders')),
2815 2795 ('p', 'prefix', '', _('directory prefix for files in archive')),
2816 2796 ('r', 'rev', '', _('revision to distribute')),
2817 2797 ('t', 'type', '', _('type of distribution to create')),
2818 2798 ('I', 'include', [], _('include names matching the given patterns')),
2819 2799 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2820 2800 _('hg archive [OPTION]... DEST')),
2821 2801 "backout":
2822 2802 (backout,
2823 2803 [('', 'merge', None,
2824 2804 _('merge with old dirstate parent after backout')),
2825 2805 ('m', 'message', '', _('use <text> as commit message')),
2826 2806 ('l', 'logfile', '', _('read commit message from <file>')),
2827 2807 ('d', 'date', '', _('record datecode as commit date')),
2828 2808 ('', 'parent', '', _('parent to choose when backing out merge')),
2829 2809 ('u', 'user', '', _('record user as committer')),
2830 2810 ('I', 'include', [], _('include names matching the given patterns')),
2831 2811 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2832 2812 _('hg backout [OPTION]... REV')),
2833 2813 "bundle":
2834 2814 (bundle,
2835 2815 [('f', 'force', None,
2836 2816 _('run even when remote repository is unrelated'))],
2837 2817 _('hg bundle FILE DEST')),
2838 2818 "cat":
2839 2819 (cat,
2840 2820 [('o', 'output', '', _('print output to file with formatted name')),
2841 2821 ('r', 'rev', '', _('print the given revision')),
2842 2822 ('I', 'include', [], _('include names matching the given patterns')),
2843 2823 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2844 2824 _('hg cat [OPTION]... FILE...')),
2845 2825 "^clone":
2846 2826 (clone,
2847 2827 [('U', 'noupdate', None, _('do not update the new working directory')),
2848 2828 ('r', 'rev', [],
2849 2829 _('a changeset you would like to have after cloning')),
2850 2830 ('', 'pull', None, _('use pull protocol to copy metadata')),
2851 2831 ('', 'uncompressed', None,
2852 2832 _('use uncompressed transfer (fast over LAN)')),
2853 2833 ('e', 'ssh', '', _('specify ssh command to use')),
2854 2834 ('', 'remotecmd', '',
2855 2835 _('specify hg command to run on the remote side'))],
2856 2836 _('hg clone [OPTION]... SOURCE [DEST]')),
2857 2837 "^commit|ci":
2858 2838 (commit,
2859 2839 [('A', 'addremove', None,
2860 2840 _('mark new/missing files as added/removed before committing')),
2861 2841 ('m', 'message', '', _('use <text> as commit message')),
2862 2842 ('l', 'logfile', '', _('read the commit message from <file>')),
2863 2843 ('d', 'date', '', _('record datecode as commit date')),
2864 2844 ('u', 'user', '', _('record user as commiter')),
2865 2845 ('I', 'include', [], _('include names matching the given patterns')),
2866 2846 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2867 2847 _('hg commit [OPTION]... [FILE]...')),
2868 2848 "copy|cp":
2869 2849 (copy,
2870 2850 [('A', 'after', None, _('record a copy that has already occurred')),
2871 2851 ('f', 'force', None,
2872 2852 _('forcibly copy over an existing managed file')),
2873 2853 ('I', 'include', [], _('include names matching the given patterns')),
2874 2854 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2875 2855 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2876 2856 _('hg copy [OPTION]... [SOURCE]... DEST')),
2877 2857 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2878 2858 "debugcomplete":
2879 2859 (debugcomplete,
2880 2860 [('o', 'options', None, _('show the command options'))],
2881 2861 _('debugcomplete [-o] CMD')),
2882 2862 "debugrebuildstate":
2883 2863 (debugrebuildstate,
2884 2864 [('r', 'rev', '', _('revision to rebuild to'))],
2885 2865 _('debugrebuildstate [-r REV] [REV]')),
2886 2866 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2887 2867 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2888 2868 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2889 2869 "debugstate": (debugstate, [], _('debugstate')),
2890 2870 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2891 2871 "debugindex": (debugindex, [], _('debugindex FILE')),
2892 2872 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2893 2873 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2894 2874 "debugwalk":
2895 2875 (debugwalk,
2896 2876 [('I', 'include', [], _('include names matching the given patterns')),
2897 2877 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2898 2878 _('debugwalk [OPTION]... [FILE]...')),
2899 2879 "^diff":
2900 2880 (diff,
2901 2881 [('r', 'rev', [], _('revision')),
2902 2882 ('a', 'text', None, _('treat all files as text')),
2903 2883 ('p', 'show-function', None,
2904 2884 _('show which function each change is in')),
2905 2885 ('w', 'ignore-all-space', None,
2906 2886 _('ignore white space when comparing lines')),
2907 2887 ('b', 'ignore-space-change', None,
2908 2888 _('ignore changes in the amount of white space')),
2909 2889 ('B', 'ignore-blank-lines', None,
2910 2890 _('ignore changes whose lines are all blank')),
2911 2891 ('I', 'include', [], _('include names matching the given patterns')),
2912 2892 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2913 2893 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2914 2894 "^export":
2915 2895 (export,
2916 2896 [('o', 'output', '', _('print output to file with formatted name')),
2917 2897 ('a', 'text', None, _('treat all files as text')),
2918 2898 ('', 'switch-parent', None, _('diff against the second parent'))],
2919 2899 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2920 2900 "debugforget|forget":
2921 2901 (forget,
2922 2902 [('I', 'include', [], _('include names matching the given patterns')),
2923 2903 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2924 2904 _('hg forget [OPTION]... FILE...')),
2925 2905 "grep":
2926 2906 (grep,
2927 2907 [('0', 'print0', None, _('end fields with NUL')),
2928 2908 ('', 'all', None, _('print all revisions that match')),
2929 2909 ('f', 'follow', None,
2930 2910 _('follow changeset history, or file history across copies and renames')),
2931 2911 ('i', 'ignore-case', None, _('ignore case when matching')),
2932 2912 ('l', 'files-with-matches', None,
2933 2913 _('print only filenames and revs that match')),
2934 2914 ('n', 'line-number', None, _('print matching line numbers')),
2935 2915 ('r', 'rev', [], _('search in given revision range')),
2936 2916 ('u', 'user', None, _('print user who committed change')),
2937 2917 ('I', 'include', [], _('include names matching the given patterns')),
2938 2918 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2939 2919 _('hg grep [OPTION]... PATTERN [FILE]...')),
2940 2920 "heads":
2941 2921 (heads,
2942 2922 [('b', 'branches', None, _('show branches')),
2943 2923 ('', 'style', '', _('display using template map file')),
2944 2924 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2945 2925 ('', 'template', '', _('display with template'))],
2946 2926 _('hg heads [-b] [-r <rev>]')),
2947 2927 "help": (help_, [], _('hg help [COMMAND]')),
2948 2928 "identify|id": (identify, [], _('hg identify')),
2949 2929 "import|patch":
2950 2930 (import_,
2951 2931 [('p', 'strip', 1,
2952 2932 _('directory strip option for patch. This has the same\n'
2953 2933 'meaning as the corresponding patch option')),
2954 2934 ('m', 'message', '', _('use <text> as commit message')),
2955 2935 ('b', 'base', '', _('base path')),
2956 2936 ('f', 'force', None,
2957 2937 _('skip check for outstanding uncommitted changes'))],
2958 2938 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2959 2939 "incoming|in": (incoming,
2960 2940 [('M', 'no-merges', None, _('do not show merges')),
2961 2941 ('f', 'force', None,
2962 2942 _('run even when remote repository is unrelated')),
2963 2943 ('', 'style', '', _('display using template map file')),
2964 2944 ('n', 'newest-first', None, _('show newest record first')),
2965 2945 ('', 'bundle', '', _('file to store the bundles into')),
2966 2946 ('p', 'patch', None, _('show patch')),
2967 2947 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2968 2948 ('', 'template', '', _('display with template')),
2969 2949 ('e', 'ssh', '', _('specify ssh command to use')),
2970 2950 ('', 'remotecmd', '',
2971 2951 _('specify hg command to run on the remote side'))],
2972 2952 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2973 2953 ' [--bundle FILENAME] [SOURCE]')),
2974 2954 "^init":
2975 2955 (init,
2976 2956 [('e', 'ssh', '', _('specify ssh command to use')),
2977 2957 ('', 'remotecmd', '',
2978 2958 _('specify hg command to run on the remote side'))],
2979 2959 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2980 2960 "locate":
2981 2961 (locate,
2982 2962 [('r', 'rev', '', _('search the repository as it stood at rev')),
2983 2963 ('0', 'print0', None,
2984 2964 _('end filenames with NUL, for use with xargs')),
2985 2965 ('f', 'fullpath', None,
2986 2966 _('print complete paths from the filesystem root')),
2987 2967 ('I', 'include', [], _('include names matching the given patterns')),
2988 2968 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2989 2969 _('hg locate [OPTION]... [PATTERN]...')),
2990 2970 "^log|history":
2991 2971 (log,
2992 2972 [('b', 'branches', None, _('show branches')),
2993 2973 ('f', 'follow', None,
2994 2974 _('follow changeset history, or file history across copies and renames')),
2995 2975 ('', 'follow-first', None,
2996 2976 _('only follow the first parent of merge changesets')),
2997 2977 ('k', 'keyword', [], _('search for a keyword')),
2998 2978 ('l', 'limit', '', _('limit number of changes displayed')),
2999 2979 ('r', 'rev', [], _('show the specified revision or range')),
3000 2980 ('M', 'no-merges', None, _('do not show merges')),
3001 2981 ('', 'style', '', _('display using template map file')),
3002 2982 ('m', 'only-merges', None, _('show only merges')),
3003 2983 ('p', 'patch', None, _('show patch')),
3004 2984 ('', 'template', '', _('display with template')),
3005 2985 ('I', 'include', [], _('include names matching the given patterns')),
3006 2986 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3007 2987 _('hg log [OPTION]... [FILE]')),
3008 2988 "manifest": (manifest, [], _('hg manifest [REV]')),
3009 2989 "merge":
3010 2990 (merge,
3011 2991 [('b', 'branch', '', _('merge with head of a specific branch')),
3012 2992 ('f', 'force', None, _('force a merge with outstanding changes'))],
3013 2993 _('hg merge [-b TAG] [-f] [REV]')),
3014 2994 "outgoing|out": (outgoing,
3015 2995 [('M', 'no-merges', None, _('do not show merges')),
3016 2996 ('f', 'force', None,
3017 2997 _('run even when remote repository is unrelated')),
3018 2998 ('p', 'patch', None, _('show patch')),
3019 2999 ('', 'style', '', _('display using template map file')),
3020 3000 ('r', 'rev', [], _('a specific revision you would like to push')),
3021 3001 ('n', 'newest-first', None, _('show newest record first')),
3022 3002 ('', 'template', '', _('display with template')),
3023 3003 ('e', 'ssh', '', _('specify ssh command to use')),
3024 3004 ('', 'remotecmd', '',
3025 3005 _('specify hg command to run on the remote side'))],
3026 3006 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
3027 3007 "^parents":
3028 3008 (parents,
3029 3009 [('b', 'branches', None, _('show branches')),
3030 3010 ('r', 'rev', '', _('show parents from the specified rev')),
3031 3011 ('', 'style', '', _('display using template map file')),
3032 3012 ('', 'template', '', _('display with template'))],
3033 3013 _('hg parents [-b] [-r REV] [FILE]')),
3034 3014 "paths": (paths, [], _('hg paths [NAME]')),
3035 3015 "^pull":
3036 3016 (pull,
3037 3017 [('u', 'update', None,
3038 3018 _('update the working directory to tip after pull')),
3039 3019 ('e', 'ssh', '', _('specify ssh command to use')),
3040 3020 ('f', 'force', None,
3041 3021 _('run even when remote repository is unrelated')),
3042 3022 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3043 3023 ('', 'remotecmd', '',
3044 3024 _('specify hg command to run on the remote side'))],
3045 3025 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3046 3026 "^push":
3047 3027 (push,
3048 3028 [('f', 'force', None, _('force push')),
3049 3029 ('e', 'ssh', '', _('specify ssh command to use')),
3050 3030 ('r', 'rev', [], _('a specific revision you would like to push')),
3051 3031 ('', 'remotecmd', '',
3052 3032 _('specify hg command to run on the remote side'))],
3053 3033 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
3054 3034 "debugrawcommit|rawcommit":
3055 3035 (rawcommit,
3056 3036 [('p', 'parent', [], _('parent')),
3057 3037 ('d', 'date', '', _('date code')),
3058 3038 ('u', 'user', '', _('user')),
3059 3039 ('F', 'files', '', _('file list')),
3060 3040 ('m', 'message', '', _('commit message')),
3061 3041 ('l', 'logfile', '', _('commit message file'))],
3062 3042 _('hg debugrawcommit [OPTION]... [FILE]...')),
3063 3043 "recover": (recover, [], _('hg recover')),
3064 3044 "^remove|rm":
3065 3045 (remove,
3066 3046 [('A', 'after', None, _('record remove that has already occurred')),
3067 3047 ('f', 'force', None, _('remove file even if modified')),
3068 3048 ('I', 'include', [], _('include names matching the given patterns')),
3069 3049 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3070 3050 _('hg remove [OPTION]... FILE...')),
3071 3051 "rename|mv":
3072 3052 (rename,
3073 3053 [('A', 'after', None, _('record a rename that has already occurred')),
3074 3054 ('f', 'force', None,
3075 3055 _('forcibly copy over an existing managed file')),
3076 3056 ('I', 'include', [], _('include names matching the given patterns')),
3077 3057 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3078 3058 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3079 3059 _('hg rename [OPTION]... SOURCE... DEST')),
3080 3060 "^revert":
3081 3061 (revert,
3082 3062 [('r', 'rev', '', _('revision to revert to')),
3083 3063 ('', 'no-backup', None, _('do not save backup copies of files')),
3084 3064 ('I', 'include', [], _('include names matching given patterns')),
3085 3065 ('X', 'exclude', [], _('exclude names matching given patterns')),
3086 3066 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3087 3067 _('hg revert [-r REV] [NAME]...')),
3088 3068 "rollback": (rollback, [], _('hg rollback')),
3089 3069 "root": (root, [], _('hg root')),
3090 3070 "^serve":
3091 3071 (serve,
3092 3072 [('A', 'accesslog', '', _('name of access log file to write to')),
3093 3073 ('d', 'daemon', None, _('run server in background')),
3094 3074 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3095 3075 ('E', 'errorlog', '', _('name of error log file to write to')),
3096 3076 ('p', 'port', 0, _('port to use (default: 8000)')),
3097 3077 ('a', 'address', '', _('address to use')),
3098 3078 ('n', 'name', '',
3099 3079 _('name to show in web pages (default: working dir)')),
3100 3080 ('', 'webdir-conf', '', _('name of the webdir config file'
3101 3081 ' (serve more than one repo)')),
3102 3082 ('', 'pid-file', '', _('name of file to write process ID to')),
3103 3083 ('', 'stdio', None, _('for remote clients')),
3104 3084 ('t', 'templates', '', _('web templates to use')),
3105 3085 ('', 'style', '', _('template style to use')),
3106 3086 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3107 3087 _('hg serve [OPTION]...')),
3108 3088 "^status|st":
3109 3089 (status,
3110 3090 [('A', 'all', None, _('show status of all files')),
3111 3091 ('m', 'modified', None, _('show only modified files')),
3112 3092 ('a', 'added', None, _('show only added files')),
3113 3093 ('r', 'removed', None, _('show only removed files')),
3114 3094 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3115 3095 ('c', 'clean', None, _('show only files without changes')),
3116 3096 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3117 3097 ('i', 'ignored', None, _('show ignored files')),
3118 3098 ('n', 'no-status', None, _('hide status prefix')),
3119 3099 ('C', 'copies', None, _('show source of copied files')),
3120 3100 ('0', 'print0', None,
3121 3101 _('end filenames with NUL, for use with xargs')),
3122 3102 ('I', 'include', [], _('include names matching the given patterns')),
3123 3103 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3124 3104 _('hg status [OPTION]... [FILE]...')),
3125 3105 "tag":
3126 3106 (tag,
3127 3107 [('l', 'local', None, _('make the tag local')),
3128 3108 ('m', 'message', '', _('message for tag commit log entry')),
3129 3109 ('d', 'date', '', _('record datecode as commit date')),
3130 3110 ('u', 'user', '', _('record user as commiter')),
3131 3111 ('r', 'rev', '', _('revision to tag'))],
3132 3112 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3133 3113 "tags": (tags, [], _('hg tags')),
3134 3114 "tip":
3135 3115 (tip,
3136 3116 [('b', 'branches', None, _('show branches')),
3137 3117 ('', 'style', '', _('display using template map file')),
3138 3118 ('p', 'patch', None, _('show patch')),
3139 3119 ('', 'template', '', _('display with template'))],
3140 3120 _('hg tip [-b] [-p]')),
3141 3121 "unbundle":
3142 3122 (unbundle,
3143 3123 [('u', 'update', None,
3144 3124 _('update the working directory to tip after unbundle'))],
3145 3125 _('hg unbundle [-u] FILE')),
3146 3126 "debugundo|undo": (undo, [], _('hg undo')),
3147 3127 "^update|up|checkout|co":
3148 3128 (update,
3149 3129 [('b', 'branch', '', _('checkout the head of a specific branch')),
3150 3130 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3151 3131 ('C', 'clean', None, _('overwrite locally modified files')),
3152 3132 ('f', 'force', None, _('force a merge with outstanding changes'))],
3153 3133 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3154 3134 "verify": (verify, [], _('hg verify')),
3155 3135 "version": (show_version, [], _('hg version')),
3156 3136 }
3157 3137
3158 3138 globalopts = [
3159 3139 ('R', 'repository', '',
3160 3140 _('repository root directory or symbolic path name')),
3161 3141 ('', 'cwd', '', _('change working directory')),
3162 3142 ('y', 'noninteractive', None,
3163 3143 _('do not prompt, assume \'yes\' for any required answers')),
3164 3144 ('q', 'quiet', None, _('suppress output')),
3165 3145 ('v', 'verbose', None, _('enable additional output')),
3166 3146 ('', 'config', [], _('set/override config option')),
3167 3147 ('', 'debug', None, _('enable debugging output')),
3168 3148 ('', 'debugger', None, _('start debugger')),
3169 3149 ('', 'lsprof', None, _('print improved command execution profile')),
3170 3150 ('', 'traceback', None, _('print traceback on exception')),
3171 3151 ('', 'time', None, _('time how long the command takes')),
3172 3152 ('', 'profile', None, _('print command execution profile')),
3173 3153 ('', 'version', None, _('output version information and exit')),
3174 3154 ('h', 'help', None, _('display help and exit')),
3175 3155 ]
3176 3156
3177 3157 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3178 3158 " debugindex debugindexdot")
3179 3159 optionalrepo = ("paths serve debugconfig")
3180 3160
3181 3161 def findpossible(cmd):
3182 3162 """
3183 3163 Return cmd -> (aliases, command table entry)
3184 3164 for each matching command.
3185 3165 Return debug commands (or their aliases) only if no normal command matches.
3186 3166 """
3187 3167 choice = {}
3188 3168 debugchoice = {}
3189 3169 for e in table.keys():
3190 3170 aliases = e.lstrip("^").split("|")
3191 3171 found = None
3192 3172 if cmd in aliases:
3193 3173 found = cmd
3194 3174 else:
3195 3175 for a in aliases:
3196 3176 if a.startswith(cmd):
3197 3177 found = a
3198 3178 break
3199 3179 if found is not None:
3200 3180 if aliases[0].startswith("debug"):
3201 3181 debugchoice[found] = (aliases, table[e])
3202 3182 else:
3203 3183 choice[found] = (aliases, table[e])
3204 3184
3205 3185 if not choice and debugchoice:
3206 3186 choice = debugchoice
3207 3187
3208 3188 return choice
3209 3189
3210 3190 def findcmd(cmd):
3211 3191 """Return (aliases, command table entry) for command string."""
3212 3192 choice = findpossible(cmd)
3213 3193
3214 3194 if choice.has_key(cmd):
3215 3195 return choice[cmd]
3216 3196
3217 3197 if len(choice) > 1:
3218 3198 clist = choice.keys()
3219 3199 clist.sort()
3220 3200 raise AmbiguousCommand(cmd, clist)
3221 3201
3222 3202 if choice:
3223 3203 return choice.values()[0]
3224 3204
3225 3205 raise UnknownCommand(cmd)
3226 3206
3227 3207 def catchterm(*args):
3228 3208 raise util.SignalInterrupt
3229 3209
3230 3210 def run():
3231 3211 sys.exit(dispatch(sys.argv[1:]))
3232 3212
3233 3213 class ParseError(Exception):
3234 3214 """Exception raised on errors in parsing the command line."""
3235 3215
3236 3216 def parse(ui, args):
3237 3217 options = {}
3238 3218 cmdoptions = {}
3239 3219
3240 3220 try:
3241 3221 args = fancyopts.fancyopts(args, globalopts, options)
3242 3222 except fancyopts.getopt.GetoptError, inst:
3243 3223 raise ParseError(None, inst)
3244 3224
3245 3225 if args:
3246 3226 cmd, args = args[0], args[1:]
3247 3227 aliases, i = findcmd(cmd)
3248 3228 cmd = aliases[0]
3249 3229 defaults = ui.config("defaults", cmd)
3250 3230 if defaults:
3251 3231 args = defaults.split() + args
3252 3232 c = list(i[1])
3253 3233 else:
3254 3234 cmd = None
3255 3235 c = []
3256 3236
3257 3237 # combine global options into local
3258 3238 for o in globalopts:
3259 3239 c.append((o[0], o[1], options[o[1]], o[3]))
3260 3240
3261 3241 try:
3262 3242 args = fancyopts.fancyopts(args, c, cmdoptions)
3263 3243 except fancyopts.getopt.GetoptError, inst:
3264 3244 raise ParseError(cmd, inst)
3265 3245
3266 3246 # separate global options back out
3267 3247 for o in globalopts:
3268 3248 n = o[1]
3269 3249 options[n] = cmdoptions[n]
3270 3250 del cmdoptions[n]
3271 3251
3272 3252 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3273 3253
3274 3254 external = {}
3275 3255
3276 3256 def findext(name):
3277 3257 '''return module with given extension name'''
3278 3258 try:
3279 3259 return sys.modules[external[name]]
3280 3260 except KeyError:
3281 3261 for k, v in external.iteritems():
3282 3262 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3283 3263 return sys.modules[v]
3284 3264 raise KeyError(name)
3285 3265
3286 3266 def dispatch(args):
3287 3267 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3288 3268 num = getattr(signal, name, None)
3289 3269 if num: signal.signal(num, catchterm)
3290 3270
3291 3271 try:
3292 3272 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3293 3273 except util.Abort, inst:
3294 3274 sys.stderr.write(_("abort: %s\n") % inst)
3295 3275 return -1
3296 3276
3297 3277 for ext_name, load_from_name in u.extensions():
3298 3278 try:
3299 3279 if load_from_name:
3300 3280 # the module will be loaded in sys.modules
3301 3281 # choose an unique name so that it doesn't
3302 3282 # conflicts with other modules
3303 3283 module_name = "hgext_%s" % ext_name.replace('.', '_')
3304 3284 mod = imp.load_source(module_name, load_from_name)
3305 3285 else:
3306 3286 def importh(name):
3307 3287 mod = __import__(name)
3308 3288 components = name.split('.')
3309 3289 for comp in components[1:]:
3310 3290 mod = getattr(mod, comp)
3311 3291 return mod
3312 3292 try:
3313 3293 mod = importh("hgext.%s" % ext_name)
3314 3294 except ImportError:
3315 3295 mod = importh(ext_name)
3316 3296 external[ext_name] = mod.__name__
3317 3297 except (util.SignalInterrupt, KeyboardInterrupt):
3318 3298 raise
3319 3299 except Exception, inst:
3320 3300 u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
3321 3301 if u.print_exc():
3322 3302 return 1
3323 3303
3324 3304 for name in external.itervalues():
3325 3305 mod = sys.modules[name]
3326 3306 uisetup = getattr(mod, 'uisetup', None)
3327 3307 if uisetup:
3328 3308 uisetup(u)
3329 3309 cmdtable = getattr(mod, 'cmdtable', {})
3330 3310 for t in cmdtable:
3331 3311 if t in table:
3332 3312 u.warn(_("module %s overrides %s\n") % (name, t))
3333 3313 table.update(cmdtable)
3334 3314
3335 3315 try:
3336 3316 cmd, func, args, options, cmdoptions = parse(u, args)
3337 3317 if options["time"]:
3338 3318 def get_times():
3339 3319 t = os.times()
3340 3320 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3341 3321 t = (t[0], t[1], t[2], t[3], time.clock())
3342 3322 return t
3343 3323 s = get_times()
3344 3324 def print_time():
3345 3325 t = get_times()
3346 3326 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3347 3327 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3348 3328 atexit.register(print_time)
3349 3329
3350 3330 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3351 3331 not options["noninteractive"], options["traceback"],
3352 3332 options["config"])
3353 3333
3354 3334 # enter the debugger before command execution
3355 3335 if options['debugger']:
3356 3336 pdb.set_trace()
3357 3337
3358 3338 try:
3359 3339 if options['cwd']:
3360 3340 try:
3361 3341 os.chdir(options['cwd'])
3362 3342 except OSError, inst:
3363 3343 raise util.Abort('%s: %s' %
3364 3344 (options['cwd'], inst.strerror))
3365 3345
3366 3346 path = u.expandpath(options["repository"]) or ""
3367 3347 repo = path and hg.repository(u, path=path) or None
3368 3348
3369 3349 if options['help']:
3370 3350 return help_(u, cmd, options['version'])
3371 3351 elif options['version']:
3372 3352 return show_version(u)
3373 3353 elif not cmd:
3374 3354 return help_(u, 'shortlist')
3375 3355
3376 3356 if cmd not in norepo.split():
3377 3357 try:
3378 3358 if not repo:
3379 3359 repo = hg.repository(u, path=path)
3380 3360 u = repo.ui
3381 3361 for name in external.itervalues():
3382 3362 mod = sys.modules[name]
3383 3363 if hasattr(mod, 'reposetup'):
3384 3364 mod.reposetup(u, repo)
3385 3365 hg.repo_setup_hooks.append(mod.reposetup)
3386 3366 except hg.RepoError:
3387 3367 if cmd not in optionalrepo.split():
3388 3368 raise
3389 3369 d = lambda: func(u, repo, *args, **cmdoptions)
3390 3370 else:
3391 3371 d = lambda: func(u, *args, **cmdoptions)
3392 3372
3393 3373 # reupdate the options, repo/.hg/hgrc may have changed them
3394 3374 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3395 3375 not options["noninteractive"], options["traceback"],
3396 3376 options["config"])
3397 3377
3398 3378 try:
3399 3379 if options['profile']:
3400 3380 import hotshot, hotshot.stats
3401 3381 prof = hotshot.Profile("hg.prof")
3402 3382 try:
3403 3383 try:
3404 3384 return prof.runcall(d)
3405 3385 except:
3406 3386 try:
3407 3387 u.warn(_('exception raised - generating '
3408 3388 'profile anyway\n'))
3409 3389 except:
3410 3390 pass
3411 3391 raise
3412 3392 finally:
3413 3393 prof.close()
3414 3394 stats = hotshot.stats.load("hg.prof")
3415 3395 stats.strip_dirs()
3416 3396 stats.sort_stats('time', 'calls')
3417 3397 stats.print_stats(40)
3418 3398 elif options['lsprof']:
3419 3399 try:
3420 3400 from mercurial import lsprof
3421 3401 except ImportError:
3422 3402 raise util.Abort(_(
3423 3403 'lsprof not available - install from '
3424 3404 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3425 3405 p = lsprof.Profiler()
3426 3406 p.enable(subcalls=True)
3427 3407 try:
3428 3408 return d()
3429 3409 finally:
3430 3410 p.disable()
3431 3411 stats = lsprof.Stats(p.getstats())
3432 3412 stats.sort()
3433 3413 stats.pprint(top=10, file=sys.stderr, climit=5)
3434 3414 else:
3435 3415 return d()
3436 3416 finally:
3437 3417 u.flush()
3438 3418 except:
3439 3419 # enter the debugger when we hit an exception
3440 3420 if options['debugger']:
3441 3421 pdb.post_mortem(sys.exc_info()[2])
3442 3422 u.print_exc()
3443 3423 raise
3444 3424 except ParseError, inst:
3445 3425 if inst.args[0]:
3446 3426 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3447 3427 help_(u, inst.args[0])
3448 3428 else:
3449 3429 u.warn(_("hg: %s\n") % inst.args[1])
3450 3430 help_(u, 'shortlist')
3451 3431 except AmbiguousCommand, inst:
3452 3432 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3453 3433 (inst.args[0], " ".join(inst.args[1])))
3454 3434 except UnknownCommand, inst:
3455 3435 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3456 3436 help_(u, 'shortlist')
3457 3437 except hg.RepoError, inst:
3458 3438 u.warn(_("abort: %s!\n") % inst)
3459 3439 except lock.LockHeld, inst:
3460 3440 if inst.errno == errno.ETIMEDOUT:
3461 3441 reason = _('timed out waiting for lock held by %s') % inst.locker
3462 3442 else:
3463 3443 reason = _('lock held by %s') % inst.locker
3464 3444 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3465 3445 except lock.LockUnavailable, inst:
3466 3446 u.warn(_("abort: could not lock %s: %s\n") %
3467 3447 (inst.desc or inst.filename, inst.strerror))
3468 3448 except revlog.RevlogError, inst:
3469 3449 u.warn(_("abort: "), inst, "!\n")
3470 3450 except util.SignalInterrupt:
3471 3451 u.warn(_("killed!\n"))
3472 3452 except KeyboardInterrupt:
3473 3453 try:
3474 3454 u.warn(_("interrupted!\n"))
3475 3455 except IOError, inst:
3476 3456 if inst.errno == errno.EPIPE:
3477 3457 if u.debugflag:
3478 3458 u.warn(_("\nbroken pipe\n"))
3479 3459 else:
3480 3460 raise
3481 3461 except IOError, inst:
3482 3462 if hasattr(inst, "code"):
3483 3463 u.warn(_("abort: %s\n") % inst)
3484 3464 elif hasattr(inst, "reason"):
3485 3465 u.warn(_("abort: error: %s\n") % inst.reason[1])
3486 3466 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3487 3467 if u.debugflag:
3488 3468 u.warn(_("broken pipe\n"))
3489 3469 elif getattr(inst, "strerror", None):
3490 3470 if getattr(inst, "filename", None):
3491 3471 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3492 3472 else:
3493 3473 u.warn(_("abort: %s\n") % inst.strerror)
3494 3474 else:
3495 3475 raise
3496 3476 except OSError, inst:
3497 3477 if hasattr(inst, "filename"):
3498 3478 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3499 3479 else:
3500 3480 u.warn(_("abort: %s\n") % inst.strerror)
3501 3481 except util.Abort, inst:
3502 3482 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3503 3483 except TypeError, inst:
3504 3484 # was this an argument error?
3505 3485 tb = traceback.extract_tb(sys.exc_info()[2])
3506 3486 if len(tb) > 2: # no
3507 3487 raise
3508 3488 u.debug(inst, "\n")
3509 3489 u.warn(_("%s: invalid arguments\n") % cmd)
3510 3490 help_(u, cmd)
3511 3491 except SystemExit, inst:
3512 3492 # Commands shouldn't sys.exit directly, but give a return code.
3513 3493 # Just in case catch this and and pass exit code to caller.
3514 3494 return inst.code
3515 3495 except:
3516 3496 u.warn(_("** unknown exception encountered, details follow\n"))
3517 3497 u.warn(_("** report bug details to "
3518 3498 "http://www.selenic.com/mercurial/bts\n"))
3519 3499 u.warn(_("** or mercurial@selenic.com\n"))
3520 3500 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3521 3501 % version.get_version())
3522 3502 raise
3523 3503
3524 3504 return -1
General Comments 0
You need to be logged in to leave comments. Login now