Mercurial > hg > mercurial-crew-with-dirclash
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): |