##// END OF EJS Templates
bundlerepo: remove relative import, fix a comment
Benoit Boissinot -
r1946:9fee186f default
parent child Browse files
Show More
@@ -1,213 +1,208
1 1 """
2 2 bundlerepo.py - repository class for viewing uncompressed bundles
3 3
4 4 This provides a read-only repository interface to bundles as if
5 5 they were part of the actual repository.
6 6
7 7 Copyright 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
8 8
9 9 This software may be used and distributed according to the terms
10 10 of the GNU General Public License, incorporated herein by reference.
11 11 """
12 12
13 13 from node import *
14 14 from i18n import gettext as _
15 15 from demandload import demandload
16 16 demandload(globals(), "util os struct")
17 17
18 from changelog import changelog
19 from manifest import manifest
20 from filelog import filelog
21 from localrepo import localrepository
22 from revlog import *
18 import localrepo, changelog, manifest, filelog, revlog
23 19
24 20 def getchunk(source):
25 21 """get a chunk from a group"""
26 22 d = source.read(4)
27 23 if not d:
28 24 return ""
29 25 l = struct.unpack(">l", d)[0]
30 26 if l <= 4:
31 27 return ""
32 28 d = source.read(l - 4)
33 29 if len(d) < l - 4:
34 30 raise util.Abort(_("premature EOF reading chunk"
35 31 " (got %d bytes, expected %d)")
36 32 % (len(d), l - 4))
37 33 return d
38 34
39 class bundlerevlog(revlog):
35 class bundlerevlog(revlog.revlog):
40 36 def __init__(self, opener, indexfile, datafile, bundlefile,
41 37 linkmapper=None):
42 38 # How it works:
43 39 # to retrieve a revision, we need to know the offset of
44 40 # the revision in the bundlefile (an opened file).
45 41 #
46 42 # We store this offset in the index (start), to differentiate a
47 43 # rev in the bundle and from a rev in the revlog, we check
48 44 # len(index[r]). If the tuple is bigger than 7, it is a bundle
49 45 # (it is bigger since we store the node to which the delta is)
50 46 #
51 revlog.__init__(self, opener, indexfile, datafile)
47 revlog.revlog.__init__(self, opener, indexfile, datafile)
52 48 self.bundlefile = bundlefile
53 49 def genchunk():
54 50 while 1:
55 51 pos = bundlefile.tell()
56 52 chunk = getchunk(bundlefile)
57 53 if not chunk:
58 54 break
59 55 yield chunk, pos + 4 # XXX struct.calcsize(">l") == 4
60 56 n = self.count()
61 57 prev = None
62 58 for chunk, start in genchunk():
63 59 size = len(chunk)
64 60 if size < 80:
65 61 raise util.Abort("invalid changegroup")
66 62 start += 80
67 63 size -= 80
68 64 node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80])
69 65 if node in self.nodemap:
70 66 prev = node
71 67 continue
72 68 for p in (p1, p2):
73 69 if not p in self.nodemap:
74 70 raise RevlogError(_("unknown parent %s") % short(p1))
75 71 if linkmapper is None:
76 72 link = n
77 73 else:
78 74 link = linkmapper(cs)
79 75
80 76 if not prev:
81 77 prev = p1
82 78 # start, size, base is not used, link, p1, p2, delta ref
83 # warning:
84 79 e = (start, size, None, link, p1, p2, node, prev)
85 80 self.index.append(e)
86 81 self.nodemap[node] = n
87 82 prev = node
88 83 n += 1
89 84
90 85 def bundle(self, rev):
91 86 """is rev from the bundle"""
92 87 if rev < 0:
93 88 return False
94 89 return len(self.index[rev]) > 7
95 90 def bundlebase(self, rev): return self.index[rev][7]
96 91 def chunk(self, rev):
97 92 # Warning: in case of bundle, the diff is against bundlebase,
98 93 # not against rev - 1
99 94 # XXX: could use some caching
100 95 if not self.bundle(rev):
101 return revlog.chunk(self, rev)
96 return revlog.revlog.chunk(self, rev)
102 97 self.bundlefile.seek(self.start(rev))
103 98 return self.bundlefile.read(self.length(rev))
104 99
105 100 def revdiff(self, rev1, rev2):
106 101 """return or calculate a delta between two revisions"""
107 102 if self.bundle(rev1) and self.bundle(rev2):
108 103 # hot path for bundle
109 104 revb = self.rev(self.bundlebase(rev2))
110 105 if revb == rev1:
111 106 return self.chunk(rev2)
112 107 elif not self.bundle(rev1) and not self.bundle(rev2):
113 return revlog.chunk(self, rev1, rev2)
108 return revlog.revlog.chunk(self, rev1, rev2)
114 109
115 110 return self.diff(self.revision(self.node(rev1)),
116 111 self.revision(self.node(rev2)))
117 112
118 113 def revision(self, node):
119 114 """return an uncompressed revision of a given"""
120 115 if node == nullid: return ""
121 116
122 117 text = None
123 118 chain = []
124 119 iter_node = node
125 120 rev = self.rev(iter_node)
126 121 # reconstruct the revision if it is from a changegroup
127 122 while self.bundle(rev):
128 123 if self.cache and self.cache[0] == iter_node:
129 124 text = self.cache[2]
130 125 break
131 126 chain.append(rev)
132 127 iter_node = self.bundlebase(rev)
133 128 rev = self.rev(iter_node)
134 129 if text is None:
135 text = revlog.revision(self, iter_node)
130 text = revlog.revlog.revision(self, iter_node)
136 131
137 132 while chain:
138 133 delta = self.chunk(chain.pop())
139 134 text = self.patches(text, [delta])
140 135
141 136 p1, p2 = self.parents(node)
142 if node != hash(text, p1, p2):
137 if node != revlog.hash(text, p1, p2):
143 138 raise RevlogError(_("integrity check failed on %s:%d")
144 139 % (self.datafile, self.rev(node)))
145 140
146 141 self.cache = (node, rev, text)
147 142 return text
148 143
149 144 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
150 145 raise NotImplementedError
151 146 def addgroup(self, revs, linkmapper, transaction, unique=0):
152 147 raise NotImplementedError
153 148 def strip(self, rev, minlink):
154 149 raise NotImplementedError
155 150 def checksize(self):
156 151 raise NotImplementedError
157 152
158 class bundlechangelog(bundlerevlog, changelog):
153 class bundlechangelog(bundlerevlog, changelog.changelog):
159 154 def __init__(self, opener, bundlefile):
160 changelog.__init__(self, opener)
155 changelog.changelog.__init__(self, opener)
161 156 bundlerevlog.__init__(self, opener, "00changelog.i", "00changelog.d",
162 157 bundlefile)
163 158
164 class bundlemanifest(bundlerevlog, manifest):
159 class bundlemanifest(bundlerevlog, manifest.manifest):
165 160 def __init__(self, opener, bundlefile, linkmapper):
166 manifest.__init__(self, opener)
161 manifest.manifest.__init__(self, opener)
167 162 bundlerevlog.__init__(self, opener, self.indexfile, self.datafile,
168 163 bundlefile, linkmapper)
169 164
170 class bundlefilelog(bundlerevlog, filelog):
165 class bundlefilelog(bundlerevlog, filelog.filelog):
171 166 def __init__(self, opener, path, bundlefile, linkmapper):
172 filelog.__init__(self, opener, path)
167 filelog.filelog.__init__(self, opener, path)
173 168 bundlerevlog.__init__(self, opener, self.indexfile, self.datafile,
174 169 bundlefile, linkmapper)
175 170
176 class bundlerepository(localrepository):
171 class bundlerepository(localrepo.localrepository):
177 172 def __init__(self, ui, path, bundlename):
178 localrepository.__init__(self, ui, path)
173 localrepo.localrepository.__init__(self, ui, path)
179 174 f = open(bundlename, "rb")
180 175 s = os.fstat(f.fileno())
181 176 self.bundlefile = f
182 177 header = self.bundlefile.read(4)
183 178 if header == "HG10":
184 179 raise util.Abort(_("%s: compressed bundle not supported")
185 180 % bundlename)
186 181 elif header != "HG11":
187 182 raise util.Abort(_("%s: not a Mercurial bundle file") % bundlename)
188 183 self.changelog = bundlechangelog(self.opener, self.bundlefile)
189 184 self.manifest = bundlemanifest(self.opener, self.bundlefile,
190 185 self.changelog.rev)
191 186 # dict with the mapping 'filename' -> position in the bundle
192 187 self.bundlefilespos = {}
193 188 while 1:
194 189 f = getchunk(self.bundlefile)
195 190 if not f:
196 191 break
197 192 self.bundlefilespos[f] = self.bundlefile.tell()
198 193 while getchunk(self.bundlefile):
199 194 pass
200 195
201 196 def dev(self):
202 197 return -1
203 198
204 199 def file(self, f):
205 200 if f[0] == '/':
206 201 f = f[1:]
207 202 if f in self.bundlefilespos:
208 203 self.bundlefile.seek(self.bundlefilespos[f])
209 204 return bundlefilelog(self.opener, f, self.bundlefile,
210 205 self.changelog.rev)
211 206 else:
212 return filelog(self.opener, f)
207 return filelog.filelog(self.opener, f)
213 208
General Comments 0
You need to be logged in to leave comments. Login now