##// END OF EJS Templates
store: simplify class hierarchy
Matt Mackall -
r6898:69aeaaaf default
parent child Browse files
Show More
@@ -1,126 +1,125 b''
1 # store.py - repository store handling for Mercurial
1 # store.py - repository store handling for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import os, stat, osutil, util
9 import os, stat, osutil, util
10
10
11 def _buildencodefun():
11 def _buildencodefun():
12 e = '_'
12 e = '_'
13 win_reserved = [ord(x) for x in '\\:*?"<>|']
13 win_reserved = [ord(x) for x in '\\:*?"<>|']
14 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
14 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
15 for x in (range(32) + range(126, 256) + win_reserved):
15 for x in (range(32) + range(126, 256) + win_reserved):
16 cmap[chr(x)] = "~%02x" % x
16 cmap[chr(x)] = "~%02x" % x
17 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
17 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
18 cmap[chr(x)] = e + chr(x).lower()
18 cmap[chr(x)] = e + chr(x).lower()
19 dmap = {}
19 dmap = {}
20 for k, v in cmap.iteritems():
20 for k, v in cmap.iteritems():
21 dmap[v] = k
21 dmap[v] = k
22 def decode(s):
22 def decode(s):
23 i = 0
23 i = 0
24 while i < len(s):
24 while i < len(s):
25 for l in xrange(1, 4):
25 for l in xrange(1, 4):
26 try:
26 try:
27 yield dmap[s[i:i+l]]
27 yield dmap[s[i:i+l]]
28 i += l
28 i += l
29 break
29 break
30 except KeyError:
30 except KeyError:
31 pass
31 pass
32 else:
32 else:
33 raise KeyError
33 raise KeyError
34 return (lambda s: "".join([cmap[c] for c in s]),
34 return (lambda s: "".join([cmap[c] for c in s]),
35 lambda s: "".join(list(decode(s))))
35 lambda s: "".join(list(decode(s))))
36
36
37 encodefilename, decodefilename = _buildencodefun()
37 encodefilename, decodefilename = _buildencodefun()
38
38
39 def _dirwalk(path, recurse):
39 def _dirwalk(path, recurse):
40 '''yields (filename, size)'''
40 '''yields (filename, size)'''
41 for e, kind, st in osutil.listdir(path, stat=True):
41 for e, kind, st in osutil.listdir(path, stat=True):
42 pe = os.path.join(path, e)
42 pe = os.path.join(path, e)
43 if kind == stat.S_IFDIR:
43 if kind == stat.S_IFDIR:
44 if recurse:
44 if recurse:
45 for x in _dirwalk(pe, True):
45 for x in _dirwalk(pe, True):
46 yield x
46 yield x
47 elif kind == stat.S_IFREG:
47 elif kind == stat.S_IFREG:
48 yield pe, st.st_size
48 yield pe, st.st_size
49
49
50 class _store:
50 def _calcmode(path):
51 '''base class for local repository stores'''
52 def __init__(self, path):
53 self.path = path
54 try:
51 try:
55 # files in .hg/ will be created using this mode
52 # files in .hg/ will be created using this mode
56 mode = os.stat(self.path).st_mode
53 mode = os.stat(path).st_mode
57 # avoid some useless chmods
54 # avoid some useless chmods
58 if (0777 & ~util._umask) == (0777 & mode):
55 if (0777 & ~util._umask) == (0777 & mode):
59 mode = None
56 mode = None
60 except OSError:
57 except OSError:
61 mode = None
58 mode = None
62 self.createmode = mode
59 return mode
60
61 class basicstore:
62 '''base class for local repository stores'''
63 def __init__(self, path, opener):
64 self.path = path
65 self.createmode = _calcmode(path)
66 self.opener = opener(self.path)
67 self.opener.createmode = self.createmode
63
68
64 def join(self, f):
69 def join(self, f):
65 return os.path.join(self.path, f)
70 return os.path.join(self.path, f)
66
71
67 def _revlogfiles(self, relpath='', recurse=False):
72 def _revlogfiles(self, relpath='', recurse=False):
68 '''yields (filename, size)'''
73 '''yields (filename, size)'''
69 if relpath:
74 if relpath:
70 path = os.path.join(self.path, relpath)
75 path = os.path.join(self.path, relpath)
71 else:
76 else:
72 path = self.path
77 path = self.path
73 if not os.path.isdir(path):
78 if not os.path.isdir(path):
74 return
79 return
75 striplen = len(self.path) + len(os.sep)
80 striplen = len(self.path) + len(os.sep)
76 filetypes = ('.d', '.i')
81 filetypes = ('.d', '.i')
77 for f, size in _dirwalk(path, recurse):
82 for f, size in _dirwalk(path, recurse):
78 if (len(f) > 2) and f[-2:] in filetypes:
83 if (len(f) > 2) and f[-2:] in filetypes:
79 yield util.pconvert(f[striplen:]), size
84 yield util.pconvert(f[striplen:]), size
80
85
81 def datafiles(self, reporterror=None):
86 def datafiles(self, reporterror=None):
82 for x in self._revlogfiles('data', True):
87 for x in self._revlogfiles('data', True):
83 yield x
88 yield x
84
89
85 def walk(self):
90 def walk(self):
86 '''yields (direncoded filename, size)'''
91 '''yields (direncoded filename, size)'''
87 # yield data files first
92 # yield data files first
88 for x in self.datafiles():
93 for x in self.datafiles():
89 yield x
94 yield x
90 # yield manifest before changelog
95 # yield manifest before changelog
91 meta = util.sort(self._revlogfiles())
96 meta = util.sort(self._revlogfiles())
92 meta.reverse()
97 meta.reverse()
93 for x in meta:
98 for x in meta:
94 yield x
99 yield x
95
100
96 class directstore(_store):
101 class encodedstore(basicstore):
97 def __init__(self, path, opener):
102 def __init__(self, path, opener):
98 _store.__init__(self, path)
103 self.path = os.path.join(path, 'store')
99 self.opener = opener(self.path)
104 self.createmode = _calcmode(self.path)
100 self.opener.createmode = self.createmode
101
102 class encodedstore(_store):
103 def __init__(self, path, opener):
104 _store.__init__(self, os.path.join(path, 'store'))
105 self.encodefn = encodefilename
105 self.encodefn = encodefilename
106 op = opener(self.path)
106 op = opener(self.path)
107 op.createmode = self.createmode
107 op.createmode = self.createmode
108 self.opener = lambda f, *args, **kw: op(self.encodefn(f), *args, **kw)
108 self.opener = lambda f, *args, **kw: op(self.encodefn(f), *args, **kw)
109
109
110 def datafiles(self, reporterror=None):
110 def datafiles(self, reporterror=None):
111 for f, size in self._revlogfiles('data', True):
111 for f, size in self._revlogfiles('data', True):
112 try:
112 try:
113 yield decodefilename(f), size
113 yield decodefilename(f), size
114 except KeyError:
114 except KeyError:
115 if not reporterror:
115 if not reporterror:
116 raise
116 raise
117 reporterror(_("cannot decode filename '%s'") % f)
117 reporterror(_("cannot decode filename '%s'") % f)
118
118
119 def join(self, f):
119 def join(self, f):
120 return os.path.join(self.path, self.encodefn(f))
120 return os.path.join(self.path, self.encodefn(f))
121
121
122 def store(requirements, path, opener):
122 def store(requirements, path, opener):
123 if 'store' not in requirements:
123 if 'store' in requirements:
124 return directstore(path, opener)
125 else:
126 return encodedstore(path, opener)
124 return encodedstore(path, opener)
125 return basicstore(path, opener)
@@ -1,26 +1,26 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo % prepare repo
3 echo % prepare repo
4 hg init
4 hg init
5 echo "some text" > FOO.txt
5 echo "some text" > FOO.txt
6 echo "another text" > bar.txt
6 echo "another text" > bar.txt
7 echo "more text" > QUICK.txt
7 echo "more text" > QUICK.txt
8 hg add
8 hg add
9 hg ci -d '0 0' -mtest1
9 hg ci -d '0 0' -mtest1
10
10
11 echo
11 echo
12 echo % verify
12 echo % verify
13 hg verify
13 hg verify
14
14
15 echo
15 echo
16 echo % introduce some bugs in repo
16 echo % introduce some bugs in repo
17 cd .hg/store/data
17 cd .hg/store/data
18 mv _f_o_o.txt.i X_f_o_o.txt.i
18 mv _f_o_o.txt.i X_f_o_o.txt.i
19 mv bar.txt.i xbar.txt.i
19 mv bar.txt.i xbar.txt.i
20 rm _q_u_i_c_k.txt.i
20 rm _q_u_i_c_k.txt.i
21
21
22 echo
22 echo
23 echo % verify
23 echo % verify
24 hg verify
24 hg verify
25
25
26 return 0
26 exit 0
General Comments 0
You need to be logged in to leave comments. Login now