comparison mercurial/dirstate.py @ 4615:a8be3c875988

dirstate: hide internal vars Add an __iter__ method so commands don't need to poke at _map.
author Matt Mackall <mpm@selenic.com>
date Mon, 18 Jun 2007 13:24:34 -0500
parents 3a645af7fb76
children 9b00b73a5286
comparison
equal deleted inserted replaced
4614:3a645af7fb76 4615:a8be3c875988
16 _format = ">cllll" 16 _format = ">cllll"
17 17
18 class dirstate(object): 18 class dirstate(object):
19 19
20 def __init__(self, opener, ui, root): 20 def __init__(self, opener, ui, root):
21 self.opener = opener 21 self._opener = opener
22 self.root = root 22 self._root = root
23 self._dirty = 0 23 self._dirty = 0
24 self.ui = ui 24 self._ui = ui
25 25
26 def __getattr__(self, name): 26 def __getattr__(self, name):
27 if name == 'map': 27 if name == '_map':
28 self.read() 28 self.read()
29 return self.map 29 return self._map
30 elif name == 'copymap': 30 elif name == '_copymap':
31 self.read() 31 self.read()
32 return self.copymap 32 return self._copymap
33 elif name == '_branch': 33 elif name == '_branch':
34 try: 34 try:
35 self._branch = self.opener("branch").read().strip()\ 35 self._branch = self._opener("branch").read().strip()\
36 or "default" 36 or "default"
37 except IOError: 37 except IOError:
38 self._branch = "default" 38 self._branch = "default"
39 return self._branch 39 return self._branch
40 elif name == 'pl': 40 elif name == '_pl':
41 self.pl = [nullid, nullid] 41 self._pl = [nullid, nullid]
42 try: 42 try:
43 st = self.opener("dirstate").read(40) 43 st = self._opener("dirstate").read(40)
44 if len(st) == 40: 44 if len(st) == 40:
45 self.pl = st[:20], st[20:40] 45 self._pl = st[:20], st[20:40]
46 except IOError, err: 46 except IOError, err:
47 if err.errno != errno.ENOENT: raise 47 if err.errno != errno.ENOENT: raise
48 return self.pl 48 return self._pl
49 elif name == 'dirs': 49 elif name == 'dirs':
50 self.dirs = {} 50 self.dirs = {}
51 for f in self.map: 51 for f in self._map:
52 self.updatedirs(f, 1) 52 self.updatedirs(f, 1)
53 return self.dirs 53 return self.dirs
54 elif name == '_ignore': 54 elif name == '_ignore':
55 files = [self.wjoin('.hgignore')] + self.ui.hgignorefiles() 55 files = [self.wjoin('.hgignore')] + self._ui.hgignorefiles()
56 self._ignore = ignore.ignore(self.root, files, self.ui.warn) 56 self._ignore = ignore.ignore(self._root, files, self._ui.warn)
57 return self._ignore 57 return self._ignore
58 elif name == '_slash': 58 elif name == '_slash':
59 self._slash = self.ui.configbool('ui', 'slash') and os.sep != '/' 59 self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/'
60 return self._slash 60 return self._slash
61 else: 61 else:
62 raise AttributeError, name 62 raise AttributeError, name
63 63
64 def wjoin(self, f): 64 def wjoin(self, f):
65 return os.path.join(self.root, f) 65 return os.path.join(self._root, f)
66 66
67 def getcwd(self): 67 def getcwd(self):
68 cwd = os.getcwd() 68 cwd = os.getcwd()
69 if cwd == self.root: return '' 69 if cwd == self._root: return ''
70 # self.root ends with a path separator if self.root is '/' or 'C:\' 70 # self._root ends with a path separator if self._root is '/' or 'C:\'
71 rootsep = self.root 71 rootsep = self._root
72 if not rootsep.endswith(os.sep): 72 if not rootsep.endswith(os.sep):
73 rootsep += os.sep 73 rootsep += os.sep
74 if cwd.startswith(rootsep): 74 if cwd.startswith(rootsep):
75 return cwd[len(rootsep):] 75 return cwd[len(rootsep):]
76 else: 76 else:
78 return cwd 78 return cwd
79 79
80 def pathto(self, f, cwd=None): 80 def pathto(self, f, cwd=None):
81 if cwd is None: 81 if cwd is None:
82 cwd = self.getcwd() 82 cwd = self.getcwd()
83 path = util.pathto(self.root, cwd, f) 83 path = util.pathto(self._root, cwd, f)
84 if self._slash: 84 if self._slash:
85 return path.replace(os.sep, '/') 85 return path.replace(os.sep, '/')
86 return path 86 return path
87 87
88 def __del__(self): 88 def __del__(self):
89 self.write() 89 self.write()
90 90
91 def __getitem__(self, key): 91 def __getitem__(self, key):
92 return self.map[key] 92 return self._map[key]
93 93
94 def __contains__(self, key): 94 def __contains__(self, key):
95 return key in self.map 95 return key in self._map
96
97 def __iter__(self):
98 a = self._map.keys()
99 a.sort()
100 for x in a:
101 yield x
96 102
97 def parents(self): 103 def parents(self):
98 return self.pl 104 return self._pl
99 105
100 def branch(self): 106 def branch(self):
101 return self._branch 107 return self._branch
102 108
103 def markdirty(self): 109 def markdirty(self):
104 self._dirty = 1 110 self._dirty = 1
105 111
106 def setparents(self, p1, p2=nullid): 112 def setparents(self, p1, p2=nullid):
107 self.markdirty() 113 self.markdirty()
108 self.pl = p1, p2 114 self._pl = p1, p2
109 115
110 def setbranch(self, branch): 116 def setbranch(self, branch):
111 self._branch = branch 117 self._branch = branch
112 self.opener("branch", "w").write(branch + '\n') 118 self._opener("branch", "w").write(branch + '\n')
113 119
114 def state(self, key): 120 def state(self, key):
115 return self.map.get(key, ("?",))[0] 121 return self._map.get(key, ("?",))[0]
116 122
117 def read(self): 123 def read(self):
118 self.map = {} 124 self._map = {}
119 self.copymap = {} 125 self._copymap = {}
120 self.pl = [nullid, nullid] 126 self._pl = [nullid, nullid]
121 try: 127 try:
122 st = self.opener("dirstate").read() 128 st = self._opener("dirstate").read()
123 except IOError, err: 129 except IOError, err:
124 if err.errno != errno.ENOENT: raise 130 if err.errno != errno.ENOENT: raise
125 return 131 return
126 if not st: 132 if not st:
127 return 133 return
128 134
129 self.pl = [st[:20], st[20: 40]] 135 self._pl = [st[:20], st[20: 40]]
130 136
131 # deref fields so they will be local in loop 137 # deref fields so they will be local in loop
132 dmap = self.map 138 dmap = self._map
133 copymap = self.copymap 139 copymap = self._copymap
134 unpack = struct.unpack 140 unpack = struct.unpack
135 141
136 pos = 40 142 pos = 40
137 e_size = struct.calcsize(_format) 143 e_size = struct.calcsize(_format)
138 144
148 copymap[f] = c 154 copymap[f] = c
149 dmap[f] = e[:4] 155 dmap[f] = e[:4]
150 pos = newpos 156 pos = newpos
151 157
152 def invalidate(self): 158 def invalidate(self):
153 for a in "map copymap _branch pl dirs _ignore".split(): 159 for a in "_map _copymap _branch pl dirs _ignore".split():
154 if hasattr(self, a): 160 if hasattr(self, a):
155 self.__delattr__(a) 161 self.__delattr__(a)
156 162
157 def copy(self, source, dest): 163 def copy(self, source, dest):
158 self.markdirty() 164 self.markdirty()
159 self.copymap[dest] = source 165 self._copymap[dest] = source
160 166
161 def copied(self, file): 167 def copied(self, file):
162 return self.copymap.get(file, None) 168 return self._copymap.get(file, None)
163 169
164 def copies(self): 170 def copies(self):
165 return self.copymap 171 return self._copymap
166 172
167 def updatedirs(self, path, delta): 173 def updatedirs(self, path, delta):
168 for c in strutil.findall(path, '/'): 174 for c in strutil.findall(path, '/'):
169 pc = path[:c] 175 pc = path[:c]
170 self.dirs.setdefault(pc, 0) 176 self.dirs.setdefault(pc, 0)
181 raise util.Abort(_('directory named %r already in dirstate') % 187 raise util.Abort(_('directory named %r already in dirstate') %
182 f) 188 f)
183 for d in prefixes(f): 189 for d in prefixes(f):
184 if d in seendirs: 190 if d in seendirs:
185 break 191 break
186 if d in self.map: 192 if d in self._map:
187 raise util.Abort(_('file named %r already in dirstate') % 193 raise util.Abort(_('file named %r already in dirstate') %
188 d) 194 d)
189 seendirs[d] = True 195 seendirs[d] = True
190 # disallowed 196 # disallowed
191 if '\r' in f or '\n' in f: 197 if '\r' in f or '\n' in f:
202 self.markdirty() 208 self.markdirty()
203 if state == "a": 209 if state == "a":
204 self.checkinterfering(files) 210 self.checkinterfering(files)
205 for f in files: 211 for f in files:
206 if state == "r": 212 if state == "r":
207 self.map[f] = ('r', 0, 0, 0) 213 self._map[f] = ('r', 0, 0, 0)
208 self.updatedirs(f, -1) 214 self.updatedirs(f, -1)
209 else: 215 else:
210 if state == "a": 216 if state == "a":
211 self.updatedirs(f, 1) 217 self.updatedirs(f, 1)
212 s = os.lstat(self.wjoin(f)) 218 s = os.lstat(self.wjoin(f))
213 st_size = kw.get('st_size', s.st_size) 219 st_size = kw.get('st_size', s.st_size)
214 st_mtime = kw.get('st_mtime', s.st_mtime) 220 st_mtime = kw.get('st_mtime', s.st_mtime)
215 self.map[f] = (state, s.st_mode, st_size, st_mtime) 221 self._map[f] = (state, s.st_mode, st_size, st_mtime)
216 if self.copymap.has_key(f): 222 if self._copymap.has_key(f):
217 del self.copymap[f] 223 del self._copymap[f]
218 224
219 def forget(self, files): 225 def forget(self, files):
220 if not files: return 226 if not files: return
221 self.markdirty() 227 self.markdirty()
222 for f in files: 228 for f in files:
223 try: 229 try:
224 del self.map[f] 230 del self._map[f]
225 self.updatedirs(f, -1) 231 self.updatedirs(f, -1)
226 except KeyError: 232 except KeyError:
227 self.ui.warn(_("not in dirstate: %s!\n") % f) 233 self._ui.warn(_("not in dirstate: %s!\n") % f)
228 pass 234 pass
229 235
230 def rebuild(self, parent, files): 236 def rebuild(self, parent, files):
231 self.invalidate() 237 self.invalidate()
232 for f in files: 238 for f in files:
233 if files.execf(f): 239 if files.execf(f):
234 self.map[f] = ('n', 0777, -1, 0) 240 self._map[f] = ('n', 0777, -1, 0)
235 else: 241 else:
236 self.map[f] = ('n', 0666, -1, 0) 242 self._map[f] = ('n', 0666, -1, 0)
237 self.pl = (parent, nullid) 243 self._pl = (parent, nullid)
238 self.markdirty() 244 self.markdirty()
239 245
240 def write(self): 246 def write(self):
241 if not self._dirty: 247 if not self._dirty:
242 return 248 return
243 cs = cStringIO.StringIO() 249 cs = cStringIO.StringIO()
244 cs.write("".join(self.pl)) 250 cs.write("".join(self._pl))
245 for f, e in self.map.iteritems(): 251 for f, e in self._map.iteritems():
246 c = self.copied(f) 252 c = self.copied(f)
247 if c: 253 if c:
248 f = f + "\0" + c 254 f = f + "\0" + c
249 e = struct.pack(_format, e[0], e[1], e[2], e[3], len(f)) 255 e = struct.pack(_format, e[0], e[1], e[2], e[3], len(f))
250 cs.write(e) 256 cs.write(e)
251 cs.write(f) 257 cs.write(f)
252 st = self.opener("dirstate", "w", atomictemp=True) 258 st = self._opener("dirstate", "w", atomictemp=True)
253 st.write(cs.getvalue()) 259 st.write(cs.getvalue())
254 st.rename() 260 st.rename()
255 self._dirty = 0 261 self._dirty = 0
256 262
257 def filterfiles(self, files): 263 def filterfiles(self, files):
258 ret = {} 264 ret = {}
259 unknown = [] 265 unknown = []
260 266
261 for x in files: 267 for x in files:
262 if x == '.': 268 if x == '.':
263 return self.map.copy() 269 return self._map.copy()
264 if x not in self.map: 270 if x not in self._map:
265 unknown.append(x) 271 unknown.append(x)
266 else: 272 else:
267 ret[x] = self.map[x] 273 ret[x] = self._map[x]
268 274
269 if not unknown: 275 if not unknown:
270 return ret 276 return ret
271 277
272 b = self.map.keys() 278 b = self._map.keys()
273 b.sort() 279 b.sort()
274 blen = len(b) 280 blen = len(b)
275 281
276 for x in unknown: 282 for x in unknown:
277 bs = bisect.bisect(b, "%s%s" % (x, '/')) 283 bs = bisect.bisect(b, "%s%s" % (x, '/'))
278 while bs < blen: 284 while bs < blen:
279 s = b[bs] 285 s = b[bs]
280 if len(s) > len(x) and s.startswith(x): 286 if len(s) > len(x) and s.startswith(x):
281 ret[s] = self.map[s] 287 ret[s] = self._map[s]
282 else: 288 else:
283 break 289 break
284 bs += 1 290 bs += 1
285 return ret 291 return ret
286 292
292 if stat.S_ISCHR(st.st_mode): kind = _('character device') 298 if stat.S_ISCHR(st.st_mode): kind = _('character device')
293 elif stat.S_ISBLK(st.st_mode): kind = _('block device') 299 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
294 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo') 300 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
295 elif stat.S_ISSOCK(st.st_mode): kind = _('socket') 301 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
296 elif stat.S_ISDIR(st.st_mode): kind = _('directory') 302 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
297 self.ui.warn(_('%s: unsupported file type (type is %s)\n') 303 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
298 % (self.pathto(f), kind)) 304 % (self.pathto(f), kind))
299 return False 305 return False
300 306
301 def walk(self, files=None, match=util.always, badmatch=None): 307 def walk(self, files=None, match=util.always, badmatch=None):
302 # filter out the stat 308 # filter out the stat
320 ''' 326 '''
321 327
322 # walk all files by default 328 # walk all files by default
323 if not files: 329 if not files:
324 files = ['.'] 330 files = ['.']
325 dc = self.map.copy() 331 dc = self._map.copy()
326 else: 332 else:
327 files = util.unique(files) 333 files = util.unique(files)
328 dc = self.filterfiles(files) 334 dc = self.filterfiles(files)
329 335
330 def imatch(file_): 336 def imatch(file_):
335 ignore = self._ignore 341 ignore = self._ignore
336 if ignored: 342 if ignored:
337 imatch = match 343 imatch = match
338 ignore = util.never 344 ignore = util.never
339 345
340 # self.root may end with a path separator when self.root == '/' 346 # self._root may end with a path separator when self._root == '/'
341 common_prefix_len = len(self.root) 347 common_prefix_len = len(self._root)
342 if not self.root.endswith(os.sep): 348 if not self._root.endswith(os.sep):
343 common_prefix_len += 1 349 common_prefix_len += 1
344 # recursion free walker, faster than os.walk. 350 # recursion free walker, faster than os.walk.
345 def findfiles(s): 351 def findfiles(s):
346 work = [s] 352 work = [s]
347 if directories: 353 if directories:
400 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'): 406 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
401 found = True 407 found = True
402 break 408 break
403 if not found: 409 if not found:
404 if inst.errno != errno.ENOENT or not badmatch: 410 if inst.errno != errno.ENOENT or not badmatch:
405 self.ui.warn('%s: %s\n' % (self.pathto(ff), 411 self._ui.warn('%s: %s\n' % (self.pathto(ff),
406 inst.strerror)) 412 inst.strerror))
407 elif badmatch and badmatch(ff) and imatch(nf): 413 elif badmatch and badmatch(ff) and imatch(nf):
408 yield 'b', ff, None 414 yield 'b', ff, None
409 continue 415 continue
410 if stat.S_ISDIR(st.st_mode): 416 if stat.S_ISDIR(st.st_mode):