27 wireprototypes, |
27 wireprototypes, |
28 ) |
28 ) |
29 from mercurial.interfaces import repository |
29 from mercurial.interfaces import repository |
30 from mercurial.utils import stringutil |
30 from mercurial.utils import stringutil |
31 |
31 |
32 _NARROWACL_SECTION = 'narrowacl' |
32 _NARROWACL_SECTION = b'narrowacl' |
33 _CHANGESPECPART = 'narrow:changespec' |
33 _CHANGESPECPART = b'narrow:changespec' |
34 _RESSPECS = 'narrow:responsespec' |
34 _RESSPECS = b'narrow:responsespec' |
35 _SPECPART = 'narrow:spec' |
35 _SPECPART = b'narrow:spec' |
36 _SPECPART_INCLUDE = 'include' |
36 _SPECPART_INCLUDE = b'include' |
37 _SPECPART_EXCLUDE = 'exclude' |
37 _SPECPART_EXCLUDE = b'exclude' |
38 _KILLNODESIGNAL = 'KILL' |
38 _KILLNODESIGNAL = b'KILL' |
39 _DONESIGNAL = 'DONE' |
39 _DONESIGNAL = b'DONE' |
40 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text) |
40 _ELIDEDCSHEADER = b'>20s20s20sl' # cset id, p1, p2, len(text) |
41 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text) |
41 _ELIDEDMFHEADER = b'>20s20s20s20sl' # manifest id, p1, p2, link id, len(text) |
42 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER) |
42 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER) |
43 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER) |
43 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER) |
44 |
44 |
45 # Serve a changegroup for a client with a narrow clone. |
45 # Serve a changegroup for a client with a narrow clone. |
46 def getbundlechangegrouppart_narrow( |
46 def getbundlechangegrouppart_narrow( |
51 b2caps=None, |
51 b2caps=None, |
52 heads=None, |
52 heads=None, |
53 common=None, |
53 common=None, |
54 **kwargs |
54 **kwargs |
55 ): |
55 ): |
56 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses') |
56 assert repo.ui.configbool(b'experimental', b'narrowservebrokenellipses') |
57 |
57 |
58 cgversions = b2caps.get('changegroup') |
58 cgversions = b2caps.get(b'changegroup') |
59 cgversions = [ |
59 cgversions = [ |
60 v |
60 v |
61 for v in cgversions |
61 for v in cgversions |
62 if v in changegroup.supportedoutgoingversions(repo) |
62 if v in changegroup.supportedoutgoingversions(repo) |
63 ] |
63 ] |
64 if not cgversions: |
64 if not cgversions: |
65 raise ValueError(_('no common changegroup version')) |
65 raise ValueError(_(b'no common changegroup version')) |
66 version = max(cgversions) |
66 version = max(cgversions) |
67 |
67 |
68 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', []))) |
68 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', []))) |
69 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', []))) |
69 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', []))) |
70 newinclude = sorted(filter(bool, kwargs.get(r'includepats', []))) |
70 newinclude = sorted(filter(bool, kwargs.get(r'includepats', []))) |
125 # c) goto a |
125 # c) goto a |
126 # |
126 # |
127 # until they've built up the full new state. |
127 # until they've built up the full new state. |
128 # Convert to revnums and intersect with "common". The client should |
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. |
129 # have made it a subset of "common" already, but let's be safe. |
130 known = set(repo.revs("%ln & ::%ln", known, common)) |
130 known = set(repo.revs(b"%ln & ::%ln", known, common)) |
131 # TODO: we could send only roots() of this set, and the |
131 # TODO: we could send only roots() of this set, and the |
132 # list of nodes in common, and the client could work out |
132 # list of nodes in common, and the client could work out |
133 # what to strip, instead of us explicitly sending every |
133 # what to strip, instead of us explicitly sending every |
134 # single node. |
134 # single node. |
135 deadrevs = known |
135 deadrevs = known |
152 ellipses=True, |
152 ellipses=True, |
153 shallow=depth is not None, |
153 shallow=depth is not None, |
154 ellipsisroots=newellipsis, |
154 ellipsisroots=newellipsis, |
155 fullnodes=newfull, |
155 fullnodes=newfull, |
156 ) |
156 ) |
157 cgdata = packer.generate(common, newvisit, False, 'narrow_widen') |
157 cgdata = packer.generate(common, newvisit, False, b'narrow_widen') |
158 |
158 |
159 part = bundler.newpart('changegroup', data=cgdata) |
159 part = bundler.newpart(b'changegroup', data=cgdata) |
160 part.addparam('version', version) |
160 part.addparam(b'version', version) |
161 if 'treemanifest' in repo.requirements: |
161 if b'treemanifest' in repo.requirements: |
162 part.addparam('treemanifest', '1') |
162 part.addparam(b'treemanifest', b'1') |
163 |
163 |
164 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis( |
164 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis( |
165 repo, common, heads, set(), newmatch, depth=depth |
165 repo, common, heads, set(), newmatch, depth=depth |
166 ) |
166 ) |
167 |
167 |
168 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes)) |
168 repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes)) |
169 if visitnodes: |
169 if visitnodes: |
170 packer = changegroup.getbundler( |
170 packer = changegroup.getbundler( |
171 version, |
171 version, |
172 repo, |
172 repo, |
173 matcher=newmatch, |
173 matcher=newmatch, |
174 ellipses=True, |
174 ellipses=True, |
175 shallow=depth is not None, |
175 shallow=depth is not None, |
176 ellipsisroots=ellipsisroots, |
176 ellipsisroots=ellipsisroots, |
177 fullnodes=relevant_nodes, |
177 fullnodes=relevant_nodes, |
178 ) |
178 ) |
179 cgdata = packer.generate(common, visitnodes, False, 'narrow_widen') |
179 cgdata = packer.generate(common, visitnodes, False, b'narrow_widen') |
180 |
180 |
181 part = bundler.newpart('changegroup', data=cgdata) |
181 part = bundler.newpart(b'changegroup', data=cgdata) |
182 part.addparam('version', version) |
182 part.addparam(b'version', version) |
183 if 'treemanifest' in repo.requirements: |
183 if b'treemanifest' in repo.requirements: |
184 part.addparam('treemanifest', '1') |
184 part.addparam(b'treemanifest', b'1') |
185 |
185 |
186 |
186 |
187 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE)) |
187 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE)) |
188 def _handlechangespec_2(op, inpart): |
188 def _handlechangespec_2(op, inpart): |
189 # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is |
189 # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is |
190 # released. New servers will send a mandatory bundle2 part named |
190 # released. New servers will send a mandatory bundle2 part named |
191 # 'Narrowspec' and will send specs as data instead of params. |
191 # 'Narrowspec' and will send specs as data instead of params. |
192 # Refer to issue5952 and 6019 |
192 # Refer to issue5952 and 6019 |
193 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines()) |
193 includepats = set(inpart.params.get(_SPECPART_INCLUDE, b'').splitlines()) |
194 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines()) |
194 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, b'').splitlines()) |
195 narrowspec.validatepatterns(includepats) |
195 narrowspec.validatepatterns(includepats) |
196 narrowspec.validatepatterns(excludepats) |
196 narrowspec.validatepatterns(excludepats) |
197 |
197 |
198 if not repository.NARROW_REQUIREMENT in op.repo.requirements: |
198 if not repository.NARROW_REQUIREMENT in op.repo.requirements: |
199 op.repo.requirements.add(repository.NARROW_REQUIREMENT) |
199 op.repo.requirements.add(repository.NARROW_REQUIREMENT) |
253 def applychanges(self, repo, tr, changes): |
253 def applychanges(self, repo, tr, changes): |
254 pass |
254 pass |
255 |
255 |
256 localrepo.localrepository._bookmarks.set(repo, dummybmstore()) |
256 localrepo.localrepository._bookmarks.set(repo, dummybmstore()) |
257 chgrpfile = repair.strip( |
257 chgrpfile = repair.strip( |
258 op.ui, repo, list(clkills), backup=True, topic='widen' |
258 op.ui, repo, list(clkills), backup=True, topic=b'widen' |
259 ) |
259 ) |
260 if chgrpfile: |
260 if chgrpfile: |
261 op._widen_uninterr = repo.ui.uninterruptible() |
261 op._widen_uninterr = repo.ui.uninterruptible() |
262 op._widen_uninterr.__enter__() |
262 op._widen_uninterr.__enter__() |
263 # presence of _widen_bundle attribute activates widen handler later |
263 # presence of _widen_bundle attribute activates widen handler later |
264 op._widen_bundle = chgrpfile |
264 op._widen_bundle = chgrpfile |
265 # Set the new narrowspec if we're widening. The setnewnarrowpats() method |
265 # Set the new narrowspec if we're widening. The setnewnarrowpats() method |
266 # will currently always be there when using the core+narrowhg server, but |
266 # will currently always be there when using the core+narrowhg server, but |
267 # other servers may include a changespec part even when not widening (e.g. |
267 # other servers may include a changespec part even when not widening (e.g. |
268 # because we're deepening a shallow repo). |
268 # because we're deepening a shallow repo). |
269 if util.safehasattr(repo, 'setnewnarrowpats'): |
269 if util.safehasattr(repo, b'setnewnarrowpats'): |
270 repo.setnewnarrowpats() |
270 repo.setnewnarrowpats() |
271 |
271 |
272 |
272 |
273 def handlechangegroup_widen(op, inpart): |
273 def handlechangegroup_widen(op, inpart): |
274 """Changegroup exchange handler which restores temporarily-stripped nodes""" |
274 """Changegroup exchange handler which restores temporarily-stripped nodes""" |
279 |
279 |
280 chgrpfile = op._widen_bundle |
280 chgrpfile = op._widen_bundle |
281 del op._widen_bundle |
281 del op._widen_bundle |
282 vfs = repo.vfs |
282 vfs = repo.vfs |
283 |
283 |
284 ui.note(_("adding branch\n")) |
284 ui.note(_(b"adding branch\n")) |
285 f = vfs.open(chgrpfile, "rb") |
285 f = vfs.open(chgrpfile, b"rb") |
286 try: |
286 try: |
287 gen = exchange.readbundle(ui, f, chgrpfile, vfs) |
287 gen = exchange.readbundle(ui, f, chgrpfile, vfs) |
288 # silence internal shuffling chatter |
288 # silence internal shuffling chatter |
289 override = {('ui', 'quiet'): True} |
289 override = {(b'ui', b'quiet'): True} |
290 if ui.verbose: |
290 if ui.verbose: |
291 override = {} |
291 override = {} |
292 with ui.configoverride(override): |
292 with ui.configoverride(override): |
293 if isinstance(gen, bundle2.unbundle20): |
293 if isinstance(gen, bundle2.unbundle20): |
294 with repo.transaction('strip') as tr: |
294 with repo.transaction(b'strip') as tr: |
295 bundle2.processbundle(repo, gen, lambda: tr) |
295 bundle2.processbundle(repo, gen, lambda: tr) |
296 else: |
296 else: |
297 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True) |
297 gen.apply( |
|
298 repo, b'strip', b'bundle:' + vfs.join(chgrpfile), True |
|
299 ) |
298 finally: |
300 finally: |
299 f.close() |
301 f.close() |
300 |
302 |
301 # remove undo files |
303 # remove undo files |
302 for undovfs, undofile in repo.undofiles(): |
304 for undovfs, undofile in repo.undofiles(): |
303 try: |
305 try: |
304 undovfs.unlink(undofile) |
306 undovfs.unlink(undofile) |
305 except OSError as e: |
307 except OSError as e: |
306 if e.errno != errno.ENOENT: |
308 if e.errno != errno.ENOENT: |
307 ui.warn( |
309 ui.warn( |
308 _('error removing %s: %s\n') |
310 _(b'error removing %s: %s\n') |
309 % (undovfs.join(undofile), stringutil.forcebytestr(e)) |
311 % (undovfs.join(undofile), stringutil.forcebytestr(e)) |
310 ) |
312 ) |
311 |
313 |
312 # Remove partial backup only if there were no exceptions |
314 # Remove partial backup only if there were no exceptions |
313 op._widen_uninterr.__exit__(None, None, None) |
315 op._widen_uninterr.__exit__(None, None, None) |
316 |
318 |
317 def setup(): |
319 def setup(): |
318 """Enable narrow repo support in bundle2-related extension points.""" |
320 """Enable narrow repo support in bundle2-related extension points.""" |
319 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS |
321 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS |
320 |
322 |
321 getbundleargs['narrow'] = 'boolean' |
323 getbundleargs[b'narrow'] = b'boolean' |
322 getbundleargs['depth'] = 'plain' |
324 getbundleargs[b'depth'] = b'plain' |
323 getbundleargs['oldincludepats'] = 'csv' |
325 getbundleargs[b'oldincludepats'] = b'csv' |
324 getbundleargs['oldexcludepats'] = 'csv' |
326 getbundleargs[b'oldexcludepats'] = b'csv' |
325 getbundleargs['known'] = 'csv' |
327 getbundleargs[b'known'] = b'csv' |
326 |
328 |
327 # Extend changegroup serving to handle requests from narrow clients. |
329 # Extend changegroup serving to handle requests from narrow clients. |
328 origcgfn = exchange.getbundle2partsmapping['changegroup'] |
330 origcgfn = exchange.getbundle2partsmapping[b'changegroup'] |
329 |
331 |
330 def wrappedcgfn(*args, **kwargs): |
332 def wrappedcgfn(*args, **kwargs): |
331 repo = args[1] |
333 repo = args[1] |
332 if repo.ui.has_section(_NARROWACL_SECTION): |
334 if repo.ui.has_section(_NARROWACL_SECTION): |
333 kwargs = exchange.applynarrowacl(repo, kwargs) |
335 kwargs = exchange.applynarrowacl(repo, kwargs) |
334 |
336 |
335 if kwargs.get(r'narrow', False) and repo.ui.configbool( |
337 if kwargs.get(r'narrow', False) and repo.ui.configbool( |
336 'experimental', 'narrowservebrokenellipses' |
338 b'experimental', b'narrowservebrokenellipses' |
337 ): |
339 ): |
338 getbundlechangegrouppart_narrow(*args, **kwargs) |
340 getbundlechangegrouppart_narrow(*args, **kwargs) |
339 else: |
341 else: |
340 origcgfn(*args, **kwargs) |
342 origcgfn(*args, **kwargs) |
341 |
343 |
342 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn |
344 exchange.getbundle2partsmapping[b'changegroup'] = wrappedcgfn |
343 |
345 |
344 # Extend changegroup receiver so client can fixup after widen requests. |
346 # Extend changegroup receiver so client can fixup after widen requests. |
345 origcghandler = bundle2.parthandlermapping['changegroup'] |
347 origcghandler = bundle2.parthandlermapping[b'changegroup'] |
346 |
348 |
347 def wrappedcghandler(op, inpart): |
349 def wrappedcghandler(op, inpart): |
348 origcghandler(op, inpart) |
350 origcghandler(op, inpart) |
349 if util.safehasattr(op, '_widen_bundle'): |
351 if util.safehasattr(op, b'_widen_bundle'): |
350 handlechangegroup_widen(op, inpart) |
352 handlechangegroup_widen(op, inpart) |
351 if util.safehasattr(op, '_bookmarksbackup'): |
353 if util.safehasattr(op, b'_bookmarksbackup'): |
352 localrepo.localrepository._bookmarks.set( |
354 localrepo.localrepository._bookmarks.set( |
353 op.repo, op._bookmarksbackup |
355 op.repo, op._bookmarksbackup |
354 ) |
356 ) |
355 del op._bookmarksbackup |
357 del op._bookmarksbackup |
356 |
358 |
357 wrappedcghandler.params = origcghandler.params |
359 wrappedcghandler.params = origcghandler.params |
358 bundle2.parthandlermapping['changegroup'] = wrappedcghandler |
360 bundle2.parthandlermapping[b'changegroup'] = wrappedcghandler |