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