##// END OF EJS Templates
scmutil.filecache: support watching over multiple files
Siddharth Agarwal -
r20045:b3684fd2 default
parent child Browse files
Show More
@@ -786,23 +786,26 b' class filecacheentry(object):'
786 786 entry.refresh()
787 787
788 788 class filecache(object):
789 '''A property like decorator that tracks a file under .hg/ for updates.
789 '''A property like decorator that tracks files under .hg/ for updates.
790 790
791 791 Records stat info when called in _filecache.
792 792
793 On subsequent calls, compares old stat info with new info, and recreates
794 the object when needed, updating the new stat info in _filecache.
793 On subsequent calls, compares old stat info with new info, and recreates the
794 object when any of the files changes, updating the new stat info in
795 _filecache.
795 796
796 797 Mercurial either atomic renames or appends for files under .hg,
797 798 so to ensure the cache is reliable we need the filesystem to be able
798 799 to tell us if a file has been replaced. If it can't, we fallback to
799 800 recreating the object on every call (essentially the same behaviour as
800 propertycache).'''
801 def __init__(self, path):
802 self.path = path
801 propertycache).
802
803 '''
804 def __init__(self, *paths):
805 self.paths = paths
803 806
804 807 def join(self, obj, fname):
805 """Used to compute the runtime path of the cached file.
808 """Used to compute the runtime path of a cached file.
806 809
807 810 Users should subclass filecache and provide their own version of this
808 811 function to call the appropriate join function on 'obj' (an instance
@@ -827,11 +830,11 b' class filecache(object):'
827 830 if entry.changed():
828 831 entry.obj = self.func(obj)
829 832 else:
830 path = self.join(obj, self.path)
833 paths = [self.join(obj, path) for path in self.paths]
831 834
832 835 # We stat -before- creating the object so our cache doesn't lie if
833 836 # a writer modified between the time we read and stat
834 entry = filecachesubentry(path, True)
837 entry = filecacheentry(paths, True)
835 838 entry.obj = self.func(obj)
836 839
837 840 obj._filecache[self.name] = entry
@@ -843,7 +846,8 b' class filecache(object):'
843 846 if self.name not in obj._filecache:
844 847 # we add an entry for the missing value because X in __dict__
845 848 # implies X in _filecache
846 ce = filecachesubentry(self.join(obj, self.path), False)
849 paths = [self.join(obj, path) for path in self.paths]
850 ce = filecacheentry(paths, False)
847 851 obj._filecache[self.name] = ce
848 852 else:
849 853 ce = obj._filecache[self.name]
@@ -18,7 +18,7 b' class fakerepo(object):'
18 18 def sjoin(self, p):
19 19 return p
20 20
21 @filecache('x')
21 @filecache('x', 'y')
22 22 def cached(self):
23 23 print 'creating'
24 24 return 'string from function'
@@ -31,12 +31,12 b' class fakerepo(object):'
31 31 pass
32 32
33 33 def basic(repo):
34 print "* file doesn't exist"
34 print "* neither file exists"
35 35 # calls function
36 36 repo.cached
37 37
38 38 repo.invalidate()
39 print "* file still doesn't exist"
39 print "* neither file still exists"
40 40 # uses cache
41 41 repo.cached
42 42
@@ -57,7 +57,7 b' def basic(repo):'
57 57 repo.cached
58 58
59 59 repo.invalidate()
60 print "* nothing changed with file x"
60 print "* nothing changed with either file"
61 61 # stats file again, reuses object
62 62 repo.cached
63 63
@@ -72,6 +72,41 b' def basic(repo):'
72 72 print "* file x changed inode"
73 73 repo.cached
74 74
75 # create empty file y
76 f = open('y', 'w')
77 f.close()
78 repo.invalidate()
79 print "* empty file y created"
80 # should recreate the object
81 repo.cached
82
83 f = open('y', 'w')
84 f.write('A')
85 f.close()
86 repo.invalidate()
87 print "* file y changed size"
88 # should recreate the object
89 repo.cached
90
91 f = scmutil.opener('.')('y', 'w', atomictemp=True)
92 f.write('B')
93 f.close()
94
95 repo.invalidate()
96 print "* file y changed inode"
97 repo.cached
98
99 f = scmutil.opener('.')('x', 'w', atomictemp=True)
100 f.write('c')
101 f.close()
102 f = scmutil.opener('.')('y', 'w', atomictemp=True)
103 f.write('C')
104 f.close()
105
106 repo.invalidate()
107 print "* both files changed inode"
108 repo.cached
109
75 110 def fakeuncacheable():
76 111 def wrapcacheable(orig, *args, **kwargs):
77 112 return False
@@ -83,10 +118,11 b' def fakeuncacheable():'
83 118 origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
84 119 wrapcacheable)
85 120
86 try:
87 os.remove('x')
88 except OSError:
89 pass
121 for fn in ['x', 'y']:
122 try:
123 os.remove(fn)
124 except OSError:
125 pass
90 126
91 127 basic(fakerepo())
92 128
@@ -110,9 +146,10 b' def test_filecache_synced():'
110 146
111 147 def setbeforeget(repo):
112 148 os.remove('x')
149 os.remove('y')
113 150 repo.cached = 'string set externally'
114 151 repo.invalidate()
115 print "* file x doesn't exist"
152 print "* neither file exists"
116 153 print repo.cached
117 154 repo.invalidate()
118 155 f = open('x', 'w')
@@ -121,6 +158,18 b' def setbeforeget(repo):'
121 158 print "* file x created"
122 159 print repo.cached
123 160
161 repo.cached = 'string 2 set externally'
162 repo.invalidate()
163 print "* string set externally again"
164 print repo.cached
165
166 repo.invalidate()
167 f = open('y', 'w')
168 f.write('b')
169 f.close()
170 print "* file y created"
171 print repo.cached
172
124 173 print 'basic:'
125 174 print
126 175 basic(fakerepo())
@@ -1,30 +1,46 b''
1 1 basic:
2 2
3 * file doesn't exist
3 * neither file exists
4 4 creating
5 * file still doesn't exist
5 * neither file still exists
6 6 * empty file x created
7 7 creating
8 8 * file x changed size
9 9 creating
10 * nothing changed with file x
10 * nothing changed with either file
11 11 * file x changed inode
12 12 creating
13 * empty file y created
14 creating
15 * file y changed size
16 creating
17 * file y changed inode
18 creating
19 * both files changed inode
20 creating
13 21
14 22 fakeuncacheable:
15 23
16 * file doesn't exist
24 * neither file exists
17 25 creating
18 * file still doesn't exist
26 * neither file still exists
19 27 creating
20 28 * empty file x created
21 29 creating
22 30 * file x changed size
23 31 creating
24 * nothing changed with file x
32 * nothing changed with either file
25 33 creating
26 34 * file x changed inode
27 35 creating
36 * empty file y created
37 creating
38 * file y changed size
39 creating
40 * file y changed inode
41 creating
42 * both files changed inode
43 creating
28 44 repository tip rolled back to revision -1 (undo commit)
29 45 working directory now based on revision -1
30 46 repository tip rolled back to revision -1 (undo commit)
@@ -32,8 +48,13 b' working directory now based on revision '
32 48
33 49 setbeforeget:
34 50
35 * file x doesn't exist
51 * neither file exists
36 52 string set externally
37 53 * file x created
38 54 creating
39 55 string from function
56 * string set externally again
57 string 2 set externally
58 * file y created
59 creating
60 string from function
General Comments 0
You need to be logged in to leave comments. Login now