##// END OF EJS Templates
narrow: drop server support for widening using the getbundle command (BC)...
Martin von Zweigbergk -
r43537:e94f4579 default
parent child Browse files
Show More
@@ -1,459 +1,386 b''
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 nullid
15 bin,
16 nullid,
17 )
18 from mercurial import (
15 from mercurial import (
19 bundle2,
16 bundle2,
20 changegroup,
17 changegroup,
21 error,
18 error,
22 exchange,
19 exchange,
23 localrepo,
20 localrepo,
24 narrowspec,
21 narrowspec,
25 repair,
22 repair,
26 util,
23 util,
27 wireprototypes,
24 wireprototypes,
28 )
25 )
29 from mercurial.interfaces import repository
26 from mercurial.interfaces import repository
30 from mercurial.utils import stringutil
27 from mercurial.utils import stringutil
31
28
32 _NARROWACL_SECTION = b'narrowacl'
29 _NARROWACL_SECTION = b'narrowacl'
33 _CHANGESPECPART = b'narrow:changespec'
30 _CHANGESPECPART = b'narrow:changespec'
34 _RESSPECS = b'narrow:responsespec'
31 _RESSPECS = b'narrow:responsespec'
35 _SPECPART = b'narrow:spec'
32 _SPECPART = b'narrow:spec'
36 _SPECPART_INCLUDE = b'include'
33 _SPECPART_INCLUDE = b'include'
37 _SPECPART_EXCLUDE = b'exclude'
34 _SPECPART_EXCLUDE = b'exclude'
38 _KILLNODESIGNAL = b'KILL'
35 _KILLNODESIGNAL = b'KILL'
39 _DONESIGNAL = b'DONE'
36 _DONESIGNAL = b'DONE'
40 _ELIDEDCSHEADER = b'>20s20s20sl' # cset id, p1, p2, len(text)
37 _ELIDEDCSHEADER = b'>20s20s20sl' # cset id, p1, p2, len(text)
41 _ELIDEDMFHEADER = b'>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
38 _ELIDEDMFHEADER = b'>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
42 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
39 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
43 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
40 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
44
41
45 # Serve a changegroup for a client with a narrow clone.
42 # Serve a changegroup for a client with a narrow clone.
46 def getbundlechangegrouppart_narrow(
43 def getbundlechangegrouppart_narrow(
47 bundler,
44 bundler,
48 repo,
45 repo,
49 source,
46 source,
50 bundlecaps=None,
47 bundlecaps=None,
51 b2caps=None,
48 b2caps=None,
52 heads=None,
49 heads=None,
53 common=None,
50 common=None,
54 **kwargs
51 **kwargs
55 ):
52 ):
56 assert repo.ui.configbool(b'experimental', b'narrowservebrokenellipses')
53 assert repo.ui.configbool(b'experimental', b'narrowservebrokenellipses')
57
54
58 cgversions = b2caps.get(b'changegroup')
55 cgversions = b2caps.get(b'changegroup')
59 cgversions = [
56 cgversions = [
60 v
57 v
61 for v in cgversions
58 for v in cgversions
62 if v in changegroup.supportedoutgoingversions(repo)
59 if v in changegroup.supportedoutgoingversions(repo)
63 ]
60 ]
64 if not cgversions:
61 if not cgversions:
65 raise ValueError(_(b'no common changegroup version'))
62 raise ValueError(_(b'no common changegroup version'))
66 version = max(cgversions)
63 version = max(cgversions)
67
64
68 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
65 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
69 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
66 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
70 newinclude = sorted(filter(bool, kwargs.get(r'includepats', [])))
71 newexclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
72 known = {bin(n) for n in kwargs.get(r'known', [])}
73 generateellipsesbundle2(
67 generateellipsesbundle2(
74 bundler,
68 bundler,
75 repo,
69 repo,
76 oldinclude,
70 include,
77 oldexclude,
71 exclude,
78 newinclude,
79 newexclude,
80 version,
72 version,
81 common,
73 common,
82 heads,
74 heads,
83 known,
84 kwargs.get(r'depth', None),
75 kwargs.get(r'depth', None),
85 )
76 )
86
77
87
78
88 def generateellipsesbundle2(
79 def generateellipsesbundle2(
89 bundler,
80 bundler, repo, include, exclude, version, common, heads, depth,
90 repo,
91 oldinclude,
92 oldexclude,
93 newinclude,
94 newexclude,
95 version,
96 common,
97 heads,
98 known,
99 depth,
100 ):
81 ):
101 newmatch = narrowspec.match(
82 match = narrowspec.match(repo.root, include=include, exclude=exclude)
102 repo.root, include=newinclude, exclude=newexclude
103 )
104 if depth is not None:
83 if depth is not None:
105 depth = int(depth)
84 depth = int(depth)
106 if depth < 1:
85 if depth < 1:
107 raise error.Abort(_(b'depth must be positive, got %d') % depth)
86 raise error.Abort(_(b'depth must be positive, got %d') % depth)
108
87
109 heads = set(heads or repo.heads())
88 heads = set(heads or repo.heads())
110 common = set(common or [nullid])
89 common = set(common or [nullid])
111 if known and (oldinclude != newinclude or oldexclude != newexclude):
112 # Steps:
113 # 1. Send kill for "$known & ::common"
114 #
115 # 2. Send changegroup for ::common
116 #
117 # 3. Proceed.
118 #
119 # In the future, we can send kills for only the specific
120 # nodes we know should go away or change shape, and then
121 # send a data stream that tells the client something like this:
122 #
123 # a) apply this changegroup
124 # b) apply nodes XXX, YYY, ZZZ that you already have
125 # c) goto a
126 #
127 # until they've built up the full new state.
128 # Convert to revnums and intersect with "common". The client should
129 # have made it a subset of "common" already, but let's be safe.
130 known = set(repo.revs(b"%ln & ::%ln", known, common))
131 # TODO: we could send only roots() of this set, and the
132 # list of nodes in common, and the client could work out
133 # what to strip, instead of us explicitly sending every
134 # single node.
135 deadrevs = known
136
137 def genkills():
138 for r in deadrevs:
139 yield _KILLNODESIGNAL
140 yield repo.changelog.node(r)
141 yield _DONESIGNAL
142
143 bundler.newpart(_CHANGESPECPART, data=genkills())
144 newvisit, newfull, newellipsis = exchange._computeellipsis(
145 repo, set(), common, known, newmatch
146 )
147 if newvisit:
148 packer = changegroup.getbundler(
149 version,
150 repo,
151 matcher=newmatch,
152 ellipses=True,
153 shallow=depth is not None,
154 ellipsisroots=newellipsis,
155 fullnodes=newfull,
156 )
157 cgdata = packer.generate(common, newvisit, False, b'narrow_widen')
158
159 part = bundler.newpart(b'changegroup', data=cgdata)
160 part.addparam(b'version', version)
161 if b'treemanifest' in repo.requirements:
162 part.addparam(b'treemanifest', b'1')
163
90
164 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
91 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
165 repo, common, heads, set(), newmatch, depth=depth
92 repo, common, heads, set(), match, depth=depth
166 )
93 )
167
94
168 repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes))
95 repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes))
169 if visitnodes:
96 if visitnodes:
170 packer = changegroup.getbundler(
97 packer = changegroup.getbundler(
171 version,
98 version,
172 repo,
99 repo,
173 matcher=newmatch,
100 matcher=match,
174 ellipses=True,
101 ellipses=True,
175 shallow=depth is not None,
102 shallow=depth is not None,
176 ellipsisroots=ellipsisroots,
103 ellipsisroots=ellipsisroots,
177 fullnodes=relevant_nodes,
104 fullnodes=relevant_nodes,
178 )
105 )
179 cgdata = packer.generate(common, visitnodes, False, b'narrow_widen')
106 cgdata = packer.generate(common, visitnodes, False, b'narrow_widen')
180
107
181 part = bundler.newpart(b'changegroup', data=cgdata)
108 part = bundler.newpart(b'changegroup', data=cgdata)
182 part.addparam(b'version', version)
109 part.addparam(b'version', version)
183 if b'treemanifest' in repo.requirements:
110 if b'treemanifest' in repo.requirements:
184 part.addparam(b'treemanifest', b'1')
111 part.addparam(b'treemanifest', b'1')
185
112
186
113
187 def generate_ellipses_bundle2_for_widening(
114 def generate_ellipses_bundle2_for_widening(
188 bundler,
115 bundler,
189 repo,
116 repo,
190 oldinclude,
117 oldinclude,
191 oldexclude,
118 oldexclude,
192 newinclude,
119 newinclude,
193 newexclude,
120 newexclude,
194 version,
121 version,
195 common,
122 common,
196 heads,
123 heads,
197 known,
124 known,
198 depth,
125 depth,
199 ):
126 ):
200 newmatch = narrowspec.match(
127 newmatch = narrowspec.match(
201 repo.root, include=newinclude, exclude=newexclude
128 repo.root, include=newinclude, exclude=newexclude
202 )
129 )
203 if depth is not None:
130 if depth is not None:
204 depth = int(depth)
131 depth = int(depth)
205 if depth < 1:
132 if depth < 1:
206 raise error.Abort(_(b'depth must be positive, got %d') % depth)
133 raise error.Abort(_(b'depth must be positive, got %d') % depth)
207
134
208 heads = set(heads or repo.heads())
135 heads = set(heads or repo.heads())
209 common = set(common or [nullid])
136 common = set(common or [nullid])
210 if known and (oldinclude != newinclude or oldexclude != newexclude):
137 if known and (oldinclude != newinclude or oldexclude != newexclude):
211 # Steps:
138 # Steps:
212 # 1. Send kill for "$known & ::common"
139 # 1. Send kill for "$known & ::common"
213 #
140 #
214 # 2. Send changegroup for ::common
141 # 2. Send changegroup for ::common
215 #
142 #
216 # 3. Proceed.
143 # 3. Proceed.
217 #
144 #
218 # In the future, we can send kills for only the specific
145 # In the future, we can send kills for only the specific
219 # nodes we know should go away or change shape, and then
146 # nodes we know should go away or change shape, and then
220 # send a data stream that tells the client something like this:
147 # send a data stream that tells the client something like this:
221 #
148 #
222 # a) apply this changegroup
149 # a) apply this changegroup
223 # b) apply nodes XXX, YYY, ZZZ that you already have
150 # b) apply nodes XXX, YYY, ZZZ that you already have
224 # c) goto a
151 # c) goto a
225 #
152 #
226 # until they've built up the full new state.
153 # until they've built up the full new state.
227 # Convert to revnums and intersect with "common". The client should
154 # Convert to revnums and intersect with "common". The client should
228 # have made it a subset of "common" already, but let's be safe.
155 # have made it a subset of "common" already, but let's be safe.
229 known = set(repo.revs(b"%ln & ::%ln", known, common))
156 known = set(repo.revs(b"%ln & ::%ln", known, common))
230 # TODO: we could send only roots() of this set, and the
157 # TODO: we could send only roots() of this set, and the
231 # list of nodes in common, and the client could work out
158 # list of nodes in common, and the client could work out
232 # what to strip, instead of us explicitly sending every
159 # what to strip, instead of us explicitly sending every
233 # single node.
160 # single node.
234 deadrevs = known
161 deadrevs = known
235
162
236 def genkills():
163 def genkills():
237 for r in deadrevs:
164 for r in deadrevs:
238 yield _KILLNODESIGNAL
165 yield _KILLNODESIGNAL
239 yield repo.changelog.node(r)
166 yield repo.changelog.node(r)
240 yield _DONESIGNAL
167 yield _DONESIGNAL
241
168
242 bundler.newpart(_CHANGESPECPART, data=genkills())
169 bundler.newpart(_CHANGESPECPART, data=genkills())
243 newvisit, newfull, newellipsis = exchange._computeellipsis(
170 newvisit, newfull, newellipsis = exchange._computeellipsis(
244 repo, set(), common, known, newmatch
171 repo, set(), common, known, newmatch
245 )
172 )
246 if newvisit:
173 if newvisit:
247 packer = changegroup.getbundler(
174 packer = changegroup.getbundler(
248 version,
175 version,
249 repo,
176 repo,
250 matcher=newmatch,
177 matcher=newmatch,
251 ellipses=True,
178 ellipses=True,
252 shallow=depth is not None,
179 shallow=depth is not None,
253 ellipsisroots=newellipsis,
180 ellipsisroots=newellipsis,
254 fullnodes=newfull,
181 fullnodes=newfull,
255 )
182 )
256 cgdata = packer.generate(common, newvisit, False, b'narrow_widen')
183 cgdata = packer.generate(common, newvisit, False, b'narrow_widen')
257
184
258 part = bundler.newpart(b'changegroup', data=cgdata)
185 part = bundler.newpart(b'changegroup', data=cgdata)
259 part.addparam(b'version', version)
186 part.addparam(b'version', version)
260 if b'treemanifest' in repo.requirements:
187 if b'treemanifest' in repo.requirements:
261 part.addparam(b'treemanifest', b'1')
188 part.addparam(b'treemanifest', b'1')
262
189
263 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
190 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
264 repo, common, heads, set(), newmatch, depth=depth
191 repo, common, heads, set(), newmatch, depth=depth
265 )
192 )
266
193
267 repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes))
194 repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes))
268 if visitnodes:
195 if visitnodes:
269 packer = changegroup.getbundler(
196 packer = changegroup.getbundler(
270 version,
197 version,
271 repo,
198 repo,
272 matcher=newmatch,
199 matcher=newmatch,
273 ellipses=True,
200 ellipses=True,
274 shallow=depth is not None,
201 shallow=depth is not None,
275 ellipsisroots=ellipsisroots,
202 ellipsisroots=ellipsisroots,
276 fullnodes=relevant_nodes,
203 fullnodes=relevant_nodes,
277 )
204 )
278 cgdata = packer.generate(common, visitnodes, False, b'narrow_widen')
205 cgdata = packer.generate(common, visitnodes, False, b'narrow_widen')
279
206
280 part = bundler.newpart(b'changegroup', data=cgdata)
207 part = bundler.newpart(b'changegroup', data=cgdata)
281 part.addparam(b'version', version)
208 part.addparam(b'version', version)
282 if b'treemanifest' in repo.requirements:
209 if b'treemanifest' in repo.requirements:
283 part.addparam(b'treemanifest', b'1')
210 part.addparam(b'treemanifest', b'1')
284
211
285
212
286 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
213 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
287 def _handlechangespec_2(op, inpart):
214 def _handlechangespec_2(op, inpart):
288 # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is
215 # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is
289 # released. New servers will send a mandatory bundle2 part named
216 # released. New servers will send a mandatory bundle2 part named
290 # 'Narrowspec' and will send specs as data instead of params.
217 # 'Narrowspec' and will send specs as data instead of params.
291 # Refer to issue5952 and 6019
218 # Refer to issue5952 and 6019
292 includepats = set(inpart.params.get(_SPECPART_INCLUDE, b'').splitlines())
219 includepats = set(inpart.params.get(_SPECPART_INCLUDE, b'').splitlines())
293 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, b'').splitlines())
220 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, b'').splitlines())
294 narrowspec.validatepatterns(includepats)
221 narrowspec.validatepatterns(includepats)
295 narrowspec.validatepatterns(excludepats)
222 narrowspec.validatepatterns(excludepats)
296
223
297 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
224 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
298 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
225 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
299 op.repo._writerequirements()
226 op.repo._writerequirements()
300 op.repo.setnarrowpats(includepats, excludepats)
227 op.repo.setnarrowpats(includepats, excludepats)
301 narrowspec.copytoworkingcopy(op.repo)
228 narrowspec.copytoworkingcopy(op.repo)
302
229
303
230
304 @bundle2.parthandler(_RESSPECS)
231 @bundle2.parthandler(_RESSPECS)
305 def _handlenarrowspecs(op, inpart):
232 def _handlenarrowspecs(op, inpart):
306 data = inpart.read()
233 data = inpart.read()
307 inc, exc = data.split(b'\0')
234 inc, exc = data.split(b'\0')
308 includepats = set(inc.splitlines())
235 includepats = set(inc.splitlines())
309 excludepats = set(exc.splitlines())
236 excludepats = set(exc.splitlines())
310 narrowspec.validatepatterns(includepats)
237 narrowspec.validatepatterns(includepats)
311 narrowspec.validatepatterns(excludepats)
238 narrowspec.validatepatterns(excludepats)
312
239
313 if repository.NARROW_REQUIREMENT not in op.repo.requirements:
240 if repository.NARROW_REQUIREMENT not in op.repo.requirements:
314 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
241 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
315 op.repo._writerequirements()
242 op.repo._writerequirements()
316 op.repo.setnarrowpats(includepats, excludepats)
243 op.repo.setnarrowpats(includepats, excludepats)
317 narrowspec.copytoworkingcopy(op.repo)
244 narrowspec.copytoworkingcopy(op.repo)
318
245
319
246
320 @bundle2.parthandler(_CHANGESPECPART)
247 @bundle2.parthandler(_CHANGESPECPART)
321 def _handlechangespec(op, inpart):
248 def _handlechangespec(op, inpart):
322 repo = op.repo
249 repo = op.repo
323 cl = repo.changelog
250 cl = repo.changelog
324
251
325 # changesets which need to be stripped entirely. either they're no longer
252 # changesets which need to be stripped entirely. either they're no longer
326 # needed in the new narrow spec, or the server is sending a replacement
253 # needed in the new narrow spec, or the server is sending a replacement
327 # in the changegroup part.
254 # in the changegroup part.
328 clkills = set()
255 clkills = set()
329
256
330 # A changespec part contains all the updates to ellipsis nodes
257 # A changespec part contains all the updates to ellipsis nodes
331 # that will happen as a result of widening or narrowing a
258 # that will happen as a result of widening or narrowing a
332 # repo. All the changes that this block encounters are ellipsis
259 # repo. All the changes that this block encounters are ellipsis
333 # nodes or flags to kill an existing ellipsis.
260 # nodes or flags to kill an existing ellipsis.
334 chunksignal = changegroup.readexactly(inpart, 4)
261 chunksignal = changegroup.readexactly(inpart, 4)
335 while chunksignal != _DONESIGNAL:
262 while chunksignal != _DONESIGNAL:
336 if chunksignal == _KILLNODESIGNAL:
263 if chunksignal == _KILLNODESIGNAL:
337 # a node used to be an ellipsis but isn't anymore
264 # a node used to be an ellipsis but isn't anymore
338 ck = changegroup.readexactly(inpart, 20)
265 ck = changegroup.readexactly(inpart, 20)
339 if cl.hasnode(ck):
266 if cl.hasnode(ck):
340 clkills.add(ck)
267 clkills.add(ck)
341 else:
268 else:
342 raise error.Abort(
269 raise error.Abort(
343 _(b'unexpected changespec node chunk type: %s') % chunksignal
270 _(b'unexpected changespec node chunk type: %s') % chunksignal
344 )
271 )
345 chunksignal = changegroup.readexactly(inpart, 4)
272 chunksignal = changegroup.readexactly(inpart, 4)
346
273
347 if clkills:
274 if clkills:
348 # preserve bookmarks that repair.strip() would otherwise strip
275 # preserve bookmarks that repair.strip() would otherwise strip
349 op._bookmarksbackup = repo._bookmarks
276 op._bookmarksbackup = repo._bookmarks
350
277
351 class dummybmstore(dict):
278 class dummybmstore(dict):
352 def applychanges(self, repo, tr, changes):
279 def applychanges(self, repo, tr, changes):
353 pass
280 pass
354
281
355 localrepo.localrepository._bookmarks.set(repo, dummybmstore())
282 localrepo.localrepository._bookmarks.set(repo, dummybmstore())
356 chgrpfile = repair.strip(
283 chgrpfile = repair.strip(
357 op.ui, repo, list(clkills), backup=True, topic=b'widen'
284 op.ui, repo, list(clkills), backup=True, topic=b'widen'
358 )
285 )
359 if chgrpfile:
286 if chgrpfile:
360 op._widen_uninterr = repo.ui.uninterruptible()
287 op._widen_uninterr = repo.ui.uninterruptible()
361 op._widen_uninterr.__enter__()
288 op._widen_uninterr.__enter__()
362 # presence of _widen_bundle attribute activates widen handler later
289 # presence of _widen_bundle attribute activates widen handler later
363 op._widen_bundle = chgrpfile
290 op._widen_bundle = chgrpfile
364 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
291 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
365 # will currently always be there when using the core+narrowhg server, but
292 # will currently always be there when using the core+narrowhg server, but
366 # other servers may include a changespec part even when not widening (e.g.
293 # other servers may include a changespec part even when not widening (e.g.
367 # because we're deepening a shallow repo).
294 # because we're deepening a shallow repo).
368 if util.safehasattr(repo, 'setnewnarrowpats'):
295 if util.safehasattr(repo, 'setnewnarrowpats'):
369 repo.setnewnarrowpats()
296 repo.setnewnarrowpats()
370
297
371
298
372 def handlechangegroup_widen(op, inpart):
299 def handlechangegroup_widen(op, inpart):
373 """Changegroup exchange handler which restores temporarily-stripped nodes"""
300 """Changegroup exchange handler which restores temporarily-stripped nodes"""
374 # We saved a bundle with stripped node data we must now restore.
301 # We saved a bundle with stripped node data we must now restore.
375 # This approach is based on mercurial/repair.py@6ee26a53c111.
302 # This approach is based on mercurial/repair.py@6ee26a53c111.
376 repo = op.repo
303 repo = op.repo
377 ui = op.ui
304 ui = op.ui
378
305
379 chgrpfile = op._widen_bundle
306 chgrpfile = op._widen_bundle
380 del op._widen_bundle
307 del op._widen_bundle
381 vfs = repo.vfs
308 vfs = repo.vfs
382
309
383 ui.note(_(b"adding branch\n"))
310 ui.note(_(b"adding branch\n"))
384 f = vfs.open(chgrpfile, b"rb")
311 f = vfs.open(chgrpfile, b"rb")
385 try:
312 try:
386 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
313 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
387 # silence internal shuffling chatter
314 # silence internal shuffling chatter
388 override = {(b'ui', b'quiet'): True}
315 override = {(b'ui', b'quiet'): True}
389 if ui.verbose:
316 if ui.verbose:
390 override = {}
317 override = {}
391 with ui.configoverride(override):
318 with ui.configoverride(override):
392 if isinstance(gen, bundle2.unbundle20):
319 if isinstance(gen, bundle2.unbundle20):
393 with repo.transaction(b'strip') as tr:
320 with repo.transaction(b'strip') as tr:
394 bundle2.processbundle(repo, gen, lambda: tr)
321 bundle2.processbundle(repo, gen, lambda: tr)
395 else:
322 else:
396 gen.apply(
323 gen.apply(
397 repo, b'strip', b'bundle:' + vfs.join(chgrpfile), True
324 repo, b'strip', b'bundle:' + vfs.join(chgrpfile), True
398 )
325 )
399 finally:
326 finally:
400 f.close()
327 f.close()
401
328
402 # remove undo files
329 # remove undo files
403 for undovfs, undofile in repo.undofiles():
330 for undovfs, undofile in repo.undofiles():
404 try:
331 try:
405 undovfs.unlink(undofile)
332 undovfs.unlink(undofile)
406 except OSError as e:
333 except OSError as e:
407 if e.errno != errno.ENOENT:
334 if e.errno != errno.ENOENT:
408 ui.warn(
335 ui.warn(
409 _(b'error removing %s: %s\n')
336 _(b'error removing %s: %s\n')
410 % (undovfs.join(undofile), stringutil.forcebytestr(e))
337 % (undovfs.join(undofile), stringutil.forcebytestr(e))
411 )
338 )
412
339
413 # Remove partial backup only if there were no exceptions
340 # Remove partial backup only if there were no exceptions
414 op._widen_uninterr.__exit__(None, None, None)
341 op._widen_uninterr.__exit__(None, None, None)
415 vfs.unlink(chgrpfile)
342 vfs.unlink(chgrpfile)
416
343
417
344
418 def setup():
345 def setup():
419 """Enable narrow repo support in bundle2-related extension points."""
346 """Enable narrow repo support in bundle2-related extension points."""
420 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
347 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
421
348
422 getbundleargs[b'narrow'] = b'boolean'
349 getbundleargs[b'narrow'] = b'boolean'
423 getbundleargs[b'depth'] = b'plain'
350 getbundleargs[b'depth'] = b'plain'
424 getbundleargs[b'oldincludepats'] = b'csv'
351 getbundleargs[b'oldincludepats'] = b'csv'
425 getbundleargs[b'oldexcludepats'] = b'csv'
352 getbundleargs[b'oldexcludepats'] = b'csv'
426 getbundleargs[b'known'] = b'csv'
353 getbundleargs[b'known'] = b'csv'
427
354
428 # Extend changegroup serving to handle requests from narrow clients.
355 # Extend changegroup serving to handle requests from narrow clients.
429 origcgfn = exchange.getbundle2partsmapping[b'changegroup']
356 origcgfn = exchange.getbundle2partsmapping[b'changegroup']
430
357
431 def wrappedcgfn(*args, **kwargs):
358 def wrappedcgfn(*args, **kwargs):
432 repo = args[1]
359 repo = args[1]
433 if repo.ui.has_section(_NARROWACL_SECTION):
360 if repo.ui.has_section(_NARROWACL_SECTION):
434 kwargs = exchange.applynarrowacl(repo, kwargs)
361 kwargs = exchange.applynarrowacl(repo, kwargs)
435
362
436 if kwargs.get(r'narrow', False) and repo.ui.configbool(
363 if kwargs.get(r'narrow', False) and repo.ui.configbool(
437 b'experimental', b'narrowservebrokenellipses'
364 b'experimental', b'narrowservebrokenellipses'
438 ):
365 ):
439 getbundlechangegrouppart_narrow(*args, **kwargs)
366 getbundlechangegrouppart_narrow(*args, **kwargs)
440 else:
367 else:
441 origcgfn(*args, **kwargs)
368 origcgfn(*args, **kwargs)
442
369
443 exchange.getbundle2partsmapping[b'changegroup'] = wrappedcgfn
370 exchange.getbundle2partsmapping[b'changegroup'] = wrappedcgfn
444
371
445 # Extend changegroup receiver so client can fixup after widen requests.
372 # Extend changegroup receiver so client can fixup after widen requests.
446 origcghandler = bundle2.parthandlermapping[b'changegroup']
373 origcghandler = bundle2.parthandlermapping[b'changegroup']
447
374
448 def wrappedcghandler(op, inpart):
375 def wrappedcghandler(op, inpart):
449 origcghandler(op, inpart)
376 origcghandler(op, inpart)
450 if util.safehasattr(op, '_widen_bundle'):
377 if util.safehasattr(op, '_widen_bundle'):
451 handlechangegroup_widen(op, inpart)
378 handlechangegroup_widen(op, inpart)
452 if util.safehasattr(op, '_bookmarksbackup'):
379 if util.safehasattr(op, '_bookmarksbackup'):
453 localrepo.localrepository._bookmarks.set(
380 localrepo.localrepository._bookmarks.set(
454 op.repo, op._bookmarksbackup
381 op.repo, op._bookmarksbackup
455 )
382 )
456 del op._bookmarksbackup
383 del op._bookmarksbackup
457
384
458 wrappedcghandler.params = origcghandler.params
385 wrappedcghandler.params = origcghandler.params
459 bundle2.parthandlermapping[b'changegroup'] = wrappedcghandler
386 bundle2.parthandlermapping[b'changegroup'] = wrappedcghandler
General Comments 0
You need to be logged in to leave comments. Login now