mercurial/wireprotov2server.py
changeset 40176 41263df08109
parent 40175 6c42409691ec
child 40177 41e2633bcd00
equal deleted inserted replaced
40175:6c42409691ec 40176:41263df08109
   775     Extensions can monkeypatch this function to provide custom caching
   775     Extensions can monkeypatch this function to provide custom caching
   776     backends.
   776     backends.
   777     """
   777     """
   778     return None
   778     return None
   779 
   779 
       
   780 def resolvenodes(repo, revisions):
       
   781     """Resolve nodes from a revisions specifier data structure."""
       
   782     cl = repo.changelog
       
   783     clhasnode = cl.hasnode
       
   784 
       
   785     seen = set()
       
   786     nodes = []
       
   787 
       
   788     if not isinstance(revisions, list):
       
   789         raise error.WireprotoCommandError('revisions must be defined as an '
       
   790                                           'array')
       
   791 
       
   792     for spec in revisions:
       
   793         if b'type' not in spec:
       
   794             raise error.WireprotoCommandError(
       
   795                 'type key not present in revision specifier')
       
   796 
       
   797         typ = spec[b'type']
       
   798 
       
   799         if typ == b'changesetexplicit':
       
   800             if b'nodes' not in spec:
       
   801                 raise error.WireprotoCommandError(
       
   802                     'nodes key not present in changesetexplicit revision '
       
   803                     'specifier')
       
   804 
       
   805             for node in spec[b'nodes']:
       
   806                 if node not in seen:
       
   807                     nodes.append(node)
       
   808                     seen.add(node)
       
   809 
       
   810         elif typ == b'changesetexplicitdepth':
       
   811             for key in (b'nodes', b'depth'):
       
   812                 if key not in spec:
       
   813                     raise error.WireprotoCommandError(
       
   814                         '%s key not present in changesetexplicitdepth revision '
       
   815                         'specifier', (key,))
       
   816 
       
   817             for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
       
   818                                  spec[b'depth'] - 1):
       
   819                 node = cl.node(rev)
       
   820 
       
   821                 if node not in seen:
       
   822                     nodes.append(node)
       
   823                     seen.add(node)
       
   824 
       
   825         elif typ == b'changesetdagrange':
       
   826             for key in (b'roots', b'heads'):
       
   827                 if key not in spec:
       
   828                     raise error.WireprotoCommandError(
       
   829                         '%s key not present in changesetdagrange revision '
       
   830                         'specifier', (key,))
       
   831 
       
   832             if not spec[b'heads']:
       
   833                 raise error.WireprotoCommandError(
       
   834                     'heads key in changesetdagrange cannot be empty')
       
   835 
       
   836             if spec[b'roots']:
       
   837                 common = [n for n in spec[b'roots'] if clhasnode(n)]
       
   838             else:
       
   839                 common = [nullid]
       
   840 
       
   841             for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
       
   842                 if n not in seen:
       
   843                     nodes.append(n)
       
   844                     seen.add(n)
       
   845 
       
   846         else:
       
   847             raise error.WireprotoCommandError(
       
   848                 'unknown revision specifier type: %s', (typ,))
       
   849 
       
   850     return nodes
       
   851 
   780 @wireprotocommand('branchmap', permission='pull')
   852 @wireprotocommand('branchmap', permission='pull')
   781 def branchmapv2(repo, proto):
   853 def branchmapv2(repo, proto):
   782     yield {encoding.fromlocal(k): v
   854     yield {encoding.fromlocal(k): v
   783            for k, v in repo.branchmap().iteritems()}
   855            for k, v in repo.branchmap().iteritems()}
   784 
   856 
   787     yield _capabilitiesv2(repo, proto)
   859     yield _capabilitiesv2(repo, proto)
   788 
   860 
   789 @wireprotocommand(
   861 @wireprotocommand(
   790     'changesetdata',
   862     'changesetdata',
   791     args={
   863     args={
   792         'noderange': {
   864         'revisions': {
   793             'type': 'list',
   865             'type': 'list',
   794             'default': lambda: None,
   866             'example': [{
   795             'example': [[b'0123456...'], [b'abcdef...']],
   867                 b'type': b'changesetexplicit',
   796         },
   868                 b'nodes': [b'abcdef...'],
   797         'nodes': {
   869             }],
   798             'type': 'list',
       
   799             'default': lambda: None,
       
   800             'example': [b'0123456...'],
       
   801         },
       
   802         'nodesdepth': {
       
   803             'type': 'int',
       
   804             'default': lambda: None,
       
   805             'example': 10,
       
   806         },
   870         },
   807         'fields': {
   871         'fields': {
   808             'type': 'set',
   872             'type': 'set',
   809             'default': set,
   873             'default': set,
   810             'example': {b'parents', b'revision'},
   874             'example': {b'parents', b'revision'},
   811             'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
   875             'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
   812         },
   876         },
   813     },
   877     },
   814     permission='pull')
   878     permission='pull')
   815 def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
   879 def changesetdata(repo, proto, revisions, fields):
   816     # TODO look for unknown fields and abort when they can't be serviced.
   880     # TODO look for unknown fields and abort when they can't be serviced.
   817     # This could probably be validated by dispatcher using validvalues.
   881     # This could probably be validated by dispatcher using validvalues.
   818 
   882 
   819     if noderange is None and nodes is None:
       
   820         raise error.WireprotoCommandError(
       
   821             'noderange or nodes must be defined')
       
   822 
       
   823     if nodesdepth is not None and nodes is None:
       
   824         raise error.WireprotoCommandError(
       
   825             'nodesdepth requires the nodes argument')
       
   826 
       
   827     if noderange is not None:
       
   828         if len(noderange) != 2:
       
   829             raise error.WireprotoCommandError(
       
   830                 'noderange must consist of 2 elements')
       
   831 
       
   832         if not noderange[1]:
       
   833             raise error.WireprotoCommandError(
       
   834                 'heads in noderange request cannot be empty')
       
   835 
       
   836     cl = repo.changelog
   883     cl = repo.changelog
   837     hasnode = cl.hasnode
   884     outgoing = resolvenodes(repo, revisions)
   838 
       
   839     seen = set()
       
   840     outgoing = []
       
   841 
       
   842     if nodes is not None:
       
   843         outgoing = [n for n in nodes if hasnode(n)]
       
   844 
       
   845         if nodesdepth:
       
   846             outgoing = [cl.node(r) for r in
       
   847                         repo.revs(b'ancestors(%ln, %d)', outgoing,
       
   848                                   nodesdepth - 1)]
       
   849 
       
   850         seen |= set(outgoing)
       
   851 
       
   852     if noderange is not None:
       
   853         if noderange[0]:
       
   854             common = [n for n in noderange[0] if hasnode(n)]
       
   855         else:
       
   856             common = [nullid]
       
   857 
       
   858         for n in discovery.outgoing(repo, common, noderange[1]).missing:
       
   859             if n not in seen:
       
   860                 outgoing.append(n)
       
   861             # Don't need to add to seen here because this is the final
       
   862             # source of nodes and there should be no duplicates in this
       
   863             # list.
       
   864 
       
   865     seen.clear()
       
   866     publishing = repo.publishing()
   885     publishing = repo.publishing()
   867 
   886 
   868     if outgoing:
   887     if outgoing:
   869         repo.hook('preoutgoing', throw=True, source='serve')
   888         repo.hook('preoutgoing', throw=True, source='serve')
   870 
   889