Show More
@@ -1,127 +1,135 | |||||
1 | import sys, os, subprocess |
|
1 | import sys, os, subprocess | |
2 |
|
2 | |||
3 | if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], |
|
3 | if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], | |
4 | 'cacheable']): |
|
4 | 'cacheable']): | |
5 | sys.exit(80) |
|
5 | sys.exit(80) | |
6 |
|
6 | |||
7 | from mercurial import util, scmutil, extensions, hg, ui |
|
7 | from mercurial import util, scmutil, extensions, hg, ui | |
8 |
|
8 | |||
9 | filecache = scmutil.filecache |
|
9 | filecache = scmutil.filecache | |
10 |
|
10 | |||
11 | class fakerepo(object): |
|
11 | class fakerepo(object): | |
12 | def __init__(self): |
|
12 | def __init__(self): | |
13 | self._filecache = {} |
|
13 | self._filecache = {} | |
14 |
|
14 | |||
15 | def join(self, p): |
|
15 | def join(self, p): | |
16 | return p |
|
16 | return p | |
17 |
|
17 | |||
18 | def sjoin(self, p): |
|
18 | def sjoin(self, p): | |
19 | return p |
|
19 | return p | |
20 |
|
20 | |||
21 | @filecache('x') |
|
21 | @filecache('x') | |
22 | def cached(self): |
|
22 | def cached(self): | |
23 | print 'creating' |
|
23 | print 'creating' | |
24 | return 'string from function' |
|
24 | return 'string from function' | |
25 |
|
25 | |||
26 | def invalidate(self): |
|
26 | def invalidate(self): | |
27 | for k in self._filecache: |
|
27 | for k in self._filecache: | |
28 | try: |
|
28 | try: | |
29 | delattr(self, k) |
|
29 | delattr(self, k) | |
30 | except AttributeError: |
|
30 | except AttributeError: | |
31 | pass |
|
31 | pass | |
32 |
|
32 | |||
33 | def basic(repo): |
|
33 | def basic(repo): | |
34 |
|
|
34 | print "* file doesn't exist" | |
|
35 | # calls function | |||
35 | repo.cached |
|
36 | repo.cached | |
36 |
|
37 | |||
37 | repo.invalidate() |
|
38 | repo.invalidate() | |
38 |
|
|
39 | print "* file still doesn't exist" | |
|
40 | # uses cache | |||
39 | repo.cached |
|
41 | repo.cached | |
40 |
|
42 | |||
41 | # create empty file |
|
43 | # create empty file | |
42 | f = open('x', 'w') |
|
44 | f = open('x', 'w') | |
43 | f.close() |
|
45 | f.close() | |
44 | repo.invalidate() |
|
46 | repo.invalidate() | |
|
47 | print "* empty file x created" | |||
45 | # should recreate the object |
|
48 | # should recreate the object | |
46 | repo.cached |
|
49 | repo.cached | |
47 |
|
50 | |||
48 | f = open('x', 'w') |
|
51 | f = open('x', 'w') | |
49 | f.write('a') |
|
52 | f.write('a') | |
50 | f.close() |
|
53 | f.close() | |
51 | repo.invalidate() |
|
54 | repo.invalidate() | |
|
55 | print "* file x changed size" | |||
52 | # should recreate the object |
|
56 | # should recreate the object | |
53 | repo.cached |
|
57 | repo.cached | |
54 |
|
58 | |||
55 | repo.invalidate() |
|
59 | repo.invalidate() | |
56 | # stats file again, nothing changed, reuses object |
|
60 | print "* nothing changed with file x" | |
|
61 | # stats file again, reuses object | |||
57 | repo.cached |
|
62 | repo.cached | |
58 |
|
63 | |||
59 | # atomic replace file, size doesn't change |
|
64 | # atomic replace file, size doesn't change | |
60 | # hopefully st_mtime doesn't change as well so this doesn't use the cache |
|
65 | # hopefully st_mtime doesn't change as well so this doesn't use the cache | |
61 | # because of inode change |
|
66 | # because of inode change | |
62 | f = scmutil.opener('.')('x', 'w', atomictemp=True) |
|
67 | f = scmutil.opener('.')('x', 'w', atomictemp=True) | |
63 | f.write('b') |
|
68 | f.write('b') | |
64 | f.close() |
|
69 | f.close() | |
65 |
|
70 | |||
66 | repo.invalidate() |
|
71 | repo.invalidate() | |
|
72 | print "* file x changed inode" | |||
67 | repo.cached |
|
73 | repo.cached | |
68 |
|
74 | |||
69 | def fakeuncacheable(): |
|
75 | def fakeuncacheable(): | |
70 | def wrapcacheable(orig, *args, **kwargs): |
|
76 | def wrapcacheable(orig, *args, **kwargs): | |
71 | return False |
|
77 | return False | |
72 |
|
78 | |||
73 | def wrapinit(orig, *args, **kwargs): |
|
79 | def wrapinit(orig, *args, **kwargs): | |
74 | pass |
|
80 | pass | |
75 |
|
81 | |||
76 | originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit) |
|
82 | originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit) | |
77 | origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable', |
|
83 | origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable', | |
78 | wrapcacheable) |
|
84 | wrapcacheable) | |
79 |
|
85 | |||
80 | try: |
|
86 | try: | |
81 | os.remove('x') |
|
87 | os.remove('x') | |
82 | except OSError: |
|
88 | except OSError: | |
83 | pass |
|
89 | pass | |
84 |
|
90 | |||
85 | basic(fakerepo()) |
|
91 | basic(fakerepo()) | |
86 |
|
92 | |||
87 | util.cachestat.cacheable = origcacheable |
|
93 | util.cachestat.cacheable = origcacheable | |
88 | util.cachestat.__init__ = originit |
|
94 | util.cachestat.__init__ = originit | |
89 |
|
95 | |||
90 | def test_filecache_synced(): |
|
96 | def test_filecache_synced(): | |
91 | # test old behaviour that caused filecached properties to go out of sync |
|
97 | # test old behaviour that caused filecached properties to go out of sync | |
92 | os.system('hg init && echo a >> a && hg ci -qAm.') |
|
98 | os.system('hg init && echo a >> a && hg ci -qAm.') | |
93 | repo = hg.repository(ui.ui()) |
|
99 | repo = hg.repository(ui.ui()) | |
94 | # first rollback clears the filecache, but changelog to stays in __dict__ |
|
100 | # first rollback clears the filecache, but changelog to stays in __dict__ | |
95 | repo.rollback() |
|
101 | repo.rollback() | |
96 | repo.commit('.') |
|
102 | repo.commit('.') | |
97 | # second rollback comes along and touches the changelog externally |
|
103 | # second rollback comes along and touches the changelog externally | |
98 | # (file is moved) |
|
104 | # (file is moved) | |
99 | repo.rollback() |
|
105 | repo.rollback() | |
100 | # but since changelog isn't under the filecache control anymore, we don't |
|
106 | # but since changelog isn't under the filecache control anymore, we don't | |
101 | # see that it changed, and return the old changelog without reconstructing |
|
107 | # see that it changed, and return the old changelog without reconstructing | |
102 | # it |
|
108 | # it | |
103 | repo.commit('.') |
|
109 | repo.commit('.') | |
104 |
|
110 | |||
105 | def setbeforeget(repo): |
|
111 | def setbeforeget(repo): | |
106 | os.remove('x') |
|
112 | os.remove('x') | |
107 | repo.cached = 'string set externally' |
|
113 | repo.cached = 'string set externally' | |
108 | repo.invalidate() |
|
114 | repo.invalidate() | |
|
115 | print "* file x doesn't exist" | |||
109 | print repo.cached |
|
116 | print repo.cached | |
110 | repo.invalidate() |
|
117 | repo.invalidate() | |
111 | f = open('x', 'w') |
|
118 | f = open('x', 'w') | |
112 | f.write('a') |
|
119 | f.write('a') | |
113 | f.close() |
|
120 | f.close() | |
|
121 | print "* file x created" | |||
114 | print repo.cached |
|
122 | print repo.cached | |
115 |
|
123 | |||
116 | print 'basic:' |
|
124 | print 'basic:' | |
117 |
|
125 | |||
118 | basic(fakerepo()) |
|
126 | basic(fakerepo()) | |
119 |
|
127 | |||
120 | print 'fakeuncacheable:' |
|
128 | print 'fakeuncacheable:' | |
121 |
|
129 | |||
122 | fakeuncacheable() |
|
130 | fakeuncacheable() | |
123 | test_filecache_synced() |
|
131 | test_filecache_synced() | |
124 |
|
132 | |||
125 | print 'setbeforeget:' |
|
133 | print 'setbeforeget:' | |
126 |
|
134 | |||
127 | setbeforeget(fakerepo()) |
|
135 | setbeforeget(fakerepo()) |
@@ -1,25 +1,39 | |||||
1 | basic: |
|
1 | basic: | |
2 |
|
2 | |||
|
3 | * file doesn't exist | |||
3 | creating |
|
4 | creating | |
|
5 | * file still doesn't exist | |||
|
6 | * empty file x created | |||
4 | creating |
|
7 | creating | |
|
8 | * file x changed size | |||
5 | creating |
|
9 | creating | |
|
10 | * nothing changed with file x | |||
|
11 | * file x changed inode | |||
6 | creating |
|
12 | creating | |
7 |
|
13 | |||
8 | fakeuncacheable: |
|
14 | fakeuncacheable: | |
9 |
|
15 | |||
|
16 | * file doesn't exist | |||
10 | creating |
|
17 | creating | |
|
18 | * file still doesn't exist | |||
11 | creating |
|
19 | creating | |
|
20 | * empty file x created | |||
12 | creating |
|
21 | creating | |
|
22 | * file x changed size | |||
13 | creating |
|
23 | creating | |
|
24 | * nothing changed with file x | |||
14 | creating |
|
25 | creating | |
|
26 | * file x changed inode | |||
15 | creating |
|
27 | creating | |
16 | repository tip rolled back to revision -1 (undo commit) |
|
28 | repository tip rolled back to revision -1 (undo commit) | |
17 | working directory now based on revision -1 |
|
29 | working directory now based on revision -1 | |
18 | repository tip rolled back to revision -1 (undo commit) |
|
30 | repository tip rolled back to revision -1 (undo commit) | |
19 | working directory now based on revision -1 |
|
31 | working directory now based on revision -1 | |
20 |
|
32 | |||
21 | setbeforeget: |
|
33 | setbeforeget: | |
22 |
|
34 | |||
|
35 | * file x doesn't exist | |||
23 | string set externally |
|
36 | string set externally | |
|
37 | * file x created | |||
24 | creating |
|
38 | creating | |
25 | string from function |
|
39 | string from function |
General Comments 0
You need to be logged in to leave comments.
Login now