##// END OF EJS Templates
filelog: remove unused _file method
Mike Edgar -
r24003:b95a5bb5 default
parent child Browse files
Show More
@@ -1,446 +1,443 b''
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, exchange
17 import changegroup, util, mdiff, discovery, cmdutil, scmutil, exchange
18 import localrepo, changelog, manifest, filelog, revlog, error, phases
18 import localrepo, changelog, manifest, filelog, revlog, error, phases
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). The base of the delta is stored in the base field.
25 # (start). The base of the delta is stored in the base field.
26 #
26 #
27 # To differentiate a rev in the bundle from a rev in the revlog, we
27 # To differentiate a rev in the bundle from a rev in the revlog, we
28 # check revision against repotiprev.
28 # check revision against repotiprev.
29 opener = scmutil.readonlyvfs(opener)
29 opener = scmutil.readonlyvfs(opener)
30 revlog.revlog.__init__(self, opener, indexfile)
30 revlog.revlog.__init__(self, opener, indexfile)
31 self.bundle = bundle
31 self.bundle = bundle
32 n = len(self)
32 n = len(self)
33 self.repotiprev = n - 1
33 self.repotiprev = n - 1
34 chain = None
34 chain = None
35 self.bundlerevs = set() # used by 'bundle()' revset expression
35 self.bundlerevs = set() # used by 'bundle()' revset expression
36 while True:
36 while True:
37 chunkdata = bundle.deltachunk(chain)
37 chunkdata = bundle.deltachunk(chain)
38 if not chunkdata:
38 if not chunkdata:
39 break
39 break
40 node = chunkdata['node']
40 node = chunkdata['node']
41 p1 = chunkdata['p1']
41 p1 = chunkdata['p1']
42 p2 = chunkdata['p2']
42 p2 = chunkdata['p2']
43 cs = chunkdata['cs']
43 cs = chunkdata['cs']
44 deltabase = chunkdata['deltabase']
44 deltabase = chunkdata['deltabase']
45 delta = chunkdata['delta']
45 delta = chunkdata['delta']
46
46
47 size = len(delta)
47 size = len(delta)
48 start = bundle.tell() - size
48 start = bundle.tell() - size
49
49
50 link = linkmapper(cs)
50 link = linkmapper(cs)
51 if node in self.nodemap:
51 if node in self.nodemap:
52 # this can happen if two branches make the same change
52 # this can happen if two branches make the same change
53 chain = node
53 chain = node
54 self.bundlerevs.add(self.nodemap[node])
54 self.bundlerevs.add(self.nodemap[node])
55 continue
55 continue
56
56
57 for p in (p1, p2):
57 for p in (p1, p2):
58 if p not in self.nodemap:
58 if p not in self.nodemap:
59 raise error.LookupError(p, self.indexfile,
59 raise error.LookupError(p, self.indexfile,
60 _("unknown parent"))
60 _("unknown parent"))
61
61
62 if deltabase not in self.nodemap:
62 if deltabase not in self.nodemap:
63 raise LookupError(deltabase, self.indexfile,
63 raise LookupError(deltabase, self.indexfile,
64 _('unknown delta base'))
64 _('unknown delta base'))
65
65
66 baserev = self.rev(deltabase)
66 baserev = self.rev(deltabase)
67 # start, size, full unc. size, base (unused), link, p1, p2, node
67 # start, size, full unc. size, base (unused), link, p1, p2, node
68 e = (revlog.offset_type(start, 0), size, -1, baserev, link,
68 e = (revlog.offset_type(start, 0), size, -1, baserev, link,
69 self.rev(p1), self.rev(p2), node)
69 self.rev(p1), self.rev(p2), node)
70 self.index.insert(-1, e)
70 self.index.insert(-1, e)
71 self.nodemap[node] = n
71 self.nodemap[node] = n
72 self.bundlerevs.add(n)
72 self.bundlerevs.add(n)
73 chain = node
73 chain = node
74 n += 1
74 n += 1
75
75
76 def _chunk(self, rev):
76 def _chunk(self, rev):
77 # Warning: in case of bundle, the diff is against what we stored as
77 # Warning: in case of bundle, the diff is against what we stored as
78 # delta base, not against rev - 1
78 # delta base, not against rev - 1
79 # XXX: could use some caching
79 # XXX: could use some caching
80 if rev <= self.repotiprev:
80 if rev <= self.repotiprev:
81 return revlog.revlog._chunk(self, rev)
81 return revlog.revlog._chunk(self, rev)
82 self.bundle.seek(self.start(rev))
82 self.bundle.seek(self.start(rev))
83 return self.bundle.read(self.length(rev))
83 return self.bundle.read(self.length(rev))
84
84
85 def revdiff(self, rev1, rev2):
85 def revdiff(self, rev1, rev2):
86 """return or calculate a delta between two revisions"""
86 """return or calculate a delta between two revisions"""
87 if rev1 > self.repotiprev and rev2 > self.repotiprev:
87 if rev1 > self.repotiprev and rev2 > self.repotiprev:
88 # hot path for bundle
88 # hot path for bundle
89 revb = self.index[rev2][3]
89 revb = self.index[rev2][3]
90 if revb == rev1:
90 if revb == rev1:
91 return self._chunk(rev2)
91 return self._chunk(rev2)
92 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
92 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
93 return revlog.revlog.revdiff(self, rev1, rev2)
93 return revlog.revlog.revdiff(self, rev1, rev2)
94
94
95 return mdiff.textdiff(self.revision(self.node(rev1)),
95 return mdiff.textdiff(self.revision(self.node(rev1)),
96 self.revision(self.node(rev2)))
96 self.revision(self.node(rev2)))
97
97
98 def revision(self, nodeorrev):
98 def revision(self, nodeorrev):
99 """return an uncompressed revision of a given node or revision
99 """return an uncompressed revision of a given node or revision
100 number.
100 number.
101 """
101 """
102 if isinstance(nodeorrev, int):
102 if isinstance(nodeorrev, int):
103 rev = nodeorrev
103 rev = nodeorrev
104 node = self.node(rev)
104 node = self.node(rev)
105 else:
105 else:
106 node = nodeorrev
106 node = nodeorrev
107 rev = self.rev(node)
107 rev = self.rev(node)
108
108
109 if node == nullid:
109 if node == nullid:
110 return ""
110 return ""
111
111
112 text = None
112 text = None
113 chain = []
113 chain = []
114 iterrev = rev
114 iterrev = rev
115 # reconstruct the revision if it is from a changegroup
115 # reconstruct the revision if it is from a changegroup
116 while iterrev > self.repotiprev:
116 while iterrev > self.repotiprev:
117 if self._cache and self._cache[1] == iterrev:
117 if self._cache and self._cache[1] == iterrev:
118 text = self._cache[2]
118 text = self._cache[2]
119 break
119 break
120 chain.append(iterrev)
120 chain.append(iterrev)
121 iterrev = self.index[iterrev][3]
121 iterrev = self.index[iterrev][3]
122 if text is None:
122 if text is None:
123 text = self.baserevision(iterrev)
123 text = self.baserevision(iterrev)
124
124
125 while chain:
125 while chain:
126 delta = self._chunk(chain.pop())
126 delta = self._chunk(chain.pop())
127 text = mdiff.patches(text, [delta])
127 text = mdiff.patches(text, [delta])
128
128
129 self._checkhash(text, node, rev)
129 self._checkhash(text, node, rev)
130 self._cache = (node, rev, text)
130 self._cache = (node, rev, text)
131 return text
131 return text
132
132
133 def baserevision(self, nodeorrev):
133 def baserevision(self, nodeorrev):
134 # Revlog subclasses may override 'revision' method to modify format of
134 # Revlog subclasses may override 'revision' method to modify format of
135 # content retrieved from revlog. To use bundlerevlog with such class one
135 # content retrieved from revlog. To use bundlerevlog with such class one
136 # needs to override 'baserevision' and make more specific call here.
136 # needs to override 'baserevision' and make more specific call here.
137 return revlog.revlog.revision(self, nodeorrev)
137 return revlog.revlog.revision(self, nodeorrev)
138
138
139 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
139 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
140 raise NotImplementedError
140 raise NotImplementedError
141 def addgroup(self, revs, linkmapper, transaction):
141 def addgroup(self, revs, linkmapper, transaction):
142 raise NotImplementedError
142 raise NotImplementedError
143 def strip(self, rev, minlink):
143 def strip(self, rev, minlink):
144 raise NotImplementedError
144 raise NotImplementedError
145 def checksize(self):
145 def checksize(self):
146 raise NotImplementedError
146 raise NotImplementedError
147
147
148 class bundlechangelog(bundlerevlog, changelog.changelog):
148 class bundlechangelog(bundlerevlog, changelog.changelog):
149 def __init__(self, opener, bundle):
149 def __init__(self, opener, bundle):
150 changelog.changelog.__init__(self, opener)
150 changelog.changelog.__init__(self, opener)
151 linkmapper = lambda x: x
151 linkmapper = lambda x: x
152 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
152 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
153 linkmapper)
153 linkmapper)
154
154
155 def baserevision(self, nodeorrev):
155 def baserevision(self, nodeorrev):
156 # Although changelog doesn't override 'revision' method, some extensions
156 # Although changelog doesn't override 'revision' method, some extensions
157 # may replace this class with another that does. Same story with
157 # may replace this class with another that does. Same story with
158 # manifest and filelog classes.
158 # manifest and filelog classes.
159 return changelog.changelog.revision(self, nodeorrev)
159 return changelog.changelog.revision(self, nodeorrev)
160
160
161 class bundlemanifest(bundlerevlog, manifest.manifest):
161 class bundlemanifest(bundlerevlog, manifest.manifest):
162 def __init__(self, opener, bundle, linkmapper):
162 def __init__(self, opener, bundle, linkmapper):
163 manifest.manifest.__init__(self, opener)
163 manifest.manifest.__init__(self, opener)
164 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
164 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
165 linkmapper)
165 linkmapper)
166
166
167 def baserevision(self, nodeorrev):
167 def baserevision(self, nodeorrev):
168 return manifest.manifest.revision(self, nodeorrev)
168 return manifest.manifest.revision(self, nodeorrev)
169
169
170 class bundlefilelog(bundlerevlog, filelog.filelog):
170 class bundlefilelog(bundlerevlog, filelog.filelog):
171 def __init__(self, opener, path, bundle, linkmapper, repo):
171 def __init__(self, opener, path, bundle, linkmapper, repo):
172 filelog.filelog.__init__(self, opener, path)
172 filelog.filelog.__init__(self, opener, path)
173 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
173 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
174 linkmapper)
174 linkmapper)
175 self._repo = repo
175 self._repo = repo
176
176
177 def baserevision(self, nodeorrev):
177 def baserevision(self, nodeorrev):
178 return filelog.filelog.revision(self, nodeorrev)
178 return filelog.filelog.revision(self, nodeorrev)
179
179
180 def _file(self, f):
181 self._repo.file(f)
182
183 class bundlepeer(localrepo.localpeer):
180 class bundlepeer(localrepo.localpeer):
184 def canpush(self):
181 def canpush(self):
185 return False
182 return False
186
183
187 class bundlephasecache(phases.phasecache):
184 class bundlephasecache(phases.phasecache):
188 def __init__(self, *args, **kwargs):
185 def __init__(self, *args, **kwargs):
189 super(bundlephasecache, self).__init__(*args, **kwargs)
186 super(bundlephasecache, self).__init__(*args, **kwargs)
190 if util.safehasattr(self, 'opener'):
187 if util.safehasattr(self, 'opener'):
191 self.opener = scmutil.readonlyvfs(self.opener)
188 self.opener = scmutil.readonlyvfs(self.opener)
192
189
193 def write(self):
190 def write(self):
194 raise NotImplementedError
191 raise NotImplementedError
195
192
196 def _write(self, fp):
193 def _write(self, fp):
197 raise NotImplementedError
194 raise NotImplementedError
198
195
199 def _updateroots(self, phase, newroots, tr):
196 def _updateroots(self, phase, newroots, tr):
200 self.phaseroots[phase] = newroots
197 self.phaseroots[phase] = newroots
201 self.invalidate()
198 self.invalidate()
202 self.dirty = True
199 self.dirty = True
203
200
204 class bundlerepository(localrepo.localrepository):
201 class bundlerepository(localrepo.localrepository):
205 def __init__(self, ui, path, bundlename):
202 def __init__(self, ui, path, bundlename):
206 self._tempparent = None
203 self._tempparent = None
207 try:
204 try:
208 localrepo.localrepository.__init__(self, ui, path)
205 localrepo.localrepository.__init__(self, ui, path)
209 except error.RepoError:
206 except error.RepoError:
210 self._tempparent = tempfile.mkdtemp()
207 self._tempparent = tempfile.mkdtemp()
211 localrepo.instance(ui, self._tempparent, 1)
208 localrepo.instance(ui, self._tempparent, 1)
212 localrepo.localrepository.__init__(self, ui, self._tempparent)
209 localrepo.localrepository.__init__(self, ui, self._tempparent)
213 self.ui.setconfig('phases', 'publish', False, 'bundlerepo')
210 self.ui.setconfig('phases', 'publish', False, 'bundlerepo')
214
211
215 if path:
212 if path:
216 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
213 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
217 else:
214 else:
218 self._url = 'bundle:' + bundlename
215 self._url = 'bundle:' + bundlename
219
216
220 self.tempfile = None
217 self.tempfile = None
221 f = util.posixfile(bundlename, "rb")
218 f = util.posixfile(bundlename, "rb")
222 self.bundle = exchange.readbundle(ui, f, bundlename)
219 self.bundle = exchange.readbundle(ui, f, bundlename)
223 if self.bundle.compressed():
220 if self.bundle.compressed():
224 fdtemp, temp = self.vfs.mkstemp(prefix="hg-bundle-",
221 fdtemp, temp = self.vfs.mkstemp(prefix="hg-bundle-",
225 suffix=".hg10un")
222 suffix=".hg10un")
226 self.tempfile = temp
223 self.tempfile = temp
227 fptemp = os.fdopen(fdtemp, 'wb')
224 fptemp = os.fdopen(fdtemp, 'wb')
228
225
229 try:
226 try:
230 fptemp.write("HG10UN")
227 fptemp.write("HG10UN")
231 while True:
228 while True:
232 chunk = self.bundle.read(2**18)
229 chunk = self.bundle.read(2**18)
233 if not chunk:
230 if not chunk:
234 break
231 break
235 fptemp.write(chunk)
232 fptemp.write(chunk)
236 finally:
233 finally:
237 fptemp.close()
234 fptemp.close()
238
235
239 f = self.vfs.open(self.tempfile, mode="rb")
236 f = self.vfs.open(self.tempfile, mode="rb")
240 self.bundle = exchange.readbundle(ui, f, bundlename, self.vfs)
237 self.bundle = exchange.readbundle(ui, f, bundlename, self.vfs)
241
238
242 # dict with the mapping 'filename' -> position in the bundle
239 # dict with the mapping 'filename' -> position in the bundle
243 self.bundlefilespos = {}
240 self.bundlefilespos = {}
244
241
245 self.firstnewrev = self.changelog.repotiprev + 1
242 self.firstnewrev = self.changelog.repotiprev + 1
246 phases.retractboundary(self, None, phases.draft,
243 phases.retractboundary(self, None, phases.draft,
247 [ctx.node() for ctx in self[self.firstnewrev:]])
244 [ctx.node() for ctx in self[self.firstnewrev:]])
248
245
249 @localrepo.unfilteredpropertycache
246 @localrepo.unfilteredpropertycache
250 def _phasecache(self):
247 def _phasecache(self):
251 return bundlephasecache(self, self._phasedefaults)
248 return bundlephasecache(self, self._phasedefaults)
252
249
253 @localrepo.unfilteredpropertycache
250 @localrepo.unfilteredpropertycache
254 def changelog(self):
251 def changelog(self):
255 # consume the header if it exists
252 # consume the header if it exists
256 self.bundle.changelogheader()
253 self.bundle.changelogheader()
257 c = bundlechangelog(self.svfs, self.bundle)
254 c = bundlechangelog(self.svfs, self.bundle)
258 self.manstart = self.bundle.tell()
255 self.manstart = self.bundle.tell()
259 return c
256 return c
260
257
261 @localrepo.unfilteredpropertycache
258 @localrepo.unfilteredpropertycache
262 def manifest(self):
259 def manifest(self):
263 self.bundle.seek(self.manstart)
260 self.bundle.seek(self.manstart)
264 # consume the header if it exists
261 # consume the header if it exists
265 self.bundle.manifestheader()
262 self.bundle.manifestheader()
266 m = bundlemanifest(self.svfs, self.bundle, self.changelog.rev)
263 m = bundlemanifest(self.svfs, self.bundle, self.changelog.rev)
267 self.filestart = self.bundle.tell()
264 self.filestart = self.bundle.tell()
268 return m
265 return m
269
266
270 @localrepo.unfilteredpropertycache
267 @localrepo.unfilteredpropertycache
271 def manstart(self):
268 def manstart(self):
272 self.changelog
269 self.changelog
273 return self.manstart
270 return self.manstart
274
271
275 @localrepo.unfilteredpropertycache
272 @localrepo.unfilteredpropertycache
276 def filestart(self):
273 def filestart(self):
277 self.manifest
274 self.manifest
278 return self.filestart
275 return self.filestart
279
276
280 def url(self):
277 def url(self):
281 return self._url
278 return self._url
282
279
283 def file(self, f):
280 def file(self, f):
284 if not self.bundlefilespos:
281 if not self.bundlefilespos:
285 self.bundle.seek(self.filestart)
282 self.bundle.seek(self.filestart)
286 while True:
283 while True:
287 chunkdata = self.bundle.filelogheader()
284 chunkdata = self.bundle.filelogheader()
288 if not chunkdata:
285 if not chunkdata:
289 break
286 break
290 fname = chunkdata['filename']
287 fname = chunkdata['filename']
291 self.bundlefilespos[fname] = self.bundle.tell()
288 self.bundlefilespos[fname] = self.bundle.tell()
292 while True:
289 while True:
293 c = self.bundle.deltachunk(None)
290 c = self.bundle.deltachunk(None)
294 if not c:
291 if not c:
295 break
292 break
296
293
297 if f in self.bundlefilespos:
294 if f in self.bundlefilespos:
298 self.bundle.seek(self.bundlefilespos[f])
295 self.bundle.seek(self.bundlefilespos[f])
299 return bundlefilelog(self.svfs, f, self.bundle,
296 return bundlefilelog(self.svfs, f, self.bundle,
300 self.changelog.rev, self)
297 self.changelog.rev, self)
301 else:
298 else:
302 return filelog.filelog(self.svfs, f)
299 return filelog.filelog(self.svfs, f)
303
300
304 def close(self):
301 def close(self):
305 """Close assigned bundle file immediately."""
302 """Close assigned bundle file immediately."""
306 self.bundle.close()
303 self.bundle.close()
307 if self.tempfile is not None:
304 if self.tempfile is not None:
308 self.vfs.unlink(self.tempfile)
305 self.vfs.unlink(self.tempfile)
309 if self._tempparent:
306 if self._tempparent:
310 shutil.rmtree(self._tempparent, True)
307 shutil.rmtree(self._tempparent, True)
311
308
312 def cancopy(self):
309 def cancopy(self):
313 return False
310 return False
314
311
315 def peer(self):
312 def peer(self):
316 return bundlepeer(self)
313 return bundlepeer(self)
317
314
318 def getcwd(self):
315 def getcwd(self):
319 return os.getcwd() # always outside the repo
316 return os.getcwd() # always outside the repo
320
317
321
318
322 def instance(ui, path, create):
319 def instance(ui, path, create):
323 if create:
320 if create:
324 raise util.Abort(_('cannot create new bundle repository'))
321 raise util.Abort(_('cannot create new bundle repository'))
325 parentpath = ui.config("bundle", "mainreporoot", "")
322 parentpath = ui.config("bundle", "mainreporoot", "")
326 if not parentpath:
323 if not parentpath:
327 # try to find the correct path to the working directory repo
324 # try to find the correct path to the working directory repo
328 parentpath = cmdutil.findrepo(os.getcwd())
325 parentpath = cmdutil.findrepo(os.getcwd())
329 if parentpath is None:
326 if parentpath is None:
330 parentpath = ''
327 parentpath = ''
331 if parentpath:
328 if parentpath:
332 # Try to make the full path relative so we get a nice, short URL.
329 # Try to make the full path relative so we get a nice, short URL.
333 # In particular, we don't want temp dir names in test outputs.
330 # In particular, we don't want temp dir names in test outputs.
334 cwd = os.getcwd()
331 cwd = os.getcwd()
335 if parentpath == cwd:
332 if parentpath == cwd:
336 parentpath = ''
333 parentpath = ''
337 else:
334 else:
338 cwd = os.path.join(cwd,'')
335 cwd = os.path.join(cwd,'')
339 if parentpath.startswith(cwd):
336 if parentpath.startswith(cwd):
340 parentpath = parentpath[len(cwd):]
337 parentpath = parentpath[len(cwd):]
341 u = util.url(path)
338 u = util.url(path)
342 path = u.localpath()
339 path = u.localpath()
343 if u.scheme == 'bundle':
340 if u.scheme == 'bundle':
344 s = path.split("+", 1)
341 s = path.split("+", 1)
345 if len(s) == 1:
342 if len(s) == 1:
346 repopath, bundlename = parentpath, s[0]
343 repopath, bundlename = parentpath, s[0]
347 else:
344 else:
348 repopath, bundlename = s
345 repopath, bundlename = s
349 else:
346 else:
350 repopath, bundlename = parentpath, path
347 repopath, bundlename = parentpath, path
351 return bundlerepository(ui, repopath, bundlename)
348 return bundlerepository(ui, repopath, bundlename)
352
349
353 class bundletransactionmanager(object):
350 class bundletransactionmanager(object):
354 def transaction(self):
351 def transaction(self):
355 return None
352 return None
356
353
357 def close(self):
354 def close(self):
358 raise NotImplementedError
355 raise NotImplementedError
359
356
360 def release(self):
357 def release(self):
361 raise NotImplementedError
358 raise NotImplementedError
362
359
363 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
360 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
364 force=False):
361 force=False):
365 '''obtains a bundle of changes incoming from other
362 '''obtains a bundle of changes incoming from other
366
363
367 "onlyheads" restricts the returned changes to those reachable from the
364 "onlyheads" restricts the returned changes to those reachable from the
368 specified heads.
365 specified heads.
369 "bundlename", if given, stores the bundle to this file path permanently;
366 "bundlename", if given, stores the bundle to this file path permanently;
370 otherwise it's stored to a temp file and gets deleted again when you call
367 otherwise it's stored to a temp file and gets deleted again when you call
371 the returned "cleanupfn".
368 the returned "cleanupfn".
372 "force" indicates whether to proceed on unrelated repos.
369 "force" indicates whether to proceed on unrelated repos.
373
370
374 Returns a tuple (local, csets, cleanupfn):
371 Returns a tuple (local, csets, cleanupfn):
375
372
376 "local" is a local repo from which to obtain the actual incoming
373 "local" is a local repo from which to obtain the actual incoming
377 changesets; it is a bundlerepo for the obtained bundle when the
374 changesets; it is a bundlerepo for the obtained bundle when the
378 original "other" is remote.
375 original "other" is remote.
379 "csets" lists the incoming changeset node ids.
376 "csets" lists the incoming changeset node ids.
380 "cleanupfn" must be called without arguments when you're done processing
377 "cleanupfn" must be called without arguments when you're done processing
381 the changes; it closes both the original "other" and the one returned
378 the changes; it closes both the original "other" and the one returned
382 here.
379 here.
383 '''
380 '''
384 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
381 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
385 force=force)
382 force=force)
386 common, incoming, rheads = tmp
383 common, incoming, rheads = tmp
387 if not incoming:
384 if not incoming:
388 try:
385 try:
389 if bundlename:
386 if bundlename:
390 os.unlink(bundlename)
387 os.unlink(bundlename)
391 except OSError:
388 except OSError:
392 pass
389 pass
393 return repo, [], other.close
390 return repo, [], other.close
394
391
395 commonset = set(common)
392 commonset = set(common)
396 rheads = [x for x in rheads if x not in commonset]
393 rheads = [x for x in rheads if x not in commonset]
397
394
398 bundle = None
395 bundle = None
399 bundlerepo = None
396 bundlerepo = None
400 localrepo = other.local()
397 localrepo = other.local()
401 if bundlename or not localrepo:
398 if bundlename or not localrepo:
402 # create a bundle (uncompressed if other repo is not local)
399 # create a bundle (uncompressed if other repo is not local)
403
400
404 if other.capable('getbundle'):
401 if other.capable('getbundle'):
405 cg = other.getbundle('incoming', common=common, heads=rheads)
402 cg = other.getbundle('incoming', common=common, heads=rheads)
406 elif onlyheads is None and not other.capable('changegroupsubset'):
403 elif onlyheads is None and not other.capable('changegroupsubset'):
407 # compat with older servers when pulling all remote heads
404 # compat with older servers when pulling all remote heads
408 cg = other.changegroup(incoming, "incoming")
405 cg = other.changegroup(incoming, "incoming")
409 rheads = None
406 rheads = None
410 else:
407 else:
411 cg = other.changegroupsubset(incoming, rheads, 'incoming')
408 cg = other.changegroupsubset(incoming, rheads, 'incoming')
412 bundletype = localrepo and "HG10BZ" or "HG10UN"
409 bundletype = localrepo and "HG10BZ" or "HG10UN"
413 fname = bundle = changegroup.writebundle(ui, cg, bundlename, bundletype)
410 fname = bundle = changegroup.writebundle(ui, cg, bundlename, bundletype)
414 # keep written bundle?
411 # keep written bundle?
415 if bundlename:
412 if bundlename:
416 bundle = None
413 bundle = None
417 if not localrepo:
414 if not localrepo:
418 # use the created uncompressed bundlerepo
415 # use the created uncompressed bundlerepo
419 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
416 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
420 fname)
417 fname)
421 # this repo contains local and other now, so filter out local again
418 # this repo contains local and other now, so filter out local again
422 common = repo.heads()
419 common = repo.heads()
423 if localrepo:
420 if localrepo:
424 # Part of common may be remotely filtered
421 # Part of common may be remotely filtered
425 # So use an unfiltered version
422 # So use an unfiltered version
426 # The discovery process probably need cleanup to avoid that
423 # The discovery process probably need cleanup to avoid that
427 localrepo = localrepo.unfiltered()
424 localrepo = localrepo.unfiltered()
428
425
429 csets = localrepo.changelog.findmissing(common, rheads)
426 csets = localrepo.changelog.findmissing(common, rheads)
430
427
431 if bundlerepo:
428 if bundlerepo:
432 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
429 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
433 remotephases = other.listkeys('phases')
430 remotephases = other.listkeys('phases')
434
431
435 pullop = exchange.pulloperation(bundlerepo, other, heads=reponodes)
432 pullop = exchange.pulloperation(bundlerepo, other, heads=reponodes)
436 pullop.trmanager = bundletransactionmanager()
433 pullop.trmanager = bundletransactionmanager()
437 exchange._pullapplyphases(pullop, remotephases)
434 exchange._pullapplyphases(pullop, remotephases)
438
435
439 def cleanup():
436 def cleanup():
440 if bundlerepo:
437 if bundlerepo:
441 bundlerepo.close()
438 bundlerepo.close()
442 if bundle:
439 if bundle:
443 os.unlink(bundle)
440 os.unlink(bundle)
444 other.close()
441 other.close()
445
442
446 return (localrepo, csets, cleanup)
443 return (localrepo, csets, cleanup)
@@ -1,112 +1,109 b''
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.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 import error, revlog
8 import error, revlog
9 import re
9 import re
10
10
11 _mdre = re.compile('\1\n')
11 _mdre = re.compile('\1\n')
12 def parsemeta(text):
12 def parsemeta(text):
13 """return (metadatadict, keylist, metadatasize)"""
13 """return (metadatadict, keylist, metadatasize)"""
14 # text can be buffer, so we can't use .startswith or .index
14 # text can be buffer, so we can't use .startswith or .index
15 if text[:2] != '\1\n':
15 if text[:2] != '\1\n':
16 return None, None
16 return None, None
17 s = _mdre.search(text, 2).start()
17 s = _mdre.search(text, 2).start()
18 mtext = text[2:s]
18 mtext = text[2:s]
19 meta = {}
19 meta = {}
20 for l in mtext.splitlines():
20 for l in mtext.splitlines():
21 k, v = l.split(": ", 1)
21 k, v = l.split(": ", 1)
22 meta[k] = v
22 meta[k] = v
23 return meta, (s + 2)
23 return meta, (s + 2)
24
24
25 def packmeta(meta, text):
25 def packmeta(meta, text):
26 keys = sorted(meta.iterkeys())
26 keys = sorted(meta.iterkeys())
27 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys)
27 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys)
28 return "\1\n%s\1\n%s" % (metatext, text)
28 return "\1\n%s\1\n%s" % (metatext, text)
29
29
30 def _censoredtext(text):
30 def _censoredtext(text):
31 m, offs = parsemeta(text)
31 m, offs = parsemeta(text)
32 return m and "censored" in m and not text[offs:]
32 return m and "censored" in m and not text[offs:]
33
33
34 class filelog(revlog.revlog):
34 class filelog(revlog.revlog):
35 def __init__(self, opener, path):
35 def __init__(self, opener, path):
36 super(filelog, self).__init__(opener,
36 super(filelog, self).__init__(opener,
37 "/".join(("data", path + ".i")))
37 "/".join(("data", path + ".i")))
38
38
39 def read(self, node):
39 def read(self, node):
40 t = self.revision(node)
40 t = self.revision(node)
41 if not t.startswith('\1\n'):
41 if not t.startswith('\1\n'):
42 return t
42 return t
43 s = t.index('\1\n', 2)
43 s = t.index('\1\n', 2)
44 return t[s + 2:]
44 return t[s + 2:]
45
45
46 def add(self, text, meta, transaction, link, p1=None, p2=None):
46 def add(self, text, meta, transaction, link, p1=None, p2=None):
47 if meta or text.startswith('\1\n'):
47 if meta or text.startswith('\1\n'):
48 text = packmeta(meta, text)
48 text = packmeta(meta, text)
49 return self.addrevision(text, transaction, link, p1, p2)
49 return self.addrevision(text, transaction, link, p1, p2)
50
50
51 def renamed(self, node):
51 def renamed(self, node):
52 if self.parents(node)[0] != revlog.nullid:
52 if self.parents(node)[0] != revlog.nullid:
53 return False
53 return False
54 t = self.revision(node)
54 t = self.revision(node)
55 m = parsemeta(t)[0]
55 m = parsemeta(t)[0]
56 if m and "copy" in m:
56 if m and "copy" in m:
57 return (m["copy"], revlog.bin(m["copyrev"]))
57 return (m["copy"], revlog.bin(m["copyrev"]))
58 return False
58 return False
59
59
60 def size(self, rev):
60 def size(self, rev):
61 """return the size of a given revision"""
61 """return the size of a given revision"""
62
62
63 # for revisions with renames, we have to go the slow way
63 # for revisions with renames, we have to go the slow way
64 node = self.node(rev)
64 node = self.node(rev)
65 if self.renamed(node):
65 if self.renamed(node):
66 return len(self.read(node))
66 return len(self.read(node))
67 if self._iscensored(rev):
67 if self._iscensored(rev):
68 return 0
68 return 0
69
69
70 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
70 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
71 return super(filelog, self).size(rev)
71 return super(filelog, self).size(rev)
72
72
73 def cmp(self, node, text):
73 def cmp(self, node, text):
74 """compare text with a given file revision
74 """compare text with a given file revision
75
75
76 returns True if text is different than what is stored.
76 returns True if text is different than what is stored.
77 """
77 """
78
78
79 t = text
79 t = text
80 if text.startswith('\1\n'):
80 if text.startswith('\1\n'):
81 t = '\1\n\1\n' + text
81 t = '\1\n\1\n' + text
82
82
83 samehashes = not super(filelog, self).cmp(node, t)
83 samehashes = not super(filelog, self).cmp(node, t)
84 if samehashes:
84 if samehashes:
85 return False
85 return False
86
86
87 # censored files compare against the empty file
87 # censored files compare against the empty file
88 if self._iscensored(self.rev(node)):
88 if self._iscensored(self.rev(node)):
89 return text != ''
89 return text != ''
90
90
91 # renaming a file produces a different hash, even if the data
91 # renaming a file produces a different hash, even if the data
92 # remains unchanged. Check if it's the case (slow):
92 # remains unchanged. Check if it's the case (slow):
93 if self.renamed(node):
93 if self.renamed(node):
94 t2 = self.read(node)
94 t2 = self.read(node)
95 return t2 != text
95 return t2 != text
96
96
97 return True
97 return True
98
98
99 def checkhash(self, text, p1, p2, node, rev=None):
99 def checkhash(self, text, p1, p2, node, rev=None):
100 try:
100 try:
101 super(filelog, self).checkhash(text, p1, p2, node, rev=rev)
101 super(filelog, self).checkhash(text, p1, p2, node, rev=rev)
102 except error.RevlogError:
102 except error.RevlogError:
103 if _censoredtext(text):
103 if _censoredtext(text):
104 raise error.CensoredNodeError(self.indexfile, node)
104 raise error.CensoredNodeError(self.indexfile, node)
105 raise
105 raise
106
106
107 def _file(self, f):
108 return filelog(self.opener, f)
109
110 def _iscensored(self, rev):
107 def _iscensored(self, rev):
111 """Check if a file revision is censored."""
108 """Check if a file revision is censored."""
112 return self.flags(rev) & revlog.REVIDX_ISCENSORED
109 return self.flags(rev) & revlog.REVIDX_ISCENSORED
@@ -1,239 +1,236 b''
1 # unionrepo.py - repository class for viewing union of repository changesets
1 # unionrepo.py - repository class for viewing union of repository changesets
2 #
2 #
3 # Derived from bundlerepo.py
3 # Derived from bundlerepo.py
4 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
4 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
5 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
5 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 """Repository class for "in-memory pull" of one local repository to another,
10 """Repository class for "in-memory pull" of one local repository to another,
11 allowing operations like diff and log with revsets.
11 allowing operations like diff and log with revsets.
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
16 import os
17 import util, mdiff, cmdutil, scmutil
17 import util, mdiff, cmdutil, scmutil
18 import localrepo, changelog, manifest, filelog, revlog
18 import localrepo, changelog, manifest, filelog, revlog
19
19
20 class unionrevlog(revlog.revlog):
20 class unionrevlog(revlog.revlog):
21 def __init__(self, opener, indexfile, revlog2, linkmapper):
21 def __init__(self, opener, indexfile, revlog2, linkmapper):
22 # How it works:
22 # How it works:
23 # To retrieve a revision, we just need to know the node id so we can
23 # To retrieve a revision, we just need to know the node id so we can
24 # look it up in revlog2.
24 # look it up in revlog2.
25 #
25 #
26 # To differentiate a rev in the second revlog from a rev in the revlog,
26 # To differentiate a rev in the second revlog from a rev in the revlog,
27 # we check revision against repotiprev.
27 # we check revision against repotiprev.
28 opener = scmutil.readonlyvfs(opener)
28 opener = scmutil.readonlyvfs(opener)
29 revlog.revlog.__init__(self, opener, indexfile)
29 revlog.revlog.__init__(self, opener, indexfile)
30 self.revlog2 = revlog2
30 self.revlog2 = revlog2
31
31
32 n = len(self)
32 n = len(self)
33 self.repotiprev = n - 1
33 self.repotiprev = n - 1
34 self.bundlerevs = set() # used by 'bundle()' revset expression
34 self.bundlerevs = set() # used by 'bundle()' revset expression
35 for rev2 in self.revlog2:
35 for rev2 in self.revlog2:
36 rev = self.revlog2.index[rev2]
36 rev = self.revlog2.index[rev2]
37 # rev numbers - in revlog2, very different from self.rev
37 # rev numbers - in revlog2, very different from self.rev
38 _start, _csize, _rsize, _base, linkrev, p1rev, p2rev, node = rev
38 _start, _csize, _rsize, _base, linkrev, p1rev, p2rev, node = rev
39
39
40 if linkmapper is None: # link is to same revlog
40 if linkmapper is None: # link is to same revlog
41 assert linkrev == rev2 # we never link back
41 assert linkrev == rev2 # we never link back
42 link = n
42 link = n
43 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
43 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
44 link = linkmapper(linkrev)
44 link = linkmapper(linkrev)
45
45
46 if node in self.nodemap:
46 if node in self.nodemap:
47 # this happens for the common revlog revisions
47 # this happens for the common revlog revisions
48 self.bundlerevs.add(self.nodemap[node])
48 self.bundlerevs.add(self.nodemap[node])
49 continue
49 continue
50
50
51 p1node = self.revlog2.node(p1rev)
51 p1node = self.revlog2.node(p1rev)
52 p2node = self.revlog2.node(p2rev)
52 p2node = self.revlog2.node(p2rev)
53
53
54 e = (None, None, None, None,
54 e = (None, None, None, None,
55 link, self.rev(p1node), self.rev(p2node), node)
55 link, self.rev(p1node), self.rev(p2node), node)
56 self.index.insert(-1, e)
56 self.index.insert(-1, e)
57 self.nodemap[node] = n
57 self.nodemap[node] = n
58 self.bundlerevs.add(n)
58 self.bundlerevs.add(n)
59 n += 1
59 n += 1
60
60
61 def _chunk(self, rev):
61 def _chunk(self, rev):
62 if rev <= self.repotiprev:
62 if rev <= self.repotiprev:
63 return revlog.revlog._chunk(self, rev)
63 return revlog.revlog._chunk(self, rev)
64 return self.revlog2._chunk(self.node(rev))
64 return self.revlog2._chunk(self.node(rev))
65
65
66 def revdiff(self, rev1, rev2):
66 def revdiff(self, rev1, rev2):
67 """return or calculate a delta between two revisions"""
67 """return or calculate a delta between two revisions"""
68 if rev1 > self.repotiprev and rev2 > self.repotiprev:
68 if rev1 > self.repotiprev and rev2 > self.repotiprev:
69 return self.revlog2.revdiff(
69 return self.revlog2.revdiff(
70 self.revlog2.rev(self.node(rev1)),
70 self.revlog2.rev(self.node(rev1)),
71 self.revlog2.rev(self.node(rev2)))
71 self.revlog2.rev(self.node(rev2)))
72 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
72 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
73 return self.baserevdiff(rev1, rev2)
73 return self.baserevdiff(rev1, rev2)
74
74
75 return mdiff.textdiff(self.revision(self.node(rev1)),
75 return mdiff.textdiff(self.revision(self.node(rev1)),
76 self.revision(self.node(rev2)))
76 self.revision(self.node(rev2)))
77
77
78 def revision(self, nodeorrev):
78 def revision(self, nodeorrev):
79 """return an uncompressed revision of a given node or revision
79 """return an uncompressed revision of a given node or revision
80 number.
80 number.
81 """
81 """
82 if isinstance(nodeorrev, int):
82 if isinstance(nodeorrev, int):
83 rev = nodeorrev
83 rev = nodeorrev
84 node = self.node(rev)
84 node = self.node(rev)
85 else:
85 else:
86 node = nodeorrev
86 node = nodeorrev
87 rev = self.rev(node)
87 rev = self.rev(node)
88
88
89 if node == nullid:
89 if node == nullid:
90 return ""
90 return ""
91
91
92 if rev > self.repotiprev:
92 if rev > self.repotiprev:
93 text = self.revlog2.revision(node)
93 text = self.revlog2.revision(node)
94 self._cache = (node, rev, text)
94 self._cache = (node, rev, text)
95 else:
95 else:
96 text = self.baserevision(rev)
96 text = self.baserevision(rev)
97 # already cached
97 # already cached
98 return text
98 return text
99
99
100 def baserevision(self, nodeorrev):
100 def baserevision(self, nodeorrev):
101 # Revlog subclasses may override 'revision' method to modify format of
101 # Revlog subclasses may override 'revision' method to modify format of
102 # content retrieved from revlog. To use unionrevlog with such class one
102 # content retrieved from revlog. To use unionrevlog with such class one
103 # needs to override 'baserevision' and make more specific call here.
103 # needs to override 'baserevision' and make more specific call here.
104 return revlog.revlog.revision(self, nodeorrev)
104 return revlog.revlog.revision(self, nodeorrev)
105
105
106 def baserevdiff(self, rev1, rev2):
106 def baserevdiff(self, rev1, rev2):
107 # Exists for the same purpose as baserevision.
107 # Exists for the same purpose as baserevision.
108 return revlog.revlog.revdiff(self, rev1, rev2)
108 return revlog.revlog.revdiff(self, rev1, rev2)
109
109
110 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
110 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
111 raise NotImplementedError
111 raise NotImplementedError
112 def addgroup(self, revs, linkmapper, transaction):
112 def addgroup(self, revs, linkmapper, transaction):
113 raise NotImplementedError
113 raise NotImplementedError
114 def strip(self, rev, minlink):
114 def strip(self, rev, minlink):
115 raise NotImplementedError
115 raise NotImplementedError
116 def checksize(self):
116 def checksize(self):
117 raise NotImplementedError
117 raise NotImplementedError
118
118
119 class unionchangelog(unionrevlog, changelog.changelog):
119 class unionchangelog(unionrevlog, changelog.changelog):
120 def __init__(self, opener, opener2):
120 def __init__(self, opener, opener2):
121 changelog.changelog.__init__(self, opener)
121 changelog.changelog.__init__(self, opener)
122 linkmapper = None
122 linkmapper = None
123 changelog2 = changelog.changelog(opener2)
123 changelog2 = changelog.changelog(opener2)
124 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
124 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
125 linkmapper)
125 linkmapper)
126
126
127 def baserevision(self, nodeorrev):
127 def baserevision(self, nodeorrev):
128 # Although changelog doesn't override 'revision' method, some extensions
128 # Although changelog doesn't override 'revision' method, some extensions
129 # may replace this class with another that does. Same story with
129 # may replace this class with another that does. Same story with
130 # manifest and filelog classes.
130 # manifest and filelog classes.
131 return changelog.changelog.revision(self, nodeorrev)
131 return changelog.changelog.revision(self, nodeorrev)
132
132
133 def baserevdiff(self, rev1, rev2):
133 def baserevdiff(self, rev1, rev2):
134 return changelog.changelog.revdiff(self, rev1, rev2)
134 return changelog.changelog.revdiff(self, rev1, rev2)
135
135
136 class unionmanifest(unionrevlog, manifest.manifest):
136 class unionmanifest(unionrevlog, manifest.manifest):
137 def __init__(self, opener, opener2, linkmapper):
137 def __init__(self, opener, opener2, linkmapper):
138 manifest.manifest.__init__(self, opener)
138 manifest.manifest.__init__(self, opener)
139 manifest2 = manifest.manifest(opener2)
139 manifest2 = manifest.manifest(opener2)
140 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
140 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
141 linkmapper)
141 linkmapper)
142
142
143 def baserevision(self, nodeorrev):
143 def baserevision(self, nodeorrev):
144 return manifest.manifest.revision(self, nodeorrev)
144 return manifest.manifest.revision(self, nodeorrev)
145
145
146 def baserevdiff(self, rev1, rev2):
146 def baserevdiff(self, rev1, rev2):
147 return manifest.manifest.revdiff(self, rev1, rev2)
147 return manifest.manifest.revdiff(self, rev1, rev2)
148
148
149 class unionfilelog(unionrevlog, filelog.filelog):
149 class unionfilelog(unionrevlog, filelog.filelog):
150 def __init__(self, opener, path, opener2, linkmapper, repo):
150 def __init__(self, opener, path, opener2, linkmapper, repo):
151 filelog.filelog.__init__(self, opener, path)
151 filelog.filelog.__init__(self, opener, path)
152 filelog2 = filelog.filelog(opener2, path)
152 filelog2 = filelog.filelog(opener2, path)
153 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
153 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
154 linkmapper)
154 linkmapper)
155 self._repo = repo
155 self._repo = repo
156
156
157 def baserevision(self, nodeorrev):
157 def baserevision(self, nodeorrev):
158 return filelog.filelog.revision(self, nodeorrev)
158 return filelog.filelog.revision(self, nodeorrev)
159
159
160 def baserevdiff(self, rev1, rev2):
160 def baserevdiff(self, rev1, rev2):
161 return filelog.filelog.revdiff(self, rev1, rev2)
161 return filelog.filelog.revdiff(self, rev1, rev2)
162
162
163 def _file(self, f):
164 self._repo.file(f)
165
166 class unionpeer(localrepo.localpeer):
163 class unionpeer(localrepo.localpeer):
167 def canpush(self):
164 def canpush(self):
168 return False
165 return False
169
166
170 class unionrepository(localrepo.localrepository):
167 class unionrepository(localrepo.localrepository):
171 def __init__(self, ui, path, path2):
168 def __init__(self, ui, path, path2):
172 localrepo.localrepository.__init__(self, ui, path)
169 localrepo.localrepository.__init__(self, ui, path)
173 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
170 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
174
171
175 self._url = 'union:%s+%s' % (util.expandpath(path),
172 self._url = 'union:%s+%s' % (util.expandpath(path),
176 util.expandpath(path2))
173 util.expandpath(path2))
177 self.repo2 = localrepo.localrepository(ui, path2)
174 self.repo2 = localrepo.localrepository(ui, path2)
178
175
179 @localrepo.unfilteredpropertycache
176 @localrepo.unfilteredpropertycache
180 def changelog(self):
177 def changelog(self):
181 return unionchangelog(self.svfs, self.repo2.svfs)
178 return unionchangelog(self.svfs, self.repo2.svfs)
182
179
183 def _clrev(self, rev2):
180 def _clrev(self, rev2):
184 """map from repo2 changelog rev to temporary rev in self.changelog"""
181 """map from repo2 changelog rev to temporary rev in self.changelog"""
185 node = self.repo2.changelog.node(rev2)
182 node = self.repo2.changelog.node(rev2)
186 return self.changelog.rev(node)
183 return self.changelog.rev(node)
187
184
188 @localrepo.unfilteredpropertycache
185 @localrepo.unfilteredpropertycache
189 def manifest(self):
186 def manifest(self):
190 return unionmanifest(self.svfs, self.repo2.svfs,
187 return unionmanifest(self.svfs, self.repo2.svfs,
191 self._clrev)
188 self._clrev)
192
189
193 def url(self):
190 def url(self):
194 return self._url
191 return self._url
195
192
196 def file(self, f):
193 def file(self, f):
197 return unionfilelog(self.svfs, f, self.repo2.svfs,
194 return unionfilelog(self.svfs, f, self.repo2.svfs,
198 self._clrev, self)
195 self._clrev, self)
199
196
200 def close(self):
197 def close(self):
201 self.repo2.close()
198 self.repo2.close()
202
199
203 def cancopy(self):
200 def cancopy(self):
204 return False
201 return False
205
202
206 def peer(self):
203 def peer(self):
207 return unionpeer(self)
204 return unionpeer(self)
208
205
209 def getcwd(self):
206 def getcwd(self):
210 return os.getcwd() # always outside the repo
207 return os.getcwd() # always outside the repo
211
208
212 def instance(ui, path, create):
209 def instance(ui, path, create):
213 if create:
210 if create:
214 raise util.Abort(_('cannot create new union repository'))
211 raise util.Abort(_('cannot create new union repository'))
215 parentpath = ui.config("bundle", "mainreporoot", "")
212 parentpath = ui.config("bundle", "mainreporoot", "")
216 if not parentpath:
213 if not parentpath:
217 # try to find the correct path to the working directory repo
214 # try to find the correct path to the working directory repo
218 parentpath = cmdutil.findrepo(os.getcwd())
215 parentpath = cmdutil.findrepo(os.getcwd())
219 if parentpath is None:
216 if parentpath is None:
220 parentpath = ''
217 parentpath = ''
221 if parentpath:
218 if parentpath:
222 # Try to make the full path relative so we get a nice, short URL.
219 # Try to make the full path relative so we get a nice, short URL.
223 # In particular, we don't want temp dir names in test outputs.
220 # In particular, we don't want temp dir names in test outputs.
224 cwd = os.getcwd()
221 cwd = os.getcwd()
225 if parentpath == cwd:
222 if parentpath == cwd:
226 parentpath = ''
223 parentpath = ''
227 else:
224 else:
228 cwd = os.path.join(cwd,'')
225 cwd = os.path.join(cwd,'')
229 if parentpath.startswith(cwd):
226 if parentpath.startswith(cwd):
230 parentpath = parentpath[len(cwd):]
227 parentpath = parentpath[len(cwd):]
231 if path.startswith('union:'):
228 if path.startswith('union:'):
232 s = path.split(":", 1)[1].split("+", 1)
229 s = path.split(":", 1)[1].split("+", 1)
233 if len(s) == 1:
230 if len(s) == 1:
234 repopath, repopath2 = parentpath, s[0]
231 repopath, repopath2 = parentpath, s[0]
235 else:
232 else:
236 repopath, repopath2 = s
233 repopath, repopath2 = s
237 else:
234 else:
238 repopath, repopath2 = parentpath, path
235 repopath, repopath2 = parentpath, path
239 return unionrepository(ui, repopath, repopath2)
236 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now