##// END OF EJS Templates
bundlerepo: store validated deltabase rev in basemap instead of node...
Mads Kiilerich -
r18416:87f370c5 default
parent child Browse files
Show More
@@ -1,380 +1,386
1 # bundlerepo.py - repository class for viewing uncompressed bundles
1 # bundlerepo.py - repository class for viewing uncompressed bundles
2 #
2 #
3 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
3 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Repository class for viewing uncompressed bundles.
8 """Repository class for viewing uncompressed bundles.
9
9
10 This provides a read-only repository interface to bundles as if they
10 This provides a read-only repository interface to bundles as if they
11 were part of the actual repository.
11 were part of the actual repository.
12 """
12 """
13
13
14 from node import nullid
14 from node import nullid
15 from i18n import _
15 from i18n import _
16 import os, tempfile, shutil
16 import os, tempfile, shutil
17 import changegroup, util, mdiff, discovery, cmdutil, scmutil
17 import changegroup, util, mdiff, discovery, cmdutil, scmutil
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, bundle, linkmapper):
21 def __init__(self, opener, indexfile, bundle, linkmapper):
22 # How it works:
22 # How it works:
23 # To retrieve a revision, we need to know the offset of the revision in
23 # To retrieve a revision, we need to know the offset of the revision in
24 # the bundle (an unbundle object). We store this offset in the index
24 # the bundle (an unbundle object). We store this offset in the index
25 # (start).
25 # (start).
26 #
26 #
27 # basemap is indexed with revisions coming from the bundle, and it
27 # basemap is indexed with revisions coming from the bundle, and it
28 # maps to the node that is the base of the corresponding delta.
28 # maps to the revision that is the base of the corresponding delta.
29 #
29 #
30 # To differentiate a rev in the bundle from a rev in the revlog, we
30 # To differentiate a rev in the bundle from a rev in the revlog, we
31 # check revision against basemap.
31 # check revision against basemap.
32 opener = scmutil.readonlyvfs(opener)
32 opener = scmutil.readonlyvfs(opener)
33 revlog.revlog.__init__(self, opener, indexfile)
33 revlog.revlog.__init__(self, opener, indexfile)
34 self.bundle = bundle
34 self.bundle = bundle
35 self.basemap = {}
35 self.basemap = {} # mapping rev to delta base rev
36 n = len(self)
36 n = len(self)
37 chain = None
37 chain = None
38 self.bundlerevs = set() # used by 'bundle()' revset expression
38 self.bundlerevs = set() # used by 'bundle()' revset expression
39 while True:
39 while True:
40 chunkdata = bundle.deltachunk(chain)
40 chunkdata = bundle.deltachunk(chain)
41 if not chunkdata:
41 if not chunkdata:
42 break
42 break
43 node = chunkdata['node']
43 node = chunkdata['node']
44 p1 = chunkdata['p1']
44 p1 = chunkdata['p1']
45 p2 = chunkdata['p2']
45 p2 = chunkdata['p2']
46 cs = chunkdata['cs']
46 cs = chunkdata['cs']
47 deltabase = chunkdata['deltabase']
47 deltabase = chunkdata['deltabase']
48 delta = chunkdata['delta']
48 delta = chunkdata['delta']
49
49
50 size = len(delta)
50 size = len(delta)
51 start = bundle.tell() - size
51 start = bundle.tell() - size
52
52
53 link = linkmapper(cs)
53 link = linkmapper(cs)
54 if node in self.nodemap:
54 if node in self.nodemap:
55 # this can happen if two branches make the same change
55 # this can happen if two branches make the same change
56 chain = node
56 chain = node
57 self.bundlerevs.add(self.nodemap[node])
57 self.bundlerevs.add(self.nodemap[node])
58 continue
58 continue
59
59
60 for p in (p1, p2):
60 for p in (p1, p2):
61 if p not in self.nodemap:
61 if p not in self.nodemap:
62 raise error.LookupError(p, self.indexfile,
62 raise error.LookupError(p, self.indexfile,
63 _("unknown parent"))
63 _("unknown parent"))
64
65 if deltabase not in self.nodemap:
66 raise LookupError(deltabase, self.indexfile,
67 _('unknown delta base'))
68
69 baserev = self.rev(deltabase)
64 # start, size, full unc. size, base (unused), link, p1, p2, node
70 # start, size, full unc. size, base (unused), link, p1, p2, node
65 e = (revlog.offset_type(start, 0), size, -1, -1, link,
71 e = (revlog.offset_type(start, 0), size, -1, -1, link,
66 self.rev(p1), self.rev(p2), node)
72 self.rev(p1), self.rev(p2), node)
67 self.basemap[n] = deltabase
73 self.basemap[n] = baserev
68 self.index.insert(-1, e)
74 self.index.insert(-1, e)
69 self.nodemap[node] = n
75 self.nodemap[node] = n
70 self.bundlerevs.add(n)
76 self.bundlerevs.add(n)
71 chain = node
77 chain = node
72 n += 1
78 n += 1
73
79
74 def _chunk(self, rev):
80 def _chunk(self, rev):
75 # Warning: in case of bundle, the diff is against self.basemap,
81 # Warning: in case of bundle, the diff is against self.basemap,
76 # not against rev - 1
82 # not against rev - 1
77 # XXX: could use some caching
83 # XXX: could use some caching
78 if rev not in self.basemap:
84 if rev not in self.basemap:
79 return revlog.revlog._chunk(self, rev)
85 return revlog.revlog._chunk(self, rev)
80 self.bundle.seek(self.start(rev))
86 self.bundle.seek(self.start(rev))
81 return self.bundle.read(self.length(rev))
87 return self.bundle.read(self.length(rev))
82
88
83 def revdiff(self, rev1, rev2):
89 def revdiff(self, rev1, rev2):
84 """return or calculate a delta between two revisions"""
90 """return or calculate a delta between two revisions"""
85 if rev1 in self.basemap and rev2 in self.basemap:
91 if rev1 in self.basemap and rev2 in self.basemap:
86 # hot path for bundle
92 # hot path for bundle
87 revb = self.rev(self.basemap[rev2])
93 revb = self.basemap[rev2]
88 if revb == rev1:
94 if revb == rev1:
89 return self._chunk(rev2)
95 return self._chunk(rev2)
90 elif rev1 not in self.basemap and rev2 not in self.basemap:
96 elif rev1 not in self.basemap and rev2 not in self.basemap:
91 return revlog.revlog.revdiff(self, rev1, rev2)
97 return revlog.revlog.revdiff(self, rev1, rev2)
92
98
93 return mdiff.textdiff(self.revision(self.node(rev1)),
99 return mdiff.textdiff(self.revision(self.node(rev1)),
94 self.revision(self.node(rev2)))
100 self.revision(self.node(rev2)))
95
101
96 def revision(self, nodeorrev):
102 def revision(self, nodeorrev):
97 """return an uncompressed revision of a given node or revision
103 """return an uncompressed revision of a given node or revision
98 number.
104 number.
99 """
105 """
100 if isinstance(nodeorrev, int):
106 if isinstance(nodeorrev, int):
101 rev = nodeorrev
107 rev = nodeorrev
102 node = self.node(rev)
108 node = self.node(rev)
103 else:
109 else:
104 node = nodeorrev
110 node = nodeorrev
105 rev = self.rev(node)
111 rev = self.rev(node)
106
112
107 if node == nullid:
113 if node == nullid:
108 return ""
114 return ""
109
115
110 text = None
116 text = None
111 chain = []
117 chain = []
112 iterrev = rev
118 iterrev = rev
113 # reconstruct the revision if it is from a changegroup
119 # reconstruct the revision if it is from a changegroup
114 while iterrev in self.basemap:
120 while iterrev in self.basemap:
115 if self._cache and self._cache[1] == iterrev:
121 if self._cache and self._cache[1] == iterrev:
116 text = self._cache[2]
122 text = self._cache[2]
117 break
123 break
118 chain.append(iterrev)
124 chain.append(iterrev)
119 iterrev = self.rev(self.basemap[iterrev])
125 iterrev = self.basemap[iterrev]
120 if text is None:
126 if text is None:
121 text = revlog.revlog.revision(self, iterrev)
127 text = revlog.revlog.revision(self, iterrev)
122
128
123 while chain:
129 while chain:
124 delta = self._chunk(chain.pop())
130 delta = self._chunk(chain.pop())
125 text = mdiff.patches(text, [delta])
131 text = mdiff.patches(text, [delta])
126
132
127 p1, p2 = self.parents(node)
133 p1, p2 = self.parents(node)
128 if node != revlog.hash(text, p1, p2):
134 if node != revlog.hash(text, p1, p2):
129 raise error.RevlogError(_("integrity check failed on %s:%d")
135 raise error.RevlogError(_("integrity check failed on %s:%d")
130 % (self.datafile, rev))
136 % (self.datafile, rev))
131
137
132 self._cache = (node, rev, text)
138 self._cache = (node, rev, text)
133 return text
139 return text
134
140
135 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
141 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
136 raise NotImplementedError
142 raise NotImplementedError
137 def addgroup(self, revs, linkmapper, transaction):
143 def addgroup(self, revs, linkmapper, transaction):
138 raise NotImplementedError
144 raise NotImplementedError
139 def strip(self, rev, minlink):
145 def strip(self, rev, minlink):
140 raise NotImplementedError
146 raise NotImplementedError
141 def checksize(self):
147 def checksize(self):
142 raise NotImplementedError
148 raise NotImplementedError
143
149
144 class bundlechangelog(bundlerevlog, changelog.changelog):
150 class bundlechangelog(bundlerevlog, changelog.changelog):
145 def __init__(self, opener, bundle):
151 def __init__(self, opener, bundle):
146 changelog.changelog.__init__(self, opener)
152 changelog.changelog.__init__(self, opener)
147 linkmapper = lambda x: x
153 linkmapper = lambda x: x
148 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
154 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
149 linkmapper)
155 linkmapper)
150
156
151 class bundlemanifest(bundlerevlog, manifest.manifest):
157 class bundlemanifest(bundlerevlog, manifest.manifest):
152 def __init__(self, opener, bundle, linkmapper):
158 def __init__(self, opener, bundle, linkmapper):
153 manifest.manifest.__init__(self, opener)
159 manifest.manifest.__init__(self, opener)
154 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
160 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
155 linkmapper)
161 linkmapper)
156
162
157 class bundlefilelog(bundlerevlog, filelog.filelog):
163 class bundlefilelog(bundlerevlog, filelog.filelog):
158 def __init__(self, opener, path, bundle, linkmapper, repo):
164 def __init__(self, opener, path, bundle, linkmapper, repo):
159 filelog.filelog.__init__(self, opener, path)
165 filelog.filelog.__init__(self, opener, path)
160 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
166 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
161 linkmapper)
167 linkmapper)
162 self._repo = repo
168 self._repo = repo
163
169
164 def _file(self, f):
170 def _file(self, f):
165 self._repo.file(f)
171 self._repo.file(f)
166
172
167 class bundlepeer(localrepo.localpeer):
173 class bundlepeer(localrepo.localpeer):
168 def canpush(self):
174 def canpush(self):
169 return False
175 return False
170
176
171 class bundlerepository(localrepo.localrepository):
177 class bundlerepository(localrepo.localrepository):
172 def __init__(self, ui, path, bundlename):
178 def __init__(self, ui, path, bundlename):
173 self._tempparent = None
179 self._tempparent = None
174 try:
180 try:
175 localrepo.localrepository.__init__(self, ui, path)
181 localrepo.localrepository.__init__(self, ui, path)
176 except error.RepoError:
182 except error.RepoError:
177 self._tempparent = tempfile.mkdtemp()
183 self._tempparent = tempfile.mkdtemp()
178 localrepo.instance(ui, self._tempparent, 1)
184 localrepo.instance(ui, self._tempparent, 1)
179 localrepo.localrepository.__init__(self, ui, self._tempparent)
185 localrepo.localrepository.__init__(self, ui, self._tempparent)
180 self.ui.setconfig('phases', 'publish', False)
186 self.ui.setconfig('phases', 'publish', False)
181
187
182 if path:
188 if path:
183 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
189 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
184 else:
190 else:
185 self._url = 'bundle:' + bundlename
191 self._url = 'bundle:' + bundlename
186
192
187 self.tempfile = None
193 self.tempfile = None
188 f = util.posixfile(bundlename, "rb")
194 f = util.posixfile(bundlename, "rb")
189 self.bundle = changegroup.readbundle(f, bundlename)
195 self.bundle = changegroup.readbundle(f, bundlename)
190 if self.bundle.compressed():
196 if self.bundle.compressed():
191 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
197 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
192 suffix=".hg10un", dir=self.path)
198 suffix=".hg10un", dir=self.path)
193 self.tempfile = temp
199 self.tempfile = temp
194 fptemp = os.fdopen(fdtemp, 'wb')
200 fptemp = os.fdopen(fdtemp, 'wb')
195
201
196 try:
202 try:
197 fptemp.write("HG10UN")
203 fptemp.write("HG10UN")
198 while True:
204 while True:
199 chunk = self.bundle.read(2**18)
205 chunk = self.bundle.read(2**18)
200 if not chunk:
206 if not chunk:
201 break
207 break
202 fptemp.write(chunk)
208 fptemp.write(chunk)
203 finally:
209 finally:
204 fptemp.close()
210 fptemp.close()
205
211
206 f = util.posixfile(self.tempfile, "rb")
212 f = util.posixfile(self.tempfile, "rb")
207 self.bundle = changegroup.readbundle(f, bundlename)
213 self.bundle = changegroup.readbundle(f, bundlename)
208
214
209 # dict with the mapping 'filename' -> position in the bundle
215 # dict with the mapping 'filename' -> position in the bundle
210 self.bundlefilespos = {}
216 self.bundlefilespos = {}
211
217
212 @localrepo.unfilteredpropertycache
218 @localrepo.unfilteredpropertycache
213 def changelog(self):
219 def changelog(self):
214 # consume the header if it exists
220 # consume the header if it exists
215 self.bundle.changelogheader()
221 self.bundle.changelogheader()
216 c = bundlechangelog(self.sopener, self.bundle)
222 c = bundlechangelog(self.sopener, self.bundle)
217 self.manstart = self.bundle.tell()
223 self.manstart = self.bundle.tell()
218 return c
224 return c
219
225
220 @localrepo.unfilteredpropertycache
226 @localrepo.unfilteredpropertycache
221 def manifest(self):
227 def manifest(self):
222 self.bundle.seek(self.manstart)
228 self.bundle.seek(self.manstart)
223 # consume the header if it exists
229 # consume the header if it exists
224 self.bundle.manifestheader()
230 self.bundle.manifestheader()
225 m = bundlemanifest(self.sopener, self.bundle, self.changelog.rev)
231 m = bundlemanifest(self.sopener, self.bundle, self.changelog.rev)
226 self.filestart = self.bundle.tell()
232 self.filestart = self.bundle.tell()
227 return m
233 return m
228
234
229 @localrepo.unfilteredpropertycache
235 @localrepo.unfilteredpropertycache
230 def manstart(self):
236 def manstart(self):
231 self.changelog
237 self.changelog
232 return self.manstart
238 return self.manstart
233
239
234 @localrepo.unfilteredpropertycache
240 @localrepo.unfilteredpropertycache
235 def filestart(self):
241 def filestart(self):
236 self.manifest
242 self.manifest
237 return self.filestart
243 return self.filestart
238
244
239 def url(self):
245 def url(self):
240 return self._url
246 return self._url
241
247
242 def file(self, f):
248 def file(self, f):
243 if not self.bundlefilespos:
249 if not self.bundlefilespos:
244 self.bundle.seek(self.filestart)
250 self.bundle.seek(self.filestart)
245 while True:
251 while True:
246 chunkdata = self.bundle.filelogheader()
252 chunkdata = self.bundle.filelogheader()
247 if not chunkdata:
253 if not chunkdata:
248 break
254 break
249 fname = chunkdata['filename']
255 fname = chunkdata['filename']
250 self.bundlefilespos[fname] = self.bundle.tell()
256 self.bundlefilespos[fname] = self.bundle.tell()
251 while True:
257 while True:
252 c = self.bundle.deltachunk(None)
258 c = self.bundle.deltachunk(None)
253 if not c:
259 if not c:
254 break
260 break
255
261
256 if f[0] == '/':
262 if f[0] == '/':
257 f = f[1:]
263 f = f[1:]
258 if f in self.bundlefilespos:
264 if f in self.bundlefilespos:
259 self.bundle.seek(self.bundlefilespos[f])
265 self.bundle.seek(self.bundlefilespos[f])
260 return bundlefilelog(self.sopener, f, self.bundle,
266 return bundlefilelog(self.sopener, f, self.bundle,
261 self.changelog.rev, self)
267 self.changelog.rev, self)
262 else:
268 else:
263 return filelog.filelog(self.sopener, f)
269 return filelog.filelog(self.sopener, f)
264
270
265 def close(self):
271 def close(self):
266 """Close assigned bundle file immediately."""
272 """Close assigned bundle file immediately."""
267 self.bundle.close()
273 self.bundle.close()
268 if self.tempfile is not None:
274 if self.tempfile is not None:
269 os.unlink(self.tempfile)
275 os.unlink(self.tempfile)
270 if self._tempparent:
276 if self._tempparent:
271 shutil.rmtree(self._tempparent, True)
277 shutil.rmtree(self._tempparent, True)
272
278
273 def cancopy(self):
279 def cancopy(self):
274 return False
280 return False
275
281
276 def peer(self):
282 def peer(self):
277 return bundlepeer(self)
283 return bundlepeer(self)
278
284
279 def getcwd(self):
285 def getcwd(self):
280 return os.getcwd() # always outside the repo
286 return os.getcwd() # always outside the repo
281
287
282
288
283 def instance(ui, path, create):
289 def instance(ui, path, create):
284 if create:
290 if create:
285 raise util.Abort(_('cannot create new bundle repository'))
291 raise util.Abort(_('cannot create new bundle repository'))
286 parentpath = ui.config("bundle", "mainreporoot", "")
292 parentpath = ui.config("bundle", "mainreporoot", "")
287 if not parentpath:
293 if not parentpath:
288 # try to find the correct path to the working directory repo
294 # try to find the correct path to the working directory repo
289 parentpath = cmdutil.findrepo(os.getcwd())
295 parentpath = cmdutil.findrepo(os.getcwd())
290 if parentpath is None:
296 if parentpath is None:
291 parentpath = ''
297 parentpath = ''
292 if parentpath:
298 if parentpath:
293 # Try to make the full path relative so we get a nice, short URL.
299 # Try to make the full path relative so we get a nice, short URL.
294 # In particular, we don't want temp dir names in test outputs.
300 # In particular, we don't want temp dir names in test outputs.
295 cwd = os.getcwd()
301 cwd = os.getcwd()
296 if parentpath == cwd:
302 if parentpath == cwd:
297 parentpath = ''
303 parentpath = ''
298 else:
304 else:
299 cwd = os.path.join(cwd,'')
305 cwd = os.path.join(cwd,'')
300 if parentpath.startswith(cwd):
306 if parentpath.startswith(cwd):
301 parentpath = parentpath[len(cwd):]
307 parentpath = parentpath[len(cwd):]
302 u = util.url(path)
308 u = util.url(path)
303 path = u.localpath()
309 path = u.localpath()
304 if u.scheme == 'bundle':
310 if u.scheme == 'bundle':
305 s = path.split("+", 1)
311 s = path.split("+", 1)
306 if len(s) == 1:
312 if len(s) == 1:
307 repopath, bundlename = parentpath, s[0]
313 repopath, bundlename = parentpath, s[0]
308 else:
314 else:
309 repopath, bundlename = s
315 repopath, bundlename = s
310 else:
316 else:
311 repopath, bundlename = parentpath, path
317 repopath, bundlename = parentpath, path
312 return bundlerepository(ui, repopath, bundlename)
318 return bundlerepository(ui, repopath, bundlename)
313
319
314 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
320 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
315 force=False):
321 force=False):
316 '''obtains a bundle of changes incoming from other
322 '''obtains a bundle of changes incoming from other
317
323
318 "onlyheads" restricts the returned changes to those reachable from the
324 "onlyheads" restricts the returned changes to those reachable from the
319 specified heads.
325 specified heads.
320 "bundlename", if given, stores the bundle to this file path permanently;
326 "bundlename", if given, stores the bundle to this file path permanently;
321 otherwise it's stored to a temp file and gets deleted again when you call
327 otherwise it's stored to a temp file and gets deleted again when you call
322 the returned "cleanupfn".
328 the returned "cleanupfn".
323 "force" indicates whether to proceed on unrelated repos.
329 "force" indicates whether to proceed on unrelated repos.
324
330
325 Returns a tuple (local, csets, cleanupfn):
331 Returns a tuple (local, csets, cleanupfn):
326
332
327 "local" is a local repo from which to obtain the actual incoming
333 "local" is a local repo from which to obtain the actual incoming
328 changesets; it is a bundlerepo for the obtained bundle when the
334 changesets; it is a bundlerepo for the obtained bundle when the
329 original "other" is remote.
335 original "other" is remote.
330 "csets" lists the incoming changeset node ids.
336 "csets" lists the incoming changeset node ids.
331 "cleanupfn" must be called without arguments when you're done processing
337 "cleanupfn" must be called without arguments when you're done processing
332 the changes; it closes both the original "other" and the one returned
338 the changes; it closes both the original "other" and the one returned
333 here.
339 here.
334 '''
340 '''
335 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
341 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
336 force=force)
342 force=force)
337 common, incoming, rheads = tmp
343 common, incoming, rheads = tmp
338 if not incoming:
344 if not incoming:
339 try:
345 try:
340 if bundlename:
346 if bundlename:
341 os.unlink(bundlename)
347 os.unlink(bundlename)
342 except OSError:
348 except OSError:
343 pass
349 pass
344 return repo, [], other.close
350 return repo, [], other.close
345
351
346 bundle = None
352 bundle = None
347 bundlerepo = None
353 bundlerepo = None
348 localrepo = other.local()
354 localrepo = other.local()
349 if bundlename or not localrepo:
355 if bundlename or not localrepo:
350 # create a bundle (uncompressed if other repo is not local)
356 # create a bundle (uncompressed if other repo is not local)
351
357
352 if other.capable('getbundle'):
358 if other.capable('getbundle'):
353 cg = other.getbundle('incoming', common=common, heads=rheads)
359 cg = other.getbundle('incoming', common=common, heads=rheads)
354 elif onlyheads is None and not other.capable('changegroupsubset'):
360 elif onlyheads is None and not other.capable('changegroupsubset'):
355 # compat with older servers when pulling all remote heads
361 # compat with older servers when pulling all remote heads
356 cg = other.changegroup(incoming, "incoming")
362 cg = other.changegroup(incoming, "incoming")
357 rheads = None
363 rheads = None
358 else:
364 else:
359 cg = other.changegroupsubset(incoming, rheads, 'incoming')
365 cg = other.changegroupsubset(incoming, rheads, 'incoming')
360 bundletype = localrepo and "HG10BZ" or "HG10UN"
366 bundletype = localrepo and "HG10BZ" or "HG10UN"
361 fname = bundle = changegroup.writebundle(cg, bundlename, bundletype)
367 fname = bundle = changegroup.writebundle(cg, bundlename, bundletype)
362 # keep written bundle?
368 # keep written bundle?
363 if bundlename:
369 if bundlename:
364 bundle = None
370 bundle = None
365 if not localrepo:
371 if not localrepo:
366 # use the created uncompressed bundlerepo
372 # use the created uncompressed bundlerepo
367 localrepo = bundlerepo = bundlerepository(ui, repo.root, fname)
373 localrepo = bundlerepo = bundlerepository(ui, repo.root, fname)
368 # this repo contains local and other now, so filter out local again
374 # this repo contains local and other now, so filter out local again
369 common = repo.heads()
375 common = repo.heads()
370
376
371 csets = localrepo.changelog.findmissing(common, rheads)
377 csets = localrepo.changelog.findmissing(common, rheads)
372
378
373 def cleanup():
379 def cleanup():
374 if bundlerepo:
380 if bundlerepo:
375 bundlerepo.close()
381 bundlerepo.close()
376 if bundle:
382 if bundle:
377 os.unlink(bundle)
383 os.unlink(bundle)
378 other.close()
384 other.close()
379
385
380 return (localrepo, csets, cleanup)
386 return (localrepo, csets, cleanup)
General Comments 0
You need to be logged in to leave comments. Login now