sapling/tests/test-context.py
Jun Wu e1e3cc79e7 filecommit: add a fast path to reuse raw revision data
Summary:
This is a resend of https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-May/097693.html,
with Yuya's comments addressed and some additional comments.

The original commit message is:

> The high-level idea is similar to metadataonlyctx.
> If filelog parents and metadata match, then raw revision data (rawtext,
> rawflags, hash) could be reused. This saves time calculating hash or going
> through flag processors.

Note in the original patch, the amend operation is not using the fast path.
But it uses the fast path today. That's because singhsrb's D636 change
(cmdutil: remove the redundant commit during amend):

```
                    # If the file being considered is not amongst the files
                    # to be amended, we should return the file context from the
                    # old changeset. This avoids issues when only some files in
                    # the working copy are being amended but there are also
                    # changes to other files from the old changeset.
                    if path not in filestoamend:
                        return old.filectx(path)
```

Reviewed By: DurhamG

Differential Revision: D8986780

fbshipit-source-id: 7d18957a713f90eafb786446972020f7939c3671
2018-07-27 20:06:07 -07:00

223 lines
6.0 KiB
Python

from __future__ import absolute_import, print_function
import os
from mercurial import context, encoding, hg, scmutil, ui as uimod
from mercurial.node import hex
u = uimod.ui.load()
repo = hg.repository(u, "test1", create=1)
os.chdir("test1")
# create 'foo' with fixed time stamp
f = open("foo", "wb")
f.write(b"foo\n")
f.close()
os.utime("foo", (1000, 1000))
# add+commit 'foo'
repo[None].add(["foo"])
repo.commit(text="commit1", date="0 0")
d = repo[None]["foo"].date()
if os.name == "nt":
d = d[:2]
print("workingfilectx.date = (%d, %d)" % d)
# test memctx with non-ASCII commit message
def filectxfn(repo, memctx, path):
return context.memfilectx(repo, memctx, "foo", "")
ctx = context.memctx(
repo, ["tip", None], encoding.tolocal("Gr\xc3\xbcezi!"), ["foo"], filectxfn
)
ctx.commit()
for enc in "ASCII", "Latin-1", "UTF-8":
encoding.encoding = enc
print("%-8s: %s" % (enc, repo["tip"].description()))
# test performing a status
def getfilectx(repo, memctx, f):
fctx = memctx.parents()[0][f]
data, flags = fctx.data(), fctx.flags()
if f == "foo":
data += "bar\n"
return context.memfilectx(repo, memctx, f, data, "l" in flags, "x" in flags)
ctxa = repo.changectx(0)
ctxb = context.memctx(
repo,
[ctxa.node(), None],
"test diff",
["foo"],
getfilectx,
ctxa.user(),
ctxa.date(),
)
print(ctxb.status(ctxa))
# test performing a diff on a memctx
for d in ctxb.diff(ctxa, git=True):
print(d, end="")
# test safeness and correctness of "ctx.status()"
print("= checking context.status():")
# ancestor "wcctx ~ 2"
actx2 = repo["."]
repo.wwrite("bar-m", "bar-m\n", "")
repo.wwrite("bar-r", "bar-r\n", "")
repo[None].add(["bar-m", "bar-r"])
repo.commit(text="add bar-m, bar-r", date="0 0")
# ancestor "wcctx ~ 1"
actx1 = repo["."]
repo.wwrite("bar-m", "bar-m bar-m\n", "")
repo.wwrite("bar-a", "bar-a\n", "")
repo[None].add(["bar-a"])
repo[None].forget(["bar-r"])
# status at this point:
# M bar-m
# A bar-a
# R bar-r
# C foo
print("== checking workingctx.status:")
wctx = repo[None]
print("wctx._status=%s" % (str(wctx._status)))
print('=== with "pattern match":')
print(actx1.status(other=wctx, match=scmutil.matchfiles(repo, ["bar-m", "foo"])))
print("wctx._status=%s" % (str(wctx._status)))
print(actx2.status(other=wctx, match=scmutil.matchfiles(repo, ["bar-m", "foo"])))
print("wctx._status=%s" % (str(wctx._status)))
print('=== with "always match" and "listclean=True":')
print(actx1.status(other=wctx, listclean=True))
print("wctx._status=%s" % (str(wctx._status)))
print(actx2.status(other=wctx, listclean=True))
print("wctx._status=%s" % (str(wctx._status)))
print("== checking workingcommitctx.status:")
wcctx = context.workingcommitctx(
repo, scmutil.status(["bar-m"], ["bar-a"], [], [], [], [], []), text="", date="0 0"
)
print("wcctx._status=%s" % (str(wcctx._status)))
print('=== with "always match":')
print(actx1.status(other=wcctx))
print("wcctx._status=%s" % (str(wcctx._status)))
print(actx2.status(other=wcctx))
print("wcctx._status=%s" % (str(wcctx._status)))
print('=== with "always match" and "listclean=True":')
print(actx1.status(other=wcctx, listclean=True))
print("wcctx._status=%s" % (str(wcctx._status)))
print(actx2.status(other=wcctx, listclean=True))
print("wcctx._status=%s" % (str(wcctx._status)))
print('=== with "pattern match":')
print(actx1.status(other=wcctx, match=scmutil.matchfiles(repo, ["bar-m", "foo"])))
print("wcctx._status=%s" % (str(wcctx._status)))
print(actx2.status(other=wcctx, match=scmutil.matchfiles(repo, ["bar-m", "foo"])))
print("wcctx._status=%s" % (str(wcctx._status)))
print('=== with "pattern match" and "listclean=True":')
print(
actx1.status(
other=wcctx, match=scmutil.matchfiles(repo, ["bar-r", "foo"]), listclean=True
)
)
print("wcctx._status=%s" % (str(wcctx._status)))
print(
actx2.status(
other=wcctx, match=scmutil.matchfiles(repo, ["bar-r", "foo"]), listclean=True
)
)
print("wcctx._status=%s" % (str(wcctx._status)))
os.chdir("..")
# test manifestlog being changed
print("== commit with manifestlog invalidated")
repo = hg.repository(u, "test2", create=1)
os.chdir("test2")
# make some commits
for i in [b"1", b"2", b"3"]:
with open(i, "wb") as f:
f.write(i)
status = scmutil.status([], [i], [], [], [], [], [])
ctx = context.workingcommitctx(
repo, status, text=i, user=b"test@test.com", date=(0, 0)
)
ctx.p1().manifest() # side effect: cache manifestctx
n = repo.commitctx(ctx)
print("commit %s: %s" % (i, hex(n)))
# touch 00manifest.i mtime so storecache could expire.
# repo.__dict__['manifestlog'] is deleted by transaction releasefn.
st = repo.svfs.stat("00manifest.i")
repo.svfs.utime("00manifest.i", (st.st_mtime + 1, st.st_mtime + 1))
# read the file just committed
try:
if repo[n][i].data() != i:
print("data mismatch")
except Exception as ex:
print("cannot read data: %r" % ex)
with repo.wlock(), repo.lock(), repo.transaction("test"):
with open(b"4", "wb") as f:
f.write(b"4")
repo.dirstate.normal("4")
repo.commit("4")
revsbefore = len(repo.changelog)
repo.invalidate(clearfilecache=True)
revsafter = len(repo.changelog)
if revsbefore != revsafter:
print("changeset lost by repo.invalidate()")
# Copy filectx from repo to newrepo using overlayfilectx and memctx
# overlayfilectx implements rawdata, rawflags, and a fast path would
# be used to skip calculating hash.
print("=== filelog rawdata reuse ===")
os.chdir(os.getenv("TESTTMP"))
u.setconfig("ui", "debug", "1")
newrepo = hg.repository(u, "test3", create=1)
def copyctx(newrepo, ctx):
cl = newrepo.changelog
p1 = cl.node(len(cl) - 1)
files = ctx.files()
desc = "copied: %s" % ctx.description()
def getfctx(repo, memctx, path):
if path not in ctx:
return None
return context.overlayfilectx(ctx[path])
return context.memctx(newrepo, [p1, None], desc, files, getfctx)
for rev in repo:
print("copying rev %d from test1 to test3" % rev)
copyctx(newrepo, repo[rev]).commit()