Show More
@@ -0,0 +1,55 b'' | |||||
|
1 | # exchangev2.py - repository exchange for wire protocol version 2 | |||
|
2 | # | |||
|
3 | # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms of the | |||
|
6 | # GNU General Public License version 2 or any later version. | |||
|
7 | ||||
|
8 | from __future__ import absolute_import | |||
|
9 | ||||
|
10 | from .node import ( | |||
|
11 | nullid, | |||
|
12 | ) | |||
|
13 | from . import ( | |||
|
14 | setdiscovery, | |||
|
15 | ) | |||
|
16 | ||||
|
17 | def pull(pullop): | |||
|
18 | """Pull using wire protocol version 2.""" | |||
|
19 | repo = pullop.repo | |||
|
20 | remote = pullop.remote | |||
|
21 | ||||
|
22 | # Figure out what needs to be fetched. | |||
|
23 | common, fetch, remoteheads = _pullchangesetdiscovery( | |||
|
24 | repo, remote, pullop.heads, abortwhenunrelated=pullop.force) | |||
|
25 | ||||
|
26 | def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True): | |||
|
27 | """Determine which changesets need to be pulled.""" | |||
|
28 | ||||
|
29 | if heads: | |||
|
30 | knownnode = repo.changelog.hasnode | |||
|
31 | if all(knownnode(head) for head in heads): | |||
|
32 | return heads, False, heads | |||
|
33 | ||||
|
34 | # TODO wire protocol version 2 is capable of more efficient discovery | |||
|
35 | # than setdiscovery. Consider implementing something better. | |||
|
36 | common, fetch, remoteheads = setdiscovery.findcommonheads( | |||
|
37 | repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated) | |||
|
38 | ||||
|
39 | common = set(common) | |||
|
40 | remoteheads = set(remoteheads) | |||
|
41 | ||||
|
42 | # If a remote head is filtered locally, put it back in the common set. | |||
|
43 | # See the comment in exchange._pulldiscoverychangegroup() for more. | |||
|
44 | ||||
|
45 | if fetch and remoteheads: | |||
|
46 | nodemap = repo.unfiltered().changelog.nodemap | |||
|
47 | ||||
|
48 | common |= {head for head in remoteheads if head in nodemap} | |||
|
49 | ||||
|
50 | if set(remoteheads).issubset(common): | |||
|
51 | fetch = [] | |||
|
52 | ||||
|
53 | common.discard(nullid) | |||
|
54 | ||||
|
55 | return common, fetch, remoteheads |
@@ -0,0 +1,53 b'' | |||||
|
1 | Tests for wire protocol version 2 exchange. | |||
|
2 | Tests in this file should be folded into existing tests once protocol | |||
|
3 | v2 has enough features that it can be enabled via #testcase in existing | |||
|
4 | tests. | |||
|
5 | ||||
|
6 | $ . $TESTDIR/wireprotohelpers.sh | |||
|
7 | $ enablehttpv2client | |||
|
8 | ||||
|
9 | $ hg init server-simple | |||
|
10 | $ enablehttpv2 server-simple | |||
|
11 | $ cd server-simple | |||
|
12 | $ cat >> .hg/hgrc << EOF | |||
|
13 | > [phases] | |||
|
14 | > publish = false | |||
|
15 | > EOF | |||
|
16 | $ echo a0 > a | |||
|
17 | $ echo b0 > b | |||
|
18 | $ hg -q commit -A -m 'commit 0' | |||
|
19 | ||||
|
20 | $ echo a1 > a | |||
|
21 | $ hg commit -m 'commit 1' | |||
|
22 | $ hg phase --public -r . | |||
|
23 | $ echo a2 > a | |||
|
24 | $ hg commit -m 'commit 2' | |||
|
25 | ||||
|
26 | $ hg -q up -r 0 | |||
|
27 | $ echo b1 > b | |||
|
28 | $ hg -q commit -m 'head 2 commit 1' | |||
|
29 | $ echo b2 > b | |||
|
30 | $ hg -q commit -m 'head 2 commit 2' | |||
|
31 | ||||
|
32 | $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log | |||
|
33 | $ cat hg.pid > $DAEMON_PIDS | |||
|
34 | ||||
|
35 | $ cd .. | |||
|
36 | ||||
|
37 | Test basic clone | |||
|
38 | ||||
|
39 | $ hg --debug clone -U http://localhost:$HGPORT client-simple | |||
|
40 | using http://localhost:$HGPORT/ | |||
|
41 | sending capabilities command | |||
|
42 | query 1; heads | |||
|
43 | sending 2 commands | |||
|
44 | sending command heads: {} | |||
|
45 | sending command known: { | |||
|
46 | 'nodes': [] | |||
|
47 | } | |||
|
48 | received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation) | |||
|
49 | received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation) | |||
|
50 | received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) | |||
|
51 | received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation) | |||
|
52 | received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation) | |||
|
53 | received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) |
@@ -26,6 +26,7 b' from . import (' | |||||
26 | changegroup, |
|
26 | changegroup, | |
27 | discovery, |
|
27 | discovery, | |
28 | error, |
|
28 | error, | |
|
29 | exchangev2, | |||
29 | lock as lockmod, |
|
30 | lock as lockmod, | |
30 | logexchange, |
|
31 | logexchange, | |
31 | narrowspec, |
|
32 | narrowspec, | |
@@ -1506,17 +1507,21 b' def pull(repo, remote, heads=None, force' | |||||
1506 |
|
1507 | |||
1507 | pullop.trmanager = transactionmanager(repo, 'pull', remote.url()) |
|
1508 | pullop.trmanager = transactionmanager(repo, 'pull', remote.url()) | |
1508 | with repo.wlock(), repo.lock(), pullop.trmanager: |
|
1509 | with repo.wlock(), repo.lock(), pullop.trmanager: | |
1509 | # This should ideally be in _pullbundle2(). However, it needs to run |
|
1510 | # Use the modern wire protocol, if available. | |
1510 | # before discovery to avoid extra work. |
|
1511 | if remote.capable('exchangev2'): | |
1511 | _maybeapplyclonebundle(pullop) |
|
1512 | exchangev2.pull(pullop) | |
1512 | streamclone.maybeperformlegacystreamclone(pullop) |
|
1513 | else: | |
1513 | _pulldiscovery(pullop) |
|
1514 | # This should ideally be in _pullbundle2(). However, it needs to run | |
1514 | if pullop.canusebundle2: |
|
1515 | # before discovery to avoid extra work. | |
1515 |
_ |
|
1516 | _maybeapplyclonebundle(pullop) | |
1516 | _pullchangeset(pullop) |
|
1517 | streamclone.maybeperformlegacystreamclone(pullop) | |
1517 |
|
|
1518 | _pulldiscovery(pullop) | |
1518 | _pullbookmarks(pullop) |
|
1519 | if pullop.canusebundle2: | |
1519 |
_ |
|
1520 | _fullpullbundle2(repo, pullop) | |
|
1521 | _pullchangeset(pullop) | |||
|
1522 | _pullphase(pullop) | |||
|
1523 | _pullbookmarks(pullop) | |||
|
1524 | _pullobsolete(pullop) | |||
1520 |
|
1525 | |||
1521 | # storing remotenames |
|
1526 | # storing remotenames | |
1522 | if repo.ui.configbool('experimental', 'remotenames'): |
|
1527 | if repo.ui.configbool('experimental', 'remotenames'): |
@@ -802,7 +802,8 b' class httpv2peer(object):' | |||||
802 | return True |
|
802 | return True | |
803 |
|
803 | |||
804 | # Other concepts. |
|
804 | # Other concepts. | |
805 | if name in ('bundle2',): |
|
805 | # TODO remove exchangev2 once we have a command implemented. | |
|
806 | if name in ('bundle2', 'exchangev2'): | |||
806 | return True |
|
807 | return True | |
807 |
|
808 | |||
808 | # Alias command-* to presence of command of that name. |
|
809 | # Alias command-* to presence of command of that name. |
General Comments 0
You need to be logged in to leave comments.
Login now