##// END OF EJS Templates
unionrevlog: extract 'baserevision' and 'baserevdiff' methods...
Wojciech Lopata -
r19630:bb67f630 default
parent child Browse files
Show More
@@ -1,208 +1,239 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 revlog.revlog.revdiff(self, 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 = revlog.revlog.revision(self, 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):
101 # Revlog subclasses may override 'revision' method to modify format of
102 # content retrieved from revlog. To use unionrevlog with such class one
103 # needs to override 'baserevision' and make more specific call here.
104 return revlog.revlog.revision(self, nodeorrev)
105
106 def baserevdiff(self, rev1, rev2):
107 # Exists for the same purpose as baserevision.
108 return revlog.revlog.revdiff(self, rev1, rev2)
109
100 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):
101 raise NotImplementedError
111 raise NotImplementedError
102 def addgroup(self, revs, linkmapper, transaction):
112 def addgroup(self, revs, linkmapper, transaction):
103 raise NotImplementedError
113 raise NotImplementedError
104 def strip(self, rev, minlink):
114 def strip(self, rev, minlink):
105 raise NotImplementedError
115 raise NotImplementedError
106 def checksize(self):
116 def checksize(self):
107 raise NotImplementedError
117 raise NotImplementedError
108
118
109 class unionchangelog(unionrevlog, changelog.changelog):
119 class unionchangelog(unionrevlog, changelog.changelog):
110 def __init__(self, opener, opener2):
120 def __init__(self, opener, opener2):
111 changelog.changelog.__init__(self, opener)
121 changelog.changelog.__init__(self, opener)
112 linkmapper = None
122 linkmapper = None
113 changelog2 = changelog.changelog(opener2)
123 changelog2 = changelog.changelog(opener2)
114 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
124 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
115 linkmapper)
125 linkmapper)
116
126
127 def baserevision(self, nodeorrev):
128 # Although changelog doesn't override 'revision' method, some extensions
129 # may replace this class with another that does. Same story with
130 # manifest and filelog classes.
131 return changelog.changelog.revision(self, nodeorrev)
132
133 def baserevdiff(self, rev1, rev2):
134 return changelog.changelog.revdiff(self, rev1, rev2)
135
117 class unionmanifest(unionrevlog, manifest.manifest):
136 class unionmanifest(unionrevlog, manifest.manifest):
118 def __init__(self, opener, opener2, linkmapper):
137 def __init__(self, opener, opener2, linkmapper):
119 manifest.manifest.__init__(self, opener)
138 manifest.manifest.__init__(self, opener)
120 manifest2 = manifest.manifest(opener2)
139 manifest2 = manifest.manifest(opener2)
121 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
140 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
122 linkmapper)
141 linkmapper)
123
142
143 def baserevision(self, nodeorrev):
144 return manifest.manifest.revision(self, nodeorrev)
145
146 def baserevdiff(self, rev1, rev2):
147 return manifest.manifest.revdiff(self, rev1, rev2)
148
124 class unionfilelog(unionrevlog, filelog.filelog):
149 class unionfilelog(unionrevlog, filelog.filelog):
125 def __init__(self, opener, path, opener2, linkmapper, repo):
150 def __init__(self, opener, path, opener2, linkmapper, repo):
126 filelog.filelog.__init__(self, opener, path)
151 filelog.filelog.__init__(self, opener, path)
127 filelog2 = filelog.filelog(opener2, path)
152 filelog2 = filelog.filelog(opener2, path)
128 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
153 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
129 linkmapper)
154 linkmapper)
130 self._repo = repo
155 self._repo = repo
131
156
157 def baserevision(self, nodeorrev):
158 return filelog.filelog.revision(self, nodeorrev)
159
160 def baserevdiff(self, rev1, rev2):
161 return filelog.filelog.revdiff(self, rev1, rev2)
162
132 def _file(self, f):
163 def _file(self, f):
133 self._repo.file(f)
164 self._repo.file(f)
134
165
135 class unionpeer(localrepo.localpeer):
166 class unionpeer(localrepo.localpeer):
136 def canpush(self):
167 def canpush(self):
137 return False
168 return False
138
169
139 class unionrepository(localrepo.localrepository):
170 class unionrepository(localrepo.localrepository):
140 def __init__(self, ui, path, path2):
171 def __init__(self, ui, path, path2):
141 localrepo.localrepository.__init__(self, ui, path)
172 localrepo.localrepository.__init__(self, ui, path)
142 self.ui.setconfig('phases', 'publish', False)
173 self.ui.setconfig('phases', 'publish', False)
143
174
144 self._url = 'union:%s+%s' % (util.expandpath(path),
175 self._url = 'union:%s+%s' % (util.expandpath(path),
145 util.expandpath(path2))
176 util.expandpath(path2))
146 self.repo2 = localrepo.localrepository(ui, path2)
177 self.repo2 = localrepo.localrepository(ui, path2)
147
178
148 @localrepo.unfilteredpropertycache
179 @localrepo.unfilteredpropertycache
149 def changelog(self):
180 def changelog(self):
150 return unionchangelog(self.sopener, self.repo2.sopener)
181 return unionchangelog(self.sopener, self.repo2.sopener)
151
182
152 def _clrev(self, rev2):
183 def _clrev(self, rev2):
153 """map from repo2 changelog rev to temporary rev in self.changelog"""
184 """map from repo2 changelog rev to temporary rev in self.changelog"""
154 node = self.repo2.changelog.node(rev2)
185 node = self.repo2.changelog.node(rev2)
155 return self.changelog.rev(node)
186 return self.changelog.rev(node)
156
187
157 @localrepo.unfilteredpropertycache
188 @localrepo.unfilteredpropertycache
158 def manifest(self):
189 def manifest(self):
159 return unionmanifest(self.sopener, self.repo2.sopener,
190 return unionmanifest(self.sopener, self.repo2.sopener,
160 self._clrev)
191 self._clrev)
161
192
162 def url(self):
193 def url(self):
163 return self._url
194 return self._url
164
195
165 def file(self, f):
196 def file(self, f):
166 return unionfilelog(self.sopener, f, self.repo2.sopener,
197 return unionfilelog(self.sopener, f, self.repo2.sopener,
167 self._clrev, self)
198 self._clrev, self)
168
199
169 def close(self):
200 def close(self):
170 self.repo2.close()
201 self.repo2.close()
171
202
172 def cancopy(self):
203 def cancopy(self):
173 return False
204 return False
174
205
175 def peer(self):
206 def peer(self):
176 return unionpeer(self)
207 return unionpeer(self)
177
208
178 def getcwd(self):
209 def getcwd(self):
179 return os.getcwd() # always outside the repo
210 return os.getcwd() # always outside the repo
180
211
181 def instance(ui, path, create):
212 def instance(ui, path, create):
182 if create:
213 if create:
183 raise util.Abort(_('cannot create new union repository'))
214 raise util.Abort(_('cannot create new union repository'))
184 parentpath = ui.config("bundle", "mainreporoot", "")
215 parentpath = ui.config("bundle", "mainreporoot", "")
185 if not parentpath:
216 if not parentpath:
186 # try to find the correct path to the working directory repo
217 # try to find the correct path to the working directory repo
187 parentpath = cmdutil.findrepo(os.getcwd())
218 parentpath = cmdutil.findrepo(os.getcwd())
188 if parentpath is None:
219 if parentpath is None:
189 parentpath = ''
220 parentpath = ''
190 if parentpath:
221 if parentpath:
191 # Try to make the full path relative so we get a nice, short URL.
222 # Try to make the full path relative so we get a nice, short URL.
192 # In particular, we don't want temp dir names in test outputs.
223 # In particular, we don't want temp dir names in test outputs.
193 cwd = os.getcwd()
224 cwd = os.getcwd()
194 if parentpath == cwd:
225 if parentpath == cwd:
195 parentpath = ''
226 parentpath = ''
196 else:
227 else:
197 cwd = os.path.join(cwd,'')
228 cwd = os.path.join(cwd,'')
198 if parentpath.startswith(cwd):
229 if parentpath.startswith(cwd):
199 parentpath = parentpath[len(cwd):]
230 parentpath = parentpath[len(cwd):]
200 if path.startswith('union:'):
231 if path.startswith('union:'):
201 s = path.split(":", 1)[1].split("+", 1)
232 s = path.split(":", 1)[1].split("+", 1)
202 if len(s) == 1:
233 if len(s) == 1:
203 repopath, repopath2 = parentpath, s[0]
234 repopath, repopath2 = parentpath, s[0]
204 else:
235 else:
205 repopath, repopath2 = s
236 repopath, repopath2 = s
206 else:
237 else:
207 repopath, repopath2 = parentpath, path
238 repopath, repopath2 = parentpath, path
208 return unionrepository(ui, repopath, repopath2)
239 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now