store.py
132 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
/ mercurial / store.py
Adrian Buehlmann
|
r6839 | # store.py - repository store handling for Mercurial | ||
# | ||||
# Copyright 2008 Matt Mackall <mpm@selenic.com> | ||||
# | ||||
# This software may be used and distributed according to the terms | ||||
# of the GNU General Public License, incorporated herein by reference. | ||||
Adrian Buehlmann
|
r6892 | from i18n import _ | ||
Adrian Buehlmann
|
r6840 | import os, stat, osutil, util | ||
Adrian Buehlmann
|
r6839 | def _buildencodefun(): | ||
e = '_' | ||||
win_reserved = [ord(x) for x in '\\:*?"<>|'] | ||||
cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ]) | ||||
for x in (range(32) + range(126, 256) + win_reserved): | ||||
cmap[chr(x)] = "~%02x" % x | ||||
for x in range(ord("A"), ord("Z")+1) + [ord(e)]: | ||||
cmap[chr(x)] = e + chr(x).lower() | ||||
dmap = {} | ||||
for k, v in cmap.iteritems(): | ||||
dmap[v] = k | ||||
def decode(s): | ||||
i = 0 | ||||
while i < len(s): | ||||
for l in xrange(1, 4): | ||||
try: | ||||
yield dmap[s[i:i+l]] | ||||
i += l | ||||
break | ||||
except KeyError: | ||||
pass | ||||
else: | ||||
raise KeyError | ||||
return (lambda s: "".join([cmap[c] for c in s]), | ||||
lambda s: "".join(list(decode(s)))) | ||||
encodefilename, decodefilename = _buildencodefun() | ||||
Adrian Buehlmann
|
r6840 | def _dirwalk(path, recurse): | ||
'''yields (filename, size)''' | ||||
for e, kind, st in osutil.listdir(path, stat=True): | ||||
pe = os.path.join(path, e) | ||||
if kind == stat.S_IFDIR: | ||||
if recurse: | ||||
for x in _dirwalk(pe, True): | ||||
yield x | ||||
elif kind == stat.S_IFREG: | ||||
yield pe, st.st_size | ||||
class _store: | ||||
'''base class for local repository stores''' | ||||
def __init__(self, path): | ||||
self.path = path | ||||
try: | ||||
# files in .hg/ will be created using this mode | ||||
mode = os.stat(self.path).st_mode | ||||
# avoid some useless chmods | ||||
if (0777 & ~util._umask) == (0777 & mode): | ||||
mode = None | ||||
except OSError: | ||||
mode = None | ||||
self.createmode = mode | ||||
def join(self, f): | ||||
return os.path.join(self.path, f) | ||||
def _revlogfiles(self, relpath='', recurse=False): | ||||
'''yields (filename, size)''' | ||||
if relpath: | ||||
path = os.path.join(self.path, relpath) | ||||
else: | ||||
path = self.path | ||||
Adrian Buehlmann
|
r6890 | if not os.path.isdir(path): | ||
return | ||||
Adrian Buehlmann
|
r6840 | striplen = len(self.path) + len(os.sep) | ||
filetypes = ('.d', '.i') | ||||
for f, size in _dirwalk(path, recurse): | ||||
if (len(f) > 2) and f[-2:] in filetypes: | ||||
yield util.pconvert(f[striplen:]), size | ||||
Adrian Buehlmann
|
r6892 | def datafiles(self, reporterror=None): | ||
Adrian Buehlmann
|
r6840 | for x in self._revlogfiles('data', True): | ||
yield x | ||||
def walk(self): | ||||
'''yields (direncoded filename, size)''' | ||||
# yield data files first | ||||
Adrian Buehlmann
|
r6892 | for x in self.datafiles(): | ||
Adrian Buehlmann
|
r6840 | yield x | ||
# yield manifest before changelog | ||||
meta = util.sort(self._revlogfiles()) | ||||
meta.reverse() | ||||
for x in meta: | ||||
yield x | ||||
class directstore(_store): | ||||
def __init__(self, path): | ||||
_store.__init__(self, path) | ||||
self.opener = util.opener(self.path) | ||||
self.opener.createmode = self.createmode | ||||
class encodedstore(_store): | ||||
def __init__(self, path): | ||||
_store.__init__(self, os.path.join(path, 'store')) | ||||
self.encodefn = encodefilename | ||||
op = util.opener(self.path) | ||||
op.createmode = self.createmode | ||||
self.opener = lambda f, *args, **kw: op(self.encodefn(f), *args, **kw) | ||||
Adrian Buehlmann
|
r6892 | def datafiles(self, reporterror=None): | ||
Adrian Buehlmann
|
r6840 | for f, size in self._revlogfiles('data', True): | ||
Adrian Buehlmann
|
r6892 | try: | ||
yield decodefilename(f), size | ||||
except KeyError: | ||||
if not reporterror: | ||||
raise | ||||
reporterror(_("cannot decode filename '%s'") % f) | ||||
Adrian Buehlmann
|
r6840 | |||
def join(self, f): | ||||
return os.path.join(self.path, self.encodefn(f)) | ||||
def encodefn(requirements): | ||||
if 'store' not in requirements: | ||||
return lambda x: x | ||||
else: | ||||
return encodefilename | ||||
def store(requirements, path): | ||||
if 'store' not in requirements: | ||||
return directstore(path) | ||||
else: | ||||
return encodedstore(path) | ||||