959 caps = set(['HG2X']) |
959 caps = set(['HG2X']) |
960 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) |
960 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) |
961 caps.add('bundle2=' + urllib.quote(capsblob)) |
961 caps.add('bundle2=' + urllib.quote(capsblob)) |
962 return caps |
962 return caps |
963 |
963 |
|
964 # List of names of steps to perform for a bundle2 for getbundle, order matters. |
|
965 getbundle2partsorder = [] |
|
966 |
|
967 # Mapping between step name and function |
|
968 # |
|
969 # This exists to help extensions wrap steps if necessary |
|
970 getbundle2partsmapping = {} |
|
971 |
|
972 def getbundle2partsgenerator(stepname): |
|
973 """decorator for function generating bundle2 part for getbundle |
|
974 |
|
975 The function is added to the step -> function mapping and appended to the |
|
976 list of steps. Beware that decorated functions will be added in order |
|
977 (this may matter). |
|
978 |
|
979 You can only use this decorator for new steps, if you want to wrap a step |
|
980 from an extension, attack the getbundle2partsmapping dictionary directly.""" |
|
981 def dec(func): |
|
982 assert stepname not in getbundle2partsmapping |
|
983 getbundle2partsmapping[stepname] = func |
|
984 getbundle2partsorder.append(stepname) |
|
985 return func |
|
986 return dec |
|
987 |
964 def getbundle(repo, source, heads=None, common=None, bundlecaps=None, |
988 def getbundle(repo, source, heads=None, common=None, bundlecaps=None, |
965 **kwargs): |
989 **kwargs): |
966 """return a full bundle (with potentially multiple kind of parts) |
990 """return a full bundle (with potentially multiple kind of parts) |
967 |
991 |
968 Could be a bundle HG10 or a bundle HG2X depending on bundlecaps |
992 Could be a bundle HG10 or a bundle HG2X depending on bundlecaps |
974 have a clearer idea of the API we what to query different data. |
998 have a clearer idea of the API we what to query different data. |
975 |
999 |
976 The implementation is at a very early stage and will get massive rework |
1000 The implementation is at a very early stage and will get massive rework |
977 when the API of bundle is refined. |
1001 when the API of bundle is refined. |
978 """ |
1002 """ |
979 cg = None |
1003 # bundle10 case |
980 if kwargs.get('cg', True): |
|
981 # build changegroup bundle here. |
|
982 cg = changegroup.getchangegroup(repo, source, heads=heads, |
|
983 common=common, bundlecaps=bundlecaps) |
|
984 elif 'HG2X' not in bundlecaps: |
|
985 raise ValueError(_('request for bundle10 must include changegroup')) |
|
986 if bundlecaps is None or 'HG2X' not in bundlecaps: |
1004 if bundlecaps is None or 'HG2X' not in bundlecaps: |
|
1005 if bundlecaps and not kwargs.get('cg', True): |
|
1006 raise ValueError(_('request for bundle10 must include changegroup')) |
|
1007 |
987 if kwargs: |
1008 if kwargs: |
988 raise ValueError(_('unsupported getbundle arguments: %s') |
1009 raise ValueError(_('unsupported getbundle arguments: %s') |
989 % ', '.join(sorted(kwargs.keys()))) |
1010 % ', '.join(sorted(kwargs.keys()))) |
990 return cg |
1011 return changegroup.getchangegroup(repo, source, heads=heads, |
991 # very crude first implementation, |
1012 common=common, bundlecaps=bundlecaps) |
992 # the bundle API will change and the generation will be done lazily. |
1013 |
|
1014 # bundle20 case |
993 b2caps = {} |
1015 b2caps = {} |
994 for bcaps in bundlecaps: |
1016 for bcaps in bundlecaps: |
995 if bcaps.startswith('bundle2='): |
1017 if bcaps.startswith('bundle2='): |
996 blob = urllib.unquote(bcaps[len('bundle2='):]) |
1018 blob = urllib.unquote(bcaps[len('bundle2='):]) |
997 b2caps.update(bundle2.decodecaps(blob)) |
1019 b2caps.update(bundle2.decodecaps(blob)) |
998 bundler = bundle2.bundle20(repo.ui, b2caps) |
1020 bundler = bundle2.bundle20(repo.ui, b2caps) |
|
1021 |
|
1022 for name in getbundle2partsorder: |
|
1023 func = getbundle2partsmapping[name] |
|
1024 func(bundler, repo, source, heads=heads, common=common, |
|
1025 bundlecaps=bundlecaps, b2caps=b2caps, **kwargs) |
|
1026 |
|
1027 return util.chunkbuffer(bundler.getchunks()) |
|
1028 |
|
1029 @getbundle2partsgenerator('changegroup') |
|
1030 def _getbundlechangegrouppart(bundler, repo, source, heads=None, common=None, |
|
1031 bundlecaps=None, b2caps=None, **kwargs): |
|
1032 """add a changegroup part to the requested bundle""" |
|
1033 cg = None |
|
1034 if kwargs.get('cg', True): |
|
1035 # build changegroup bundle here. |
|
1036 cg = changegroup.getchangegroup(repo, source, heads=heads, |
|
1037 common=common, bundlecaps=bundlecaps) |
|
1038 |
999 if cg: |
1039 if cg: |
1000 bundler.newpart('b2x:changegroup', data=cg.getchunks()) |
1040 bundler.newpart('b2x:changegroup', data=cg.getchunks()) |
|
1041 |
|
1042 @getbundle2partsgenerator('listkeys') |
|
1043 def _getbundlelistkeysparts(bundler, repo, source, heads=None, common=None, |
|
1044 bundlecaps=None, b2caps=None, **kwargs): |
|
1045 """add parts containing listkeys namespaces to the requested bundle""" |
1001 listkeys = kwargs.get('listkeys', ()) |
1046 listkeys = kwargs.get('listkeys', ()) |
1002 for namespace in listkeys: |
1047 for namespace in listkeys: |
1003 part = bundler.newpart('b2x:listkeys') |
1048 part = bundler.newpart('b2x:listkeys') |
1004 part.addparam('namespace', namespace) |
1049 part.addparam('namespace', namespace) |
1005 keys = repo.listkeys(namespace).items() |
1050 keys = repo.listkeys(namespace).items() |
1006 part.data = pushkey.encodekeys(keys) |
1051 part.data = pushkey.encodekeys(keys) |
1007 _getbundleobsmarkerpart(bundler, repo, source, heads=heads, common=common, |
1052 |
1008 bundlecaps=bundlecaps, b2caps=b2caps, **kwargs) |
1053 @getbundle2partsgenerator('obsmarkers') |
1009 _getbundleextrapart(bundler, repo, source, heads=heads, common=common, |
|
1010 bundlecaps=bundlecaps, b2caps=b2caps, **kwargs) |
|
1011 return util.chunkbuffer(bundler.getchunks()) |
|
1012 |
|
1013 def _getbundleobsmarkerpart(bundler, repo, source, heads=None, common=None, |
1054 def _getbundleobsmarkerpart(bundler, repo, source, heads=None, common=None, |
1014 bundlecaps=None, b2caps=None, **kwargs): |
1055 bundlecaps=None, b2caps=None, **kwargs): |
1015 """add an obsolescence markers part to the requested bundle""" |
1056 """add an obsolescence markers part to the requested bundle""" |
1016 if kwargs.get('obsmarkers', False): |
1057 if kwargs.get('obsmarkers', False): |
1017 if heads is None: |
1058 if heads is None: |
1018 heads = repo.heads() |
1059 heads = repo.heads() |
1019 subset = [c.node() for c in repo.set('::%ln', heads)] |
1060 subset = [c.node() for c in repo.set('::%ln', heads)] |
1020 markers = repo.obsstore.relevantmarkers(subset) |
1061 markers = repo.obsstore.relevantmarkers(subset) |
1021 buildobsmarkerspart(bundler, markers) |
1062 buildobsmarkerspart(bundler, markers) |
1022 |
1063 |
|
1064 @getbundle2partsgenerator('extra') |
1023 def _getbundleextrapart(bundler, repo, source, heads=None, common=None, |
1065 def _getbundleextrapart(bundler, repo, source, heads=None, common=None, |
1024 bundlecaps=None, b2caps=None, **kwargs): |
1066 bundlecaps=None, b2caps=None, **kwargs): |
1025 """hook function to let extensions add parts to the requested bundle""" |
1067 """hook function to let extensions add parts to the requested bundle""" |
1026 pass |
1068 pass |
1027 |
1069 |