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