filemerge._mergecheck: add check for change/delete conflicts
Merge tools that perform an actual 3-way merge can't handle change/delete
conflicts. This adds a check for that.
import sys, os, subprocess
if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
'cacheable']):
sys.exit(80)
from mercurial import util, scmutil, extensions, hg, ui
filecache = scmutil.filecache
class fakerepo(object):
def __init__(self):
self._filecache = {}
def join(self, p):
return p
def sjoin(self, p):
return p
@filecache('x', 'y')
def cached(self):
print 'creating'
return 'string from function'
def invalidate(self):
for k in self._filecache:
try:
delattr(self, k)
except AttributeError:
pass
def basic(repo):
print "* neither file exists"
# calls function
repo.cached
repo.invalidate()
print "* neither file still exists"
# uses cache
repo.cached
# create empty file
f = open('x', 'w')
f.close()
repo.invalidate()
print "* empty file x created"
# should recreate the object
repo.cached
f = open('x', 'w')
f.write('a')
f.close()
repo.invalidate()
print "* file x changed size"
# should recreate the object
repo.cached
repo.invalidate()
print "* nothing changed with either file"
# stats file again, reuses object
repo.cached
# atomic replace file, size doesn't change
# hopefully st_mtime doesn't change as well so this doesn't use the cache
# because of inode change
f = scmutil.opener('.')('x', 'w', atomictemp=True)
f.write('b')
f.close()
repo.invalidate()
print "* file x changed inode"
repo.cached
# create empty file y
f = open('y', 'w')
f.close()
repo.invalidate()
print "* empty file y created"
# should recreate the object
repo.cached
f = open('y', 'w')
f.write('A')
f.close()
repo.invalidate()
print "* file y changed size"
# should recreate the object
repo.cached
f = scmutil.opener('.')('y', 'w', atomictemp=True)
f.write('B')
f.close()
repo.invalidate()
print "* file y changed inode"
repo.cached
f = scmutil.opener('.')('x', 'w', atomictemp=True)
f.write('c')
f.close()
f = scmutil.opener('.')('y', 'w', atomictemp=True)
f.write('C')
f.close()
repo.invalidate()
print "* both files changed inode"
repo.cached
def fakeuncacheable():
def wrapcacheable(orig, *args, **kwargs):
return False
def wrapinit(orig, *args, **kwargs):
pass
originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit)
origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
wrapcacheable)
for fn in ['x', 'y']:
try:
os.remove(fn)
except OSError:
pass
basic(fakerepo())
util.cachestat.cacheable = origcacheable
util.cachestat.__init__ = originit
def test_filecache_synced():
# test old behavior that caused filecached properties to go out of sync
os.system('hg init && echo a >> a && hg ci -qAm.')
repo = hg.repository(ui.ui())
# first rollback clears the filecache, but changelog to stays in __dict__
repo.rollback()
repo.commit('.')
# second rollback comes along and touches the changelog externally
# (file is moved)
repo.rollback()
# but since changelog isn't under the filecache control anymore, we don't
# see that it changed, and return the old changelog without reconstructing
# it
repo.commit('.')
def setbeforeget(repo):
os.remove('x')
os.remove('y')
repo.cached = 'string set externally'
repo.invalidate()
print "* neither file exists"
print repo.cached
repo.invalidate()
f = open('x', 'w')
f.write('a')
f.close()
print "* file x created"
print repo.cached
repo.cached = 'string 2 set externally'
repo.invalidate()
print "* string set externally again"
print repo.cached
repo.invalidate()
f = open('y', 'w')
f.write('b')
f.close()
print "* file y created"
print repo.cached
print 'basic:'
print
basic(fakerepo())
print
print 'fakeuncacheable:'
print
fakeuncacheable()
test_filecache_synced()
print
print 'setbeforeget:'
print
setbeforeget(fakerepo())