##// END OF EJS Templates
narrowrevlog: replace AssertionError with ProgrammingError...
Augie Fackler -
r36111:142ce66a default
parent child Browse files
Show More
@@ -1,176 +1,177 b''
1 # narrowrevlog.py - revlog storing irrelevant nodes as "ellipsis" nodes
1 # narrowrevlog.py - revlog storing irrelevant nodes as "ellipsis" nodes
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from mercurial import (
10 from mercurial import (
11 error,
11 manifest,
12 manifest,
12 revlog,
13 revlog,
13 util,
14 util,
14 )
15 )
15
16
16 def readtransform(self, text):
17 def readtransform(self, text):
17 return text, False
18 return text, False
18
19
19 def writetransform(self, text):
20 def writetransform(self, text):
20 return text, False
21 return text, False
21
22
22 def rawtransform(self, text):
23 def rawtransform(self, text):
23 return False
24 return False
24
25
25 revlog.addflagprocessor(revlog.REVIDX_ELLIPSIS,
26 revlog.addflagprocessor(revlog.REVIDX_ELLIPSIS,
26 (readtransform, writetransform, rawtransform))
27 (readtransform, writetransform, rawtransform))
27
28
28 def setup():
29 def setup():
29 # We just wanted to add the flag processor, which is done at module
30 # We just wanted to add the flag processor, which is done at module
30 # load time.
31 # load time.
31 pass
32 pass
32
33
33 class excludeddir(manifest.treemanifest):
34 class excludeddir(manifest.treemanifest):
34 """Stand-in for a directory that is excluded from the repository.
35 """Stand-in for a directory that is excluded from the repository.
35
36
36 With narrowing active on a repository that uses treemanifests,
37 With narrowing active on a repository that uses treemanifests,
37 some of the directory revlogs will be excluded from the resulting
38 some of the directory revlogs will be excluded from the resulting
38 clone. This is a huge storage win for clients, but means we need
39 clone. This is a huge storage win for clients, but means we need
39 some sort of pseudo-manifest to surface to internals so we can
40 some sort of pseudo-manifest to surface to internals so we can
40 detect a merge conflict outside the narrowspec. That's what this
41 detect a merge conflict outside the narrowspec. That's what this
41 class is: it stands in for a directory whose node is known, but
42 class is: it stands in for a directory whose node is known, but
42 whose contents are unknown.
43 whose contents are unknown.
43 """
44 """
44 def __init__(self, dir, node):
45 def __init__(self, dir, node):
45 super(excludeddir, self).__init__(dir)
46 super(excludeddir, self).__init__(dir)
46 self._node = node
47 self._node = node
47 # Add an empty file, which will be included by iterators and such,
48 # Add an empty file, which will be included by iterators and such,
48 # appearing as the directory itself (i.e. something like "dir/")
49 # appearing as the directory itself (i.e. something like "dir/")
49 self._files[''] = node
50 self._files[''] = node
50 self._flags[''] = 't'
51 self._flags[''] = 't'
51
52
52 # Manifests outside the narrowspec should never be modified, so avoid
53 # Manifests outside the narrowspec should never be modified, so avoid
53 # copying. This makes a noticeable difference when there are very many
54 # copying. This makes a noticeable difference when there are very many
54 # directories outside the narrowspec. Also, it makes sense for the copy to
55 # directories outside the narrowspec. Also, it makes sense for the copy to
55 # be of the same type as the original, which would not happen with the
56 # be of the same type as the original, which would not happen with the
56 # super type's copy().
57 # super type's copy().
57 def copy(self):
58 def copy(self):
58 return self
59 return self
59
60
60 class excludeddirmanifestctx(manifest.treemanifestctx):
61 class excludeddirmanifestctx(manifest.treemanifestctx):
61 """context wrapper for excludeddir - see that docstring for rationale"""
62 """context wrapper for excludeddir - see that docstring for rationale"""
62 def __init__(self, dir, node):
63 def __init__(self, dir, node):
63 self._dir = dir
64 self._dir = dir
64 self._node = node
65 self._node = node
65
66
66 def read(self):
67 def read(self):
67 return excludeddir(self._dir, self._node)
68 return excludeddir(self._dir, self._node)
68
69
69 def write(self, *args):
70 def write(self, *args):
70 raise AssertionError('Attempt to write manifest from excluded dir %s' %
71 raise error.ProgrammingError(
71 self._dir)
72 'attempt to write manifest from excluded dir %s' % self._dir)
72
73
73 class excludedmanifestrevlog(manifest.manifestrevlog):
74 class excludedmanifestrevlog(manifest.manifestrevlog):
74 """Stand-in for excluded treemanifest revlogs.
75 """Stand-in for excluded treemanifest revlogs.
75
76
76 When narrowing is active on a treemanifest repository, we'll have
77 When narrowing is active on a treemanifest repository, we'll have
77 references to directories we can't see due to the revlog being
78 references to directories we can't see due to the revlog being
78 skipped. This class exists to conform to the manifestrevlog
79 skipped. This class exists to conform to the manifestrevlog
79 interface for those directories and proactively prevent writes to
80 interface for those directories and proactively prevent writes to
80 outside the narrowspec.
81 outside the narrowspec.
81 """
82 """
82
83
83 def __init__(self, dir):
84 def __init__(self, dir):
84 self._dir = dir
85 self._dir = dir
85
86
86 def __len__(self):
87 def __len__(self):
87 raise AssertionError('Attempt to get length of excluded dir %s' %
88 raise error.ProgrammingError(
88 self._dir)
89 'attempt to get length of excluded dir %s' % self._dir)
89
90
90 def rev(self, node):
91 def rev(self, node):
91 raise AssertionError('Attempt to get rev from excluded dir %s' %
92 raise error.ProgrammingError(
92 self._dir)
93 'attempt to get rev from excluded dir %s' % self._dir)
93
94
94 def linkrev(self, node):
95 def linkrev(self, node):
95 raise AssertionError('Attempt to get linkrev from excluded dir %s' %
96 raise error.ProgrammingError(
96 self._dir)
97 'attempt to get linkrev from excluded dir %s' % self._dir)
97
98
98 def node(self, rev):
99 def node(self, rev):
99 raise AssertionError('Attempt to get node from excluded dir %s' %
100 raise error.ProgrammingError(
100 self._dir)
101 'attempt to get node from excluded dir %s' % self._dir)
101
102
102 def add(self, *args, **kwargs):
103 def add(self, *args, **kwargs):
103 # We should never write entries in dirlogs outside the narrow clone.
104 # We should never write entries in dirlogs outside the narrow clone.
104 # However, the method still gets called from writesubtree() in
105 # However, the method still gets called from writesubtree() in
105 # _addtree(), so we need to handle it. We should possibly make that
106 # _addtree(), so we need to handle it. We should possibly make that
106 # avoid calling add() with a clean manifest (_dirty is always False
107 # avoid calling add() with a clean manifest (_dirty is always False
107 # in excludeddir instances).
108 # in excludeddir instances).
108 pass
109 pass
109
110
110 def makenarrowmanifestrevlog(mfrevlog, repo):
111 def makenarrowmanifestrevlog(mfrevlog, repo):
111 if util.safehasattr(mfrevlog, '_narrowed'):
112 if util.safehasattr(mfrevlog, '_narrowed'):
112 return
113 return
113
114
114 class narrowmanifestrevlog(mfrevlog.__class__):
115 class narrowmanifestrevlog(mfrevlog.__class__):
115 # This function is called via debug{revlog,index,data}, but also during
116 # This function is called via debug{revlog,index,data}, but also during
116 # at least some push operations. This will be used to wrap/exclude the
117 # at least some push operations. This will be used to wrap/exclude the
117 # child directories when using treemanifests.
118 # child directories when using treemanifests.
118 def dirlog(self, dir):
119 def dirlog(self, dir):
119 if dir and not dir.endswith('/'):
120 if dir and not dir.endswith('/'):
120 dir = dir + '/'
121 dir = dir + '/'
121 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
122 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
122 return excludedmanifestrevlog(dir)
123 return excludedmanifestrevlog(dir)
123 result = super(narrowmanifestrevlog, self).dirlog(dir)
124 result = super(narrowmanifestrevlog, self).dirlog(dir)
124 makenarrowmanifestrevlog(result, repo)
125 makenarrowmanifestrevlog(result, repo)
125 return result
126 return result
126
127
127 mfrevlog.__class__ = narrowmanifestrevlog
128 mfrevlog.__class__ = narrowmanifestrevlog
128 mfrevlog._narrowed = True
129 mfrevlog._narrowed = True
129
130
130 def makenarrowmanifestlog(mfl, repo):
131 def makenarrowmanifestlog(mfl, repo):
131 class narrowmanifestlog(mfl.__class__):
132 class narrowmanifestlog(mfl.__class__):
132 def get(self, dir, node, verify=True):
133 def get(self, dir, node, verify=True):
133 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
134 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
134 return excludeddirmanifestctx(dir, node)
135 return excludeddirmanifestctx(dir, node)
135 return super(narrowmanifestlog, self).get(dir, node, verify=verify)
136 return super(narrowmanifestlog, self).get(dir, node, verify=verify)
136 mfl.__class__ = narrowmanifestlog
137 mfl.__class__ = narrowmanifestlog
137
138
138 def makenarrowfilelog(fl, narrowmatch):
139 def makenarrowfilelog(fl, narrowmatch):
139 class narrowfilelog(fl.__class__):
140 class narrowfilelog(fl.__class__):
140 def renamed(self, node):
141 def renamed(self, node):
141 m = super(narrowfilelog, self).renamed(node)
142 m = super(narrowfilelog, self).renamed(node)
142 if m and not narrowmatch(m[0]):
143 if m and not narrowmatch(m[0]):
143 return None
144 return None
144 return m
145 return m
145
146
146 def size(self, rev):
147 def size(self, rev):
147 # We take advantage of the fact that remotefilelog
148 # We take advantage of the fact that remotefilelog
148 # lacks a node() method to just skip the
149 # lacks a node() method to just skip the
149 # rename-checking logic when on remotefilelog. This
150 # rename-checking logic when on remotefilelog. This
150 # might be incorrect on other non-revlog-based storage
151 # might be incorrect on other non-revlog-based storage
151 # engines, but for now this seems to be fine.
152 # engines, but for now this seems to be fine.
152 if util.safehasattr(self, 'node'):
153 if util.safehasattr(self, 'node'):
153 node = self.node(rev)
154 node = self.node(rev)
154 # Because renamed() is overridden above to
155 # Because renamed() is overridden above to
155 # sometimes return None even if there is metadata
156 # sometimes return None even if there is metadata
156 # in the revlog, size can be incorrect for
157 # in the revlog, size can be incorrect for
157 # copies/renames, so we need to make sure we call
158 # copies/renames, so we need to make sure we call
158 # the super class's implementation of renamed()
159 # the super class's implementation of renamed()
159 # for the purpose of size calculation.
160 # for the purpose of size calculation.
160 if super(narrowfilelog, self).renamed(node):
161 if super(narrowfilelog, self).renamed(node):
161 return len(self.read(node))
162 return len(self.read(node))
162 return super(narrowfilelog, self).size(rev)
163 return super(narrowfilelog, self).size(rev)
163
164
164 def cmp(self, node, text):
165 def cmp(self, node, text):
165 different = super(narrowfilelog, self).cmp(node, text)
166 different = super(narrowfilelog, self).cmp(node, text)
166 if different:
167 if different:
167 # Similar to size() above, if the file was copied from
168 # Similar to size() above, if the file was copied from
168 # a file outside the narrowspec, the super class's
169 # a file outside the narrowspec, the super class's
169 # would have returned True because we tricked it into
170 # would have returned True because we tricked it into
170 # thinking that the file was not renamed.
171 # thinking that the file was not renamed.
171 if super(narrowfilelog, self).renamed(node):
172 if super(narrowfilelog, self).renamed(node):
172 t2 = self.read(node)
173 t2 = self.read(node)
173 return t2 != text
174 return t2 != text
174 return different
175 return different
175
176
176 fl.__class__ = narrowfilelog
177 fl.__class__ = narrowfilelog
General Comments 0
You need to be logged in to leave comments. Login now