dirstate.py
596 lines
| 19.0 KiB
| text/x-python
|
PythonLexer
/ mercurial / dirstate.py
mpm@selenic.com
|
r1089 | """ | ||
dirstate.py - working directory tracking for mercurial | ||||
Thomas Arendsen Hein
|
r4635 | Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | ||
mpm@selenic.com
|
r1089 | |||
This software may be used and distributed according to the terms | ||||
of the GNU General Public License, incorporated herein by reference. | ||||
""" | ||||
Joel Rosdahl
|
r6211 | from node import nullid | ||
Matt Mackall
|
r3891 | from i18n import _ | ||
Matt Mackall
|
r6767 | import struct, os, bisect, stat, util, errno, ignore | ||
Alexis S. L. Carvalho
|
r6326 | import cStringIO, osutil, sys | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4610 | _unknown = ('?', 0, 0, 0) | ||
_format = ">cllll" | ||||
Matt Mackall
|
r6767 | def _finddirs(path): | ||
pos = len(path) | ||||
while 1: | ||||
pos = path.rfind('/', 0, pos) | ||||
if pos == -1: | ||||
break | ||||
yield path[:pos] | ||||
Eric Hopper
|
r1559 | class dirstate(object): | ||
Benoit Boissinot
|
r2393 | |||
mpm@selenic.com
|
r1089 | def __init__(self, opener, ui, root): | ||
Matt Mackall
|
r4614 | self._opener = opener | ||
self._root = root | ||||
Matt Mackall
|
r4903 | self._dirty = False | ||
Matt Mackall
|
r4965 | self._dirtypl = False | ||
Matt Mackall
|
r4614 | self._ui = ui | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4603 | def __getattr__(self, name): | ||
Matt Mackall
|
r4614 | if name == '_map': | ||
Matt Mackall
|
r4615 | self._read() | ||
Matt Mackall
|
r4614 | return self._map | ||
elif name == '_copymap': | ||||
Matt Mackall
|
r4615 | self._read() | ||
Matt Mackall
|
r4614 | return self._copymap | ||
Paul Moore
|
r6677 | elif name == '_foldmap': | ||
_foldmap = {} | ||||
for name in self._map: | ||||
norm = os.path.normcase(os.path.normpath(name)) | ||||
_foldmap[norm] = name | ||||
self._foldmap = _foldmap | ||||
return self._foldmap | ||||
Matt Mackall
|
r4604 | elif name == '_branch': | ||
try: | ||||
Thomas Arendsen Hein
|
r4633 | self._branch = (self._opener("branch").read().strip() | ||
or "default") | ||||
Matt Mackall
|
r4604 | except IOError: | ||
self._branch = "default" | ||||
return self._branch | ||||
Matt Mackall
|
r4614 | elif name == '_pl': | ||
self._pl = [nullid, nullid] | ||||
Matt Mackall
|
r4604 | try: | ||
Matt Mackall
|
r4614 | st = self._opener("dirstate").read(40) | ||
Matt Mackall
|
r4604 | if len(st) == 40: | ||
Matt Mackall
|
r4614 | self._pl = st[:20], st[20:40] | ||
Matt Mackall
|
r4604 | except IOError, err: | ||
if err.errno != errno.ENOENT: raise | ||||
Matt Mackall
|
r4614 | return self._pl | ||
Matt Mackall
|
r4615 | elif name == '_dirs': | ||
Matt Mackall
|
r6767 | dirs = {} | ||
for f,s in self._map.items(): | ||||
if s[0] != 'r': | ||||
for base in _finddirs(f): | ||||
dirs[base] = dirs.get(base, 0) + 1 | ||||
self._dirs = dirs | ||||
Matt Mackall
|
r4615 | return self._dirs | ||
Matt Mackall
|
r4609 | elif name == '_ignore': | ||
Matt Mackall
|
r4905 | files = [self._join('.hgignore')] | ||
Matt Mackall
|
r4620 | for name, path in self._ui.configitems("ui"): | ||
if name == 'ignore' or name.startswith('ignore.'): | ||||
files.append(os.path.expanduser(path)) | ||||
Matt Mackall
|
r4614 | self._ignore = ignore.ignore(self._root, files, self._ui.warn) | ||
Matt Mackall
|
r4609 | return self._ignore | ||
Matt Mackall
|
r4611 | elif name == '_slash': | ||
Matt Mackall
|
r4614 | self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/' | ||
Matt Mackall
|
r4611 | return self._slash | ||
Matt Mackall
|
r6743 | elif name == '_checklink': | ||
self._checklink = util.checklink(self._root) | ||||
return self._checklink | ||||
Alexis S. L. Carvalho
|
r6257 | elif name == '_checkexec': | ||
self._checkexec = util.checkexec(self._root) | ||||
return self._checkexec | ||||
Matt Mackall
|
r6746 | elif name == '_checkcase': | ||
self._checkcase = not util.checkcase(self._join('.hg')) | ||||
return self._checkcase | ||||
Paul Moore
|
r6677 | elif name == 'normalize': | ||
Matt Mackall
|
r6746 | if self._checkcase: | ||
Paul Moore
|
r6677 | self.normalize = self._normalize | ||
else: | ||||
self.normalize = lambda x: x | ||||
return self.normalize | ||||
Matt Mackall
|
r4603 | else: | ||
raise AttributeError, name | ||||
Matt Mackall
|
r4905 | def _join(self, f): | ||
Matt Mackall
|
r4614 | return os.path.join(self._root, f) | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r6743 | def flagfunc(self, fallback): | ||
if self._checklink: | ||||
if self._checkexec: | ||||
def f(x): | ||||
p = os.path.join(self._root, x) | ||||
if os.path.islink(p): | ||||
return 'l' | ||||
if util.is_exec(p): | ||||
return 'x' | ||||
return '' | ||||
return f | ||||
def f(x): | ||||
if os.path.islink(os.path.join(self._root, x)): | ||||
return 'l' | ||||
if 'x' in fallback(x): | ||||
return 'x' | ||||
return '' | ||||
return f | ||||
if self._checkexec: | ||||
def f(x): | ||||
if 'l' in fallback(x): | ||||
return 'l' | ||||
if util.is_exec(os.path.join(self._root, x)): | ||||
return 'x' | ||||
return '' | ||||
return f | ||||
return fallback | ||||
mpm@selenic.com
|
r1089 | def getcwd(self): | ||
cwd = os.getcwd() | ||||
Matt Mackall
|
r4614 | if cwd == self._root: return '' | ||
# self._root ends with a path separator if self._root is '/' or 'C:\' | ||||
rootsep = self._root | ||||
Shun-ichi GOTO
|
r5843 | if not util.endswithsep(rootsep): | ||
Alexis S. L. Carvalho
|
r4230 | rootsep += os.sep | ||
if cwd.startswith(rootsep): | ||||
return cwd[len(rootsep):] | ||||
else: | ||||
# we're outside the repo. return an absolute path. | ||||
return cwd | ||||
mpm@selenic.com
|
r1089 | |||
Alexis S. L. Carvalho
|
r4525 | def pathto(self, f, cwd=None): | ||
if cwd is None: | ||||
cwd = self.getcwd() | ||||
Matt Mackall
|
r4614 | path = util.pathto(self._root, cwd, f) | ||
Alexis S. L. Carvalho
|
r4527 | if self._slash: | ||
Shun-ichi GOTO
|
r5842 | return util.normpath(path) | ||
Alexis S. L. Carvalho
|
r4527 | return path | ||
Alexis S. L. Carvalho
|
r4525 | |||
mpm@selenic.com
|
r1089 | def __getitem__(self, key): | ||
Matt Mackall
|
r4906 | ''' current states: | ||
n normal | ||||
m needs merging | ||||
r marked for removal | ||||
a marked for addition | ||||
? not tracked''' | ||||
return self._map.get(key, ("?",))[0] | ||||
mpm@selenic.com
|
r1089 | |||
def __contains__(self, key): | ||||
Matt Mackall
|
r4614 | return key in self._map | ||
def __iter__(self): | ||||
Matt Mackall
|
r6762 | for x in util.sort(self._map): | ||
Matt Mackall
|
r4614 | yield x | ||
mpm@selenic.com
|
r1089 | |||
def parents(self): | ||||
Matt Mackall
|
r4614 | return self._pl | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4179 | def branch(self): | ||
return self._branch | ||||
mpm@selenic.com
|
r1089 | def setparents(self, p1, p2=nullid): | ||
Matt Mackall
|
r4965 | self._dirty = self._dirtypl = True | ||
Matt Mackall
|
r4614 | self._pl = p1, p2 | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4179 | def setbranch(self, branch): | ||
self._branch = branch | ||||
Matt Mackall
|
r4614 | self._opener("branch", "w").write(branch + '\n') | ||
Matt Mackall
|
r4179 | |||
Matt Mackall
|
r4615 | def _read(self): | ||
Matt Mackall
|
r4614 | self._map = {} | ||
self._copymap = {} | ||||
Alexis S. L. Carvalho
|
r4952 | if not self._dirtypl: | ||
self._pl = [nullid, nullid] | ||||
Matt Mackall
|
r4607 | try: | ||
Matt Mackall
|
r4614 | st = self._opener("dirstate").read() | ||
Matt Mackall
|
r4607 | except IOError, err: | ||
if err.errno != errno.ENOENT: raise | ||||
return | ||||
if not st: | ||||
return | ||||
Alexis S. L. Carvalho
|
r4952 | if not self._dirtypl: | ||
self._pl = [st[:20], st[20: 40]] | ||||
mpm@selenic.com
|
r1089 | |||
Vadim Gelfer
|
r2427 | # deref fields so they will be local in loop | ||
Matt Mackall
|
r4614 | dmap = self._map | ||
copymap = self._copymap | ||||
Vadim Gelfer
|
r2427 | unpack = struct.unpack | ||
Matt Mackall
|
r4610 | e_size = struct.calcsize(_format) | ||
Matt Mackall
|
r5327 | pos1 = 40 | ||
l = len(st) | ||||
Vadim Gelfer
|
r2427 | |||
Matt Mackall
|
r5327 | # the inner loop | ||
while pos1 < l: | ||||
pos2 = pos1 + e_size | ||||
e = unpack(">cllll", st[pos1:pos2]) # a literal here is faster | ||||
pos1 = pos2 + e[4] | ||||
f = st[pos2:pos1] | ||||
mpm@selenic.com
|
r1089 | if '\0' in f: | ||
f, c = f.split('\0') | ||||
Matt Mackall
|
r3154 | copymap[f] = c | ||
Matt Mackall
|
r5327 | dmap[f] = e # we hold onto e[4] because making a subtuple is slow | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4613 | def invalidate(self): | ||
Paul Moore
|
r6677 | for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split(): | ||
Alexis S. L. Carvalho
|
r4953 | if a in self.__dict__: | ||
delattr(self, a) | ||||
Matt Mackall
|
r4903 | self._dirty = False | ||
Bryan O'Sullivan
|
r4375 | |||
mpm@selenic.com
|
r1089 | def copy(self, source, dest): | ||
Patrick Mezard
|
r6680 | if source == dest: | ||
return | ||||
Matt Mackall
|
r4903 | self._dirty = True | ||
Matt Mackall
|
r4614 | self._copymap[dest] = source | ||
mpm@selenic.com
|
r1089 | |||
def copied(self, file): | ||||
Matt Mackall
|
r4614 | return self._copymap.get(file, None) | ||
Matt Mackall
|
r3154 | |||
def copies(self): | ||||
Matt Mackall
|
r4614 | return self._copymap | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r6767 | def _droppath(self, f): | ||
if self[f] not in "?r" and "_dirs" in self.__dict__: | ||||
Matt Mackall
|
r5326 | dirs = self._dirs | ||
Matt Mackall
|
r6767 | for base in _finddirs(f): | ||
if dirs[base] == 1: | ||||
del dirs[base] | ||||
else: | ||||
dirs[base] -= 1 | ||||
Vadim Gelfer
|
r2953 | |||
Matt Mackall
|
r6767 | def _addpath(self, f, check=False): | ||
Maxim Dounin
|
r5487 | oldstate = self[f] | ||
Matt Mackall
|
r6767 | if check or oldstate == "r": | ||
if '\r' in f or '\n' in f: | ||||
raise util.Abort( | ||||
_("'\\n' and '\\r' disallowed in filenames: %r") % f) | ||||
if f in self._dirs: | ||||
raise util.Abort(_('directory %r already in dirstate') % f) | ||||
# shadows | ||||
for d in _finddirs(f): | ||||
if d in self._dirs: | ||||
break | ||||
if d in self._map and self[d] != 'r': | ||||
raise util.Abort( | ||||
_('file %r in dirstate clashes with %r') % (d, f)) | ||||
if oldstate in "?r" and "_dirs" in self.__dict__: | ||||
dirs = self._dirs | ||||
for base in _finddirs(f): | ||||
dirs[base] = dirs.get(base, 0) + 1 | ||||
Maxim Dounin
|
r5487 | |||
Matt Mackall
|
r4904 | def normal(self, f): | ||
Alexis S. L. Carvalho
|
r5210 | 'mark a file normal and clean' | ||
Matt Mackall
|
r4904 | self._dirty = True | ||
Matt Mackall
|
r6767 | self._addpath(f) | ||
Matt Mackall
|
r4905 | s = os.lstat(self._join(f)) | ||
Matt Mackall
|
r5327 | self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0) | ||
Christian Ebert
|
r5915 | if f in self._copymap: | ||
Matt Mackall
|
r4904 | del self._copymap[f] | ||
mpm@selenic.com
|
r1089 | |||
Alexis S. L. Carvalho
|
r5210 | def normallookup(self, f): | ||
Matt Mackall
|
r4904 | 'mark a file normal, but possibly dirty' | ||
Alexis S. L. Carvalho
|
r6298 | if self._pl[1] != nullid and f in self._map: | ||
# if there is a merge going on and the file was either | ||||
# in state 'm' or dirty before being removed, restore that state. | ||||
entry = self._map[f] | ||||
if entry[0] == 'r' and entry[2] in (-1, -2): | ||||
source = self._copymap.get(f) | ||||
if entry[2] == -1: | ||||
self.merge(f) | ||||
elif entry[2] == -2: | ||||
self.normaldirty(f) | ||||
if source: | ||||
self.copy(source, f) | ||||
return | ||||
if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2: | ||||
return | ||||
Matt Mackall
|
r4903 | self._dirty = True | ||
Matt Mackall
|
r6767 | self._addpath(f) | ||
Matt Mackall
|
r5327 | self._map[f] = ('n', 0, -1, -1, 0) | ||
Alexis S. L. Carvalho
|
r5210 | if f in self._copymap: | ||
del self._copymap[f] | ||||
def normaldirty(self, f): | ||||
'mark a file normal, but dirty' | ||||
self._dirty = True | ||||
Matt Mackall
|
r6767 | self._addpath(f) | ||
Matt Mackall
|
r5327 | self._map[f] = ('n', 0, -2, -1, 0) | ||
Matt Mackall
|
r4904 | if f in self._copymap: | ||
del self._copymap[f] | ||||
def add(self, f): | ||||
'mark a file added' | ||||
self._dirty = True | ||||
Matt Mackall
|
r6767 | self._addpath(f, True) | ||
Matt Mackall
|
r5327 | self._map[f] = ('a', 0, -1, -1, 0) | ||
Matt Mackall
|
r4904 | if f in self._copymap: | ||
del self._copymap[f] | ||||
Matt Mackall
|
r4616 | |||
Matt Mackall
|
r4904 | def remove(self, f): | ||
'mark a file removed' | ||||
self._dirty = True | ||||
Matt Mackall
|
r6767 | self._droppath(f) | ||
Alexis S. L. Carvalho
|
r6297 | size = 0 | ||
if self._pl[1] != nullid and f in self._map: | ||||
entry = self._map[f] | ||||
if entry[0] == 'm': | ||||
size = -1 | ||||
elif entry[0] == 'n' and entry[2] == -2: | ||||
size = -2 | ||||
self._map[f] = ('r', 0, size, 0, 0) | ||||
if size == 0 and f in self._copymap: | ||||
Matt Mackall
|
r4904 | del self._copymap[f] | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r4904 | def merge(self, f): | ||
'mark a file merged' | ||||
Matt Mackall
|
r4903 | self._dirty = True | ||
Matt Mackall
|
r4905 | s = os.lstat(self._join(f)) | ||
Matt Mackall
|
r6767 | self._addpath(f) | ||
Matt Mackall
|
r5327 | self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0) | ||
Matt Mackall
|
r4904 | if f in self._copymap: | ||
del self._copymap[f] | ||||
def forget(self, f): | ||||
'forget a file' | ||||
self._dirty = True | ||||
try: | ||||
Patrick Mezard
|
r6807 | self._droppath(f) | ||
Matt Mackall
|
r4904 | del self._map[f] | ||
except KeyError: | ||||
Thomas Arendsen Hein
|
r6057 | self._ui.warn(_("not in dirstate: %s\n") % f) | ||
mpm@selenic.com
|
r1089 | |||
Paul Moore
|
r6677 | def _normalize(self, path): | ||
Matt Mackall
|
r6822 | if path not in self._foldmap: | ||
if not os.path.exists(path): | ||||
return path | ||||
self._foldmap[path] = util.fspath(path, self._root) | ||||
return self._foldmap[path] | ||||
Paul Moore
|
r6677 | |||
Alexis S. L. Carvalho
|
r5065 | def clear(self): | ||
self._map = {} | ||||
Maxim Dounin
|
r5487 | if "_dirs" in self.__dict__: | ||
delattr(self, "_dirs"); | ||||
Alexis S. L. Carvalho
|
r5065 | self._copymap = {} | ||
self._pl = [nullid, nullid] | ||||
Alexis S. L. Carvalho
|
r5123 | self._dirty = True | ||
Alexis S. L. Carvalho
|
r5065 | |||
Benoit Boissinot
|
r1755 | def rebuild(self, parent, files): | ||
Alexis S. L. Carvalho
|
r5065 | self.clear() | ||
Matt Mackall
|
r2832 | for f in files: | ||
Matt Mackall
|
r6750 | if 'x' in files.flags(f): | ||
Matt Mackall
|
r5327 | self._map[f] = ('n', 0777, -1, 0, 0) | ||
Benoit Boissinot
|
r1755 | else: | ||
Matt Mackall
|
r5327 | self._map[f] = ('n', 0666, -1, 0, 0) | ||
Matt Mackall
|
r4614 | self._pl = (parent, nullid) | ||
Matt Mackall
|
r4903 | self._dirty = True | ||
mpm@selenic.com
|
r1089 | |||
def write(self): | ||||
Matt Mackall
|
r4612 | if not self._dirty: | ||
Benoit Boissinot
|
r1794 | return | ||
Alexis S. L. Carvalho
|
r6326 | st = self._opener("dirstate", "w", atomictemp=True) | ||
Matt Mackall
|
r6327 | |||
try: | ||||
gran = int(self._ui.config('dirstate', 'granularity', 1)) | ||||
except ValueError: | ||||
gran = 1 | ||||
limit = sys.maxint | ||||
if gran > 0: | ||||
limit = util.fstat(st).st_mtime - gran | ||||
Bryan O'Sullivan
|
r4374 | cs = cStringIO.StringIO() | ||
Matt Mackall
|
r5327 | copymap = self._copymap | ||
pack = struct.pack | ||||
write = cs.write | ||||
write("".join(self._pl)) | ||||
Matt Mackall
|
r4614 | for f, e in self._map.iteritems(): | ||
Matt Mackall
|
r5327 | if f in copymap: | ||
f = "%s\0%s" % (f, copymap[f]) | ||||
Alexis S. L. Carvalho
|
r6326 | if e[3] > limit and e[0] == 'n': | ||
e = (e[0], 0, -1, -1, 0) | ||||
Matt Mackall
|
r5327 | e = pack(_format, e[0], e[1], e[2], e[3], len(f)) | ||
write(e) | ||||
write(f) | ||||
Bryan O'Sullivan
|
r4374 | st.write(cs.getvalue()) | ||
Alexis S. L. Carvalho
|
r4507 | st.rename() | ||
Matt Mackall
|
r4965 | self._dirty = self._dirtypl = False | ||
mpm@selenic.com
|
r1089 | |||
Alexis S. L. Carvalho
|
r6032 | def _dirignore(self, f): | ||
Patrick Mezard
|
r6479 | if f == '.': | ||
return False | ||||
Alexis S. L. Carvalho
|
r6032 | if self._ignore(f): | ||
return True | ||||
Matt Mackall
|
r6767 | for p in _finddirs(f): | ||
if self._ignore(p): | ||||
Alexis S. L. Carvalho
|
r6032 | return True | ||
return False | ||||
Matt Mackall
|
r6755 | def walk(self, match, unknown, ignored): | ||
Matt Mackall
|
r3529 | ''' | ||
walk recursively through the directory tree, finding all files | ||||
matched by the match function | ||||
Matt Mackall
|
r6818 | results are yielded in a tuple (filename, stat), where stat | ||
Matt Mackall
|
r3529 | and st is the stat result if the file was found in the directory. | ||
''' | ||||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r6578 | def fwarn(f, msg): | ||
self._ui.warn('%s: %s\n' % (self.pathto(ff), msg)) | ||||
return False | ||||
Matt Mackall
|
r6589 | badfn = fwarn | ||
if hasattr(match, 'bad'): | ||||
badfn = match.bad | ||||
Matt Mackall
|
r6578 | |||
Matt Mackall
|
r6830 | def badtype(f, mode): | ||
kind = 'unknown' | ||||
if stat.S_ISCHR(mode): kind = _('character device') | ||||
elif stat.S_ISBLK(mode): kind = _('block device') | ||||
elif stat.S_ISFIFO(mode): kind = _('fifo') | ||||
elif stat.S_ISSOCK(mode): kind = _('socket') | ||||
elif stat.S_ISDIR(mode): kind = _('directory') | ||||
self._ui.warn(_('%s: unsupported file type (type is %s)\n') | ||||
% (self.pathto(f), kind)) | ||||
Thomas Arendsen Hein
|
r6201 | # TODO: don't walk unknown directories if unknown and ignored are False | ||
Matt Mackall
|
r4609 | ignore = self._ignore | ||
Alexis S. L. Carvalho
|
r6032 | dirignore = self._dirignore | ||
Alexis S. L. Carvalho
|
r4193 | if ignored: | ||
ignore = util.never | ||||
Alexis S. L. Carvalho
|
r6032 | dirignore = util.never | ||
Matt Mackall
|
r3534 | |||
Matt Mackall
|
r6834 | matchfn = match.matchfn | ||
Matt Mackall
|
r6831 | dmap = self._map | ||
Matt Mackall
|
r5000 | normpath = util.normpath | ||
Matt Mackall
|
r6822 | normalize = self.normalize | ||
Bryan O'Sullivan
|
r5396 | listdir = osutil.listdir | ||
Matt Mackall
|
r5000 | lstat = os.lstat | ||
bisect_left = bisect.bisect_left | ||||
pconvert = util.pconvert | ||||
Matt Mackall
|
r6830 | getkind = stat.S_IFMT | ||
Matt Mackall
|
r6828 | dirkind = stat.S_IFDIR | ||
Matt Mackall
|
r6830 | regkind = stat.S_IFREG | ||
lnkkind = stat.S_IFLNK | ||||
Matt Mackall
|
r6831 | join = self._join | ||
Matt Mackall
|
r6820 | work = [] | ||
wadd = work.append | ||||
Matt Mackall
|
r6831 | files = util.unique(match.files()) | ||
if not files or '.' in files: | ||||
files = [''] | ||||
results = {'.hg': None} | ||||
Matt Mackall
|
r5000 | |||
Matt Mackall
|
r6826 | # step 1: find all explicit files | ||
Matt Mackall
|
r6820 | for ff in util.sort(files): | ||
Matt Mackall
|
r6822 | nf = normalize(normpath(ff)) | ||
Matt Mackall
|
r6829 | if nf in results: | ||
Matt Mackall
|
r6820 | continue | ||
try: | ||||
Matt Mackall
|
r6831 | st = lstat(join(nf)) | ||
Matt Mackall
|
r6830 | kind = getkind(st.st_mode) | ||
if kind == dirkind: | ||||
Matt Mackall
|
r6828 | if not dirignore(nf): | ||
wadd(nf) | ||||
Matt Mackall
|
r6830 | elif kind == regkind or kind == lnkkind: | ||
results[nf] = st | ||||
Matt Mackall
|
r6828 | else: | ||
Matt Mackall
|
r6830 | badtype(ff, kind) | ||
if nf in dmap: | ||||
Matt Mackall
|
r6829 | results[nf] = None | ||
Matt Mackall
|
r6820 | except OSError, inst: | ||
keep = False | ||||
Matt Mackall
|
r6828 | prefix = nf + "/" | ||
Matt Mackall
|
r6821 | for fn in dmap: | ||
Matt Mackall
|
r6828 | if nf == fn or fn.startswith(prefix): | ||
Matt Mackall
|
r6820 | keep = True | ||
break | ||||
if not keep: | ||||
if inst.errno != errno.ENOENT: | ||||
fwarn(ff, inst.strerror) | ||||
Matt Mackall
|
r6832 | elif badfn(ff, inst.strerror): | ||
Matt Mackall
|
r6834 | if (nf in dmap or not ignore(nf)) and matchfn(nf): | ||
Matt Mackall
|
r6832 | results[nf] = None | ||
Matt Mackall
|
r6820 | |||
Matt Mackall
|
r6826 | # step 2: visit subdirectories | ||
while work: | ||||
nd = work.pop() | ||||
if hasattr(match, 'dir'): | ||||
match.dir(nd) | ||||
Matt Mackall
|
r6831 | entries = listdir(join(nd), stat=True) | ||
Matt Mackall
|
r6826 | if nd == '.': | ||
nd = '' | ||||
else: | ||||
# do not recurse into a repo contained in this | ||||
# one. use bisect to find .hg directory so speed | ||||
# is good on big directory. | ||||
hg = bisect_left(entries, ('.hg')) | ||||
if hg < len(entries) and entries[hg][0] == '.hg' \ | ||||
Matt Mackall
|
r6828 | and entries[hg][1] == dirkind: | ||
mason@suse.com
|
r1183 | continue | ||
Matt Mackall
|
r6826 | for f, kind, st in entries: | ||
Matt Mackall
|
r6828 | nf = normalize(nd and (nd + "/" + f) or f) | ||
Matt Mackall
|
r6829 | if nf not in results: | ||
Matt Mackall
|
r6828 | if kind == dirkind: | ||
if not ignore(nf): | ||||
wadd(nf) | ||||
Matt Mackall
|
r6834 | if nf in dmap and matchfn(nf): | ||
Matt Mackall
|
r6829 | results[nf] = None | ||
Matt Mackall
|
r6832 | elif kind == regkind or kind == lnkkind: | ||
if nf in dmap: | ||||
Matt Mackall
|
r6834 | if matchfn(nf): | ||
Matt Mackall
|
r6832 | results[nf] = st | ||
Matt Mackall
|
r6834 | elif matchfn(nf) and not ignore(nf): | ||
Matt Mackall
|
r6829 | results[nf] = st | ||
Matt Mackall
|
r6834 | elif nf in dmap and matchfn(nf): | ||
Matt Mackall
|
r6832 | results[nf] = None | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r6826 | # step 3: report unseen items in the dmap hash | ||
Matt Mackall
|
r6833 | visit = [f for f in dmap if f not in results and match(f)] | ||
for nf in util.sort(visit): | ||||
results[nf] = None | ||||
try: | ||||
st = lstat(join(nf)) | ||||
kind = getkind(st.st_mode) | ||||
if kind == regkind or kind == lnkkind: | ||||
results[nf] = st | ||||
except OSError, inst: | ||||
if inst.errno not in (errno.ENOENT, errno.ENOTDIR): | ||||
raise | ||||
Matt Mackall
|
r6829 | |||
Matt Mackall
|
r6831 | del results['.hg'] | ||
Matt Mackall
|
r6829 | return results | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r6753 | def status(self, match, ignored, clean, unknown): | ||
listignored, listclean, listunknown = ignored, clean, unknown | ||||
Thomas Arendsen Hein
|
r2022 | lookup, modified, added, unknown, ignored = [], [], [], [], [] | ||
Vadim Gelfer
|
r2661 | removed, deleted, clean = [], [], [] | ||
mpm@selenic.com
|
r1089 | |||
Matt Mackall
|
r5003 | _join = self._join | ||
lstat = os.lstat | ||||
cmap = self._copymap | ||||
dmap = self._map | ||||
ladd = lookup.append | ||||
madd = modified.append | ||||
aadd = added.append | ||||
uadd = unknown.append | ||||
iadd = ignored.append | ||||
radd = removed.append | ||||
dadd = deleted.append | ||||
cadd = clean.append | ||||
Matt Mackall
|
r6829 | for fn, st in self.walk(match, listunknown, listignored).iteritems(): | ||
Matt Mackall
|
r6591 | if fn not in dmap: | ||
Matt Mackall
|
r6753 | if (listignored or match.exact(fn)) and self._dirignore(fn): | ||
if listignored: | ||||
Alexis S. L. Carvalho
|
r6033 | iadd(fn) | ||
Matt Mackall
|
r6753 | elif listunknown: | ||
Matt Mackall
|
r5003 | uadd(fn) | ||
Benoit Boissinot
|
r1471 | continue | ||
Matt Mackall
|
r6591 | |||
state, mode, size, time, foo = dmap[fn] | ||||
Matt Mackall
|
r6818 | if not st and state in "nma": | ||
dadd(fn) | ||||
elif state == 'n': | ||||
Alexis S. L. Carvalho
|
r6257 | if (size >= 0 and | ||
(size != st.st_size | ||||
or ((mode ^ st.st_mode) & 0100 and self._checkexec)) | ||||
Alexis S. L. Carvalho
|
r5210 | or size == -2 | ||
Alexis S. L. Carvalho
|
r4677 | or fn in self._copymap): | ||
Matt Mackall
|
r5003 | madd(fn) | ||
Alexis S. L. Carvalho
|
r2962 | elif time != int(st.st_mtime): | ||
Matt Mackall
|
r5003 | ladd(fn) | ||
Matt Mackall
|
r6753 | elif listclean: | ||
Matt Mackall
|
r5003 | cadd(fn) | ||
Matt Mackall
|
r6590 | elif state == 'm': | ||
Matt Mackall
|
r5003 | madd(fn) | ||
Matt Mackall
|
r6590 | elif state == 'a': | ||
Matt Mackall
|
r5003 | aadd(fn) | ||
Matt Mackall
|
r6590 | elif state == 'r': | ||
Matt Mackall
|
r5003 | radd(fn) | ||
mason@suse.com
|
r1183 | |||
Vadim Gelfer
|
r2661 | return (lookup, modified, added, removed, deleted, unknown, ignored, | ||
clean) | ||||