Mercurial > public > mercurial-scm > hg
comparison mercurial/bundlerepo.py @ 12332:680fe77ab5b8
bundlerepo: use bundle objects everywhere
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Fri, 17 Sep 2010 19:24:29 -0500 |
parents | 40935b59518b |
children | 44c7dfc2f6a3 |
comparison
equal
deleted
inserted
replaced
12331:40935b59518b | 12332:680fe77ab5b8 |
---|---|
16 import os, struct, tempfile, shutil | 16 import os, struct, tempfile, shutil |
17 import changegroup, util, mdiff | 17 import changegroup, util, mdiff |
18 import localrepo, changelog, manifest, filelog, revlog, error | 18 import localrepo, changelog, manifest, filelog, revlog, error |
19 | 19 |
20 class bundlerevlog(revlog.revlog): | 20 class bundlerevlog(revlog.revlog): |
21 def __init__(self, opener, indexfile, bundlefile, | 21 def __init__(self, opener, indexfile, bundle, |
22 linkmapper=None): | 22 linkmapper=None): |
23 # How it works: | 23 # How it works: |
24 # to retrieve a revision, we need to know the offset of | 24 # to retrieve a revision, we need to know the offset of |
25 # the revision in the bundlefile (an opened file). | 25 # the revision in the bundle (an unbundle object). |
26 # | 26 # |
27 # We store this offset in the index (start), to differentiate a | 27 # We store this offset in the index (start), to differentiate a |
28 # rev in the bundle and from a rev in the revlog, we check | 28 # rev in the bundle and from a rev in the revlog, we check |
29 # len(index[r]). If the tuple is bigger than 7, it is a bundle | 29 # len(index[r]). If the tuple is bigger than 7, it is a bundle |
30 # (it is bigger since we store the node to which the delta is) | 30 # (it is bigger since we store the node to which the delta is) |
31 # | 31 # |
32 revlog.revlog.__init__(self, opener, indexfile) | 32 revlog.revlog.__init__(self, opener, indexfile) |
33 self.bundlefile = bundlefile | 33 self.bundle = bundle |
34 self.basemap = {} | 34 self.basemap = {} |
35 def chunkpositer(): | 35 def chunkpositer(): |
36 for chunk in changegroup.chunkiter(bundlefile): | 36 for chunk in changegroup.chunkiter(bundle): |
37 pos = bundlefile.tell() | 37 pos = bundle.tell() |
38 yield chunk, pos - len(chunk) | 38 yield chunk, pos - len(chunk) |
39 n = len(self) | 39 n = len(self) |
40 prev = None | 40 prev = None |
41 for chunk, start in chunkpositer(): | 41 for chunk, start in chunkpositer(): |
42 size = len(chunk) | 42 size = len(chunk) |
66 self.index.insert(-1, e) | 66 self.index.insert(-1, e) |
67 self.nodemap[node] = n | 67 self.nodemap[node] = n |
68 prev = node | 68 prev = node |
69 n += 1 | 69 n += 1 |
70 | 70 |
71 def bundle(self, rev): | 71 def inbundle(self, rev): |
72 """is rev from the bundle""" | 72 """is rev from the bundle""" |
73 if rev < 0: | 73 if rev < 0: |
74 return False | 74 return False |
75 return rev in self.basemap | 75 return rev in self.basemap |
76 def bundlebase(self, rev): | 76 def bundlebase(self, rev): |
77 return self.basemap[rev] | 77 return self.basemap[rev] |
78 def _chunk(self, rev): | 78 def _chunk(self, rev): |
79 # Warning: in case of bundle, the diff is against bundlebase, | 79 # Warning: in case of bundle, the diff is against bundlebase, |
80 # not against rev - 1 | 80 # not against rev - 1 |
81 # XXX: could use some caching | 81 # XXX: could use some caching |
82 if not self.bundle(rev): | 82 if not self.inbundle(rev): |
83 return revlog.revlog._chunk(self, rev) | 83 return revlog.revlog._chunk(self, rev) |
84 self.bundlefile.seek(self.start(rev)) | 84 self.bundle.seek(self.start(rev)) |
85 return self.bundlefile.read(self.length(rev)) | 85 return self.bundle.read(self.length(rev)) |
86 | 86 |
87 def revdiff(self, rev1, rev2): | 87 def revdiff(self, rev1, rev2): |
88 """return or calculate a delta between two revisions""" | 88 """return or calculate a delta between two revisions""" |
89 if self.bundle(rev1) and self.bundle(rev2): | 89 if self.inbundle(rev1) and self.inbundle(rev2): |
90 # hot path for bundle | 90 # hot path for bundle |
91 revb = self.rev(self.bundlebase(rev2)) | 91 revb = self.rev(self.bundlebase(rev2)) |
92 if revb == rev1: | 92 if revb == rev1: |
93 return self._chunk(rev2) | 93 return self._chunk(rev2) |
94 elif not self.bundle(rev1) and not self.bundle(rev2): | 94 elif not self.inbundle(rev1) and not self.inbundle(rev2): |
95 return revlog.revlog.revdiff(self, rev1, rev2) | 95 return revlog.revlog.revdiff(self, rev1, rev2) |
96 | 96 |
97 return mdiff.textdiff(self.revision(self.node(rev1)), | 97 return mdiff.textdiff(self.revision(self.node(rev1)), |
98 self.revision(self.node(rev2))) | 98 self.revision(self.node(rev2))) |
99 | 99 |
105 text = None | 105 text = None |
106 chain = [] | 106 chain = [] |
107 iter_node = node | 107 iter_node = node |
108 rev = self.rev(iter_node) | 108 rev = self.rev(iter_node) |
109 # reconstruct the revision if it is from a changegroup | 109 # reconstruct the revision if it is from a changegroup |
110 while self.bundle(rev): | 110 while self.inbundle(rev): |
111 if self._cache and self._cache[0] == iter_node: | 111 if self._cache and self._cache[0] == iter_node: |
112 text = self._cache[2] | 112 text = self._cache[2] |
113 break | 113 break |
114 chain.append(rev) | 114 chain.append(rev) |
115 iter_node = self.bundlebase(rev) | 115 iter_node = self.bundlebase(rev) |
137 raise NotImplementedError | 137 raise NotImplementedError |
138 def checksize(self): | 138 def checksize(self): |
139 raise NotImplementedError | 139 raise NotImplementedError |
140 | 140 |
141 class bundlechangelog(bundlerevlog, changelog.changelog): | 141 class bundlechangelog(bundlerevlog, changelog.changelog): |
142 def __init__(self, opener, bundlefile): | 142 def __init__(self, opener, bundle): |
143 changelog.changelog.__init__(self, opener) | 143 changelog.changelog.__init__(self, opener) |
144 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile) | 144 bundlerevlog.__init__(self, opener, self.indexfile, bundle) |
145 | 145 |
146 class bundlemanifest(bundlerevlog, manifest.manifest): | 146 class bundlemanifest(bundlerevlog, manifest.manifest): |
147 def __init__(self, opener, bundlefile, linkmapper): | 147 def __init__(self, opener, bundle, linkmapper): |
148 manifest.manifest.__init__(self, opener) | 148 manifest.manifest.__init__(self, opener) |
149 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile, | 149 bundlerevlog.__init__(self, opener, self.indexfile, bundle, |
150 linkmapper) | 150 linkmapper) |
151 | 151 |
152 class bundlefilelog(bundlerevlog, filelog.filelog): | 152 class bundlefilelog(bundlerevlog, filelog.filelog): |
153 def __init__(self, opener, path, bundlefile, linkmapper): | 153 def __init__(self, opener, path, bundle, linkmapper): |
154 filelog.filelog.__init__(self, opener, path) | 154 filelog.filelog.__init__(self, opener, path) |
155 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile, | 155 bundlerevlog.__init__(self, opener, self.indexfile, bundle, |
156 linkmapper) | 156 linkmapper) |
157 | 157 |
158 class bundlerepository(localrepo.localrepository): | 158 class bundlerepository(localrepo.localrepository): |
159 def __init__(self, ui, path, bundlename): | 159 def __init__(self, ui, path, bundlename): |
160 self._tempparent = None | 160 self._tempparent = None |
169 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename | 169 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename |
170 else: | 170 else: |
171 self._url = 'bundle:' + bundlename | 171 self._url = 'bundle:' + bundlename |
172 | 172 |
173 self.tempfile = None | 173 self.tempfile = None |
174 self.bundlefile = open(bundlename, "rb") | 174 f = open(bundlename, "rb") |
175 b = changegroup.readbundle(self.bundlefile, bundlename) | 175 self.bundle = changegroup.readbundle(f, bundlename) |
176 if b.compressed(): | 176 if self.bundle.compressed(): |
177 # we need a seekable, decompressed bundle | 177 # we need a seekable, decompressed bundle |
178 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-", | 178 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-", |
179 suffix=".hg10un", dir=self.path) | 179 suffix=".hg10un", dir=self.path) |
180 self.tempfile = temp | 180 self.tempfile = temp |
181 fptemp = os.fdopen(fdtemp, 'wb') | 181 fptemp = os.fdopen(fdtemp, 'wb') |
182 | 182 |
183 try: | 183 try: |
184 fptemp.write("HG10UN") | 184 fptemp.write("HG10UN") |
185 while 1: | 185 while 1: |
186 chunk = b.read(2**18) | 186 chunk = self.bundle.read(2**18) |
187 if not chunk: | 187 if not chunk: |
188 break | 188 break |
189 fptemp.write(chunk) | 189 fptemp.write(chunk) |
190 finally: | 190 finally: |
191 fptemp.close() | 191 fptemp.close() |
192 self.bundlefile.close() | 192 |
193 | 193 f = open(self.tempfile, "rb") |
194 self.bundlefile = open(self.tempfile, "rb") | 194 self.bundle = changegroup.readbundle(f, bundlename) |
195 self.bundlefile.seek(6) | |
196 | 195 |
197 # dict with the mapping 'filename' -> position in the bundle | 196 # dict with the mapping 'filename' -> position in the bundle |
198 self.bundlefilespos = {} | 197 self.bundlefilespos = {} |
199 | 198 |
200 @util.propertycache | 199 @util.propertycache |
201 def changelog(self): | 200 def changelog(self): |
202 c = bundlechangelog(self.sopener, self.bundlefile) | 201 c = bundlechangelog(self.sopener, self.bundle) |
203 self.manstart = self.bundlefile.tell() | 202 self.manstart = self.bundle.tell() |
204 return c | 203 return c |
205 | 204 |
206 @util.propertycache | 205 @util.propertycache |
207 def manifest(self): | 206 def manifest(self): |
208 self.bundlefile.seek(self.manstart) | 207 self.bundle.seek(self.manstart) |
209 m = bundlemanifest(self.sopener, self.bundlefile, self.changelog.rev) | 208 m = bundlemanifest(self.sopener, self.bundle, self.changelog.rev) |
210 self.filestart = self.bundlefile.tell() | 209 self.filestart = self.bundle.tell() |
211 return m | 210 return m |
212 | 211 |
213 @util.propertycache | 212 @util.propertycache |
214 def manstart(self): | 213 def manstart(self): |
215 self.changelog | 214 self.changelog |
223 def url(self): | 222 def url(self): |
224 return self._url | 223 return self._url |
225 | 224 |
226 def file(self, f): | 225 def file(self, f): |
227 if not self.bundlefilespos: | 226 if not self.bundlefilespos: |
228 self.bundlefile.seek(self.filestart) | 227 self.bundle.seek(self.filestart) |
229 while 1: | 228 while 1: |
230 chunk = changegroup.getchunk(self.bundlefile) | 229 chunk = changegroup.getchunk(self.bundle) |
231 if not chunk: | 230 if not chunk: |
232 break | 231 break |
233 self.bundlefilespos[chunk] = self.bundlefile.tell() | 232 self.bundlefilespos[chunk] = self.bundle.tell() |
234 for c in changegroup.chunkiter(self.bundlefile): | 233 for c in changegroup.chunkiter(self.bundle): |
235 pass | 234 pass |
236 | 235 |
237 if f[0] == '/': | 236 if f[0] == '/': |
238 f = f[1:] | 237 f = f[1:] |
239 if f in self.bundlefilespos: | 238 if f in self.bundlefilespos: |
240 self.bundlefile.seek(self.bundlefilespos[f]) | 239 self.bundle.seek(self.bundlefilespos[f]) |
241 return bundlefilelog(self.sopener, f, self.bundlefile, | 240 return bundlefilelog(self.sopener, f, self.bundle, |
242 self.changelog.rev) | 241 self.changelog.rev) |
243 else: | 242 else: |
244 return filelog.filelog(self.sopener, f) | 243 return filelog.filelog(self.sopener, f) |
245 | 244 |
246 def __del__(self): | 245 def __del__(self): |
247 bundlefile = getattr(self, 'bundlefile', None) | 246 del self.bundle |
248 if bundlefile and not bundlefile.closed: | |
249 bundlefile.close() | |
250 tempfile = getattr(self, 'tempfile', None) | |
251 if tempfile is not None: | 247 if tempfile is not None: |
252 os.unlink(tempfile) | 248 os.unlink(tempfile) |
253 if self._tempparent: | 249 if self._tempparent: |
254 shutil.rmtree(self._tempparent, True) | 250 shutil.rmtree(self._tempparent, True) |
255 | 251 |