diff mercurial/store.py @ 6840:80e51429cb9a

introduce store classes move store walking from streamclone.py into store.py
author Adrian Buehlmann <adrian@cadifra.com>
date Thu, 24 Jul 2008 16:32:52 +0200
parents 01db3e101362
children fddef0602859
line wrap: on
line diff
--- a/mercurial/store.py	Thu Jul 24 16:32:51 2008 +0200
+++ b/mercurial/store.py	Thu Jul 24 16:32:52 2008 +0200
@@ -5,6 +5,8 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
+import os, stat, osutil, util
+
 def _buildencodefun():
     e = '_'
     win_reserved = [ord(x) for x in '\\:*?"<>|']
@@ -33,7 +35,91 @@
 
 encodefilename, decodefilename = _buildencodefun()
 
-def encodedopener(openerfn, fn):
-    def o(path, *args, **kw):
-        return openerfn(fn(path), *args, **kw)
-    return o
+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
+        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
+
+    def _datafiles(self):
+        for x in self._revlogfiles('data', True):
+            yield x
+
+    def walk(self):
+        '''yields (direncoded filename, size)'''
+        # yield data files first
+        for x in self._datafiles():
+            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.encodefn = lambda x: x
+        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)
+
+    def _datafiles(self):
+        for f, size in self._revlogfiles('data', True):
+            yield decodefilename(f), size
+
+    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)