mercurial/bundle2.py
changeset 51667 6fc31e7bd5db
parent 51658 a0f1378b932e
child 51686 493034cc3265
equal deleted inserted replaced
51666:a09435c0eb14 51667:6fc31e7bd5db
   151 import os
   151 import os
   152 import re
   152 import re
   153 import string
   153 import string
   154 import struct
   154 import struct
   155 import sys
   155 import sys
       
   156 import typing
   156 
   157 
   157 from .i18n import _
   158 from .i18n import _
   158 from .node import (
   159 from .node import (
   159     hex,
   160     hex,
   160     short,
   161     short,
   178 from .utils import (
   179 from .utils import (
   179     stringutil,
   180     stringutil,
   180     urlutil,
   181     urlutil,
   181 )
   182 )
   182 from .interfaces import repository
   183 from .interfaces import repository
       
   184 
       
   185 if typing.TYPE_CHECKING:
       
   186     from typing import (
       
   187         Dict,
       
   188         List,
       
   189         Optional,
       
   190         Tuple,
       
   191         Union,
       
   192     )
       
   193 
       
   194     Capabilities = Dict[bytes, Union[List[bytes], Tuple[bytes, ...]]]
   183 
   195 
   184 urlerr = util.urlerr
   196 urlerr = util.urlerr
   185 urlreq = util.urlreq
   197 urlreq = util.urlreq
   186 
   198 
   187 _pack = struct.pack
   199 _pack = struct.pack
   600             outpart.addparam(
   612             outpart.addparam(
   601                 b'in-reply-to', pycompat.bytestr(part.id), mandatory=False
   613                 b'in-reply-to', pycompat.bytestr(part.id), mandatory=False
   602             )
   614             )
   603 
   615 
   604 
   616 
   605 def decodecaps(blob):
   617 def decodecaps(blob: bytes) -> "Capabilities":
   606     """decode a bundle2 caps bytes blob into a dictionary
   618     """decode a bundle2 caps bytes blob into a dictionary
   607 
   619 
   608     The blob is a list of capabilities (one per line)
   620     The blob is a list of capabilities (one per line)
   609     Capabilities may have values using a line of the form::
   621     Capabilities may have values using a line of the form::
   610 
   622 
   660     populate it. Then call `getchunks` to retrieve all the binary chunks of
   672     populate it. Then call `getchunks` to retrieve all the binary chunks of
   661     data that compose the bundle2 container."""
   673     data that compose the bundle2 container."""
   662 
   674 
   663     _magicstring = b'HG20'
   675     _magicstring = b'HG20'
   664 
   676 
   665     def __init__(self, ui, capabilities=()):
   677     def __init__(self, ui, capabilities: "Optional[Capabilities]" = None):
       
   678         if capabilities is None:
       
   679             capabilities = {}
       
   680 
   666         self.ui = ui
   681         self.ui = ui
   667         self._params = []
   682         self._params = []
   668         self._parts = []
   683         self._parts = []
   669         self.capabilities = dict(capabilities)
   684         self.capabilities: "Capabilities" = dict(capabilities)
   670         self._compengine = util.compengines.forbundletype(b'UN')
   685         self._compengine = util.compengines.forbundletype(b'UN')
   671         self._compopts = None
   686         self._compopts = None
   672         # If compression is being handled by a consumer of the raw
   687         # If compression is being handled by a consumer of the raw
   673         # data (e.g. the wire protocol), unsetting this flag tells
   688         # data (e.g. the wire protocol), unsetting this flag tells
   674         # consumers that the bundle is best left uncompressed.
   689         # consumers that the bundle is best left uncompressed.
  1610         return None
  1625         return None
  1611 
  1626 
  1612 
  1627 
  1613 # These are only the static capabilities.
  1628 # These are only the static capabilities.
  1614 # Check the 'getrepocaps' function for the rest.
  1629 # Check the 'getrepocaps' function for the rest.
  1615 capabilities = {
  1630 capabilities: "Capabilities" = {
  1616     b'HG20': (),
  1631     b'HG20': (),
  1617     b'bookmarks': (),
  1632     b'bookmarks': (),
  1618     b'error': (b'abort', b'unsupportedcontent', b'pushraced', b'pushkey'),
  1633     b'error': (b'abort', b'unsupportedcontent', b'pushraced', b'pushkey'),
  1619     b'listkeys': (),
  1634     b'listkeys': (),
  1620     b'pushkey': (),
  1635     b'pushkey': (),
  1624     b'phases': (b'heads',),
  1639     b'phases': (b'heads',),
  1625     b'stream': (b'v2',),
  1640     b'stream': (b'v2',),
  1626 }
  1641 }
  1627 
  1642 
  1628 
  1643 
  1629 def getrepocaps(repo, allowpushback=False, role=None):
  1644 # TODO: drop the default value for 'role'
       
  1645 def getrepocaps(repo, allowpushback: bool = False, role=None) -> "Capabilities":
  1630     """return the bundle2 capabilities for a given repo
  1646     """return the bundle2 capabilities for a given repo
  1631 
  1647 
  1632     Exists to allow extensions (like evolution) to mutate the capabilities.
  1648     Exists to allow extensions (like evolution) to mutate the capabilities.
  1633 
  1649 
  1634     The returned value is used for servers advertising their capabilities as
  1650     The returned value is used for servers advertising their capabilities as
  1673     # for legacy clients.
  1689     # for legacy clients.
  1674 
  1690 
  1675     return caps
  1691     return caps
  1676 
  1692 
  1677 
  1693 
  1678 def bundle2caps(remote):
  1694 def bundle2caps(remote) -> "Capabilities":
  1679     """return the bundle capabilities of a peer as dict"""
  1695     """return the bundle capabilities of a peer as dict"""
  1680     raw = remote.capable(b'bundle2')
  1696     raw = remote.capable(b'bundle2')
  1681     if not raw and raw != b'':
  1697     if not raw and raw != b'':
  1682         return {}
  1698         return {}
  1683     capsblob = urlreq.unquote(remote.capable(b'bundle2'))
  1699     capsblob = urlreq.unquote(remote.capable(b'bundle2'))
  1684     return decodecaps(capsblob)
  1700     return decodecaps(capsblob)
  1685 
  1701 
  1686 
  1702 
  1687 def obsmarkersversion(caps):
  1703 def obsmarkersversion(caps: "Capabilities"):
  1688     """extract the list of supported obsmarkers versions from a bundle2caps dict"""
  1704     """extract the list of supported obsmarkers versions from a bundle2caps dict"""
  1689     obscaps = caps.get(b'obsmarkers', ())
  1705     obscaps = caps.get(b'obsmarkers', ())
  1690     return [int(c[1:]) for c in obscaps if c.startswith(b'V')]
  1706     return [int(c[1:]) for c in obscaps if c.startswith(b'V')]
  1691 
  1707 
  1692 
  1708 
  1723         count = len(repo.revs(b'%ln and _internal()', outgoing.missing))
  1739         count = len(repo.revs(b'%ln and _internal()', outgoing.missing))
  1724         msg = "backup bundle would contains %d internal changesets"
  1740         msg = "backup bundle would contains %d internal changesets"
  1725         msg %= count
  1741         msg %= count
  1726         raise error.ProgrammingError(msg)
  1742         raise error.ProgrammingError(msg)
  1727 
  1743 
  1728     caps = {}
  1744     caps: "Capabilities" = {}
  1729     if opts.get(b'obsolescence', False):
  1745     if opts.get(b'obsolescence', False):
  1730         caps[b'obsmarkers'] = (b'V1',)
  1746         caps[b'obsmarkers'] = (b'V1',)
  1731     stream_version = opts.get(b'stream', b"")
  1747     stream_version = opts.get(b'stream', b"")
  1732     if stream_version == b"v2":
  1748     if stream_version == b"v2":
  1733         caps[b'stream'] = [b'v2']
  1749         caps[b'stream'] = [b'v2']