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