29 def setup(): |
28 def setup(): |
30 # We just wanted to add the flag processor, which is done at module |
29 # We just wanted to add the flag processor, which is done at module |
31 # load time. |
30 # load time. |
32 pass |
31 pass |
33 |
32 |
34 class excludeddir(manifest.treemanifest): |
|
35 """Stand-in for a directory that is excluded from the repository. |
|
36 |
|
37 With narrowing active on a repository that uses treemanifests, |
|
38 some of the directory revlogs will be excluded from the resulting |
|
39 clone. This is a huge storage win for clients, but means we need |
|
40 some sort of pseudo-manifest to surface to internals so we can |
|
41 detect a merge conflict outside the narrowspec. That's what this |
|
42 class is: it stands in for a directory whose node is known, but |
|
43 whose contents are unknown. |
|
44 """ |
|
45 def __init__(self, dir, node): |
|
46 super(excludeddir, self).__init__(dir) |
|
47 self._node = node |
|
48 # Add an empty file, which will be included by iterators and such, |
|
49 # appearing as the directory itself (i.e. something like "dir/") |
|
50 self._files[''] = node |
|
51 self._flags[''] = 't' |
|
52 |
|
53 # Manifests outside the narrowspec should never be modified, so avoid |
|
54 # copying. This makes a noticeable difference when there are very many |
|
55 # directories outside the narrowspec. Also, it makes sense for the copy to |
|
56 # be of the same type as the original, which would not happen with the |
|
57 # super type's copy(). |
|
58 def copy(self): |
|
59 return self |
|
60 |
|
61 class excludeddirmanifestctx(manifest.treemanifestctx): |
|
62 """context wrapper for excludeddir - see that docstring for rationale""" |
|
63 def __init__(self, dir, node): |
|
64 self._dir = dir |
|
65 self._node = node |
|
66 |
|
67 def read(self): |
|
68 return excludeddir(self._dir, self._node) |
|
69 |
|
70 def write(self, *args): |
|
71 raise error.ProgrammingError( |
|
72 'attempt to write manifest from excluded dir %s' % self._dir) |
|
73 |
|
74 class excludedmanifestrevlog(manifest.manifestrevlog): |
|
75 """Stand-in for excluded treemanifest revlogs. |
|
76 |
|
77 When narrowing is active on a treemanifest repository, we'll have |
|
78 references to directories we can't see due to the revlog being |
|
79 skipped. This class exists to conform to the manifestrevlog |
|
80 interface for those directories and proactively prevent writes to |
|
81 outside the narrowspec. |
|
82 """ |
|
83 |
|
84 def __init__(self, dir): |
|
85 self._dir = dir |
|
86 |
|
87 def __len__(self): |
|
88 raise error.ProgrammingError( |
|
89 'attempt to get length of excluded dir %s' % self._dir) |
|
90 |
|
91 def rev(self, node): |
|
92 raise error.ProgrammingError( |
|
93 'attempt to get rev from excluded dir %s' % self._dir) |
|
94 |
|
95 def linkrev(self, node): |
|
96 raise error.ProgrammingError( |
|
97 'attempt to get linkrev from excluded dir %s' % self._dir) |
|
98 |
|
99 def node(self, rev): |
|
100 raise error.ProgrammingError( |
|
101 'attempt to get node from excluded dir %s' % self._dir) |
|
102 |
|
103 def add(self, *args, **kwargs): |
|
104 # We should never write entries in dirlogs outside the narrow clone. |
|
105 # However, the method still gets called from writesubtree() in |
|
106 # _addtree(), so we need to handle it. We should possibly make that |
|
107 # avoid calling add() with a clean manifest (_dirty is always False |
|
108 # in excludeddir instances). |
|
109 pass |
|
110 |
|
111 def makenarrowmanifestrevlog(mfrevlog, repo): |
33 def makenarrowmanifestrevlog(mfrevlog, repo): |
112 if util.safehasattr(mfrevlog, '_narrowed'): |
34 if util.safehasattr(mfrevlog, '_narrowed'): |
113 return |
35 return |
114 |
36 |
115 class narrowmanifestrevlog(mfrevlog.__class__): |
37 class narrowmanifestrevlog(mfrevlog.__class__): |
116 # This function is called via debug{revlog,index,data}, but also during |
38 # This function is called via debug{revlog,index,data}, but also during |
117 # at least some push operations. This will be used to wrap/exclude the |
39 # at least some push operations. This will be used to wrap/exclude the |
118 # child directories when using treemanifests. |
40 # child directories when using treemanifests. |
119 def dirlog(self, d): |
41 def dirlog(self, d): |
120 if not repo.narrowmatch().visitdir(d[:-1] or '.'): |
42 if not repo.narrowmatch().visitdir(d[:-1] or '.'): |
121 return excludedmanifestrevlog(d) |
43 return manifest.excludedmanifestrevlog(d) |
122 result = super(narrowmanifestrevlog, self).dirlog(d) |
44 result = super(narrowmanifestrevlog, self).dirlog(d) |
123 makenarrowmanifestrevlog(result, repo) |
45 makenarrowmanifestrevlog(result, repo) |
124 return result |
46 return result |
125 |
47 |
126 mfrevlog.__class__ = narrowmanifestrevlog |
48 mfrevlog.__class__ = narrowmanifestrevlog |
128 |
50 |
129 def makenarrowmanifestlog(mfl, repo): |
51 def makenarrowmanifestlog(mfl, repo): |
130 class narrowmanifestlog(mfl.__class__): |
52 class narrowmanifestlog(mfl.__class__): |
131 def get(self, dir, node, verify=True): |
53 def get(self, dir, node, verify=True): |
132 if not repo.narrowmatch().visitdir(dir[:-1] or '.'): |
54 if not repo.narrowmatch().visitdir(dir[:-1] or '.'): |
133 return excludeddirmanifestctx(dir, node) |
55 return manifest.excludeddirmanifestctx(dir, node) |
134 return super(narrowmanifestlog, self).get(dir, node, verify=verify) |
56 return super(narrowmanifestlog, self).get(dir, node, verify=verify) |
135 mfl.__class__ = narrowmanifestlog |
57 mfl.__class__ = narrowmanifestlog |
136 |
58 |
137 def makenarrowfilelog(fl, narrowmatch): |
59 def makenarrowfilelog(fl, narrowmatch): |
138 class narrowfilelog(fl.__class__): |
60 class narrowfilelog(fl.__class__): |