47 remoteversions = bundle2.obsmarkersversion(bundler.capabilities) |
47 remoteversions = bundle2.obsmarkersversion(bundler.capabilities) |
48 version = obsolete.commonversion(remoteversions) |
48 version = obsolete.commonversion(remoteversions) |
49 if version is None: |
49 if version is None: |
50 raise ValueError('bundler do not support common obsmarker format') |
50 raise ValueError('bundler do not support common obsmarker format') |
51 stream = obsolete.encodemarkers(markers, True, version=version) |
51 stream = obsolete.encodemarkers(markers, True, version=version) |
52 return bundler.newpart('b2x:obsmarkers', data=stream) |
52 return bundler.newpart('obsmarkers', data=stream) |
53 return None |
53 return None |
54 |
54 |
55 def _canusebundle2(op): |
55 def _canusebundle2(op): |
56 """return true if a pull/push can use bundle2 |
56 """return true if a pull/push can use bundle2 |
57 |
57 |
58 Feel free to nuke this function when we drop the experimental option""" |
58 Feel free to nuke this function when we drop the experimental option""" |
59 return (op.repo.ui.configbool('experimental', 'bundle2-exp', False) |
59 return (op.repo.ui.configbool('experimental', 'bundle2-exp', False) |
60 and op.remote.capable('bundle2-exp')) |
60 and op.remote.capable('bundle2')) |
61 |
61 |
62 |
62 |
63 class pushoperation(object): |
63 class pushoperation(object): |
64 """A object that represent a single push operation |
64 """A object that represent a single push operation |
65 |
65 |
457 return |
457 return |
458 pushop.repo.prepushoutgoinghooks(pushop.repo, |
458 pushop.repo.prepushoutgoinghooks(pushop.repo, |
459 pushop.remote, |
459 pushop.remote, |
460 pushop.outgoing) |
460 pushop.outgoing) |
461 if not pushop.force: |
461 if not pushop.force: |
462 bundler.newpart('b2x:check:heads', data=iter(pushop.remoteheads)) |
462 bundler.newpart('check:heads', data=iter(pushop.remoteheads)) |
463 b2caps = bundle2.bundle2caps(pushop.remote) |
463 b2caps = bundle2.bundle2caps(pushop.remote) |
464 version = None |
464 version = None |
465 cgversions = b2caps.get('b2x:changegroup') |
465 cgversions = b2caps.get('changegroup') |
466 if not cgversions: # 3.1 and 3.2 ship with an empty value |
466 if not cgversions: # 3.1 and 3.2 ship with an empty value |
467 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push', |
467 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push', |
468 pushop.outgoing) |
468 pushop.outgoing) |
469 else: |
469 else: |
470 cgversions = [v for v in cgversions if v in changegroup.packermap] |
470 cgversions = [v for v in cgversions if v in changegroup.packermap] |
472 raise ValueError(_('no common changegroup version')) |
472 raise ValueError(_('no common changegroup version')) |
473 version = max(cgversions) |
473 version = max(cgversions) |
474 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push', |
474 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push', |
475 pushop.outgoing, |
475 pushop.outgoing, |
476 version=version) |
476 version=version) |
477 cgpart = bundler.newpart('b2x:changegroup', data=cg) |
477 cgpart = bundler.newpart('changegroup', data=cg) |
478 if version is not None: |
478 if version is not None: |
479 cgpart.addparam('version', version) |
479 cgpart.addparam('version', version) |
480 def handlereply(op): |
480 def handlereply(op): |
481 """extract addchangegroup returns from server reply""" |
481 """extract addchangegroup returns from server reply""" |
482 cgreplies = op.records.getreplies(cgpart.id) |
482 cgreplies = op.records.getreplies(cgpart.id) |
488 def _pushb2phases(pushop, bundler): |
488 def _pushb2phases(pushop, bundler): |
489 """handle phase push through bundle2""" |
489 """handle phase push through bundle2""" |
490 if 'phases' in pushop.stepsdone: |
490 if 'phases' in pushop.stepsdone: |
491 return |
491 return |
492 b2caps = bundle2.bundle2caps(pushop.remote) |
492 b2caps = bundle2.bundle2caps(pushop.remote) |
493 if not 'b2x:pushkey' in b2caps: |
493 if not 'pushkey' in b2caps: |
494 return |
494 return |
495 pushop.stepsdone.add('phases') |
495 pushop.stepsdone.add('phases') |
496 part2node = [] |
496 part2node = [] |
497 enc = pushkey.encode |
497 enc = pushkey.encode |
498 for newremotehead in pushop.outdatedphases: |
498 for newremotehead in pushop.outdatedphases: |
499 part = bundler.newpart('b2x:pushkey') |
499 part = bundler.newpart('pushkey') |
500 part.addparam('namespace', enc('phases')) |
500 part.addparam('namespace', enc('phases')) |
501 part.addparam('key', enc(newremotehead.hex())) |
501 part.addparam('key', enc(newremotehead.hex())) |
502 part.addparam('old', enc(str(phases.draft))) |
502 part.addparam('old', enc(str(phases.draft))) |
503 part.addparam('new', enc(str(phases.public))) |
503 part.addparam('new', enc(str(phases.public))) |
504 part2node.append((part.id, newremotehead)) |
504 part2node.append((part.id, newremotehead)) |
531 def _pushb2bookmarks(pushop, bundler): |
531 def _pushb2bookmarks(pushop, bundler): |
532 """handle phase push through bundle2""" |
532 """handle phase push through bundle2""" |
533 if 'bookmarks' in pushop.stepsdone: |
533 if 'bookmarks' in pushop.stepsdone: |
534 return |
534 return |
535 b2caps = bundle2.bundle2caps(pushop.remote) |
535 b2caps = bundle2.bundle2caps(pushop.remote) |
536 if 'b2x:pushkey' not in b2caps: |
536 if 'pushkey' not in b2caps: |
537 return |
537 return |
538 pushop.stepsdone.add('bookmarks') |
538 pushop.stepsdone.add('bookmarks') |
539 part2book = [] |
539 part2book = [] |
540 enc = pushkey.encode |
540 enc = pushkey.encode |
541 for book, old, new in pushop.outbookmarks: |
541 for book, old, new in pushop.outbookmarks: |
542 part = bundler.newpart('b2x:pushkey') |
542 part = bundler.newpart('pushkey') |
543 part.addparam('namespace', enc('bookmarks')) |
543 part.addparam('namespace', enc('bookmarks')) |
544 part.addparam('key', enc(book)) |
544 part.addparam('key', enc(book)) |
545 part.addparam('old', enc(old)) |
545 part.addparam('old', enc(old)) |
546 part.addparam('new', enc(new)) |
546 part.addparam('new', enc(new)) |
547 action = 'update' |
547 action = 'update' |
581 and pushop.ui.configbool('experimental', 'bundle2.pushback')) |
581 and pushop.ui.configbool('experimental', 'bundle2.pushback')) |
582 |
582 |
583 # create reply capability |
583 # create reply capability |
584 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo, |
584 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo, |
585 allowpushback=pushback)) |
585 allowpushback=pushback)) |
586 bundler.newpart('b2x:replycaps', data=capsblob) |
586 bundler.newpart('replycaps', data=capsblob) |
587 replyhandlers = [] |
587 replyhandlers = [] |
588 for partgenname in b2partsgenorder: |
588 for partgenname in b2partsgenorder: |
589 partgen = b2partsgenmapping[partgenname] |
589 partgen = b2partsgenmapping[partgenname] |
590 ret = partgen(pushop, bundler) |
590 ret = partgen(pushop, bundler) |
591 if callable(ret): |
591 if callable(ret): |
973 pullop.stepsdone.add('changegroup') |
973 pullop.stepsdone.add('changegroup') |
974 |
974 |
975 kwargs['common'] = pullop.common |
975 kwargs['common'] = pullop.common |
976 kwargs['heads'] = pullop.heads or pullop.rheads |
976 kwargs['heads'] = pullop.heads or pullop.rheads |
977 kwargs['cg'] = pullop.fetch |
977 kwargs['cg'] = pullop.fetch |
978 if 'b2x:listkeys' in remotecaps: |
978 if 'listkeys' in remotecaps: |
979 kwargs['listkeys'] = ['phase', 'bookmarks'] |
979 kwargs['listkeys'] = ['phase', 'bookmarks'] |
980 if not pullop.fetch: |
980 if not pullop.fetch: |
981 pullop.repo.ui.status(_("no changes found\n")) |
981 pullop.repo.ui.status(_("no changes found\n")) |
982 pullop.cgresult = 0 |
982 pullop.cgresult = 0 |
983 else: |
983 else: |
1126 pullop.repo.invalidatevolatilesets() |
1126 pullop.repo.invalidatevolatilesets() |
1127 return tr |
1127 return tr |
1128 |
1128 |
1129 def caps20to10(repo): |
1129 def caps20to10(repo): |
1130 """return a set with appropriate options to use bundle20 during getbundle""" |
1130 """return a set with appropriate options to use bundle20 during getbundle""" |
1131 caps = set(['HG2Y']) |
1131 caps = set(['HG20']) |
1132 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) |
1132 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) |
1133 caps.add('bundle2=' + urllib.quote(capsblob)) |
1133 caps.add('bundle2=' + urllib.quote(capsblob)) |
1134 return caps |
1134 return caps |
1135 |
1135 |
1136 # List of names of steps to perform for a bundle2 for getbundle, order matters. |
1136 # List of names of steps to perform for a bundle2 for getbundle, order matters. |
1159 |
1159 |
1160 def getbundle(repo, source, heads=None, common=None, bundlecaps=None, |
1160 def getbundle(repo, source, heads=None, common=None, bundlecaps=None, |
1161 **kwargs): |
1161 **kwargs): |
1162 """return a full bundle (with potentially multiple kind of parts) |
1162 """return a full bundle (with potentially multiple kind of parts) |
1163 |
1163 |
1164 Could be a bundle HG10 or a bundle HG2Y depending on bundlecaps |
1164 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps |
1165 passed. For now, the bundle can contain only changegroup, but this will |
1165 passed. For now, the bundle can contain only changegroup, but this will |
1166 changes when more part type will be available for bundle2. |
1166 changes when more part type will be available for bundle2. |
1167 |
1167 |
1168 This is different from changegroup.getchangegroup that only returns an HG10 |
1168 This is different from changegroup.getchangegroup that only returns an HG10 |
1169 changegroup bundle. They may eventually get reunited in the future when we |
1169 changegroup bundle. They may eventually get reunited in the future when we |
1210 """add a changegroup part to the requested bundle""" |
1210 """add a changegroup part to the requested bundle""" |
1211 cg = None |
1211 cg = None |
1212 if kwargs.get('cg', True): |
1212 if kwargs.get('cg', True): |
1213 # build changegroup bundle here. |
1213 # build changegroup bundle here. |
1214 version = None |
1214 version = None |
1215 cgversions = b2caps.get('b2x:changegroup') |
1215 cgversions = b2caps.get('changegroup') |
1216 if not cgversions: # 3.1 and 3.2 ship with an empty value |
1216 if not cgversions: # 3.1 and 3.2 ship with an empty value |
1217 cg = changegroup.getchangegroupraw(repo, source, heads=heads, |
1217 cg = changegroup.getchangegroupraw(repo, source, heads=heads, |
1218 common=common, |
1218 common=common, |
1219 bundlecaps=bundlecaps) |
1219 bundlecaps=bundlecaps) |
1220 else: |
1220 else: |
1226 common=common, |
1226 common=common, |
1227 bundlecaps=bundlecaps, |
1227 bundlecaps=bundlecaps, |
1228 version=version) |
1228 version=version) |
1229 |
1229 |
1230 if cg: |
1230 if cg: |
1231 part = bundler.newpart('b2x:changegroup', data=cg) |
1231 part = bundler.newpart('changegroup', data=cg) |
1232 if version is not None: |
1232 if version is not None: |
1233 part.addparam('version', version) |
1233 part.addparam('version', version) |
1234 |
1234 |
1235 @getbundle2partsgenerator('listkeys') |
1235 @getbundle2partsgenerator('listkeys') |
1236 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None, |
1236 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None, |
1237 b2caps=None, **kwargs): |
1237 b2caps=None, **kwargs): |
1238 """add parts containing listkeys namespaces to the requested bundle""" |
1238 """add parts containing listkeys namespaces to the requested bundle""" |
1239 listkeys = kwargs.get('listkeys', ()) |
1239 listkeys = kwargs.get('listkeys', ()) |
1240 for namespace in listkeys: |
1240 for namespace in listkeys: |
1241 part = bundler.newpart('b2x:listkeys') |
1241 part = bundler.newpart('listkeys') |
1242 part.addparam('namespace', namespace) |
1242 part.addparam('namespace', namespace) |
1243 keys = repo.listkeys(namespace).items() |
1243 keys = repo.listkeys(namespace).items() |
1244 part.data = pushkey.encodekeys(keys) |
1244 part.data = pushkey.encodekeys(keys) |
1245 |
1245 |
1246 @getbundle2partsgenerator('obsmarkers') |
1246 @getbundle2partsgenerator('obsmarkers') |
1286 if util.safehasattr(cg, 'params'): |
1286 if util.safehasattr(cg, 'params'): |
1287 try: |
1287 try: |
1288 tr = repo.transaction('unbundle') |
1288 tr = repo.transaction('unbundle') |
1289 tr.hookargs['source'] = source |
1289 tr.hookargs['source'] = source |
1290 tr.hookargs['url'] = url |
1290 tr.hookargs['url'] = url |
1291 tr.hookargs['bundle2-exp'] = '1' |
1291 tr.hookargs['bundle2'] = '1' |
1292 r = bundle2.processbundle(repo, cg, lambda: tr).reply |
1292 r = bundle2.processbundle(repo, cg, lambda: tr).reply |
1293 p = lambda: tr.writepending() and repo.root or "" |
1293 p = lambda: tr.writepending() and repo.root or "" |
1294 repo.hook('b2x-pretransactionclose', throw=True, pending=p, |
1294 repo.hook('b2x-pretransactionclose', throw=True, pending=p, |
1295 **tr.hookargs) |
1295 **tr.hookargs) |
1296 hookargs = dict(tr.hookargs) |
1296 hookargs = dict(tr.hookargs) |