##// END OF EJS Templates
unionrepo: use pathutil.normasprefix to ensure os.sep at the end of cwd...
FUJIWARA Katsunori -
r24835:e4f75c93 stable
parent child Browse files
Show More
@@ -1,242 +1,242 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, pathutil
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 iscensored(self, rev):
163 def iscensored(self, rev):
164 """Check if a revision is censored."""
164 """Check if a revision is censored."""
165 if rev <= self.repotiprev:
165 if rev <= self.repotiprev:
166 return filelog.filelog.iscensored(self, rev)
166 return filelog.filelog.iscensored(self, rev)
167 return self.revlog2.iscensored(rev)
167 return self.revlog2.iscensored(rev)
168
168
169 class unionpeer(localrepo.localpeer):
169 class unionpeer(localrepo.localpeer):
170 def canpush(self):
170 def canpush(self):
171 return False
171 return False
172
172
173 class unionrepository(localrepo.localrepository):
173 class unionrepository(localrepo.localrepository):
174 def __init__(self, ui, path, path2):
174 def __init__(self, ui, path, path2):
175 localrepo.localrepository.__init__(self, ui, path)
175 localrepo.localrepository.__init__(self, ui, path)
176 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
176 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
177
177
178 self._url = 'union:%s+%s' % (util.expandpath(path),
178 self._url = 'union:%s+%s' % (util.expandpath(path),
179 util.expandpath(path2))
179 util.expandpath(path2))
180 self.repo2 = localrepo.localrepository(ui, path2)
180 self.repo2 = localrepo.localrepository(ui, path2)
181
181
182 @localrepo.unfilteredpropertycache
182 @localrepo.unfilteredpropertycache
183 def changelog(self):
183 def changelog(self):
184 return unionchangelog(self.svfs, self.repo2.svfs)
184 return unionchangelog(self.svfs, self.repo2.svfs)
185
185
186 def _clrev(self, rev2):
186 def _clrev(self, rev2):
187 """map from repo2 changelog rev to temporary rev in self.changelog"""
187 """map from repo2 changelog rev to temporary rev in self.changelog"""
188 node = self.repo2.changelog.node(rev2)
188 node = self.repo2.changelog.node(rev2)
189 return self.changelog.rev(node)
189 return self.changelog.rev(node)
190
190
191 @localrepo.unfilteredpropertycache
191 @localrepo.unfilteredpropertycache
192 def manifest(self):
192 def manifest(self):
193 return unionmanifest(self.svfs, self.repo2.svfs,
193 return unionmanifest(self.svfs, self.repo2.svfs,
194 self._clrev)
194 self._clrev)
195
195
196 def url(self):
196 def url(self):
197 return self._url
197 return self._url
198
198
199 def file(self, f):
199 def file(self, f):
200 return unionfilelog(self.svfs, f, self.repo2.svfs,
200 return unionfilelog(self.svfs, f, self.repo2.svfs,
201 self._clrev, self)
201 self._clrev, self)
202
202
203 def close(self):
203 def close(self):
204 self.repo2.close()
204 self.repo2.close()
205
205
206 def cancopy(self):
206 def cancopy(self):
207 return False
207 return False
208
208
209 def peer(self):
209 def peer(self):
210 return unionpeer(self)
210 return unionpeer(self)
211
211
212 def getcwd(self):
212 def getcwd(self):
213 return os.getcwd() # always outside the repo
213 return os.getcwd() # always outside the repo
214
214
215 def instance(ui, path, create):
215 def instance(ui, path, create):
216 if create:
216 if create:
217 raise util.Abort(_('cannot create new union repository'))
217 raise util.Abort(_('cannot create new union repository'))
218 parentpath = ui.config("bundle", "mainreporoot", "")
218 parentpath = ui.config("bundle", "mainreporoot", "")
219 if not parentpath:
219 if not parentpath:
220 # try to find the correct path to the working directory repo
220 # try to find the correct path to the working directory repo
221 parentpath = cmdutil.findrepo(os.getcwd())
221 parentpath = cmdutil.findrepo(os.getcwd())
222 if parentpath is None:
222 if parentpath is None:
223 parentpath = ''
223 parentpath = ''
224 if parentpath:
224 if parentpath:
225 # Try to make the full path relative so we get a nice, short URL.
225 # Try to make the full path relative so we get a nice, short URL.
226 # In particular, we don't want temp dir names in test outputs.
226 # In particular, we don't want temp dir names in test outputs.
227 cwd = os.getcwd()
227 cwd = os.getcwd()
228 if parentpath == cwd:
228 if parentpath == cwd:
229 parentpath = ''
229 parentpath = ''
230 else:
230 else:
231 cwd = os.path.join(cwd,'')
231 cwd = pathutil.normasprefix(cwd)
232 if parentpath.startswith(cwd):
232 if parentpath.startswith(cwd):
233 parentpath = parentpath[len(cwd):]
233 parentpath = parentpath[len(cwd):]
234 if path.startswith('union:'):
234 if path.startswith('union:'):
235 s = path.split(":", 1)[1].split("+", 1)
235 s = path.split(":", 1)[1].split("+", 1)
236 if len(s) == 1:
236 if len(s) == 1:
237 repopath, repopath2 = parentpath, s[0]
237 repopath, repopath2 = parentpath, s[0]
238 else:
238 else:
239 repopath, repopath2 = s
239 repopath, repopath2 = s
240 else:
240 else:
241 repopath, repopath2 = parentpath, path
241 repopath, repopath2 = parentpath, path
242 return unionrepository(ui, repopath, repopath2)
242 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now