Mercurial > traipse_dev
view upmana/mercurial/dirstate.py @ 121:496dbf12a6cb alpha
Traipse Alpha 'OpenRPG' {091030-00}
Traipse is a distribution of OpenRPG that is designed to be easy to setup and go.
Traipse also makes it easy for developers to work on code without fear of
sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the
code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the
productivity of the user.
Update Summary (Cleaning up for Beta):
Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images!
Changes made to the map for increased portability. SnowDog has changes planned in
Core, though.
Added an initial push to the BCG. Not much to see, just shows off how it is
re-writing Main code.
Fix to remote admin commands
Minor fix to texted based server, works in /System/ folder
Some Core changes to gametree to correctly disply Pretty Print, thanks David!
Fix to Splitter Nodes not being created.
Added images to Plugin Control panel for Autostart feature
Fix to massive amounts of images loading; from Core
fix to gsclient so with_statement imports
Added 'boot' command to remote admin
Prep work in Pass tool for remote admin rankings and different passwords, ei,
Server, Admin, Moderator, etc.
Remote Admin Commands more organized, more prep work.
Added Confirmation window for sent nodes.
Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without
breaking)
{091028}
Made changes to gametree to start working with Element Tree, mostly from Core
Minor changes to Map to start working with Element Tree, from Core
Preliminary changes to map efficiency, from FlexiRPG
Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG
Changes to main.py to start working with Element Tree
{091029}
Changes made to server to start working with Element Tree.
Changes made to Meta Server Lib. Prepping test work for a multi meta network
page.
Minor bug fixed with mini to gametree
Zoom Mouse plugin added.
{091030}
Getting ready for Beta. Server needs debugging so Alpha remains bugged.
Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or
disable plugin.
Update Manager now has a partially working Status Bar. Status Bar captures
terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is
now much cleaner.
Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win
class in Debug Console.
Known: Current Alpha fails in Windows.
author | sirebral |
---|---|
date | Fri, 30 Oct 2009 22:21:40 -0500 |
parents | |
children |
line wrap: on
line source
# dirstate.py - working directory tracking for mercurial # # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2, incorporated herein by reference. from node import nullid from i18n import _ import util, ignore, osutil, parsers import struct, os, stat, errno import cStringIO, sys _unknown = ('?', 0, 0, 0) _format = ">cllll" propertycache = util.propertycache def _finddirs(path): pos = path.rfind('/') while pos != -1: yield path[:pos] pos = path.rfind('/', 0, pos) def _incdirs(dirs, path): for base in _finddirs(path): if base in dirs: dirs[base] += 1 return dirs[base] = 1 def _decdirs(dirs, path): for base in _finddirs(path): if dirs[base] > 1: dirs[base] -= 1 return del dirs[base] class dirstate(object): def __init__(self, opener, ui, root): self._opener = opener self._root = root self._rootdir = os.path.join(root, '') self._dirty = False self._dirtypl = False self._ui = ui @propertycache def _map(self): self._read() return self._map @propertycache def _copymap(self): self._read() return self._copymap @propertycache def _foldmap(self): f = {} for name in self._map: f[os.path.normcase(name)] = name return f @propertycache def _branch(self): try: return self._opener("branch").read().strip() or "default" except IOError: return "default" @propertycache def _pl(self): try: st = self._opener("dirstate").read(40) l = len(st) if l == 40: return st[:20], st[20:40] elif l > 0 and l < 40: raise util.Abort(_('working directory state appears damaged!')) except IOError, err: if err.errno != errno.ENOENT: raise return [nullid, nullid] @propertycache def _dirs(self): dirs = {} for f,s in self._map.iteritems(): if s[0] != 'r': _incdirs(dirs, f) return dirs @propertycache def _ignore(self): files = [self._join('.hgignore')] for name, path in self._ui.configitems("ui"): if name == 'ignore' or name.startswith('ignore.'): files.append(os.path.expanduser(path)) return ignore.ignore(self._root, files, self._ui.warn) @propertycache def _slash(self): return self._ui.configbool('ui', 'slash') and os.sep != '/' @propertycache def _checklink(self): return util.checklink(self._root) @propertycache def _checkexec(self): return util.checkexec(self._root) @propertycache def _checkcase(self): return not util.checkcase(self._join('.hg')) def _join(self, f): # much faster than os.path.join() # it's safe because f is always a relative path return self._rootdir + f 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.is_exec(p): return 'x' return '' return f def f(x): if os.path.islink(self._join(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(self._join(x)): return 'x' return '' return f return fallback def getcwd(self): cwd = os.getcwd() if cwd == self._root: return '' # self._root ends with a path separator if self._root is '/' or 'C:\' rootsep = self._root if not util.endswithsep(rootsep): rootsep += os.sep if cwd.startswith(rootsep): return cwd[len(rootsep):] else: # we're outside the repo. return an absolute path. return cwd def pathto(self, f, cwd=None): if cwd is None: cwd = self.getcwd() path = util.pathto(self._root, cwd, f) if self._slash: return util.normpath(path) return path def __getitem__(self, key): ''' current states: n normal m needs merging r marked for removal a marked for addition ? not tracked''' return self._map.get(key, ("?",))[0] def __contains__(self, key): return key in self._map def __iter__(self): for x in sorted(self._map): yield x def parents(self): return self._pl def branch(self): return self._branch def setparents(self, p1, p2=nullid): self._dirty = self._dirtypl = True self._pl = p1, p2 def setbranch(self, branch): self._branch = branch self._opener("branch", "w").write(branch + '\n') def _read(self): self._map = {} self._copymap = {} try: st = self._opener("dirstate").read() except IOError, err: if err.errno != errno.ENOENT: raise return if not st: return p = parsers.parse_dirstate(self._map, self._copymap, st) if not self._dirtypl: self._pl = p def invalidate(self): for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split(): if a in self.__dict__: delattr(self, a) self._dirty = False def copy(self, source, dest): """Mark dest as a copy of source. Unmark dest if source is None. """ if source == dest: return self._dirty = True if source is not None: self._copymap[dest] = source elif dest in self._copymap: del self._copymap[dest] def copied(self, file): return self._copymap.get(file, None) def copies(self): return self._copymap def _droppath(self, f): if self[f] not in "?r" and "_dirs" in self.__dict__: _decdirs(self._dirs, f) def _addpath(self, f, check=False): oldstate = self[f] 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__: _incdirs(self._dirs, f) def normal(self, f): 'mark a file normal and clean' self._dirty = True self._addpath(f) s = os.lstat(self._join(f)) self._map[f] = ('n', s.st_mode, s.st_size, int(s.st_mtime)) if f in self._copymap: del self._copymap[f] def normallookup(self, f): 'mark a file normal, but possibly dirty' 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 self._dirty = True self._addpath(f) self._map[f] = ('n', 0, -1, -1) if f in self._copymap: del self._copymap[f] def normaldirty(self, f): 'mark a file normal, but dirty' 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._dirty = True self._addpath(f, True) self._map[f] = ('a', 0, -1, -1) if f in self._copymap: del self._copymap[f] def remove(self, f): 'mark a file removed' self._dirty = True self._droppath(f) 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) if size == 0 and f in self._copymap: del self._copymap[f] def merge(self, f): 'mark a file merged' self._dirty = True s = os.lstat(self._join(f)) 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 forget(self, f): 'forget a file' self._dirty = True try: self._droppath(f) del self._map[f] except KeyError: self._ui.warn(_("not in dirstate: %s\n") % f) def _normalize(self, path, knownpath): norm_path = os.path.normcase(path) fold_path = self._foldmap.get(norm_path, None) if fold_path is None: if knownpath or not os.path.exists(os.path.join(self._root, path)): fold_path = path else: fold_path = self._foldmap.setdefault(norm_path, util.fspath(path, self._root)) return fold_path def clear(self): self._map = {} if "_dirs" in self.__dict__: delattr(self, "_dirs"); self._copymap = {} self._pl = [nullid, nullid] self._dirty = True def rebuild(self, parent, files): self.clear() for f in files: if 'x' in files.flags(f): self._map[f] = ('n', 0777, -1, 0) else: self._map[f] = ('n', 0666, -1, 0) self._pl = (parent, nullid) self._dirty = True def write(self): if not self._dirty: return st = self._opener("dirstate", "w", atomictemp=True) 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 cs = cStringIO.StringIO() copymap = self._copymap pack = struct.pack write = cs.write write("".join(self._pl)) for f, e in self._map.iteritems(): if f in copymap: f = "%s\0%s" % (f, copymap[f]) if e[3] > limit and e[0] == 'n': e = (e[0], 0, -1, -1) e = pack(_format, e[0], e[1], e[2], e[3], len(f)) write(e) write(f) st.write(cs.getvalue()) st.rename() self._dirty = self._dirtypl = False def _dirignore(self, f): if f == '.': return False if self._ignore(f): return True for p in _finddirs(f): if self._ignore(p): return True return False def walk(self, match, unknown, ignored): ''' walk recursively through the directory tree, finding all files matched by the match function results are yielded in a tuple (filename, stat), where stat and st is the stat result if the file was found in the directory. ''' def fwarn(f, msg): self._ui.warn('%s: %s\n' % (self.pathto(f), msg)) return False def badtype(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') return _('unsupported file type (type is %s)') % kind ignore = self._ignore dirignore = self._dirignore if ignored: ignore = util.never dirignore = util.never elif not unknown: # if unknown and ignored are False, skip step 2 ignore = util.always dirignore = util.always matchfn = match.matchfn badfn = match.bad dmap = self._map normpath = util.normpath listdir = osutil.listdir lstat = os.lstat getkind = stat.S_IFMT dirkind = stat.S_IFDIR regkind = stat.S_IFREG lnkkind = stat.S_IFLNK join = self._join work = [] wadd = work.append if self._checkcase: normalize = self._normalize else: normalize = lambda x, y: x exact = skipstep3 = False if matchfn == match.exact: # match.exact exact = True dirignore = util.always # skip step 2 elif match.files() and not match.anypats(): # match.match, no patterns skipstep3 = True files = set(match.files()) if not files or '.' in files: files = [''] results = {'.hg': None} # step 1: find all explicit files for ff in sorted(files): nf = normalize(normpath(ff), False) if nf in results: continue try: st = lstat(join(nf)) kind = getkind(st.st_mode) if kind == dirkind: skipstep3 = False if nf in dmap: #file deleted on disk but still in dirstate results[nf] = None match.dir(nf) if not dirignore(nf): wadd(nf) elif kind == regkind or kind == lnkkind: results[nf] = st else: badfn(ff, badtype(kind)) if nf in dmap: results[nf] = None except OSError, inst: if nf in dmap: # does it exactly match a file? results[nf] = None else: # does it match a directory? prefix = nf + "/" for fn in dmap: if fn.startswith(prefix): match.dir(nf) skipstep3 = False break else: badfn(ff, inst.strerror) # step 2: visit subdirectories while work: nd = work.pop() skip = None if nd == '.': nd = '' else: skip = '.hg' try: entries = listdir(join(nd), stat=True, skip=skip) except OSError, inst: if inst.errno == errno.EACCES: fwarn(nd, inst.strerror) continue raise for f, kind, st in entries: nf = normalize(nd and (nd + "/" + f) or f, True) if nf not in results: if kind == dirkind: if not ignore(nf): match.dir(nf) wadd(nf) if nf in dmap and matchfn(nf): results[nf] = None elif kind == regkind or kind == lnkkind: if nf in dmap: if matchfn(nf): results[nf] = st elif matchfn(nf) and not ignore(nf): results[nf] = st elif nf in dmap and matchfn(nf): results[nf] = None # step 3: report unseen items in the dmap hash 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 not getkind(st.st_mode) in (regkind, lnkkind): st = None results[nf] = st del results['.hg'] return results def status(self, match, ignored, clean, unknown): listignored, listclean, listunknown = ignored, clean, unknown lookup, modified, added, unknown, ignored = [], [], [], [], [] removed, deleted, clean = [], [], [] 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 for fn, st in self.walk(match, listunknown, listignored).iteritems(): if fn not in dmap: if (listignored or match.exact(fn)) and self._dirignore(fn): if listignored: iadd(fn) elif listunknown: uadd(fn) continue state, mode, size, time = dmap[fn] if not st and state in "nma": dadd(fn) elif state == 'n': if (size >= 0 and (size != st.st_size or ((mode ^ st.st_mode) & 0100 and self._checkexec)) or size == -2 or fn in self._copymap): madd(fn) elif time != int(st.st_mtime): ladd(fn) elif listclean: cadd(fn) elif state == 'm': madd(fn) elif state == 'a': aadd(fn) elif state == 'r': radd(fn) return (lookup, modified, added, removed, deleted, unknown, ignored, clean)