diff options
Diffstat (limited to 'mercurial/dirstate.py')
-rw-r--r-- | mercurial/dirstate.py | 192 |
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: |