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)