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