##// END OF EJS Templates
introduce unionrepo repository class for viewing union of repositories
Mads Kiilerich -
r3302:ead7a902 beta
parent child Browse files
Show More
@@ -0,0 +1,181
1 # unionrepo.py - repository class for viewing union of repositories
2 #
3 # Derived from Mercurial 2.5 bundlerepo.py
4 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
5 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
6 #
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.
9
10 """Repository class for in-memory pull of one local repository to another.
11 """
12
13 from mercurial.node import nullid
14 from mercurial import util, mdiff
15 from mercurial import localrepo, changelog, manifest, filelog, revlog
16
17 class unionrevlog(revlog.revlog):
18 def __init__(self, opener, indexfile, revlog2, linkmapper):
19 # How it works:
20 # To retrieve a revision, we just need to know the node id so we can
21 # look it up in revlog2.
22 #
23 # basemap is indexed with revisions coming from the second revlog.
24 #
25 # To differentiate a rev in the second revlog from a rev in the revlog,
26 # we check revision against basemap.
27 revlog.revlog.__init__(self, opener, indexfile)
28 self.revlog2 = revlog2
29
30 self.basemap = {} # mapping rev that is in revlog2 to ... nothing
31 n = len(self)
32 self.bundlerevs = set() # used by 'bundle()' revset expression
33 for rev2 in self.revlog2:
34 rev = self.revlog2.index[rev2]
35 # rev numbers - in revlog2, very different from self.rev
36 _start, _csize, _rsize, _base, linkrev, p1rev, p2rev, node = rev
37
38 if linkmapper is None: # link is to same revlog
39 assert linkrev == rev2 # we never link back
40 link = n
41 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
42 link = linkmapper(linkrev)
43
44 if node in self.nodemap:
45 # this happens for for the common revlog revisions
46 self.bundlerevs.add(self.nodemap[node])
47 continue
48
49 p1node = self.revlog2.node(p1rev)
50 p2node = self.revlog2.node(p2rev)
51
52 e = (None, None, None, None,
53 link, self.rev(p1node), self.rev(p2node), node)
54 self.basemap[n] = None
55 self.index.insert(-1, e)
56 self.nodemap[node] = n
57 self.bundlerevs.add(n)
58 n += 1
59
60 def _chunk(self, rev):
61 if rev not in self.basemap:
62 return revlog.revlog._chunk(self, rev)
63 return self.revlog2._chunk(self.node(rev))
64
65 def revdiff(self, rev1, rev2):
66 """return or calculate a delta between two revisions"""
67 if rev1 in self.basemap and rev2 in self.basemap:
68 return self.revlog2.revdiff(
69 self.revlog2.rev(self.node(rev1)),
70 self.revlog2.rev(self.node(rev2)))
71 elif rev1 not in self.basemap and rev2 not in self.basemap:
72 return revlog.revlog.revdiff(self, rev1, rev2)
73
74 return mdiff.textdiff(self.revision(self.node(rev1)),
75 self.revision(self.node(rev2)))
76
77 def revision(self, nodeorrev):
78 """return an uncompressed revision of a given node or revision
79 number.
80 """
81 if isinstance(nodeorrev, int):
82 rev = nodeorrev
83 node = self.node(rev)
84 else:
85 node = nodeorrev
86 rev = self.rev(node)
87
88 if node == nullid:
89 return ""
90
91 if rev in self.basemap:
92 text = self.revlog2.revision(node)
93 self._cache = (node, rev, text)
94 else:
95 text = revlog.revlog.revision(self, rev)
96 # already cached
97 return text
98
99 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
100 raise NotImplementedError
101 def addgroup(self, revs, linkmapper, transaction):
102 raise NotImplementedError
103 def strip(self, rev, minlink):
104 raise NotImplementedError
105 def checksize(self):
106 raise NotImplementedError
107
108 class unionchangelog(unionrevlog, changelog.changelog):
109 def __init__(self, opener, opener2):
110 changelog.changelog.__init__(self, opener)
111 linkmapper = None
112 changelog2 = changelog.changelog(opener2)
113 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
114 linkmapper)
115
116 class unionmanifest(unionrevlog, manifest.manifest):
117 def __init__(self, opener, opener2, linkmapper):
118 manifest.manifest.__init__(self, opener)
119 manifest2 = manifest.manifest(opener2)
120 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
121 linkmapper)
122
123 class unionfilelog(unionrevlog, filelog.filelog):
124 def __init__(self, opener, path, opener2, linkmapper, repo):
125 filelog.filelog.__init__(self, opener, path)
126 filelog2 = filelog.filelog(opener2, path)
127 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
128 linkmapper)
129 self._repo = repo
130
131 def _file(self, f):
132 self._repo.file(f)
133
134 class unionpeer(localrepo.localpeer):
135 def canpush(self):
136 return False
137
138 class unionrepository(localrepo.localrepository):
139 def __init__(self, ui, path, path2):
140 localrepo.localrepository.__init__(self, ui, path)
141 self.ui.setconfig('phases', 'publish', False)
142
143 self._url = 'union:%s+%s' % (util.expandpath(path),
144 util.expandpath(path2))
145 self.repo2 = localrepo.localrepository(ui, path2)
146
147 @util.propertycache
148 def changelog(self):
149 return unionchangelog(self.sopener, self.repo2.sopener)
150
151 def _clrev(self, rev2):
152 """map from repo2 changelog rev to temporary rev in self.changelog"""
153 node = self.repo2.changelog.node(rev2)
154 return self.changelog.rev(node)
155
156 @util.propertycache
157 def manifest(self):
158 return unionmanifest(self.sopener, self.repo2.sopener,
159 self._clrev)
160
161 def url(self):
162 return self._url
163
164 def file(self, f):
165 return unionfilelog(self.sopener, f, self.repo2.sopener,
166 self._clrev, self)
167
168 def close(self):
169 self.repo2.close()
170
171 def cancopy(self):
172 return False
173
174 def peer(self):
175 return unionpeer(self)
176
177 def instance(ui, path, create):
178 u = util.url(path)
179 assert u.scheme == 'union'
180 repopath, repopath2 = u.path.split("+", 1)
181 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now