summaryrefslogtreecommitdiff
path: root/mercurial/dirstate.py
diff options
context:
space:
mode:
Diffstat (limited to 'mercurial/dirstate.py')
-rw-r--r--mercurial/dirstate.py192
1 files changed, 58 insertions, 134 deletions
diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
index e516d93..c8219b5 100644
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -4,7 +4,6 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import errno
from node import nullid
from i18n import _
@@ -14,17 +13,6 @@ import cStringIO
_format = ">cllll"
propertycache = util.propertycache
-filecache = scmutil.filecache
-
-class repocache(filecache):
- """filecache for files in .hg/"""
- def join(self, obj, fname):
- return obj._opener.join(fname)
-
-class rootcache(filecache):
- """filecache for files in the repository root"""
- def join(self, obj, fname):
- return obj._join(fname)
def _finddirs(path):
pos = path.rfind('/')
@@ -61,9 +49,8 @@ class dirstate(object):
self._rootdir = os.path.join(root, '')
self._dirty = False
self._dirtypl = False
- self._lastnormaltime = 0
+ self._lastnormaltime = None
self._ui = ui
- self._filecache = {}
@propertycache
def _map(self):
@@ -81,19 +68,14 @@ class dirstate(object):
def _foldmap(self):
f = {}
for name in self._map:
- f[util.normcase(name)] = name
- for name in self._dirs:
- f[util.normcase(name)] = name
- f['.'] = '.' # prevents useless util.fspath() invocation
+ f[os.path.normcase(name)] = name
return f
- @repocache('branch')
+ @propertycache
def _branch(self):
try:
return self._opener.read("branch").strip() or "default"
- except IOError, inst:
- if inst.errno != errno.ENOENT:
- raise
+ except IOError:
return "default"
@propertycache
@@ -120,10 +102,7 @@ class dirstate(object):
_incdirs(dirs, f)
return dirs
- def dirs(self):
- return self._dirs
-
- @rootcache('.hgignore')
+ @propertycache
def _ignore(self):
files = [self._join('.hgignore')]
for name, path in self._ui.configitems("ui"):
@@ -152,19 +131,17 @@ class dirstate(object):
# it's safe because f is always a relative path
return self._rootdir + f
- def flagfunc(self, buildfallback):
- if self._checklink and self._checkexec:
- def f(x):
- p = self._join(x)
- if os.path.islink(p):
- return 'l'
- if util.isexec(p):
- return 'x'
- return ''
- return f
-
- fallback = buildfallback()
+ def flagfunc(self, fallback):
if self._checklink:
+ if self._checkexec:
+ def f(x):
+ p = self._join(x)
+ if os.path.islink(p):
+ return 'l'
+ if util.isexec(p):
+ return 'x'
+ return ''
+ return f
def f(x):
if os.path.islink(self._join(x)):
return 'l'
@@ -180,8 +157,7 @@ class dirstate(object):
return 'x'
return ''
return f
- else:
- return fallback
+ return fallback
def getcwd(self):
cwd = os.getcwd()
@@ -237,36 +213,14 @@ class dirstate(object):
return encoding.tolocal(self._branch)
def setparents(self, p1, p2=nullid):
- """Set dirstate parents to p1 and p2.
-
- When moving from two parents to one, 'm' merged entries a
- adjusted to normal and previous copy records discarded and
- returned by the call.
-
- See localrepo.setparents()
- """
self._dirty = self._dirtypl = True
- oldp2 = self._pl[1]
self._pl = p1, p2
- copies = {}
- if oldp2 != nullid and p2 == nullid:
- # Discard 'm' markers when moving away from a merge state
- for f, s in self._map.iteritems():
- if s[0] == 'm':
- if f in self._copymap:
- copies[f] = self._copymap[f]
- self.normallookup(f)
- return copies
def setbranch(self, branch):
if branch in ['tip', '.', 'null']:
raise util.Abort(_('the name \'%s\' is reserved') % branch)
self._branch = encoding.fromlocal(branch)
- f = self._opener('branch', 'w', atomictemp=True)
- try:
- f.write(self._branch + '\n')
- finally:
- f.close()
+ self._opener.write("branch", self._branch + '\n')
def _read(self):
self._map = {}
@@ -289,7 +243,7 @@ class dirstate(object):
"_ignore"):
if a in self.__dict__:
delattr(self, a)
- self._lastnormaltime = 0
+ self._lastnormaltime = None
self._dirty = False
def copy(self, source, dest):
@@ -312,9 +266,9 @@ class dirstate(object):
if self[f] not in "?r" and "_dirs" in self.__dict__:
_decdirs(self._dirs, f)
- def _addpath(self, f, state, mode, size, mtime):
+ def _addpath(self, f, check=False):
oldstate = self[f]
- if state == 'a' or oldstate == 'r':
+ if check or oldstate == "r":
scmutil.checkfilename(f)
if f in self._dirs:
raise util.Abort(_('directory %r already in dirstate') % f)
@@ -327,14 +281,14 @@ class dirstate(object):
_('file %r in dirstate clashes with %r') % (d, f))
if oldstate in "?r" and "_dirs" in self.__dict__:
_incdirs(self._dirs, f)
- self._dirty = True
- self._map[f] = (state, mode, size, mtime)
def normal(self, f):
'''Mark a file normal and clean.'''
+ self._dirty = True
+ self._addpath(f)
s = os.lstat(self._join(f))
mtime = int(s.st_mtime)
- self._addpath(f, 'n', s.st_mode, s.st_size, mtime)
+ self._map[f] = ('n', s.st_mode, s.st_size, mtime)
if f in self._copymap:
del self._copymap[f]
if mtime > self._lastnormaltime:
@@ -361,7 +315,9 @@ class dirstate(object):
return
if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
return
- self._addpath(f, 'n', 0, -1, -1)
+ self._dirty = True
+ self._addpath(f)
+ self._map[f] = ('n', 0, -1, -1)
if f in self._copymap:
del self._copymap[f]
@@ -370,13 +326,17 @@ class dirstate(object):
if self._pl[1] == nullid:
raise util.Abort(_("setting %r to other parent "
"only allowed in merges") % f)
- self._addpath(f, 'n', 0, -2, -1)
+ self._dirty = True
+ self._addpath(f)
+ self._map[f] = ('n', 0, -2, -1)
if f in self._copymap:
del self._copymap[f]
def add(self, f):
'''Mark a file added.'''
- self._addpath(f, 'a', 0, -1, -1)
+ self._dirty = True
+ self._addpath(f, True)
+ self._map[f] = ('a', 0, -1, -1)
if f in self._copymap:
del self._copymap[f]
@@ -398,62 +358,36 @@ class dirstate(object):
def merge(self, f):
'''Mark a file merged.'''
- if self._pl[1] == nullid:
- return self.normallookup(f)
+ self._dirty = True
s = os.lstat(self._join(f))
- self._addpath(f, 'm', s.st_mode, s.st_size, int(s.st_mtime))
+ self._addpath(f)
+ self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
if f in self._copymap:
del self._copymap[f]
def drop(self, f):
'''Drop a file from the dirstate'''
- if f in self._map:
- self._dirty = True
- self._droppath(f)
- del self._map[f]
+ self._dirty = True
+ self._droppath(f)
+ del self._map[f]
- def _normalize(self, path, isknown, ignoremissing=False, exists=None):
- normed = util.normcase(path)
+ def _normalize(self, path, isknown):
+ normed = os.path.normcase(path)
folded = self._foldmap.get(normed, None)
if folded is None:
- if isknown:
+ if isknown or not os.path.lexists(os.path.join(self._root, path)):
folded = path
else:
- if exists is None:
- exists = os.path.lexists(os.path.join(self._root, path))
- if not exists:
- # Maybe a path component exists
- if not ignoremissing and '/' in path:
- d, f = path.rsplit('/', 1)
- d = self._normalize(d, isknown, ignoremissing, None)
- folded = d + "/" + f
- else:
- # No path components, preserve original case
- folded = path
- else:
- # recursively normalize leading directory components
- # against dirstate
- if '/' in normed:
- d, f = normed.rsplit('/', 1)
- d = self._normalize(d, isknown, ignoremissing, True)
- r = self._root + "/" + d
- folded = d + "/" + util.fspath(f, r)
- else:
- folded = util.fspath(normed, self._root)
- self._foldmap[normed] = folded
-
+ folded = self._foldmap.setdefault(normed,
+ util.fspath(path, self._root))
return folded
- def normalize(self, path, isknown=False, ignoremissing=False):
+ def normalize(self, path, isknown=False):
'''
normalize the case of a pathname when on a casefolding filesystem
isknown specifies whether the filename came from walking the
- disk, to avoid extra filesystem access.
-
- If ignoremissing is True, missing path are returned
- unchanged. Otherwise, we try harder to normalize possibly
- existing path components.
+ disk, to avoid extra filesystem access
The normalized case is determined based on the following precedence:
@@ -463,7 +397,7 @@ class dirstate(object):
'''
if self._checkcase:
- return self._normalize(path, isknown, ignoremissing)
+ return self._normalize(path, isknown)
return path
def clear(self):
@@ -472,7 +406,7 @@ class dirstate(object):
delattr(self, "_dirs")
self._copymap = {}
self._pl = [nullid, nullid]
- self._lastnormaltime = 0
+ self._lastnormaltime = None
self._dirty = True
def rebuild(self, parent, files):
@@ -490,24 +424,12 @@ class dirstate(object):
return
st = self._opener("dirstate", "w", atomictemp=True)
- def finish(s):
- st.write(s)
- st.close()
- self._lastnormaltime = 0
- self._dirty = self._dirtypl = False
-
# use the modification time of the newly created temporary file as the
# filesystem's notion of 'now'
- now = util.fstat(st).st_mtime
- copymap = self._copymap
- try:
- finish(parsers.pack_dirstate(self._map, copymap, self._pl, now))
- return
- except AttributeError:
- pass
+ now = int(util.fstat(st).st_mtime)
- now = int(now)
cs = cStringIO.StringIO()
+ copymap = self._copymap
pack = struct.pack
write = cs.write
write("".join(self._pl))
@@ -530,7 +452,10 @@ class dirstate(object):
e = pack(_format, e[0], e[1], e[2], e[3], len(f))
write(e)
write(f)
- finish(cs.getvalue())
+ st.write(cs.getvalue())
+ st.rename()
+ self._lastnormaltime = None
+ self._dirty = self._dirtypl = False
def _dirignore(self, f):
if f == '.':
@@ -600,11 +525,11 @@ class dirstate(object):
elif match.files() and not match.anypats(): # match.match, no patterns
skipstep3 = True
- if not exact and self._checkcase:
+ if self._checkcase:
normalize = self._normalize
skipstep3 = False
else:
- normalize = lambda x, y, z: x
+ normalize = lambda x, y: x
files = sorted(match.files())
subrepos.sort()
@@ -625,7 +550,7 @@ class dirstate(object):
# step 1: find all explicit files
for ff in files:
- nf = normalize(normpath(ff), False, True)
+ nf = normalize(normpath(ff), False)
if nf in results:
continue
@@ -675,7 +600,7 @@ class dirstate(object):
continue
raise
for f, kind, st in entries:
- nf = normalize(nd and (nd + "/" + f) or f, True, True)
+ nf = normalize(nd and (nd + "/" + f) or f, True)
if nf not in results:
if kind == dirkind:
if not ignore(nf):
@@ -696,8 +621,7 @@ class dirstate(object):
if not skipstep3 and not exact:
visit = sorted([f for f in dmap if f not in results and matchfn(f)])
for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
- if (not st is None and
- getkind(st.st_mode) not in (regkind, lnkkind)):
+ if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
st = None
results[nf] = st
for s in subrepos: