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