view tests/test-propertycache.py @ 24790:baa11dde8c0e

match: add a subclass for dirstate normalizing of the matched patterns This class is only needed on case insensitive filesystems, and only for wdir context matches. It allows the user to not match the case of the items in the filesystem- especially for naming directories, which dirstate doesn't handle[1]. Making dirstate handle mismatched directory cases is too expensive[2]. Since dirstate doesn't apply to committed csets, this is only created by overriding basectx.match() in workingctx, and only on icasefs. The default arguments have been dropped, because the ctx must be passed to the matcher in order to function. For operations that can apply to both wdir and some other context, this ends up normalizing the filename to the case as it exists in the filesystem, and using that case for the lookup in the other context. See the diff example in the test. Previously, given a directory with an inexact case: - add worked as expected - diff, forget and status would silently ignore the request - files would exit with 1 - commit, revert and remove would fail (even when the commands leading up to them worked): $ hg ci -m "AbCDef" capsdir1/capsdir abort: CapsDir1/CapsDir: no match under directory! $ hg revert -r '.^' capsdir1/capsdir capsdir1\capsdir: no such file in rev 64dae27060b7 $ hg remove capsdir1/capsdir not removing capsdir1\capsdir: no tracked files [1] Globs are normalized, so that the -I and -X don't need to be specified with a case match. Without that, the second last remove (with -X) removes the files, leaving nothing for the last remove. However, specifying the files as 'glob:**.Txt' does not work. Perhaps this requires 're.IGNORECASE'? There are only a handful of places that create matchers directly, instead of being routed through the context.match() method. Some may benefit from changing over to using ctx.match() as a factory function: revset.checkstatus() revset.contains() revset.filelog() revset._matchfiles() localrepository._loadfilter() ignore.ignore() fileset.subrepo() filemerge._picktool() overrides.addlargefiles() lfcommands.lfconvert() kwtemplate.__init__() eolfile.__init__() eolfile.checkrev() acl.buildmatch() Currently, a toplevel subrepo can be named with an inexact case. However, the path auditor gets in the way of naming _anything_ in the subrepo if the top level case doesn't match. That is trickier to handle, because there's the user provided case, the case in the filesystem, and the case stored in .hgsub. This can be fixed next cycle. --- a/tests/test-subrepo-deep-nested-change.t +++ b/tests/test-subrepo-deep-nested-change.t @@ -170,8 +170,15 @@ R sub1/sub2/test.txt $ hg update -Cq $ touch sub1/sub2/folder/bar +#if icasefs + $ hg addremove Sub1/sub2 + abort: path 'Sub1\sub2' is inside nested repo 'Sub1' + [255] + $ hg -q addremove sub1/sub2 +#else $ hg addremove sub1/sub2 adding sub1/sub2/folder/bar (glob) +#endif $ hg status -S A sub1/sub2/folder/bar ? foo/bar/abc The narrowmatcher class may need to be tweaked when that is fixed. [1] http://www.selenic.com/pipermail/mercurial-devel/2015-April/068183.html [2] http://www.selenic.com/pipermail/mercurial-devel/2015-April/068191.html
author Matt Harbison <matt_harbison@yahoo.com>
date Sun, 12 Apr 2015 01:39:21 -0400
parents 7731a2281cf0
children 84673a7c54af
line wrap: on
line source

"""test behavior of propertycache and unfiltered propertycache

The repoview overlay is quite complex. We test the behavior of
property cache of both localrepo and repoview to prevent
regression."""

import os, subprocess
import mercurial.localrepo
import mercurial.repoview
import mercurial.util
import mercurial.hg
import mercurial.ui as uimod


# create some special property cache that trace they call

calllog = []
@mercurial.util.propertycache
def testcachedfoobar(repo):
    name = repo.filtername
    if name is None:
        name = ''
    val = len(name)
    calllog.append(val)
    return val

unficalllog = []
@mercurial.localrepo.unfilteredpropertycache
def testcachedunfifoobar(repo):
    name = repo.filtername
    if name is None:
        name = ''
    val = 100 + len(name)
    unficalllog.append(val)
    return val

#plug them on repo
mercurial.localrepo.localrepository.testcachedfoobar = testcachedfoobar
mercurial.localrepo.localrepository.testcachedunfifoobar = testcachedunfifoobar


# Create an empty repo and instantiate it. It is important to run
# these tests on the real object to detect regression.
repopath = os.path.join(os.environ['TESTTMP'], 'repo')
assert subprocess.call(['hg', 'init', repopath]) == 0
ui = uimod.ui()
repo = mercurial.hg.repository(ui, path=repopath).unfiltered()


print ''
print '=== property cache ==='
print ''
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')

print ''
print '= first access on unfiltered, should do a call'
print 'access:', repo.testcachedfoobar
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')

print ''
print '= second access on unfiltered, should not do call'
print 'access', repo.testcachedfoobar
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')

print ''
print '= first access on "visible" view, should do a call'
visibleview = repo.filtered('visible')
print 'cached value ("visible" view):',
print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
print 'access:', visibleview.testcachedfoobar
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')
print 'cached value ("visible" view):',
print vars(visibleview).get('testcachedfoobar', 'NOCACHE')

print ''
print '= second access on "visible view", should not do call'
print 'access:', visibleview.testcachedfoobar
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')
print 'cached value ("visible" view):',
print vars(visibleview).get('testcachedfoobar', 'NOCACHE')

print ''
print '= no effect on other view'
immutableview = repo.filtered('immutable')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedfoobar', 'NOCACHE')
print 'access:', immutableview.testcachedfoobar
print 'calllog:', calllog
print 'cached value (unfiltered):',
print vars(repo).get('testcachedfoobar', 'NOCACHE')
print 'cached value ("visible" view):',
print vars(visibleview).get('testcachedfoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedfoobar', 'NOCACHE')

# unfiltered property cache test
print ''
print ''
print '=== unfiltered property cache ==='
print ''
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')

print ''
print '= first access on unfiltered, should do a call'
print 'access (unfiltered):', repo.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')

print ''
print '= second access on unfiltered, should not do call'
print 'access (unfiltered):', repo.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')

print ''
print '= access on view should use the unfiltered cache'
print 'access (unfiltered):      ', repo.testcachedunfifoobar
print 'access ("visible" view):  ', visibleview.testcachedunfifoobar
print 'access ("immutable" view):', immutableview.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')

print ''
print '= even if we clear the unfiltered cache'
del repo.__dict__['testcachedunfifoobar']
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
print 'unficalllog:', unficalllog
print 'access ("visible" view):  ', visibleview.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
print 'access ("immutable" view):', immutableview.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')
print 'access (unfiltered):      ', repo.testcachedunfifoobar
print 'unficalllog:', unficalllog
print 'cached value (unfiltered):      ',
print vars(repo).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("visible" view):  ',
print vars(visibleview).get('testcachedunfifoobar', 'NOCACHE')
print 'cached value ("immutable" view):',
print vars(immutableview).get('testcachedunfifoobar', 'NOCACHE')