30 scmutil, |
30 scmutil, |
31 util, |
31 util, |
32 ) |
32 ) |
33 |
33 |
34 from .interfaces import repository |
34 from .interfaces import repository |
|
35 from .revlogutils import sidedata as sidedatamod |
35 |
36 |
36 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct(b"20s20s20s20s") |
37 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct(b"20s20s20s20s") |
37 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct(b"20s20s20s20s20s") |
38 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct(b"20s20s20s20s20s") |
38 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(b">20s20s20s20s20sH") |
39 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(b">20s20s20s20s20sH") |
39 |
40 |
200 return {} |
201 return {} |
201 headerdata = readexactly(self._stream, self.deltaheadersize) |
202 headerdata = readexactly(self._stream, self.deltaheadersize) |
202 header = self.deltaheader.unpack(headerdata) |
203 header = self.deltaheader.unpack(headerdata) |
203 delta = readexactly(self._stream, l - self.deltaheadersize) |
204 delta = readexactly(self._stream, l - self.deltaheadersize) |
204 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode) |
205 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode) |
205 return (node, p1, p2, cs, deltabase, delta, flags) |
206 # cg4 forward-compat |
|
207 sidedata = {} |
|
208 return (node, p1, p2, cs, deltabase, delta, flags, sidedata) |
206 |
209 |
207 def getchunks(self): |
210 def getchunks(self): |
208 """returns all the chunks contains in the bundle |
211 """returns all the chunks contains in the bundle |
209 |
212 |
210 Used when you need to forward the binary stream to a file or another |
213 Used when you need to forward the binary stream to a file or another |
548 d = chunkdata[b"filename"] |
551 d = chunkdata[b"filename"] |
549 repo.ui.debug(b"adding %s revisions\n" % d) |
552 repo.ui.debug(b"adding %s revisions\n" % d) |
550 deltas = self.deltaiter() |
553 deltas = self.deltaiter() |
551 if not repo.manifestlog.getstorage(d).addgroup(deltas, revmap, trp): |
554 if not repo.manifestlog.getstorage(d).addgroup(deltas, revmap, trp): |
552 raise error.Abort(_(b"received dir revlog group is empty")) |
555 raise error.Abort(_(b"received dir revlog group is empty")) |
|
556 |
|
557 |
|
558 class cg4unpacker(cg3unpacker): |
|
559 """Unpacker for cg4 streams. |
|
560 |
|
561 cg4 streams add support for exchanging sidedata. |
|
562 """ |
|
563 |
|
564 version = b'04' |
|
565 |
|
566 def deltachunk(self, prevnode): |
|
567 res = super(cg4unpacker, self).deltachunk(prevnode) |
|
568 if not res: |
|
569 return res |
|
570 |
|
571 (node, p1, p2, cs, deltabase, delta, flags, _sidedata) = res |
|
572 |
|
573 sidedata_raw = getchunk(self._stream) |
|
574 sidedata = {} |
|
575 if len(sidedata_raw) > 0: |
|
576 sidedata = sidedatamod.deserialize_sidedata(sidedata_raw) |
|
577 |
|
578 return node, p1, p2, cs, deltabase, delta, flags, sidedata |
553 |
579 |
554 |
580 |
555 class headerlessfixup(object): |
581 class headerlessfixup(object): |
556 def __init__(self, fh, h): |
582 def __init__(self, fh, h): |
557 self._h = h |
583 self._h = h |
891 |
918 |
892 fullnodes is the set of changelog nodes which should not be ellipsis |
919 fullnodes is the set of changelog nodes which should not be ellipsis |
893 nodes. We store this rather than the set of nodes that should be |
920 nodes. We store this rather than the set of nodes that should be |
894 ellipsis because for very large histories we expect this to be |
921 ellipsis because for very large histories we expect this to be |
895 significantly smaller. |
922 significantly smaller. |
|
923 |
|
924 remote_sidedata is the set of sidedata categories wanted by the remote. |
896 """ |
925 """ |
897 assert oldmatcher |
926 assert oldmatcher |
898 assert matcher |
927 assert matcher |
899 self._oldmatcher = oldmatcher |
928 self._oldmatcher = oldmatcher |
900 self._matcher = matcher |
929 self._matcher = matcher |
986 clstate[b'clrevtomanifestrev'], |
1015 clstate[b'clrevtomanifestrev'], |
987 ) |
1016 ) |
988 |
1017 |
989 for tree, deltas in it: |
1018 for tree, deltas in it: |
990 if tree: |
1019 if tree: |
991 assert self.version == b'03' |
1020 assert self.version in (b'03', b'04') |
992 chunk = _fileheader(tree) |
1021 chunk = _fileheader(tree) |
993 size += len(chunk) |
1022 size += len(chunk) |
994 yield chunk |
1023 yield chunk |
995 |
1024 |
996 for delta in deltas: |
1025 for delta in deltas: |
1451 bundlecaps, |
1482 bundlecaps, |
1452 ellipses=False, |
1483 ellipses=False, |
1453 shallow=False, |
1484 shallow=False, |
1454 ellipsisroots=None, |
1485 ellipsisroots=None, |
1455 fullnodes=None, |
1486 fullnodes=None, |
|
1487 remote_sidedata=None, |
1456 ): |
1488 ): |
1457 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1489 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1458 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags |
1490 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags |
1459 ) |
1491 ) |
1460 |
1492 |
1471 ellipsisroots=ellipsisroots, |
1503 ellipsisroots=ellipsisroots, |
1472 fullnodes=fullnodes, |
1504 fullnodes=fullnodes, |
1473 ) |
1505 ) |
1474 |
1506 |
1475 |
1507 |
|
1508 def _makecg4packer( |
|
1509 repo, |
|
1510 oldmatcher, |
|
1511 matcher, |
|
1512 bundlecaps, |
|
1513 ellipses=False, |
|
1514 shallow=False, |
|
1515 ellipsisroots=None, |
|
1516 fullnodes=None, |
|
1517 remote_sidedata=None, |
|
1518 ): |
|
1519 # Same header func as cg3. Sidedata is in a separate chunk from the delta to |
|
1520 # differenciate "raw delta" and sidedata. |
|
1521 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
|
1522 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags |
|
1523 ) |
|
1524 |
|
1525 return cgpacker( |
|
1526 repo, |
|
1527 oldmatcher, |
|
1528 matcher, |
|
1529 b'04', |
|
1530 builddeltaheader=builddeltaheader, |
|
1531 manifestsend=closechunk(), |
|
1532 bundlecaps=bundlecaps, |
|
1533 ellipses=ellipses, |
|
1534 shallow=shallow, |
|
1535 ellipsisroots=ellipsisroots, |
|
1536 fullnodes=fullnodes, |
|
1537 remote_sidedata=remote_sidedata, |
|
1538 ) |
|
1539 |
|
1540 |
1476 _packermap = { |
1541 _packermap = { |
1477 b'01': (_makecg1packer, cg1unpacker), |
1542 b'01': (_makecg1packer, cg1unpacker), |
1478 # cg2 adds support for exchanging generaldelta |
1543 # cg2 adds support for exchanging generaldelta |
1479 b'02': (_makecg2packer, cg2unpacker), |
1544 b'02': (_makecg2packer, cg2unpacker), |
1480 # cg3 adds support for exchanging revlog flags and treemanifests |
1545 # cg3 adds support for exchanging revlog flags and treemanifests |
1481 b'03': (_makecg3packer, cg3unpacker), |
1546 b'03': (_makecg3packer, cg3unpacker), |
|
1547 # ch4 adds support for exchanging sidedata |
|
1548 b'04': (_makecg4packer, cg4unpacker), |
1482 } |
1549 } |
1483 |
1550 |
1484 |
1551 |
1485 def allsupportedversions(repo): |
1552 def allsupportedversions(repo): |
1486 versions = set(_packermap.keys()) |
1553 versions = set(_packermap.keys()) |
1496 # contains both normal and tree manifest at the same time. so using |
1563 # contains both normal and tree manifest at the same time. so using |
1497 # older version to pull data is viable |
1564 # older version to pull data is viable |
1498 # |
1565 # |
1499 # (or even to push subset of history) |
1566 # (or even to push subset of history) |
1500 needv03 = True |
1567 needv03 = True |
1501 if b'exp-sidedata-flag' in repo.requirements: |
1568 has_revlogv2 = requirements.REVLOGV2_REQUIREMENT in repo.requirements |
1502 needv03 = True |
1569 if not has_revlogv2: |
1503 # don't attempt to use 01/02 until we do sidedata cleaning |
1570 versions.discard(b'04') |
1504 versions.discard(b'01') |
|
1505 versions.discard(b'02') |
|
1506 if not needv03: |
1571 if not needv03: |
1507 versions.discard(b'03') |
1572 versions.discard(b'03') |
1508 return versions |
1573 return versions |
1509 |
1574 |
1510 |
1575 |
1599 bundlecaps, |
1665 bundlecaps, |
1600 ellipses=ellipses, |
1666 ellipses=ellipses, |
1601 shallow=shallow, |
1667 shallow=shallow, |
1602 ellipsisroots=ellipsisroots, |
1668 ellipsisroots=ellipsisroots, |
1603 fullnodes=fullnodes, |
1669 fullnodes=fullnodes, |
|
1670 remote_sidedata=remote_sidedata, |
1604 ) |
1671 ) |
1605 |
1672 |
1606 |
1673 |
1607 def getunbundler(version, fh, alg, extras=None): |
1674 def getunbundler(version, fh, alg, extras=None): |
1608 return _packermap[version][1](fh, alg, extras=extras) |
1675 return _packermap[version][1](fh, alg, extras=extras) |
1642 version, |
1709 version, |
1643 source, |
1710 source, |
1644 fastpath=False, |
1711 fastpath=False, |
1645 bundlecaps=None, |
1712 bundlecaps=None, |
1646 matcher=None, |
1713 matcher=None, |
|
1714 remote_sidedata=None, |
1647 ): |
1715 ): |
1648 bundler = getbundler(version, repo, bundlecaps=bundlecaps, matcher=matcher) |
1716 bundler = getbundler( |
|
1717 version, |
|
1718 repo, |
|
1719 bundlecaps=bundlecaps, |
|
1720 matcher=matcher, |
|
1721 remote_sidedata=remote_sidedata, |
|
1722 ) |
1649 |
1723 |
1650 repo = repo.unfiltered() |
1724 repo = repo.unfiltered() |
1651 commonrevs = outgoing.common |
1725 commonrevs = outgoing.common |
1652 csets = outgoing.missing |
1726 csets = outgoing.missing |
1653 heads = outgoing.ancestorsof |
1727 heads = outgoing.ancestorsof |