##// END OF EJS Templates
statichttp: use store class...
Matt Mackall -
r6897:faea0d27 default
parent child Browse files
Show More
@@ -1,82 +1,78
1 # statichttprepo.py - simple http repository class for mercurial
1 # statichttprepo.py - simple http repository class for mercurial
2 #
2 #
3 # This provides read-only repo access to repositories exported via static http
3 # This provides read-only repo access to repositories exported via static http
4 #
4 #
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 from i18n import _
10 from i18n import _
11 import changelog, httprangereader
11 import changelog, httprangereader
12 import repo, localrepo, manifest, util, store
12 import repo, localrepo, manifest, util, store
13 import urllib, urllib2, errno
13 import urllib, urllib2, errno
14
14
15 class rangereader(httprangereader.httprangereader):
15 class rangereader(httprangereader.httprangereader):
16 def read(self, size=None):
16 def read(self, size=None):
17 try:
17 try:
18 return httprangereader.httprangereader.read(self, size)
18 return httprangereader.httprangereader.read(self, size)
19 except urllib2.HTTPError, inst:
19 except urllib2.HTTPError, inst:
20 num = inst.code == 404 and errno.ENOENT or None
20 num = inst.code == 404 and errno.ENOENT or None
21 raise IOError(num, inst)
21 raise IOError(num, inst)
22 except urllib2.URLError, inst:
22 except urllib2.URLError, inst:
23 raise IOError(None, inst.reason[1])
23 raise IOError(None, inst.reason[1])
24
24
25 def opener(base):
25 def opener(base):
26 """return a function that opens files over http"""
26 """return a function that opens files over http"""
27 p = base
27 p = base
28 def o(path, mode="r"):
28 def o(path, mode="r"):
29 f = "/".join((p, urllib.quote(path)))
29 f = "/".join((p, urllib.quote(path)))
30 return rangereader(f)
30 return rangereader(f)
31 return o
31 return o
32
32
33 class statichttprepository(localrepo.localrepository):
33 class statichttprepository(localrepo.localrepository):
34 def __init__(self, ui, path):
34 def __init__(self, ui, path):
35 self._url = path
35 self._url = path
36 self.ui = ui
36 self.ui = ui
37
37
38 self.path = path.rstrip('/') + "/.hg"
38 self.path = path.rstrip('/') + "/.hg"
39 self.opener = opener(self.path)
39 self.opener = opener(self.path)
40
40
41 # find requirements
41 # find requirements
42 try:
42 try:
43 requirements = self.opener("requires").read().splitlines()
43 requirements = self.opener("requires").read().splitlines()
44 except IOError, inst:
44 except IOError, inst:
45 if inst.errno == errno.ENOENT:
45 if inst.errno == errno.ENOENT:
46 msg = _("'%s' does not appear to be an hg repository") % path
46 msg = _("'%s' does not appear to be an hg repository") % path
47 raise repo.RepoError(msg)
47 raise repo.RepoError(msg)
48 else:
48 else:
49 requirements = []
49 requirements = []
50
50
51 # check them
51 # check them
52 for r in requirements:
52 for r in requirements:
53 if r not in self.supported:
53 if r not in self.supported:
54 raise repo.RepoError(_("requirement '%s' not supported") % r)
54 raise repo.RepoError(_("requirement '%s' not supported") % r)
55
55
56 # setup store
56 # setup store
57 if "store" in requirements:
57 self.store = store.store(requirements, self.path, opener)
58 self.spath = self.path + "/store"
58 self.spath = self.store.path
59 else:
59 self.sopener = self.store.opener
60 self.spath = self.path
60 self.sjoin = self.store.join
61 self.encodefn = store.encodefn(requirements)
62 so = opener(self.spath)
63 self.sopener = lambda path, *args, **kw: so(
64 self.encodefn(path), *args, **kw)
65
61
66 self.manifest = manifest.manifest(self.sopener)
62 self.manifest = manifest.manifest(self.sopener)
67 self.changelog = changelog.changelog(self.sopener)
63 self.changelog = changelog.changelog(self.sopener)
68 self.tagscache = None
64 self.tagscache = None
69 self.nodetagscache = None
65 self.nodetagscache = None
70 self.encodepats = None
66 self.encodepats = None
71 self.decodepats = None
67 self.decodepats = None
72
68
73 def url(self):
69 def url(self):
74 return 'static-' + self._url
70 return 'static-' + self._url
75
71
76 def local(self):
72 def local(self):
77 return False
73 return False
78
74
79 def instance(ui, path, create):
75 def instance(ui, path, create):
80 if create:
76 if create:
81 raise util.Abort(_('cannot create new static-http repository'))
77 raise util.Abort(_('cannot create new static-http repository'))
82 return statichttprepository(ui, path[7:])
78 return statichttprepository(ui, path[7:])
@@ -1,132 +1,126
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 class _store:
51 '''base class for local repository stores'''
51 '''base class for local repository stores'''
52 def __init__(self, path):
52 def __init__(self, path):
53 self.path = path
53 self.path = path
54 try:
54 try:
55 # files in .hg/ will be created using this mode
55 # files in .hg/ will be created using this mode
56 mode = os.stat(self.path).st_mode
56 mode = os.stat(self.path).st_mode
57 # avoid some useless chmods
57 # avoid some useless chmods
58 if (0777 & ~util._umask) == (0777 & mode):
58 if (0777 & ~util._umask) == (0777 & mode):
59 mode = None
59 mode = None
60 except OSError:
60 except OSError:
61 mode = None
61 mode = None
62 self.createmode = mode
62 self.createmode = mode
63
63
64 def join(self, f):
64 def join(self, f):
65 return os.path.join(self.path, f)
65 return os.path.join(self.path, f)
66
66
67 def _revlogfiles(self, relpath='', recurse=False):
67 def _revlogfiles(self, relpath='', recurse=False):
68 '''yields (filename, size)'''
68 '''yields (filename, size)'''
69 if relpath:
69 if relpath:
70 path = os.path.join(self.path, relpath)
70 path = os.path.join(self.path, relpath)
71 else:
71 else:
72 path = self.path
72 path = self.path
73 if not os.path.isdir(path):
73 if not os.path.isdir(path):
74 return
74 return
75 striplen = len(self.path) + len(os.sep)
75 striplen = len(self.path) + len(os.sep)
76 filetypes = ('.d', '.i')
76 filetypes = ('.d', '.i')
77 for f, size in _dirwalk(path, recurse):
77 for f, size in _dirwalk(path, recurse):
78 if (len(f) > 2) and f[-2:] in filetypes:
78 if (len(f) > 2) and f[-2:] in filetypes:
79 yield util.pconvert(f[striplen:]), size
79 yield util.pconvert(f[striplen:]), size
80
80
81 def datafiles(self, reporterror=None):
81 def datafiles(self, reporterror=None):
82 for x in self._revlogfiles('data', True):
82 for x in self._revlogfiles('data', True):
83 yield x
83 yield x
84
84
85 def walk(self):
85 def walk(self):
86 '''yields (direncoded filename, size)'''
86 '''yields (direncoded filename, size)'''
87 # yield data files first
87 # yield data files first
88 for x in self.datafiles():
88 for x in self.datafiles():
89 yield x
89 yield x
90 # yield manifest before changelog
90 # yield manifest before changelog
91 meta = util.sort(self._revlogfiles())
91 meta = util.sort(self._revlogfiles())
92 meta.reverse()
92 meta.reverse()
93 for x in meta:
93 for x in meta:
94 yield x
94 yield x
95
95
96 class directstore(_store):
96 class directstore(_store):
97 def __init__(self, path, opener):
97 def __init__(self, path, opener):
98 _store.__init__(self, path)
98 _store.__init__(self, path)
99 self.opener = opener(self.path)
99 self.opener = opener(self.path)
100 self.opener.createmode = self.createmode
100 self.opener.createmode = self.createmode
101
101
102 class encodedstore(_store):
102 class encodedstore(_store):
103 def __init__(self, path, opener):
103 def __init__(self, path, opener):
104 _store.__init__(self, os.path.join(path, 'store'))
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 encodefn(requirements):
123 if 'store' not in requirements:
124 return lambda x: x
125 else:
126 return encodefilename
127
128 def store(requirements, path, opener):
122 def store(requirements, path, opener):
129 if 'store' not in requirements:
123 if 'store' not in requirements:
130 return directstore(path, opener)
124 return directstore(path, opener)
131 else:
125 else:
132 return encodedstore(path, opener)
126 return encodedstore(path, opener)
General Comments 0
You need to be logged in to leave comments. Login now