##// END OF EJS Templates
unionrepo: avoid unnecessary node -> rev conversion
Jun Wu -
r31724:f1e0446e default
parent child Browse files
Show More
@@ -1,260 +1,259
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 __future__ import absolute_import
15 15
16 16 from .i18n import _
17 17 from .node import nullid
18 18
19 19 from . import (
20 20 changelog,
21 21 cmdutil,
22 22 error,
23 23 filelog,
24 24 localrepo,
25 25 manifest,
26 26 mdiff,
27 27 pathutil,
28 28 pycompat,
29 29 revlog,
30 30 util,
31 31 vfs as vfsmod,
32 32 )
33 33
34 34 class unionrevlog(revlog.revlog):
35 35 def __init__(self, opener, indexfile, revlog2, linkmapper):
36 36 # How it works:
37 37 # To retrieve a revision, we just need to know the node id so we can
38 38 # look it up in revlog2.
39 39 #
40 40 # To differentiate a rev in the second revlog from a rev in the revlog,
41 41 # we check revision against repotiprev.
42 42 opener = vfsmod.readonlyvfs(opener)
43 43 revlog.revlog.__init__(self, opener, indexfile)
44 44 self.revlog2 = revlog2
45 45
46 46 n = len(self)
47 47 self.repotiprev = n - 1
48 48 self.bundlerevs = set() # used by 'bundle()' revset expression
49 49 for rev2 in self.revlog2:
50 50 rev = self.revlog2.index[rev2]
51 51 # rev numbers - in revlog2, very different from self.rev
52 52 _start, _csize, _rsize, base, linkrev, p1rev, p2rev, node = rev
53 53 flags = _start & 0xFFFF
54 54
55 55 if linkmapper is None: # link is to same revlog
56 56 assert linkrev == rev2 # we never link back
57 57 link = n
58 58 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
59 59 link = linkmapper(linkrev)
60 60
61 61 if linkmapper is not None: # link is to same revlog
62 62 base = linkmapper(base)
63 63
64 64 if node in self.nodemap:
65 65 # this happens for the common revlog revisions
66 66 self.bundlerevs.add(self.nodemap[node])
67 67 continue
68 68
69 69 p1node = self.revlog2.node(p1rev)
70 70 p2node = self.revlog2.node(p2rev)
71 71
72 72 e = (flags, None, None, base,
73 73 link, self.rev(p1node), self.rev(p2node), node)
74 74 self.index.insert(-1, e)
75 75 self.nodemap[node] = n
76 76 self.bundlerevs.add(n)
77 77 n += 1
78 78
79 79 def _chunk(self, rev):
80 80 if rev <= self.repotiprev:
81 81 return revlog.revlog._chunk(self, rev)
82 82 return self.revlog2._chunk(self.node(rev))
83 83
84 84 def revdiff(self, rev1, rev2):
85 85 """return or calculate a delta between two revisions"""
86 86 if rev1 > self.repotiprev and rev2 > self.repotiprev:
87 87 return self.revlog2.revdiff(
88 88 self.revlog2.rev(self.node(rev1)),
89 89 self.revlog2.rev(self.node(rev2)))
90 90 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
91 91 return self.baserevdiff(rev1, rev2)
92 92
93 return mdiff.textdiff(self.revision(self.node(rev1)),
94 self.revision(self.node(rev2)))
93 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
95 94
96 95 def revision(self, nodeorrev, raw=False):
97 96 """return an uncompressed revision of a given node or revision
98 97 number.
99 98 """
100 99 if isinstance(nodeorrev, int):
101 100 rev = nodeorrev
102 101 node = self.node(rev)
103 102 else:
104 103 node = nodeorrev
105 104 rev = self.rev(node)
106 105
107 106 if node == nullid:
108 107 return ""
109 108
110 109 if rev > self.repotiprev:
111 110 text = self.revlog2.revision(node)
112 111 self._cache = (node, rev, text)
113 112 else:
114 113 text = self.baserevision(rev)
115 114 # already cached
116 115 return text
117 116
118 117 def baserevision(self, nodeorrev):
119 118 # Revlog subclasses may override 'revision' method to modify format of
120 119 # content retrieved from revlog. To use unionrevlog with such class one
121 120 # needs to override 'baserevision' and make more specific call here.
122 121 return revlog.revlog.revision(self, nodeorrev)
123 122
124 123 def baserevdiff(self, rev1, rev2):
125 124 # Exists for the same purpose as baserevision.
126 125 return revlog.revlog.revdiff(self, rev1, rev2)
127 126
128 127 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
129 128 raise NotImplementedError
130 129 def addgroup(self, revs, linkmapper, transaction):
131 130 raise NotImplementedError
132 131 def strip(self, rev, minlink):
133 132 raise NotImplementedError
134 133 def checksize(self):
135 134 raise NotImplementedError
136 135
137 136 class unionchangelog(unionrevlog, changelog.changelog):
138 137 def __init__(self, opener, opener2):
139 138 changelog.changelog.__init__(self, opener)
140 139 linkmapper = None
141 140 changelog2 = changelog.changelog(opener2)
142 141 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
143 142 linkmapper)
144 143
145 144 def baserevision(self, nodeorrev):
146 145 # Although changelog doesn't override 'revision' method, some extensions
147 146 # may replace this class with another that does. Same story with
148 147 # manifest and filelog classes.
149 148 return changelog.changelog.revision(self, nodeorrev)
150 149
151 150 def baserevdiff(self, rev1, rev2):
152 151 return changelog.changelog.revdiff(self, rev1, rev2)
153 152
154 153 class unionmanifest(unionrevlog, manifest.manifestrevlog):
155 154 def __init__(self, opener, opener2, linkmapper):
156 155 manifest.manifestrevlog.__init__(self, opener)
157 156 manifest2 = manifest.manifestrevlog(opener2)
158 157 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
159 158 linkmapper)
160 159
161 160 def baserevision(self, nodeorrev):
162 161 return manifest.manifestrevlog.revision(self, nodeorrev)
163 162
164 163 def baserevdiff(self, rev1, rev2):
165 164 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
166 165
167 166 class unionfilelog(unionrevlog, filelog.filelog):
168 167 def __init__(self, opener, path, opener2, linkmapper, repo):
169 168 filelog.filelog.__init__(self, opener, path)
170 169 filelog2 = filelog.filelog(opener2, path)
171 170 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
172 171 linkmapper)
173 172 self._repo = repo
174 173
175 174 def baserevision(self, nodeorrev):
176 175 return filelog.filelog.revision(self, nodeorrev)
177 176
178 177 def baserevdiff(self, rev1, rev2):
179 178 return filelog.filelog.revdiff(self, rev1, rev2)
180 179
181 180 def iscensored(self, rev):
182 181 """Check if a revision is censored."""
183 182 if rev <= self.repotiprev:
184 183 return filelog.filelog.iscensored(self, rev)
185 184 node = self.node(rev)
186 185 return self.revlog2.iscensored(self.revlog2.rev(node))
187 186
188 187 class unionpeer(localrepo.localpeer):
189 188 def canpush(self):
190 189 return False
191 190
192 191 class unionrepository(localrepo.localrepository):
193 192 def __init__(self, ui, path, path2):
194 193 localrepo.localrepository.__init__(self, ui, path)
195 194 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
196 195
197 196 self._url = 'union:%s+%s' % (util.expandpath(path),
198 197 util.expandpath(path2))
199 198 self.repo2 = localrepo.localrepository(ui, path2)
200 199
201 200 @localrepo.unfilteredpropertycache
202 201 def changelog(self):
203 202 return unionchangelog(self.svfs, self.repo2.svfs)
204 203
205 204 def _clrev(self, rev2):
206 205 """map from repo2 changelog rev to temporary rev in self.changelog"""
207 206 node = self.repo2.changelog.node(rev2)
208 207 return self.changelog.rev(node)
209 208
210 209 def _constructmanifest(self):
211 210 return unionmanifest(self.svfs, self.repo2.svfs,
212 211 self.unfiltered()._clrev)
213 212
214 213 def url(self):
215 214 return self._url
216 215
217 216 def file(self, f):
218 217 return unionfilelog(self.svfs, f, self.repo2.svfs,
219 218 self.unfiltered()._clrev, self)
220 219
221 220 def close(self):
222 221 self.repo2.close()
223 222
224 223 def cancopy(self):
225 224 return False
226 225
227 226 def peer(self):
228 227 return unionpeer(self)
229 228
230 229 def getcwd(self):
231 230 return pycompat.getcwd() # always outside the repo
232 231
233 232 def instance(ui, path, create):
234 233 if create:
235 234 raise error.Abort(_('cannot create new union repository'))
236 235 parentpath = ui.config("bundle", "mainreporoot", "")
237 236 if not parentpath:
238 237 # try to find the correct path to the working directory repo
239 238 parentpath = cmdutil.findrepo(pycompat.getcwd())
240 239 if parentpath is None:
241 240 parentpath = ''
242 241 if parentpath:
243 242 # Try to make the full path relative so we get a nice, short URL.
244 243 # In particular, we don't want temp dir names in test outputs.
245 244 cwd = pycompat.getcwd()
246 245 if parentpath == cwd:
247 246 parentpath = ''
248 247 else:
249 248 cwd = pathutil.normasprefix(cwd)
250 249 if parentpath.startswith(cwd):
251 250 parentpath = parentpath[len(cwd):]
252 251 if path.startswith('union:'):
253 252 s = path.split(":", 1)[1].split("+", 1)
254 253 if len(s) == 1:
255 254 repopath, repopath2 = parentpath, s[0]
256 255 else:
257 256 repopath, repopath2 = s
258 257 else:
259 258 repopath, repopath2 = parentpath, path
260 259 return unionrepository(ui, repopath, repopath2)
@@ -1,65 +1,59
1 1 #require test-repo
2 2
3 3 $ . "$TESTDIR/helpers-testrepo.sh"
4 4 $ check_code="$TESTDIR"/../contrib/check-code.py
5 5 $ cd "$TESTDIR"/..
6 6
7 7 New errors are not allowed. Warnings are strongly discouraged.
8 8 (The writing "no-che?k-code" is for not skipping this file when checking.)
9 9
10 10 $ hg locate -X contrib/python-zstandard -X hgext/fsmonitor/pywatchman |
11 11 > sed 's-\\-/-g' | xargs "$check_code" --warnings --per-file=0 || false
12 12 contrib/perf.py:859:
13 13 > r.revision(r.node(x))
14 14 don't covert rev to node before passing to revision(nodeorrev)
15 15 Skipping i18n/polib.py it has no-che?k-code (glob)
16 16 mercurial/demandimport.py:312:
17 17 > if os.environ.get('HGDEMANDIMPORT') != 'disable':
18 18 use encoding.environ instead (py3)
19 19 mercurial/encoding.py:54:
20 20 > environ = os.environ
21 21 use encoding.environ instead (py3)
22 22 mercurial/encoding.py:56:
23 23 > environ = os.environb
24 24 use encoding.environ instead (py3)
25 25 mercurial/encoding.py:61:
26 26 > for k, v in os.environ.items())
27 27 use encoding.environ instead (py3)
28 28 mercurial/encoding.py:221:
29 29 > for k, v in os.environ.items())
30 30 use encoding.environ instead (py3)
31 31 Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
32 32 Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
33 33 mercurial/policy.py:46:
34 34 > if 'HGMODULEPOLICY' in os.environ:
35 35 use encoding.environ instead (py3)
36 36 mercurial/policy.py:47:
37 37 > policy = os.environ['HGMODULEPOLICY'].encode('utf-8')
38 38 use encoding.environ instead (py3)
39 39 mercurial/policy.py:49:
40 40 > policy = os.environ.get('HGMODULEPOLICY', policy)
41 41 use encoding.environ instead (py3)
42 42 Skipping mercurial/statprof.py it has no-che?k-code (glob)
43 mercurial/unionrepo.py:93:
44 > return mdiff.textdiff(self.revision(self.node(rev1)),
45 don't covert rev to node before passing to revision(nodeorrev)
46 mercurial/unionrepo.py:94:
47 > self.revision(self.node(rev2)))
48 don't covert rev to node before passing to revision(nodeorrev)
49 43 [1]
50 44
51 45 @commands in debugcommands.py should be in alphabetical order.
52 46
53 47 >>> import re
54 48 >>> commands = []
55 49 >>> with open('mercurial/debugcommands.py', 'rb') as fh:
56 50 ... for line in fh:
57 51 ... m = re.match("^@command\('([a-z]+)", line)
58 52 ... if m:
59 53 ... commands.append(m.group(1))
60 54 >>> scommands = list(sorted(commands))
61 55 >>> for i, command in enumerate(scommands):
62 56 ... if command != commands[i]:
63 57 ... print('commands in debugcommands.py not sorted; first differing '
64 58 ... 'command is %s; expected %s' % (commands[i], command))
65 59 ... break
General Comments 0
You need to be logged in to leave comments. Login now