Show More
@@ -1,71 +1,232 | |||||
1 | # repository.py - Interfaces and base classes for repositories and peers. |
|
1 | # repository.py - Interfaces and base classes for repositories and peers. | |
2 | # |
|
2 | # | |
3 | # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com> |
|
3 | # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
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. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
10 | import abc |
|
10 | import abc | |
11 |
|
11 | |||
12 | class _basepeer(object): |
|
12 | class _basepeer(object): | |
13 | """Represents a "connection" to a repository. |
|
13 | """Represents a "connection" to a repository. | |
14 |
|
14 | |||
15 | This is the base interface for representing a connection to a repository. |
|
15 | This is the base interface for representing a connection to a repository. | |
16 | It holds basic properties and methods applicable to all peer types. |
|
16 | It holds basic properties and methods applicable to all peer types. | |
17 |
|
17 | |||
18 | This is not a complete interface definition and should not be used |
|
18 | This is not a complete interface definition and should not be used | |
19 | outside of this module. |
|
19 | outside of this module. | |
20 | """ |
|
20 | """ | |
21 | __metaclass__ = abc.ABCMeta |
|
21 | __metaclass__ = abc.ABCMeta | |
22 |
|
22 | |||
23 | @abc.abstractproperty |
|
23 | @abc.abstractproperty | |
24 | def ui(self): |
|
24 | def ui(self): | |
25 | """ui.ui instance.""" |
|
25 | """ui.ui instance.""" | |
26 |
|
26 | |||
27 | @abc.abstractmethod |
|
27 | @abc.abstractmethod | |
28 | def url(self): |
|
28 | def url(self): | |
29 | """Returns a URL string representing this peer. |
|
29 | """Returns a URL string representing this peer. | |
30 |
|
30 | |||
31 | Currently, implementations expose the raw URL used to construct the |
|
31 | Currently, implementations expose the raw URL used to construct the | |
32 | instance. It may contain credentials as part of the URL. The |
|
32 | instance. It may contain credentials as part of the URL. The | |
33 | expectations of the value aren't well-defined and this could lead to |
|
33 | expectations of the value aren't well-defined and this could lead to | |
34 | data leakage. |
|
34 | data leakage. | |
35 |
|
35 | |||
36 | TODO audit/clean consumers and more clearly define the contents of this |
|
36 | TODO audit/clean consumers and more clearly define the contents of this | |
37 | value. |
|
37 | value. | |
38 | """ |
|
38 | """ | |
39 |
|
39 | |||
40 | @abc.abstractmethod |
|
40 | @abc.abstractmethod | |
41 | def local(self): |
|
41 | def local(self): | |
42 | """Returns a local repository instance. |
|
42 | """Returns a local repository instance. | |
43 |
|
43 | |||
44 | If the peer represents a local repository, returns an object that |
|
44 | If the peer represents a local repository, returns an object that | |
45 | can be used to interface with it. Otherwise returns ``None``. |
|
45 | can be used to interface with it. Otherwise returns ``None``. | |
46 | """ |
|
46 | """ | |
47 |
|
47 | |||
48 | @abc.abstractmethod |
|
48 | @abc.abstractmethod | |
49 | def peer(self): |
|
49 | def peer(self): | |
50 | """Returns an object conforming to this interface. |
|
50 | """Returns an object conforming to this interface. | |
51 |
|
51 | |||
52 | Most implementations will ``return self``. |
|
52 | Most implementations will ``return self``. | |
53 | """ |
|
53 | """ | |
54 |
|
54 | |||
55 | @abc.abstractmethod |
|
55 | @abc.abstractmethod | |
56 | def canpush(self): |
|
56 | def canpush(self): | |
57 | """Returns a boolean indicating if this peer can be pushed to.""" |
|
57 | """Returns a boolean indicating if this peer can be pushed to.""" | |
58 |
|
58 | |||
59 | @abc.abstractmethod |
|
59 | @abc.abstractmethod | |
60 | def close(self): |
|
60 | def close(self): | |
61 | """Close the connection to this peer. |
|
61 | """Close the connection to this peer. | |
62 |
|
62 | |||
63 | This is called when the peer will no longer be used. Resources |
|
63 | This is called when the peer will no longer be used. Resources | |
64 | associated with the peer should be cleaned up. |
|
64 | associated with the peer should be cleaned up. | |
65 | """ |
|
65 | """ | |
66 |
|
66 | |||
67 | class peer(_basepeer): |
|
67 | class _basewirecommands(object): | |
|
68 | """Client-side interface for communicating over the wire protocol. | |||
|
69 | ||||
|
70 | This interface is used as a gateway to the Mercurial wire protocol. | |||
|
71 | methods commonly call wire protocol commands of the same name. | |||
|
72 | """ | |||
|
73 | __metaclass__ = abc.ABCMeta | |||
|
74 | ||||
|
75 | @abc.abstractmethod | |||
|
76 | def branchmap(self): | |||
|
77 | """Obtain heads in named branches. | |||
|
78 | ||||
|
79 | Returns a dict mapping branch name to an iterable of nodes that are | |||
|
80 | heads on that branch. | |||
|
81 | """ | |||
|
82 | ||||
|
83 | @abc.abstractmethod | |||
|
84 | def capabilities(self): | |||
|
85 | """Obtain capabilities of the peer. | |||
|
86 | ||||
|
87 | Returns a set of string capabilities. | |||
|
88 | """ | |||
|
89 | ||||
|
90 | @abc.abstractmethod | |||
|
91 | def debugwireargs(self, one, two, three=None, four=None, five=None): | |||
|
92 | """Used to facilitate debugging of arguments passed over the wire.""" | |||
|
93 | ||||
|
94 | @abc.abstractmethod | |||
|
95 | def getbundle(self, source, **kwargs): | |||
|
96 | """Obtain remote repository data as a bundle. | |||
|
97 | ||||
|
98 | This command is how the bulk of repository data is transferred from | |||
|
99 | the peer to the local repository | |||
|
100 | ||||
|
101 | Returns a generator of bundle data. | |||
|
102 | """ | |||
|
103 | ||||
|
104 | @abc.abstractmethod | |||
|
105 | def heads(self): | |||
|
106 | """Determine all known head revisions in the peer. | |||
|
107 | ||||
|
108 | Returns an iterable of binary nodes. | |||
|
109 | """ | |||
|
110 | ||||
|
111 | @abc.abstractmethod | |||
|
112 | def known(self, nodes): | |||
|
113 | """Determine whether multiple nodes are known. | |||
|
114 | ||||
|
115 | Accepts an iterable of nodes whose presence to check for. | |||
|
116 | ||||
|
117 | Returns an iterable of booleans indicating of the corresponding node | |||
|
118 | at that index is known to the peer. | |||
|
119 | """ | |||
|
120 | ||||
|
121 | @abc.abstractmethod | |||
|
122 | def listkeys(self, namespace): | |||
|
123 | """Obtain all keys in a pushkey namespace. | |||
|
124 | ||||
|
125 | Returns an iterable of key names. | |||
|
126 | """ | |||
|
127 | ||||
|
128 | @abc.abstractmethod | |||
|
129 | def lookup(self, key): | |||
|
130 | """Resolve a value to a known revision. | |||
|
131 | ||||
|
132 | Returns a binary node of the resolved revision on success. | |||
|
133 | """ | |||
|
134 | ||||
|
135 | @abc.abstractmethod | |||
|
136 | def pushkey(self, namespace, key, old, new): | |||
|
137 | """Set a value using the ``pushkey`` protocol. | |||
|
138 | ||||
|
139 | Arguments correspond to the pushkey namespace and key to operate on and | |||
|
140 | the old and new values for that key. | |||
|
141 | ||||
|
142 | Returns a string with the peer result. The value inside varies by the | |||
|
143 | namespace. | |||
|
144 | """ | |||
|
145 | ||||
|
146 | @abc.abstractmethod | |||
|
147 | def stream_out(self): | |||
|
148 | """Obtain streaming clone data. | |||
|
149 | ||||
|
150 | Successful result should be a generator of data chunks. | |||
|
151 | """ | |||
|
152 | ||||
|
153 | @abc.abstractmethod | |||
|
154 | def unbundle(self, bundle, heads, url): | |||
|
155 | """Transfer repository data to the peer. | |||
|
156 | ||||
|
157 | This is how the bulk of data during a push is transferred. | |||
|
158 | ||||
|
159 | Returns the integer number of heads added to the peer. | |||
|
160 | """ | |||
|
161 | ||||
|
162 | class _baselegacywirecommands(object): | |||
|
163 | """Interface for implementing support for legacy wire protocol commands. | |||
|
164 | ||||
|
165 | Wire protocol commands transition to legacy status when they are no longer | |||
|
166 | used by modern clients. To facilitate identifying which commands are | |||
|
167 | legacy, the interfaces are split. | |||
|
168 | """ | |||
|
169 | __metaclass__ = abc.ABCMeta | |||
|
170 | ||||
|
171 | @abc.abstractmethod | |||
|
172 | def between(self, pairs): | |||
|
173 | """Obtain nodes between pairs of nodes. | |||
|
174 | ||||
|
175 | ``pairs`` is an iterable of node pairs. | |||
|
176 | ||||
|
177 | Returns an iterable of iterables of nodes corresponding to each | |||
|
178 | requested pair. | |||
|
179 | """ | |||
|
180 | ||||
|
181 | @abc.abstractmethod | |||
|
182 | def branches(self, nodes): | |||
|
183 | """Obtain ancestor changesets of specific nodes back to a branch point. | |||
|
184 | ||||
|
185 | For each requested node, the peer finds the first ancestor node that is | |||
|
186 | a DAG root or is a merge. | |||
|
187 | ||||
|
188 | Returns an iterable of iterables with the resolved values for each node. | |||
|
189 | """ | |||
|
190 | ||||
|
191 | @abc.abstractmethod | |||
|
192 | def changegroup(self, nodes, kind): | |||
|
193 | """Obtain a changegroup with data for descendants of specified nodes.""" | |||
|
194 | ||||
|
195 | @abc.abstractmethod | |||
|
196 | def changegroupsubset(self, bases, heads, kind): | |||
|
197 | pass | |||
|
198 | ||||
|
199 | class peer(_basepeer, _basewirecommands): | |||
68 | """Unified interface and base class for peer repositories. |
|
200 | """Unified interface and base class for peer repositories. | |
69 |
|
201 | |||
70 |
All peer instances must inherit from this class |
|
202 | All peer instances must inherit from this class and conform to its | |
|
203 | interface. | |||
71 | """ |
|
204 | """ | |
|
205 | ||||
|
206 | @abc.abstractmethod | |||
|
207 | def iterbatch(self): | |||
|
208 | """Obtain an object to be used for multiple method calls. | |||
|
209 | ||||
|
210 | Various operations call several methods on peer instances. If each | |||
|
211 | method call were performed immediately and serially, this would | |||
|
212 | require round trips to remote peers and/or would slow down execution. | |||
|
213 | ||||
|
214 | Some peers have the ability to "batch" method calls to avoid costly | |||
|
215 | round trips or to facilitate concurrent execution. | |||
|
216 | ||||
|
217 | This method returns an object that can be used to indicate intent to | |||
|
218 | perform batched method calls. | |||
|
219 | ||||
|
220 | The returned object is a proxy of this peer. It intercepts calls to | |||
|
221 | batchable methods and queues them instead of performing them | |||
|
222 | immediately. This proxy object has a ``submit`` method that will | |||
|
223 | perform all queued batchable method calls. A ``results()`` method | |||
|
224 | exposes the results of queued/batched method calls. It is a generator | |||
|
225 | of results in the order they were called. | |||
|
226 | ||||
|
227 | Not all peers or wire protocol implementations may actually batch method | |||
|
228 | calls. However, they must all support this API. | |||
|
229 | """ | |||
|
230 | ||||
|
231 | class legacypeer(peer, _baselegacywirecommands): | |||
|
232 | """peer but with support for legacy wire protocol commands.""" |
General Comments 0
You need to be logged in to leave comments.
Login now