Mercurial > hg
comparison mercurial/dirstate.py @ 2956:6dddcba7596a
merge.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 18 Aug 2006 21:17:28 -0700 |
parents | 3d5547845158 |
children | 882e703eaa94 |
comparison
equal
deleted
inserted
replaced
2955:9d1c3529ebbc | 2956:6dddcba7596a |
---|---|
1 """ | 1 """ |
2 dirstate.py - working directory tracking for mercurial | 2 dirstate.py - working directory tracking for mercurial |
3 | 3 |
4 Copyright 2005 Matt Mackall <mpm@selenic.com> | 4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
5 | 5 |
6 This software may be used and distributed according to the terms | 6 This software may be used and distributed according to the terms |
7 of the GNU General Public License, incorporated herein by reference. | 7 of the GNU General Public License, incorporated herein by reference. |
8 """ | 8 """ |
9 | 9 |
10 from node import * | 10 from node import * |
11 from i18n import gettext as _ | 11 from i18n import gettext as _ |
12 from demandload import * | 12 from demandload import * |
13 demandload(globals(), "struct os time bisect stat util re errno") | 13 demandload(globals(), "struct os time bisect stat strutil util re errno") |
14 | 14 |
15 class dirstate(object): | 15 class dirstate(object): |
16 format = ">cllll" | 16 format = ">cllll" |
17 | 17 |
18 def __init__(self, opener, ui, root): | 18 def __init__(self, opener, ui, root): |
20 self.root = root | 20 self.root = root |
21 self.dirty = 0 | 21 self.dirty = 0 |
22 self.ui = ui | 22 self.ui = ui |
23 self.map = None | 23 self.map = None |
24 self.pl = None | 24 self.pl = None |
25 self.dirs = None | |
25 self.copies = {} | 26 self.copies = {} |
26 self.ignorefunc = None | 27 self.ignorefunc = None |
27 self.blockignore = False | 28 self.blockignore = False |
28 | 29 |
29 def wjoin(self, f): | 30 def wjoin(self, f): |
195 self.copies[dest] = source | 196 self.copies[dest] = source |
196 | 197 |
197 def copied(self, file): | 198 def copied(self, file): |
198 return self.copies.get(file, None) | 199 return self.copies.get(file, None) |
199 | 200 |
201 def initdirs(self): | |
202 if self.dirs is None: | |
203 self.dirs = {} | |
204 for f in self.map: | |
205 self.updatedirs(f, 1) | |
206 | |
207 def updatedirs(self, path, delta): | |
208 if self.dirs is not None: | |
209 for c in strutil.findall(path, '/'): | |
210 pc = path[:c] | |
211 self.dirs.setdefault(pc, 0) | |
212 self.dirs[pc] += delta | |
213 | |
214 def checkshadows(self, files): | |
215 def prefixes(f): | |
216 for c in strutil.rfindall(f, '/'): | |
217 yield f[:c] | |
218 self.lazyread() | |
219 self.initdirs() | |
220 seendirs = {} | |
221 for f in files: | |
222 if self.dirs.get(f): | |
223 raise util.Abort(_('directory named %r already in dirstate') % | |
224 f) | |
225 for d in prefixes(f): | |
226 if d in seendirs: | |
227 break | |
228 if d in self.map: | |
229 raise util.Abort(_('file named %r already in dirstate') % | |
230 d) | |
231 seendirs[d] = True | |
232 | |
200 def update(self, files, state, **kw): | 233 def update(self, files, state, **kw): |
201 ''' current states: | 234 ''' current states: |
202 n normal | 235 n normal |
203 m needs merging | 236 m needs merging |
204 r marked for removal | 237 r marked for removal |
205 a marked for addition''' | 238 a marked for addition''' |
206 | 239 |
207 if not files: return | 240 if not files: return |
208 self.lazyread() | 241 self.lazyread() |
209 self.markdirty() | 242 self.markdirty() |
243 if state == "a": | |
244 self.initdirs() | |
245 self.checkshadows(files) | |
210 for f in files: | 246 for f in files: |
211 if state == "r": | 247 if state == "r": |
212 self.map[f] = ('r', 0, 0, 0) | 248 self.map[f] = ('r', 0, 0, 0) |
249 self.updatedirs(f, -1) | |
213 else: | 250 else: |
251 if state == "a": | |
252 self.updatedirs(f, 1) | |
214 s = os.lstat(self.wjoin(f)) | 253 s = os.lstat(self.wjoin(f)) |
215 st_size = kw.get('st_size', s.st_size) | 254 st_size = kw.get('st_size', s.st_size) |
216 st_mtime = kw.get('st_mtime', s.st_mtime) | 255 st_mtime = kw.get('st_mtime', s.st_mtime) |
217 self.map[f] = (state, s.st_mode, st_size, st_mtime) | 256 self.map[f] = (state, s.st_mode, st_size, st_mtime) |
218 if self.copies.has_key(f): | 257 if self.copies.has_key(f): |
220 | 259 |
221 def forget(self, files): | 260 def forget(self, files): |
222 if not files: return | 261 if not files: return |
223 self.lazyread() | 262 self.lazyread() |
224 self.markdirty() | 263 self.markdirty() |
264 self.initdirs() | |
225 for f in files: | 265 for f in files: |
226 try: | 266 try: |
227 del self.map[f] | 267 del self.map[f] |
268 self.updatedirs(f, -1) | |
228 except KeyError: | 269 except KeyError: |
229 self.ui.warn(_("not in dirstate: %s!\n") % f) | 270 self.ui.warn(_("not in dirstate: %s!\n") % f) |
230 pass | 271 pass |
231 | 272 |
232 def clear(self): | 273 def clear(self): |
233 self.map = {} | 274 self.map = {} |
234 self.copies = {} | 275 self.copies = {} |
276 self.dirs = None | |
235 self.markdirty() | 277 self.markdirty() |
236 | 278 |
237 def rebuild(self, parent, files): | 279 def rebuild(self, parent, files): |
238 self.clear() | 280 self.clear() |
239 umask = os.umask(0) | 281 umask = os.umask(0) |
240 os.umask(umask) | 282 os.umask(umask) |
241 for f, mode in files: | 283 for f in files: |
242 if mode: | 284 if files.execf(f): |
243 self.map[f] = ('n', ~umask, -1, 0) | 285 self.map[f] = ('n', ~umask, -1, 0) |
244 else: | 286 else: |
245 self.map[f] = ('n', ~umask & 0666, -1, 0) | 287 self.map[f] = ('n', ~umask & 0666, -1, 0) |
246 self.pl = (parent, nullid) | 288 self.pl = (parent, nullid) |
247 self.markdirty() | 289 self.markdirty() |
342 # | 384 # |
343 # dc is an optional arg for the current dirstate. dc is not modified | 385 # dc is an optional arg for the current dirstate. dc is not modified |
344 # directly by this function, but might be modified by your statmatch call. | 386 # directly by this function, but might be modified by your statmatch call. |
345 # | 387 # |
346 def walkhelper(self, files, statmatch, dc, badmatch=None): | 388 def walkhelper(self, files, statmatch, dc, badmatch=None): |
389 # self.root may end with a path separator when self.root == '/' | |
390 common_prefix_len = len(self.root) | |
391 if not self.root.endswith('/'): | |
392 common_prefix_len += 1 | |
347 # recursion free walker, faster than os.walk. | 393 # recursion free walker, faster than os.walk. |
348 def findfiles(s): | 394 def findfiles(s): |
349 work = [s] | 395 work = [s] |
350 while work: | 396 while work: |
351 top = work.pop() | 397 top = work.pop() |
352 names = os.listdir(top) | 398 names = os.listdir(top) |
353 names.sort() | 399 names.sort() |
354 # nd is the top of the repository dir tree | 400 # nd is the top of the repository dir tree |
355 nd = util.normpath(top[len(self.root) + 1:]) | 401 nd = util.normpath(top[common_prefix_len:]) |
356 if nd == '.': | 402 if nd == '.': |
357 nd = '' | 403 nd = '' |
358 else: | 404 else: |
359 # do not recurse into a repo contained in this | 405 # do not recurse into a repo contained in this |
360 # one. use bisect to find .hg directory so speed | 406 # one. use bisect to find .hg directory so speed |
432 ks.sort() | 478 ks.sort() |
433 for k in ks: | 479 for k in ks: |
434 if not seen(k) and (statmatch(k, None)): | 480 if not seen(k) and (statmatch(k, None)): |
435 yield 'm', k, None | 481 yield 'm', k, None |
436 | 482 |
437 def changes(self, files=None, match=util.always, show_ignored=None): | 483 def status(self, files=None, match=util.always, list_ignored=False, |
484 list_clean=False): | |
438 lookup, modified, added, unknown, ignored = [], [], [], [], [] | 485 lookup, modified, added, unknown, ignored = [], [], [], [], [] |
439 removed, deleted = [], [] | 486 removed, deleted, clean = [], [], [] |
440 | 487 |
441 for src, fn, st in self.statwalk(files, match, ignored=show_ignored): | 488 for src, fn, st in self.statwalk(files, match, ignored=list_ignored): |
442 try: | 489 try: |
443 type_, mode, size, time = self[fn] | 490 type_, mode, size, time = self[fn] |
444 except KeyError: | 491 except KeyError: |
445 if show_ignored and self.ignore(fn): | 492 if list_ignored and self.ignore(fn): |
446 ignored.append(fn) | 493 ignored.append(fn) |
447 else: | 494 else: |
448 unknown.append(fn) | 495 unknown.append(fn) |
449 continue | 496 continue |
450 if src == 'm': | 497 if src == 'm': |
471 if size >= 0 and (size != st.st_size | 518 if size >= 0 and (size != st.st_size |
472 or (mode ^ st.st_mode) & 0100): | 519 or (mode ^ st.st_mode) & 0100): |
473 modified.append(fn) | 520 modified.append(fn) |
474 elif time != st.st_mtime: | 521 elif time != st.st_mtime: |
475 lookup.append(fn) | 522 lookup.append(fn) |
523 elif list_clean: | |
524 clean.append(fn) | |
476 elif type_ == 'm': | 525 elif type_ == 'm': |
477 modified.append(fn) | 526 modified.append(fn) |
478 elif type_ == 'a': | 527 elif type_ == 'a': |
479 added.append(fn) | 528 added.append(fn) |
480 elif type_ == 'r': | 529 elif type_ == 'r': |
481 removed.append(fn) | 530 removed.append(fn) |
482 | 531 |
483 return (lookup, modified, added, removed, deleted, unknown, ignored) | 532 return (lookup, modified, added, removed, deleted, unknown, ignored, |
533 clean) |