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