##// END OF EJS Templates
narrow: validate patterns on incoming bundle2 part...
Gregory Szorc -
r39576:ce20caec default
parent child Browse files
Show More
@@ -1,332 +1,335
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
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 import errno
10 import errno
11 import struct
11 import struct
12
12
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.node import (
14 from mercurial.node import (
15 bin,
15 bin,
16 nullid,
16 nullid,
17 )
17 )
18 from mercurial import (
18 from mercurial import (
19 bundle2,
19 bundle2,
20 changegroup,
20 changegroup,
21 error,
21 error,
22 exchange,
22 exchange,
23 extensions,
23 extensions,
24 narrowspec,
24 narrowspec,
25 repair,
25 repair,
26 repository,
26 repository,
27 util,
27 util,
28 wireprototypes,
28 wireprototypes,
29 )
29 )
30 from mercurial.utils import (
30 from mercurial.utils import (
31 stringutil,
31 stringutil,
32 )
32 )
33
33
34 NARROWCAP = 'narrow'
34 NARROWCAP = 'narrow'
35 _NARROWACL_SECTION = 'narrowhgacl'
35 _NARROWACL_SECTION = 'narrowhgacl'
36 _CHANGESPECPART = NARROWCAP + ':changespec'
36 _CHANGESPECPART = NARROWCAP + ':changespec'
37 _SPECPART = NARROWCAP + ':spec'
37 _SPECPART = NARROWCAP + ':spec'
38 _SPECPART_INCLUDE = 'include'
38 _SPECPART_INCLUDE = 'include'
39 _SPECPART_EXCLUDE = 'exclude'
39 _SPECPART_EXCLUDE = 'exclude'
40 _KILLNODESIGNAL = 'KILL'
40 _KILLNODESIGNAL = 'KILL'
41 _DONESIGNAL = 'DONE'
41 _DONESIGNAL = 'DONE'
42 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
42 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
43 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
43 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
44 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
44 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
45 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
45 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
46
46
47 # When advertising capabilities, always include narrow clone support.
47 # When advertising capabilities, always include narrow clone support.
48 def getrepocaps_narrow(orig, repo, **kwargs):
48 def getrepocaps_narrow(orig, repo, **kwargs):
49 caps = orig(repo, **kwargs)
49 caps = orig(repo, **kwargs)
50 caps[NARROWCAP] = ['v0']
50 caps[NARROWCAP] = ['v0']
51 return caps
51 return caps
52
52
53 def getbundlechangegrouppart_widen(bundler, repo, source, bundlecaps=None,
53 def getbundlechangegrouppart_widen(bundler, repo, source, bundlecaps=None,
54 b2caps=None, heads=None, common=None,
54 b2caps=None, heads=None, common=None,
55 **kwargs):
55 **kwargs):
56 """Handling changegroup changegroup generation on the server when user
56 """Handling changegroup changegroup generation on the server when user
57 is widening their narrowspec"""
57 is widening their narrowspec"""
58
58
59 cgversions = b2caps.get('changegroup')
59 cgversions = b2caps.get('changegroup')
60 if cgversions: # 3.1 and 3.2 ship with an empty value
60 if cgversions: # 3.1 and 3.2 ship with an empty value
61 cgversions = [v for v in cgversions
61 cgversions = [v for v in cgversions
62 if v in changegroup.supportedoutgoingversions(repo)]
62 if v in changegroup.supportedoutgoingversions(repo)]
63 if not cgversions:
63 if not cgversions:
64 raise ValueError(_('no common changegroup version'))
64 raise ValueError(_('no common changegroup version'))
65 version = max(cgversions)
65 version = max(cgversions)
66 else:
66 else:
67 raise ValueError(_("server does not advertise changegroup version,"
67 raise ValueError(_("server does not advertise changegroup version,"
68 " can't negotiate support for ellipsis nodes"))
68 " can't negotiate support for ellipsis nodes"))
69
69
70 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
70 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
71 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
71 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
72 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
72 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
73 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
73 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
74 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
74 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
75 common = set(common or [nullid])
75 common = set(common or [nullid])
76
76
77 if (oldinclude != include or oldexclude != exclude):
77 if (oldinclude != include or oldexclude != exclude):
78 common = repo.revs("::%ln", common)
78 common = repo.revs("::%ln", common)
79 commonnodes = set()
79 commonnodes = set()
80 cl = repo.changelog
80 cl = repo.changelog
81 for c in common:
81 for c in common:
82 commonnodes.add(cl.node(c))
82 commonnodes.add(cl.node(c))
83 if commonnodes:
83 if commonnodes:
84 # XXX: we should only send the filelogs (and treemanifest). user
84 # XXX: we should only send the filelogs (and treemanifest). user
85 # already has the changelog and manifest
85 # already has the changelog and manifest
86 packer = changegroup.getbundler(version, repo,
86 packer = changegroup.getbundler(version, repo,
87 filematcher=newmatch,
87 filematcher=newmatch,
88 fullnodes=commonnodes)
88 fullnodes=commonnodes)
89 cgdata = packer.generate(set([nullid]), list(commonnodes), False,
89 cgdata = packer.generate(set([nullid]), list(commonnodes), False,
90 source)
90 source)
91
91
92 part = bundler.newpart('changegroup', data=cgdata)
92 part = bundler.newpart('changegroup', data=cgdata)
93 part.addparam('version', version)
93 part.addparam('version', version)
94 if 'treemanifest' in repo.requirements:
94 if 'treemanifest' in repo.requirements:
95 part.addparam('treemanifest', '1')
95 part.addparam('treemanifest', '1')
96
96
97 # Serve a changegroup for a client with a narrow clone.
97 # Serve a changegroup for a client with a narrow clone.
98 def getbundlechangegrouppart_narrow(bundler, repo, source,
98 def getbundlechangegrouppart_narrow(bundler, repo, source,
99 bundlecaps=None, b2caps=None, heads=None,
99 bundlecaps=None, b2caps=None, heads=None,
100 common=None, **kwargs):
100 common=None, **kwargs):
101 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
101 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
102
102
103 cgversions = b2caps.get('changegroup')
103 cgversions = b2caps.get('changegroup')
104 if cgversions: # 3.1 and 3.2 ship with an empty value
104 if cgversions: # 3.1 and 3.2 ship with an empty value
105 cgversions = [v for v in cgversions
105 cgversions = [v for v in cgversions
106 if v in changegroup.supportedoutgoingversions(repo)]
106 if v in changegroup.supportedoutgoingversions(repo)]
107 if not cgversions:
107 if not cgversions:
108 raise ValueError(_('no common changegroup version'))
108 raise ValueError(_('no common changegroup version'))
109 version = max(cgversions)
109 version = max(cgversions)
110 else:
110 else:
111 raise ValueError(_("server does not advertise changegroup version,"
111 raise ValueError(_("server does not advertise changegroup version,"
112 " can't negotiate support for ellipsis nodes"))
112 " can't negotiate support for ellipsis nodes"))
113
113
114 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
114 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
115 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
115 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
116 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
116 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
117
117
118 depth = kwargs.get(r'depth', None)
118 depth = kwargs.get(r'depth', None)
119 if depth is not None:
119 if depth is not None:
120 depth = int(depth)
120 depth = int(depth)
121 if depth < 1:
121 if depth < 1:
122 raise error.Abort(_('depth must be positive, got %d') % depth)
122 raise error.Abort(_('depth must be positive, got %d') % depth)
123
123
124 heads = set(heads or repo.heads())
124 heads = set(heads or repo.heads())
125 common = set(common or [nullid])
125 common = set(common or [nullid])
126 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
126 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
127 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
127 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
128 known = {bin(n) for n in kwargs.get(r'known', [])}
128 known = {bin(n) for n in kwargs.get(r'known', [])}
129 if known and (oldinclude != include or oldexclude != exclude):
129 if known and (oldinclude != include or oldexclude != exclude):
130 # Steps:
130 # Steps:
131 # 1. Send kill for "$known & ::common"
131 # 1. Send kill for "$known & ::common"
132 #
132 #
133 # 2. Send changegroup for ::common
133 # 2. Send changegroup for ::common
134 #
134 #
135 # 3. Proceed.
135 # 3. Proceed.
136 #
136 #
137 # In the future, we can send kills for only the specific
137 # In the future, we can send kills for only the specific
138 # nodes we know should go away or change shape, and then
138 # nodes we know should go away or change shape, and then
139 # send a data stream that tells the client something like this:
139 # send a data stream that tells the client something like this:
140 #
140 #
141 # a) apply this changegroup
141 # a) apply this changegroup
142 # b) apply nodes XXX, YYY, ZZZ that you already have
142 # b) apply nodes XXX, YYY, ZZZ that you already have
143 # c) goto a
143 # c) goto a
144 #
144 #
145 # until they've built up the full new state.
145 # until they've built up the full new state.
146 # Convert to revnums and intersect with "common". The client should
146 # Convert to revnums and intersect with "common". The client should
147 # have made it a subset of "common" already, but let's be safe.
147 # have made it a subset of "common" already, but let's be safe.
148 known = set(repo.revs("%ln & ::%ln", known, common))
148 known = set(repo.revs("%ln & ::%ln", known, common))
149 # TODO: we could send only roots() of this set, and the
149 # TODO: we could send only roots() of this set, and the
150 # list of nodes in common, and the client could work out
150 # list of nodes in common, and the client could work out
151 # what to strip, instead of us explicitly sending every
151 # what to strip, instead of us explicitly sending every
152 # single node.
152 # single node.
153 deadrevs = known
153 deadrevs = known
154 def genkills():
154 def genkills():
155 for r in deadrevs:
155 for r in deadrevs:
156 yield _KILLNODESIGNAL
156 yield _KILLNODESIGNAL
157 yield repo.changelog.node(r)
157 yield repo.changelog.node(r)
158 yield _DONESIGNAL
158 yield _DONESIGNAL
159 bundler.newpart(_CHANGESPECPART, data=genkills())
159 bundler.newpart(_CHANGESPECPART, data=genkills())
160 newvisit, newfull, newellipsis = exchange._computeellipsis(
160 newvisit, newfull, newellipsis = exchange._computeellipsis(
161 repo, set(), common, known, newmatch)
161 repo, set(), common, known, newmatch)
162 if newvisit:
162 if newvisit:
163 packer = changegroup.getbundler(version, repo,
163 packer = changegroup.getbundler(version, repo,
164 filematcher=newmatch,
164 filematcher=newmatch,
165 ellipses=True,
165 ellipses=True,
166 shallow=depth is not None,
166 shallow=depth is not None,
167 ellipsisroots=newellipsis,
167 ellipsisroots=newellipsis,
168 fullnodes=newfull)
168 fullnodes=newfull)
169 cgdata = packer.generate(common, newvisit, False, source)
169 cgdata = packer.generate(common, newvisit, False, source)
170
170
171 part = bundler.newpart('changegroup', data=cgdata)
171 part = bundler.newpart('changegroup', data=cgdata)
172 part.addparam('version', version)
172 part.addparam('version', version)
173 if 'treemanifest' in repo.requirements:
173 if 'treemanifest' in repo.requirements:
174 part.addparam('treemanifest', '1')
174 part.addparam('treemanifest', '1')
175
175
176 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
176 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
177 repo, common, heads, set(), newmatch, depth=depth)
177 repo, common, heads, set(), newmatch, depth=depth)
178
178
179 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
179 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
180 if visitnodes:
180 if visitnodes:
181 packer = changegroup.getbundler(version, repo,
181 packer = changegroup.getbundler(version, repo,
182 filematcher=newmatch,
182 filematcher=newmatch,
183 ellipses=True,
183 ellipses=True,
184 shallow=depth is not None,
184 shallow=depth is not None,
185 ellipsisroots=ellipsisroots,
185 ellipsisroots=ellipsisroots,
186 fullnodes=relevant_nodes)
186 fullnodes=relevant_nodes)
187 cgdata = packer.generate(common, visitnodes, False, source)
187 cgdata = packer.generate(common, visitnodes, False, source)
188
188
189 part = bundler.newpart('changegroup', data=cgdata)
189 part = bundler.newpart('changegroup', data=cgdata)
190 part.addparam('version', version)
190 part.addparam('version', version)
191 if 'treemanifest' in repo.requirements:
191 if 'treemanifest' in repo.requirements:
192 part.addparam('treemanifest', '1')
192 part.addparam('treemanifest', '1')
193
193
194 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
194 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
195 def _handlechangespec_2(op, inpart):
195 def _handlechangespec_2(op, inpart):
196 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
196 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
197 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
197 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
198 narrowspec.validatepatterns(includepats)
199 narrowspec.validatepatterns(excludepats)
200
198 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
201 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
199 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
202 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
200 op.repo._writerequirements()
203 op.repo._writerequirements()
201 op.repo.setnarrowpats(includepats, excludepats)
204 op.repo.setnarrowpats(includepats, excludepats)
202
205
203 @bundle2.parthandler(_CHANGESPECPART)
206 @bundle2.parthandler(_CHANGESPECPART)
204 def _handlechangespec(op, inpart):
207 def _handlechangespec(op, inpart):
205 repo = op.repo
208 repo = op.repo
206 cl = repo.changelog
209 cl = repo.changelog
207
210
208 # changesets which need to be stripped entirely. either they're no longer
211 # changesets which need to be stripped entirely. either they're no longer
209 # needed in the new narrow spec, or the server is sending a replacement
212 # needed in the new narrow spec, or the server is sending a replacement
210 # in the changegroup part.
213 # in the changegroup part.
211 clkills = set()
214 clkills = set()
212
215
213 # A changespec part contains all the updates to ellipsis nodes
216 # A changespec part contains all the updates to ellipsis nodes
214 # that will happen as a result of widening or narrowing a
217 # that will happen as a result of widening or narrowing a
215 # repo. All the changes that this block encounters are ellipsis
218 # repo. All the changes that this block encounters are ellipsis
216 # nodes or flags to kill an existing ellipsis.
219 # nodes or flags to kill an existing ellipsis.
217 chunksignal = changegroup.readexactly(inpart, 4)
220 chunksignal = changegroup.readexactly(inpart, 4)
218 while chunksignal != _DONESIGNAL:
221 while chunksignal != _DONESIGNAL:
219 if chunksignal == _KILLNODESIGNAL:
222 if chunksignal == _KILLNODESIGNAL:
220 # a node used to be an ellipsis but isn't anymore
223 # a node used to be an ellipsis but isn't anymore
221 ck = changegroup.readexactly(inpart, 20)
224 ck = changegroup.readexactly(inpart, 20)
222 if cl.hasnode(ck):
225 if cl.hasnode(ck):
223 clkills.add(ck)
226 clkills.add(ck)
224 else:
227 else:
225 raise error.Abort(
228 raise error.Abort(
226 _('unexpected changespec node chunk type: %s') % chunksignal)
229 _('unexpected changespec node chunk type: %s') % chunksignal)
227 chunksignal = changegroup.readexactly(inpart, 4)
230 chunksignal = changegroup.readexactly(inpart, 4)
228
231
229 if clkills:
232 if clkills:
230 # preserve bookmarks that repair.strip() would otherwise strip
233 # preserve bookmarks that repair.strip() would otherwise strip
231 bmstore = repo._bookmarks
234 bmstore = repo._bookmarks
232 class dummybmstore(dict):
235 class dummybmstore(dict):
233 def applychanges(self, repo, tr, changes):
236 def applychanges(self, repo, tr, changes):
234 pass
237 pass
235 def recordchange(self, tr): # legacy version
238 def recordchange(self, tr): # legacy version
236 pass
239 pass
237 repo._bookmarks = dummybmstore()
240 repo._bookmarks = dummybmstore()
238 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
241 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
239 topic='widen')
242 topic='widen')
240 repo._bookmarks = bmstore
243 repo._bookmarks = bmstore
241 if chgrpfile:
244 if chgrpfile:
242 op._widen_uninterr = repo.ui.uninterruptable()
245 op._widen_uninterr = repo.ui.uninterruptable()
243 op._widen_uninterr.__enter__()
246 op._widen_uninterr.__enter__()
244 # presence of _widen_bundle attribute activates widen handler later
247 # presence of _widen_bundle attribute activates widen handler later
245 op._widen_bundle = chgrpfile
248 op._widen_bundle = chgrpfile
246 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
249 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
247 # will currently always be there when using the core+narrowhg server, but
250 # will currently always be there when using the core+narrowhg server, but
248 # other servers may include a changespec part even when not widening (e.g.
251 # other servers may include a changespec part even when not widening (e.g.
249 # because we're deepening a shallow repo).
252 # because we're deepening a shallow repo).
250 if util.safehasattr(repo, 'setnewnarrowpats'):
253 if util.safehasattr(repo, 'setnewnarrowpats'):
251 repo.setnewnarrowpats()
254 repo.setnewnarrowpats()
252
255
253 def handlechangegroup_widen(op, inpart):
256 def handlechangegroup_widen(op, inpart):
254 """Changegroup exchange handler which restores temporarily-stripped nodes"""
257 """Changegroup exchange handler which restores temporarily-stripped nodes"""
255 # We saved a bundle with stripped node data we must now restore.
258 # We saved a bundle with stripped node data we must now restore.
256 # This approach is based on mercurial/repair.py@6ee26a53c111.
259 # This approach is based on mercurial/repair.py@6ee26a53c111.
257 repo = op.repo
260 repo = op.repo
258 ui = op.ui
261 ui = op.ui
259
262
260 chgrpfile = op._widen_bundle
263 chgrpfile = op._widen_bundle
261 del op._widen_bundle
264 del op._widen_bundle
262 vfs = repo.vfs
265 vfs = repo.vfs
263
266
264 ui.note(_("adding branch\n"))
267 ui.note(_("adding branch\n"))
265 f = vfs.open(chgrpfile, "rb")
268 f = vfs.open(chgrpfile, "rb")
266 try:
269 try:
267 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
270 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
268 if not ui.verbose:
271 if not ui.verbose:
269 # silence internal shuffling chatter
272 # silence internal shuffling chatter
270 ui.pushbuffer()
273 ui.pushbuffer()
271 if isinstance(gen, bundle2.unbundle20):
274 if isinstance(gen, bundle2.unbundle20):
272 with repo.transaction('strip') as tr:
275 with repo.transaction('strip') as tr:
273 bundle2.processbundle(repo, gen, lambda: tr)
276 bundle2.processbundle(repo, gen, lambda: tr)
274 else:
277 else:
275 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
278 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
276 if not ui.verbose:
279 if not ui.verbose:
277 ui.popbuffer()
280 ui.popbuffer()
278 finally:
281 finally:
279 f.close()
282 f.close()
280
283
281 # remove undo files
284 # remove undo files
282 for undovfs, undofile in repo.undofiles():
285 for undovfs, undofile in repo.undofiles():
283 try:
286 try:
284 undovfs.unlink(undofile)
287 undovfs.unlink(undofile)
285 except OSError as e:
288 except OSError as e:
286 if e.errno != errno.ENOENT:
289 if e.errno != errno.ENOENT:
287 ui.warn(_('error removing %s: %s\n') %
290 ui.warn(_('error removing %s: %s\n') %
288 (undovfs.join(undofile), stringutil.forcebytestr(e)))
291 (undovfs.join(undofile), stringutil.forcebytestr(e)))
289
292
290 # Remove partial backup only if there were no exceptions
293 # Remove partial backup only if there were no exceptions
291 op._widen_uninterr.__exit__(None, None, None)
294 op._widen_uninterr.__exit__(None, None, None)
292 vfs.unlink(chgrpfile)
295 vfs.unlink(chgrpfile)
293
296
294 def setup():
297 def setup():
295 """Enable narrow repo support in bundle2-related extension points."""
298 """Enable narrow repo support in bundle2-related extension points."""
296 extensions.wrapfunction(bundle2, 'getrepocaps', getrepocaps_narrow)
299 extensions.wrapfunction(bundle2, 'getrepocaps', getrepocaps_narrow)
297
300
298 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
301 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
299
302
300 getbundleargs['narrow'] = 'boolean'
303 getbundleargs['narrow'] = 'boolean'
301 getbundleargs['widen'] = 'boolean'
304 getbundleargs['widen'] = 'boolean'
302 getbundleargs['depth'] = 'plain'
305 getbundleargs['depth'] = 'plain'
303 getbundleargs['oldincludepats'] = 'csv'
306 getbundleargs['oldincludepats'] = 'csv'
304 getbundleargs['oldexcludepats'] = 'csv'
307 getbundleargs['oldexcludepats'] = 'csv'
305 getbundleargs['includepats'] = 'csv'
308 getbundleargs['includepats'] = 'csv'
306 getbundleargs['excludepats'] = 'csv'
309 getbundleargs['excludepats'] = 'csv'
307 getbundleargs['known'] = 'csv'
310 getbundleargs['known'] = 'csv'
308
311
309 # Extend changegroup serving to handle requests from narrow clients.
312 # Extend changegroup serving to handle requests from narrow clients.
310 origcgfn = exchange.getbundle2partsmapping['changegroup']
313 origcgfn = exchange.getbundle2partsmapping['changegroup']
311 def wrappedcgfn(*args, **kwargs):
314 def wrappedcgfn(*args, **kwargs):
312 repo = args[1]
315 repo = args[1]
313 if repo.ui.has_section(_NARROWACL_SECTION):
316 if repo.ui.has_section(_NARROWACL_SECTION):
314 kwargs = exchange.applynarrowacl(repo, kwargs)
317 kwargs = exchange.applynarrowacl(repo, kwargs)
315
318
316 if (kwargs.get(r'narrow', False) and
319 if (kwargs.get(r'narrow', False) and
317 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
320 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
318 getbundlechangegrouppart_narrow(*args, **kwargs)
321 getbundlechangegrouppart_narrow(*args, **kwargs)
319 elif kwargs.get(r'widen', False) and kwargs.get(r'narrow', False):
322 elif kwargs.get(r'widen', False) and kwargs.get(r'narrow', False):
320 getbundlechangegrouppart_widen(*args, **kwargs)
323 getbundlechangegrouppart_widen(*args, **kwargs)
321 else:
324 else:
322 origcgfn(*args, **kwargs)
325 origcgfn(*args, **kwargs)
323 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
326 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
324
327
325 # Extend changegroup receiver so client can fixup after widen requests.
328 # Extend changegroup receiver so client can fixup after widen requests.
326 origcghandler = bundle2.parthandlermapping['changegroup']
329 origcghandler = bundle2.parthandlermapping['changegroup']
327 def wrappedcghandler(op, inpart):
330 def wrappedcghandler(op, inpart):
328 origcghandler(op, inpart)
331 origcghandler(op, inpart)
329 if util.safehasattr(op, '_widen_bundle'):
332 if util.safehasattr(op, '_widen_bundle'):
330 handlechangegroup_widen(op, inpart)
333 handlechangegroup_widen(op, inpart)
331 wrappedcghandler.params = origcghandler.params
334 wrappedcghandler.params = origcghandler.params
332 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
335 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
General Comments 0
You need to be logged in to leave comments. Login now