Mercurial > hg
changeset 7787:b8d750daadde
Introduce HG_PREPEND to solve pretxn races
- add writepending to flush delayed writes to separate file
- add support in hooks for lazy evaluation of callable parameters
- add HG_PENDING to pretxn hooks
- call writepending if hook is used
- pass repo root to hook environment
- if HG_PENDING = repo root, we're in pretxn hook
- read pending data to make pending changesets visible
- filter HG_PENDING in tests/printenv.py
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 16 Feb 2009 19:35:07 -0600 |
parents | 92455c1d6f83 |
children | 0896c008cb52 |
files | mercurial/changelog.py mercurial/hook.py mercurial/localrepo.py tests/printenv.py tests/test-hook.out |
diffstat | 5 files changed, 57 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/changelog.py Sun Jan 18 19:59:51 2009 +0100 +++ b/mercurial/changelog.py Mon Feb 16 19:35:07 2009 -0600 @@ -96,7 +96,7 @@ fp = self.opener(self.indexfile, 'a') fp.write("".join(self._delaybuf)) fp.close() - del self._delaybuf + self._delaybuf = [] # split when we're done self.checkinlinesize(tr) @@ -115,6 +115,31 @@ # otherwise, divert to memory return appender(fp, self._delaybuf) + def readpending(self, file): + r = revlog.revlog(self.opener, file) + self.index = r.index + self.nodemap = r.nodemap + self._chunkcache = r._chunkcache + + def writepending(self): + "create a file containing the unfinalized state for pretxnchangegroup" + if self._delaybuf: + # make a temporary copy of the index + fp1 = self._realopener(self.indexfile) + fp2 = self._realopener(self.indexfile + ".a", "w") + fp2.write(fp1.read()) + # add pending data + fp2.write("".join(self._delaybuf)) + fp2.close() + # switch modes so finalize can simply rename + self._delaybuf = [] + self._delayname = fp1.name + + if self._delayname: + return True + + return False + def checkinlinesize(self, tr, fp=None): if self.opener == self._delayopener: return
--- a/mercurial/hook.py Sun Jan 18 19:59:51 2009 +0100 +++ b/mercurial/hook.py Mon Feb 16 19:35:07 2009 -0600 @@ -70,7 +70,13 @@ def _exthook(ui, repo, name, cmd, args, throw): ui.note(_("running hook %s: %s\n") % (name, cmd)) - env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()]) + + env = {} + for k, v in args.iteritems(): + if callable(v): + v = v() + env['HG_' + k.upper()] = v + if repo: cwd = repo.root else:
--- a/mercurial/localrepo.py Sun Jan 18 19:59:51 2009 +0100 +++ b/mercurial/localrepo.py Mon Feb 16 19:35:07 2009 -0600 @@ -88,6 +88,10 @@ def __getattr__(self, name): if name == 'changelog': self.changelog = changelog.changelog(self.sopener) + if 'HG_PENDING' in os.environ: + p = os.environ['HG_PENDING'] + if p.startswith(self.root): + self.changelog.readpending('00changelog.i.a') self.sopener.defversion = self.changelog.version return self.changelog if name == 'manifest': @@ -955,10 +959,13 @@ raise util.Abort(_("empty commit message")) text = '\n'.join(lines) + self.changelog.delayupdate() n = self.changelog.add(mn, changed + removed, text, trp, p1, p2, user, wctx.date(), extra) + p = lambda: self.changelog.writepending() and self.root or "" self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, - parent2=xp2) + parent2=xp2, pending=p) + self.changelog.finalize(trp) tr.close() if self.branchcache: @@ -2034,9 +2041,6 @@ revisions += len(fl) - o files += 1 - # make changelog see real files again - cl.finalize(trp) - newheads = len(self.changelog.heads()) heads = "" if oldheads and newheads != oldheads: @@ -2047,9 +2051,13 @@ % (changesets, revisions, files, heads)) if changesets > 0: + p = lambda: self.changelog.writepending() and self.root or "" self.hook('pretxnchangegroup', throw=True, node=hex(self.changelog.node(cor+1)), source=srctype, - url=url) + url=url, pending=p) + + # make changelog see real files again + cl.finalize(trp) tr.close() finally:
--- a/tests/printenv.py Sun Jan 18 19:59:51 2009 +0100 +++ b/tests/printenv.py Mon Feb 16 19:35:07 2009 -0600 @@ -46,6 +46,9 @@ elif url.startswith("remote:http"): os.environ["HG_URL"] = "remote:http" +if "HG_PENDING" in os.environ: + os.environ["HG_PENDING"] = os.environ["HG_PENDING"] and "true" + out.write("%s hook: " % name) for v in env: out.write("%s=%s " % (v, os.environ[v]))
--- a/tests/test-hook.out Sun Jan 18 19:59:51 2009 +0100 +++ b/tests/test-hook.out Mon Feb 16 19:35:07 2009 -0600 @@ -1,18 +1,18 @@ precommit hook: HG_PARENT1=0000000000000000000000000000000000000000 -pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 +pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=true 0:29b62aeb769f commit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 commit.b hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 updating working directory 1 files updated, 0 files merged, 0 files removed, 0 files unresolved precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b -pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b +pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true 1:b702efe96888 commit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b commit.b hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b 1 files updated, 0 files merged, 0 files removed, 0 files unresolved precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b -pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b +pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true 2:1324a5531bac commit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b commit.b hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b @@ -20,7 +20,7 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) precommit hook: HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 -pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 +pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PENDING=true 3:4c52fb2e4022 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 @@ -43,7 +43,7 @@ (run 'hg update' to get a working copy) pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 -pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 +pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PENDING=true 4:8ea2ef7ad3e8 commit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 commit.b hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 @@ -58,9 +58,9 @@ abort: pretag.forbid hook exited with status 1 4:8ea2ef7ad3e8 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 -pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 +pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true 5:fad284daf8c0 -pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 +pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true transaction abort! rollback completed abort: pretxncommit.forbid1 hook exited with status 1 @@ -80,7 +80,7 @@ searching for changes abort: prechangegroup.forbid hook exited with status 1 4:8ea2ef7ad3e8 -pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull HG_URL=file: +pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true HG_SOURCE=pull HG_URL=file: pulling from ../a searching for changes adding changesets