comparison mercurial/commands.py @ 4959:97b734fb9c6f

Use try/finally pattern to cleanup locks and transactions
author Matt Mackall <mpm@selenic.com>
date Sat, 21 Jul 2007 16:02:10 -0500
parents 9a2a73ea6135
children 126f527b3ba3
comparison
equal deleted inserted replaced
4958:9a2a73ea6135 4959:97b734fb9c6f
674 674
675 This command takes effect in the next commit. To undo a copy 675 This command takes effect in the next commit. To undo a copy
676 before that, see hg revert. 676 before that, see hg revert.
677 """ 677 """
678 wlock = repo.wlock(False) 678 wlock = repo.wlock(False)
679 errs, copied = docopy(ui, repo, pats, opts, wlock) 679 try:
680 errs, copied = docopy(ui, repo, pats, opts, wlock)
681 finally:
682 del wlock
680 return errs 683 return errs
681 684
682 def debugancestor(ui, index, rev1, rev2): 685 def debugancestor(ui, index, rev1, rev2):
683 """find the ancestor revision of two revisions in a given index""" 686 """find the ancestor revision of two revisions in a given index"""
684 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index) 687 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
711 if rev == "": 714 if rev == "":
712 rev = repo.changelog.tip() 715 rev = repo.changelog.tip()
713 ctx = repo.changectx(rev) 716 ctx = repo.changectx(rev)
714 files = ctx.manifest() 717 files = ctx.manifest()
715 wlock = repo.wlock() 718 wlock = repo.wlock()
716 repo.dirstate.rebuild(rev, files) 719 try:
720 repo.dirstate.rebuild(rev, files)
721 finally:
722 del wlock
717 723
718 def debugcheckstate(ui, repo): 724 def debugcheckstate(ui, repo):
719 """validate the correctness of the current dirstate""" 725 """validate the correctness of the current dirstate"""
720 parent1, parent2 = repo.dirstate.parents() 726 parent1, parent2 = repo.dirstate.parents()
721 m1 = repo.changectx(parent1).manifest() 727 m1 = repo.changectx(parent1).manifest()
780 786
781 wlock = repo.wlock() 787 wlock = repo.wlock()
782 try: 788 try:
783 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2)) 789 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
784 finally: 790 finally:
785 wlock.release() 791 del wlock
786 792
787 def debugstate(ui, repo): 793 def debugstate(ui, repo):
788 """show the contents of the current dirstate""" 794 """show the contents of the current dirstate"""
789 dc = repo.dirstate._map 795 dc = repo.dirstate._map
790 k = dc.keys() 796 k = dc.keys()
1579 if opts.get('exact') or not opts['force']: 1585 if opts.get('exact') or not opts['force']:
1580 cmdutil.bail_if_changed(repo) 1586 cmdutil.bail_if_changed(repo)
1581 1587
1582 d = opts["base"] 1588 d = opts["base"]
1583 strip = opts["strip"] 1589 strip = opts["strip"]
1584 1590 wlock = lock = None
1585 wlock = repo.wlock() 1591 try:
1586 lock = repo.lock() 1592 wlock = repo.wlock()
1587 1593 lock = repo.lock()
1588 for p in patches: 1594 for p in patches:
1589 pf = os.path.join(d, p) 1595 pf = os.path.join(d, p)
1590 1596
1591 if pf == '-': 1597 if pf == '-':
1592 ui.status(_("applying patch from stdin\n")) 1598 ui.status(_("applying patch from stdin\n"))
1593 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin) 1599 data = patch.extract(ui, sys.stdin)
1594 else:
1595 ui.status(_("applying %s\n") % p)
1596 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1597
1598 if tmpname is None:
1599 raise util.Abort(_('no diffs found'))
1600
1601 try:
1602 cmdline_message = cmdutil.logmessage(opts)
1603 if cmdline_message:
1604 # pickup the cmdline msg
1605 message = cmdline_message
1606 elif message:
1607 # pickup the patch msg
1608 message = message.strip()
1609 else: 1600 else:
1610 # launch the editor 1601 ui.status(_("applying %s\n") % p)
1611 message = None 1602 data = patch.extract(ui, file(pf, 'rb'))
1612 ui.debug(_('message:\n%s\n') % message) 1603
1613 1604 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1614 wp = repo.workingctx().parents() 1605
1615 if opts.get('exact'): 1606 if tmpname is None:
1616 if not nodeid or not p1: 1607 raise util.Abort(_('no diffs found'))
1617 raise util.Abort(_('not a mercurial patch')) 1608
1618 p1 = repo.lookup(p1) 1609 try:
1619 p2 = repo.lookup(p2 or hex(nullid)) 1610 cmdline_message = cmdutil.logmessage(opts)
1620 1611 if cmdline_message:
1621 if p1 != wp[0].node(): 1612 # pickup the cmdline msg
1622 hg.clean(repo, p1, wlock=wlock) 1613 message = cmdline_message
1623 repo.dirstate.setparents(p1, p2) 1614 elif message:
1624 elif p2: 1615 # pickup the patch msg
1616 message = message.strip()
1617 else:
1618 # launch the editor
1619 message = None
1620 ui.debug(_('message:\n%s\n') % message)
1621
1622 wp = repo.workingctx().parents()
1623 if opts.get('exact'):
1624 if not nodeid or not p1:
1625 raise util.Abort(_('not a mercurial patch'))
1626 p1 = repo.lookup(p1)
1627 p2 = repo.lookup(p2 or hex(nullid))
1628
1629 if p1 != wp[0].node():
1630 hg.clean(repo, p1, wlock=wlock)
1631 repo.dirstate.setparents(p1, p2)
1632 elif p2:
1633 try:
1634 p1 = repo.lookup(p1)
1635 p2 = repo.lookup(p2)
1636 if p1 == wp[0].node():
1637 repo.dirstate.setparents(p1, p2)
1638 except hg.RepoError:
1639 pass
1640 if opts.get('exact') or opts.get('import_branch'):
1641 repo.dirstate.setbranch(branch or 'default')
1642
1643 files = {}
1625 try: 1644 try:
1626 p1 = repo.lookup(p1) 1645 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1627 p2 = repo.lookup(p2) 1646 files=files)
1628 if p1 == wp[0].node(): 1647 finally:
1629 repo.dirstate.setparents(p1, p2) 1648 files = patch.updatedir(ui, repo, files, wlock=wlock)
1630 except hg.RepoError: 1649 n = repo.commit(files, message, user, date, wlock=wlock,
1631 pass 1650 lock=lock)
1632 if opts.get('exact') or opts.get('import_branch'): 1651 if opts.get('exact'):
1633 repo.dirstate.setbranch(branch or 'default') 1652 if hex(n) != nodeid:
1634 1653 repo.rollback(wlock=wlock, lock=lock)
1635 files = {} 1654 raise util.Abort(_('patch is damaged' +
1636 try: 1655 ' or loses information'))
1637 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1638 files=files)
1639 finally: 1656 finally:
1640 files = patch.updatedir(ui, repo, files, wlock=wlock) 1657 os.unlink(tmpname)
1641 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock) 1658 finally:
1642 if opts.get('exact'): 1659 del wlock, lock
1643 if hex(n) != nodeid:
1644 repo.rollback(wlock=wlock, lock=lock)
1645 raise util.Abort(_('patch is damaged or loses information'))
1646 finally:
1647 os.unlink(tmpname)
1648 1660
1649 def incoming(ui, repo, source="default", **opts): 1661 def incoming(ui, repo, source="default", **opts):
1650 """show new changesets found in source 1662 """show new changesets found in source
1651 1663
1652 Show new changesets found in the specified path/URL or the default 1664 Show new changesets found in the specified path/URL or the default
2246 2258
2247 This command takes effect in the next commit. To undo a rename 2259 This command takes effect in the next commit. To undo a rename
2248 before that, see hg revert. 2260 before that, see hg revert.
2249 """ 2261 """
2250 wlock = repo.wlock(False) 2262 wlock = repo.wlock(False)
2251 errs, copied = docopy(ui, repo, pats, opts, wlock) 2263 try:
2252 names = [] 2264 errs, copied = docopy(ui, repo, pats, opts, wlock)
2253 for abs, rel, exact in copied: 2265 names = []
2254 if ui.verbose or not exact: 2266 for abs, rel, exact in copied:
2255 ui.status(_('removing %s\n') % rel) 2267 if ui.verbose or not exact:
2256 names.append(abs) 2268 ui.status(_('removing %s\n') % rel)
2257 if not opts.get('dry_run'): 2269 names.append(abs)
2258 repo.remove(names, True, wlock=wlock) 2270 if not opts.get('dry_run'):
2259 return errs 2271 repo.remove(names, True, wlock=wlock)
2272 return errs
2273 finally:
2274 del wlock
2260 2275
2261 def revert(ui, repo, *pats, **opts): 2276 def revert(ui, repo, *pats, **opts):
2262 """revert files or dirs to their states as of some revision 2277 """revert files or dirs to their states as of some revision
2263 2278
2264 With no revision specified, revert the named files or directories 2279 With no revision specified, revert the named files or directories
2308 if node == parent: 2323 if node == parent:
2309 pmf = mf 2324 pmf = mf
2310 else: 2325 else:
2311 pmf = None 2326 pmf = None
2312 2327
2313 wlock = repo.wlock()
2314
2315 # need all matching names in dirstate and manifest of target rev, 2328 # need all matching names in dirstate and manifest of target rev,
2316 # so have to walk both. do not print errors if files exist in one 2329 # so have to walk both. do not print errors if files exist in one
2317 # but not other. 2330 # but not other.
2318 2331
2319 names = {} 2332 names = {}
2320 target_only = {} 2333 target_only = {}
2321 2334
2322 # walk dirstate. 2335 wlock = repo.wlock()
2323 2336 try:
2324 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, 2337 # walk dirstate.
2325 badmatch=mf.has_key): 2338 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2326 names[abs] = (rel, exact) 2339 badmatch=mf.has_key):
2327 if src == 'b': 2340 names[abs] = (rel, exact)
2341 if src == 'b':
2342 target_only[abs] = True
2343
2344 # walk target manifest.
2345
2346 def badmatch(path):
2347 if path in names:
2348 return True
2349 path_ = path + '/'
2350 for f in names:
2351 if f.startswith(path_):
2352 return True
2353 return False
2354
2355 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2356 badmatch=badmatch):
2357 if abs in names or src == 'b':
2358 continue
2359 names[abs] = (rel, exact)
2328 target_only[abs] = True 2360 target_only[abs] = True
2329 2361
2330 # walk target manifest. 2362 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2331 2363 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2332 def badmatch(path): 2364
2333 if path in names: 2365 revert = ([], _('reverting %s\n'))
2334 return True 2366 add = ([], _('adding %s\n'))
2335 path_ = path + '/' 2367 remove = ([], _('removing %s\n'))
2336 for f in names: 2368 forget = ([], _('forgetting %s\n'))
2337 if f.startswith(path_): 2369 undelete = ([], _('undeleting %s\n'))
2338 return True 2370 update = {}
2339 return False 2371
2340 2372 disptable = (
2341 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, 2373 # dispatch table:
2342 badmatch=badmatch): 2374 # file state
2343 if abs in names or src == 'b': 2375 # action if in target manifest
2344 continue 2376 # action if not in target manifest
2345 names[abs] = (rel, exact) 2377 # make backup if in target manifest
2346 target_only[abs] = True 2378 # make backup if not in target manifest
2347 2379 (modified, revert, remove, True, True),
2348 changes = repo.status(match=names.has_key, wlock=wlock)[:5] 2380 (added, revert, forget, True, False),
2349 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) 2381 (removed, undelete, None, False, False),
2350 2382 (deleted, revert, remove, False, False),
2351 revert = ([], _('reverting %s\n')) 2383 (unknown, add, None, True, False),
2352 add = ([], _('adding %s\n')) 2384 (target_only, add, None, False, False),
2353 remove = ([], _('removing %s\n')) 2385 )
2354 forget = ([], _('forgetting %s\n')) 2386
2355 undelete = ([], _('undeleting %s\n')) 2387 entries = names.items()
2356 update = {} 2388 entries.sort()
2357 2389
2358 disptable = ( 2390 for abs, (rel, exact) in entries:
2359 # dispatch table: 2391 mfentry = mf.get(abs)
2360 # file state 2392 target = repo.wjoin(abs)
2361 # action if in target manifest 2393 def handle(xlist, dobackup):
2362 # action if not in target manifest 2394 xlist[0].append(abs)
2363 # make backup if in target manifest 2395 update[abs] = 1
2364 # make backup if not in target manifest 2396 if dobackup and not opts['no_backup'] and util.lexists(target):
2365 (modified, revert, remove, True, True), 2397 bakname = "%s.orig" % rel
2366 (added, revert, forget, True, False), 2398 ui.note(_('saving current version of %s as %s\n') %
2367 (removed, undelete, None, False, False), 2399 (rel, bakname))
2368 (deleted, revert, remove, False, False), 2400 if not opts.get('dry_run'):
2369 (unknown, add, None, True, False), 2401 util.copyfile(target, bakname)
2370 (target_only, add, None, False, False), 2402 if ui.verbose or not exact:
2371 ) 2403 ui.status(xlist[1] % rel)
2372 2404 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2373 entries = names.items() 2405 if abs not in table: continue
2374 entries.sort() 2406 # file has changed in dirstate
2375 2407 if mfentry:
2376 for abs, (rel, exact) in entries: 2408 handle(hitlist, backuphit)
2377 mfentry = mf.get(abs) 2409 elif misslist is not None:
2378 target = repo.wjoin(abs) 2410 handle(misslist, backupmiss)
2379 def handle(xlist, dobackup): 2411 else:
2380 xlist[0].append(abs) 2412 if exact: ui.warn(_('file not managed: %s\n') % rel)
2381 update[abs] = 1 2413 break
2382 if dobackup and not opts['no_backup'] and util.lexists(target):
2383 bakname = "%s.orig" % rel
2384 ui.note(_('saving current version of %s as %s\n') %
2385 (rel, bakname))
2386 if not opts.get('dry_run'):
2387 util.copyfile(target, bakname)
2388 if ui.verbose or not exact:
2389 ui.status(xlist[1] % rel)
2390 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2391 if abs not in table: continue
2392 # file has changed in dirstate
2393 if mfentry:
2394 handle(hitlist, backuphit)
2395 elif misslist is not None:
2396 handle(misslist, backupmiss)
2397 else: 2414 else:
2398 if exact: ui.warn(_('file not managed: %s\n') % rel) 2415 # file has not changed in dirstate
2399 break 2416 if node == parent:
2400 else: 2417 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2401 # file has not changed in dirstate 2418 continue
2402 if node == parent: 2419 if pmf is None:
2403 if exact: ui.warn(_('no changes needed to %s\n') % rel) 2420 # only need parent manifest in this unlikely case,
2404 continue 2421 # so do not read by default
2405 if pmf is None: 2422 pmf = repo.changectx(parent).manifest()
2406 # only need parent manifest in this unlikely case, 2423 if abs in pmf:
2407 # so do not read by default 2424 if mfentry:
2408 pmf = repo.changectx(parent).manifest() 2425 # if version of file is same in parent and target
2409 if abs in pmf: 2426 # manifests, do nothing
2410 if mfentry: 2427 if pmf[abs] != mfentry:
2411 # if version of file is same in parent and target 2428 handle(revert, False)
2412 # manifests, do nothing 2429 else:
2413 if pmf[abs] != mfentry: 2430 handle(remove, False)
2414 handle(revert, False) 2431
2415 else: 2432 if not opts.get('dry_run'):
2416 handle(remove, False) 2433 for f in forget[0]:
2417 2434 repo.dirstate.forget(f)
2418 if not opts.get('dry_run'): 2435 r = hg.revert(repo, node, update.has_key, wlock)
2419 for f in forget[0]: 2436 for f in add[0]:
2420 repo.dirstate.forget(f) 2437 repo.dirstate.add(f)
2421 r = hg.revert(repo, node, update.has_key, wlock) 2438 for f in undelete[0]:
2422 for f in add[0]: 2439 repo.dirstate.normal(f)
2423 repo.dirstate.add(f) 2440 for f in remove[0]:
2424 for f in undelete[0]: 2441 repo.dirstate.remove(f)
2425 repo.dirstate.normal(f) 2442 return r
2426 for f in remove[0]: 2443 finally:
2427 repo.dirstate.remove(f) 2444 del wlock
2428 return r
2429 2445
2430 def rollback(ui, repo): 2446 def rollback(ui, repo):
2431 """roll back the last transaction in this repository 2447 """roll back the last transaction in this repository
2432 2448
2433 Roll back the last transaction in this repository, restoring the 2449 Roll back the last transaction in this repository, restoring the