Mercurial > hg-stable
diff mercurial/localrepo.py @ 4915: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 | 5c5d23d93447 |
line wrap: on
line diff
--- a/mercurial/localrepo.py Sat Jul 21 16:02:09 2007 -0500 +++ b/mercurial/localrepo.py Sat Jul 21 16:02:10 2007 -0500 @@ -516,28 +516,34 @@ def recover(self): l = self.lock() - if os.path.exists(self.sjoin("journal")): - self.ui.status(_("rolling back interrupted transaction\n")) - transaction.rollback(self.sopener, self.sjoin("journal")) - self.invalidate() - return True - else: - self.ui.warn(_("no interrupted transaction available\n")) - return False + try: + if os.path.exists(self.sjoin("journal")): + self.ui.status(_("rolling back interrupted transaction\n")) + transaction.rollback(self.sopener, self.sjoin("journal")) + self.invalidate() + return True + else: + self.ui.warn(_("no interrupted transaction available\n")) + return False + finally: + del l def rollback(self, wlock=None, lock=None): - if not wlock: - wlock = self.wlock() - if not lock: - lock = self.lock() - if os.path.exists(self.sjoin("undo")): - self.ui.status(_("rolling back last transaction\n")) - transaction.rollback(self.sopener, self.sjoin("undo")) - util.rename(self.join("undo.dirstate"), self.join("dirstate")) - self.invalidate() - self.dirstate.invalidate() - else: - self.ui.warn(_("no rollback information available\n")) + try: + if not wlock: + wlock = self.wlock() + if not lock: + lock = self.lock() + if os.path.exists(self.sjoin("undo")): + self.ui.status(_("rolling back last transaction\n")) + transaction.rollback(self.sopener, self.sjoin("undo")) + util.rename(self.join("undo.dirstate"), self.join("dirstate")) + self.invalidate() + self.dirstate.invalidate() + else: + self.ui.warn(_("no rollback information available\n")) + finally: + del wlock, lock def invalidate(self): for a in "changelog manifest".split(): @@ -639,164 +645,169 @@ def commit(self, files=None, text="", user=None, date=None, match=util.always, force=False, lock=None, wlock=None, force_editor=False, p1=None, p2=None, extra={}): - - commit = [] - remove = [] - changed = [] - use_dirstate = (p1 is None) # not rawcommit - extra = extra.copy() + tr = None + try: + commit = [] + remove = [] + changed = [] + use_dirstate = (p1 is None) # not rawcommit + extra = extra.copy() - if use_dirstate: - if files: - for f in files: - s = self.dirstate[f] - if s in 'nma': - commit.append(f) - elif s == 'r': - remove.append(f) - else: - self.ui.warn(_("%s not tracked!\n") % f) + if use_dirstate: + if files: + for f in files: + s = self.dirstate[f] + if s in 'nma': + commit.append(f) + elif s == 'r': + remove.append(f) + else: + self.ui.warn(_("%s not tracked!\n") % f) + else: + changes = self.status(match=match)[:5] + modified, added, removed, deleted, unknown = changes + commit = modified + added + remove = removed else: - changes = self.status(match=match)[:5] - modified, added, removed, deleted, unknown = changes - commit = modified + added - remove = removed - else: - commit = files + commit = files - if use_dirstate: - p1, p2 = self.dirstate.parents() - update_dirstate = True - else: - p1, p2 = p1, p2 or nullid - update_dirstate = (self.dirstate.parents()[0] == p1) + if use_dirstate: + p1, p2 = self.dirstate.parents() + update_dirstate = True + else: + p1, p2 = p1, p2 or nullid + update_dirstate = (self.dirstate.parents()[0] == p1) - c1 = self.changelog.read(p1) - c2 = self.changelog.read(p2) - m1 = self.manifest.read(c1[0]).copy() - m2 = self.manifest.read(c2[0]) + c1 = self.changelog.read(p1) + c2 = self.changelog.read(p2) + m1 = self.manifest.read(c1[0]).copy() + m2 = self.manifest.read(c2[0]) - if use_dirstate: - branchname = self.workingctx().branch() - try: - branchname = branchname.decode('UTF-8').encode('UTF-8') - except UnicodeDecodeError: - raise util.Abort(_('branch name not in UTF-8!')) - else: - branchname = "" + if use_dirstate: + branchname = self.workingctx().branch() + try: + branchname = branchname.decode('UTF-8').encode('UTF-8') + except UnicodeDecodeError: + raise util.Abort(_('branch name not in UTF-8!')) + else: + branchname = "" - if use_dirstate: - oldname = c1[5].get("branch") # stored in UTF-8 - if (not commit and not remove and not force and p2 == nullid - and branchname == oldname): - self.ui.status(_("nothing changed\n")) - return None + if use_dirstate: + oldname = c1[5].get("branch") # stored in UTF-8 + if (not commit and not remove and not force and p2 == nullid + and branchname == oldname): + self.ui.status(_("nothing changed\n")) + return None - xp1 = hex(p1) - if p2 == nullid: xp2 = '' - else: xp2 = hex(p2) + xp1 = hex(p1) + if p2 == nullid: xp2 = '' + else: xp2 = hex(p2) - self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) + self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) - if not wlock: - wlock = self.wlock() - if not lock: - lock = self.lock() - tr = self.transaction() + if not wlock: + wlock = self.wlock() + if not lock: + lock = self.lock() + tr = self.transaction() - # check in files - new = {} - linkrev = self.changelog.count() - commit.sort() - is_exec = util.execfunc(self.root, m1.execf) - is_link = util.linkfunc(self.root, m1.linkf) - for f in commit: - self.ui.note(f + "\n") - try: - new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed) - new_exec = is_exec(f) - new_link = is_link(f) - if not changed or changed[-1] != f: - # mention the file in the changelog if some flag changed, - # even if there was no content change. - old_exec = m1.execf(f) - old_link = m1.linkf(f) - if old_exec != new_exec or old_link != new_link: - changed.append(f) - m1.set(f, new_exec, new_link) - except (OSError, IOError): - if use_dirstate: - self.ui.warn(_("trouble committing %s!\n") % f) - raise - else: - remove.append(f) + # check in files + new = {} + linkrev = self.changelog.count() + commit.sort() + is_exec = util.execfunc(self.root, m1.execf) + is_link = util.linkfunc(self.root, m1.linkf) + for f in commit: + self.ui.note(f + "\n") + try: + new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed) + new_exec = is_exec(f) + new_link = is_link(f) + if not changed or changed[-1] != f: + # mention the file in the changelog if some + # flag changed, even if there was no content + # change. + old_exec = m1.execf(f) + old_link = m1.linkf(f) + if old_exec != new_exec or old_link != new_link: + changed.append(f) + m1.set(f, new_exec, new_link) + except (OSError, IOError): + if use_dirstate: + self.ui.warn(_("trouble committing %s!\n") % f) + raise + else: + remove.append(f) - # update manifest - m1.update(new) - remove.sort() - removed = [] + # update manifest + m1.update(new) + remove.sort() + removed = [] - for f in remove: - if f in m1: - del m1[f] - removed.append(f) - elif f in m2: - removed.append(f) - mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, removed)) + for f in remove: + if f in m1: + del m1[f] + removed.append(f) + elif f in m2: + removed.append(f) + mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], + (new, removed)) - # add changeset - new = new.keys() - new.sort() + # add changeset + new = new.keys() + new.sort() - user = user or self.ui.username() - if not text or force_editor: - edittext = [] - if text: - edittext.append(text) - edittext.append("") - edittext.append("HG: user: %s" % user) - if p2 != nullid: - edittext.append("HG: branch merge") - if branchname: - edittext.append("HG: branch %s" % util.tolocal(branchname)) - edittext.extend(["HG: changed %s" % f for f in changed]) - edittext.extend(["HG: removed %s" % f for f in removed]) - if not changed and not remove: - edittext.append("HG: no files changed") - edittext.append("") - # run editor in the repository root - olddir = os.getcwd() - os.chdir(self.root) - text = self.ui.edit("\n".join(edittext), user) - os.chdir(olddir) + user = user or self.ui.username() + if not text or force_editor: + edittext = [] + if text: + edittext.append(text) + edittext.append("") + edittext.append("HG: user: %s" % user) + if p2 != nullid: + edittext.append("HG: branch merge") + if branchname: + edittext.append("HG: branch %s" % util.tolocal(branchname)) + edittext.extend(["HG: changed %s" % f for f in changed]) + edittext.extend(["HG: removed %s" % f for f in removed]) + if not changed and not remove: + edittext.append("HG: no files changed") + edittext.append("") + # run editor in the repository root + olddir = os.getcwd() + os.chdir(self.root) + text = self.ui.edit("\n".join(edittext), user) + os.chdir(olddir) - lines = [line.rstrip() for line in text.rstrip().splitlines()] - while lines and not lines[0]: - del lines[0] - if not lines: - return None - text = '\n'.join(lines) - if branchname: - extra["branch"] = branchname - n = self.changelog.add(mn, changed + removed, text, tr, p1, p2, - user, date, extra) - self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, - parent2=xp2) - tr.close() + lines = [line.rstrip() for line in text.rstrip().splitlines()] + while lines and not lines[0]: + del lines[0] + if not lines: + return None + text = '\n'.join(lines) + if branchname: + extra["branch"] = branchname + n = self.changelog.add(mn, changed + removed, text, tr, p1, p2, + user, date, extra) + self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, + parent2=xp2) + tr.close() - if self.branchcache and "branch" in extra: - self.branchcache[util.tolocal(extra["branch"])] = n + if self.branchcache and "branch" in extra: + self.branchcache[util.tolocal(extra["branch"])] = n - if use_dirstate or update_dirstate: - self.dirstate.setparents(n) - if use_dirstate: - for f in new: - self.dirstate.normal(f) - for f in removed: - self.dirstate.forget(f) + if use_dirstate or update_dirstate: + self.dirstate.setparents(n) + if use_dirstate: + for f in new: + self.dirstate.normal(f) + for f in removed: + self.dirstate.forget(f) - self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) - return n + self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) + return n + finally: + del lock, wlock, tr def walk(self, node=None, files=[], match=util.always, badmatch=None): ''' @@ -895,18 +906,18 @@ # update dirstate for files that are actually clean if fixup: - cleanup = False - if not wlock: - try: - wlock = self.wlock(False) - cleanup = True - except lock.LockException: - pass - if wlock: - for f in fixup: - self.dirstate.normal(f) - if cleanup: - wlock.release() + fixlock = wlock + try: + if not fixlock: + try: + fixlock = self.wlock(False) + except lock.LockException: + pass + if fixlock: + for f in fixup: + self.dirstate.normal(f) + finally: + del fixlock else: # we are comparing working dir against non-parent # generate a pseudo-manifest for the working dir @@ -954,84 +965,99 @@ return (modified, added, removed, deleted, unknown, ignored, clean) def add(self, list, wlock=None): - if not wlock: - wlock = self.wlock() - for f in list: - p = self.wjoin(f) - try: - st = os.lstat(p) - except: - self.ui.warn(_("%s does not exist!\n") % f) - continue - if st.st_size > 10000000: - self.ui.warn(_("%s: files over 10MB may cause memory and" - " performance problems\n" - "(use 'hg revert %s' to unadd the file)\n") - % (f, f)) - if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): - self.ui.warn(_("%s not added: only files and symlinks " - "supported currently\n") % f) - elif self.dirstate[f] in 'an': - self.ui.warn(_("%s already tracked!\n") % f) - else: - self.dirstate.add(f) + try: + if not wlock: + wlock = self.wlock() + for f in list: + p = self.wjoin(f) + try: + st = os.lstat(p) + except: + self.ui.warn(_("%s does not exist!\n") % f) + continue + if st.st_size > 10000000: + self.ui.warn(_("%s: files over 10MB may cause memory and" + " performance problems\n" + "(use 'hg revert %s' to unadd the file)\n") + % (f, f)) + if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): + self.ui.warn(_("%s not added: only files and symlinks " + "supported currently\n") % f) + elif self.dirstate[f] in 'an': + self.ui.warn(_("%s already tracked!\n") % f) + else: + self.dirstate.add(f) + finally: + del wlock def forget(self, list, wlock=None): - if not wlock: - wlock = self.wlock() - for f in list: - if self.dirstate[f] != 'a': - self.ui.warn(_("%s not added!\n") % f) - else: - self.dirstate.forget(f) + try: + if not wlock: + wlock = self.wlock() + for f in list: + if self.dirstate[f] != 'a': + self.ui.warn(_("%s not added!\n") % f) + else: + self.dirstate.forget(f) + finally: + del wlock def remove(self, list, unlink=False, wlock=None): - if unlink: + try: + if unlink: + for f in list: + try: + util.unlink(self.wjoin(f)) + except OSError, inst: + if inst.errno != errno.ENOENT: + raise + if not wlock: + wlock = self.wlock() for f in list: - try: - util.unlink(self.wjoin(f)) - except OSError, inst: - if inst.errno != errno.ENOENT: - raise - if not wlock: - wlock = self.wlock() - for f in list: - if unlink and os.path.exists(self.wjoin(f)): - self.ui.warn(_("%s still exists!\n") % f) - elif self.dirstate[f] == 'a': - self.dirstate.forget(f) - elif f not in self.dirstate: - self.ui.warn(_("%s not tracked!\n") % f) - else: - self.dirstate.remove(f) + if unlink and os.path.exists(self.wjoin(f)): + self.ui.warn(_("%s still exists!\n") % f) + elif self.dirstate[f] == 'a': + self.dirstate.forget(f) + elif f not in self.dirstate: + self.ui.warn(_("%s not tracked!\n") % f) + else: + self.dirstate.remove(f) + finally: + del wlock def undelete(self, list, wlock=None): - p = self.dirstate.parents()[0] - mn = self.changelog.read(p)[0] - m = self.manifest.read(mn) - if not wlock: - wlock = self.wlock() - for f in list: - if self.dirstate[f] != 'r': - self.ui.warn("%s not removed!\n" % f) - else: - t = self.file(f).read(m[f]) - self.wwrite(f, t, m.flags(f)) - self.dirstate.normal(f) + try: + p = self.dirstate.parents()[0] + mn = self.changelog.read(p)[0] + m = self.manifest.read(mn) + if not wlock: + wlock = self.wlock() + for f in list: + if self.dirstate[f] != 'r': + self.ui.warn("%s not removed!\n" % f) + else: + t = self.file(f).read(m[f]) + self.wwrite(f, t, m.flags(f)) + self.dirstate.normal(f) + finally: + del wlock def copy(self, source, dest, wlock=None): - p = self.wjoin(dest) - if not (os.path.exists(p) or os.path.islink(p)): - self.ui.warn(_("%s does not exist!\n") % dest) - elif not (os.path.isfile(p) or os.path.islink(p)): - self.ui.warn(_("copy failed: %s is not a file or a " - "symbolic link\n") % dest) - else: - if not wlock: - wlock = self.wlock() - if dest not in self.dirstate: - self.dirstate.add(dest) - self.dirstate.copy(source, dest) + try: + p = self.wjoin(dest) + if not (os.path.exists(p) or os.path.islink(p)): + self.ui.warn(_("%s does not exist!\n") % dest) + elif not (os.path.isfile(p) or os.path.islink(p)): + self.ui.warn(_("copy failed: %s is not a file or a " + "symbolic link\n") % dest) + else: + if not wlock: + wlock = self.wlock() + if dest not in self.dirstate: + self.dirstate.add(dest) + self.dirstate.copy(source, dest) + finally: + del wlock def heads(self, start=None): heads = self.changelog.heads(start) @@ -1309,12 +1335,9 @@ return subset def pull(self, remote, heads=None, force=False, lock=None): - mylock = False - if not lock: - lock = self.lock() - mylock = True - try: + if not lock: + lock = self.lock() fetch = self.findincoming(remote, force=force) if fetch == [nullid]: self.ui.status(_("requesting all changes\n")) @@ -1331,8 +1354,7 @@ cg = remote.changegroupsubset(fetch, heads, 'pull') return self.addchangegroup(cg, 'pull', remote.url()) finally: - if mylock: - lock.release() + del lock def push(self, remote, force=False, revs=None): # there are two ways to push to remote repo: @@ -1405,12 +1427,14 @@ def push_addchangegroup(self, remote, force, revs): lock = remote.lock() - - ret = self.prepush(remote, force, revs) - if ret[0] is not None: - cg, remote_heads = ret - return remote.addchangegroup(cg, 'push', self.url()) - return ret[1] + try: + ret = self.prepush(remote, force, revs) + if ret[0] is not None: + cg, remote_heads = ret + return remote.addchangegroup(cg, 'push', self.url()) + return ret[1] + finally: + del lock def push_unbundle(self, remote, force, revs): # local repo finds heads on server, finds out what revs it @@ -1794,65 +1818,67 @@ changesets = files = revisions = 0 - tr = self.transaction() - # write changelog data to temp files so concurrent readers will not see # inconsistent view cl = self.changelog cl.delayupdate() oldheads = len(cl.heads()) - # pull off the changeset group - self.ui.status(_("adding changesets\n")) - cor = cl.count() - 1 - chunkiter = changegroup.chunkiter(source) - if cl.addgroup(chunkiter, csmap, tr, 1) is None: - raise util.Abort(_("received changelog group is empty")) - cnr = cl.count() - 1 - changesets = cnr - cor + tr = self.transaction() + try: + # pull off the changeset group + self.ui.status(_("adding changesets\n")) + cor = cl.count() - 1 + chunkiter = changegroup.chunkiter(source) + if cl.addgroup(chunkiter, csmap, tr, 1) is None: + raise util.Abort(_("received changelog group is empty")) + cnr = cl.count() - 1 + changesets = cnr - cor - # pull off the manifest group - self.ui.status(_("adding manifests\n")) - chunkiter = changegroup.chunkiter(source) - # no need to check for empty manifest group here: - # if the result of the merge of 1 and 2 is the same in 3 and 4, - # no new manifest will be created and the manifest group will - # be empty during the pull - self.manifest.addgroup(chunkiter, revmap, tr) + # pull off the manifest group + self.ui.status(_("adding manifests\n")) + chunkiter = changegroup.chunkiter(source) + # no need to check for empty manifest group here: + # if the result of the merge of 1 and 2 is the same in 3 and 4, + # no new manifest will be created and the manifest group will + # be empty during the pull + self.manifest.addgroup(chunkiter, revmap, tr) - # process the files - self.ui.status(_("adding file changes\n")) - while 1: - f = changegroup.getchunk(source) - if not f: - break - self.ui.debug(_("adding %s revisions\n") % f) - fl = self.file(f) - o = fl.count() - chunkiter = changegroup.chunkiter(source) - if fl.addgroup(chunkiter, revmap, tr) is None: - raise util.Abort(_("received file revlog group is empty")) - revisions += fl.count() - o - files += 1 + # process the files + self.ui.status(_("adding file changes\n")) + while 1: + f = changegroup.getchunk(source) + if not f: + break + self.ui.debug(_("adding %s revisions\n") % f) + fl = self.file(f) + o = fl.count() + chunkiter = changegroup.chunkiter(source) + if fl.addgroup(chunkiter, revmap, tr) is None: + raise util.Abort(_("received file revlog group is empty")) + revisions += fl.count() - o + files += 1 + + # make changelog see real files again + cl.finalize(tr) - # make changelog see real files again - cl.finalize(tr) + newheads = len(self.changelog.heads()) + heads = "" + if oldheads and newheads != oldheads: + heads = _(" (%+d heads)") % (newheads - oldheads) - newheads = len(self.changelog.heads()) - heads = "" - if oldheads and newheads != oldheads: - heads = _(" (%+d heads)") % (newheads - oldheads) + self.ui.status(_("added %d changesets" + " with %d changes to %d files%s\n") + % (changesets, revisions, files, heads)) - self.ui.status(_("added %d changesets" - " with %d changes to %d files%s\n") - % (changesets, revisions, files, heads)) + if changesets > 0: + self.hook('pretxnchangegroup', throw=True, + node=hex(self.changelog.node(cor+1)), source=srctype, + url=url) - if changesets > 0: - self.hook('pretxnchangegroup', throw=True, - node=hex(self.changelog.node(cor+1)), source=srctype, - url=url) - - tr.close() + tr.close() + finally: + del tr if changesets > 0: self.hook("changegroup", node=hex(self.changelog.node(cor+1)),