##// END OF EJS Templates
repository: port peer interfaces to zope.interface...
Gregory Szorc -
r37336:39f7d4ee default
parent child Browse files
Show More
@@ -184,7 +184,7 b' class httppeer(wireproto.wirepeer):'
184 % (util.timer() - start, ret.code))
184 % (util.timer() - start, ret.code))
185 return ret
185 return ret
186
186
187 # Begin of _basepeer interface.
187 # Begin of ipeerconnection interface.
188
188
189 @util.propertycache
189 @util.propertycache
190 def ui(self):
190 def ui(self):
@@ -205,9 +205,9 b' class httppeer(wireproto.wirepeer):'
205 def close(self):
205 def close(self):
206 pass
206 pass
207
207
208 # End of _basepeer interface.
208 # End of ipeerconnection interface.
209
209
210 # Begin of _basewirepeer interface.
210 # Begin of ipeercommands interface.
211
211
212 def capabilities(self):
212 def capabilities(self):
213 # self._fetchcaps() should have been called as part of peer
213 # self._fetchcaps() should have been called as part of peer
@@ -215,7 +215,7 b' class httppeer(wireproto.wirepeer):'
215 assert self._caps is not None
215 assert self._caps is not None
216 return self._caps
216 return self._caps
217
217
218 # End of _basewirepeer interface.
218 # End of ipeercommands interface.
219
219
220 # look up capabilities only when needed
220 # look up capabilities only when needed
221
221
@@ -7,8 +7,6 b''
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import abc
11
12 from .i18n import _
10 from .i18n import _
13 from .thirdparty.zope import (
11 from .thirdparty.zope import (
14 interface as zi,
12 interface as zi,
@@ -17,7 +15,7 b' from . import ('
17 error,
15 error,
18 )
16 )
19
17
20 class _basepeer(object):
18 class ipeerconnection(zi.Interface):
21 """Represents a "connection" to a repository.
19 """Represents a "connection" to a repository.
22
20
23 This is the base interface for representing a connection to a repository.
21 This is the base interface for representing a connection to a repository.
@@ -26,14 +24,9 b' class _basepeer(object):'
26 This is not a complete interface definition and should not be used
24 This is not a complete interface definition and should not be used
27 outside of this module.
25 outside of this module.
28 """
26 """
29 __metaclass__ = abc.ABCMeta
27 ui = zi.Attribute("""ui.ui instance""")
30
28
31 @abc.abstractproperty
29 def url():
32 def ui(self):
33 """ui.ui instance."""
34
35 @abc.abstractmethod
36 def url(self):
37 """Returns a URL string representing this peer.
30 """Returns a URL string representing this peer.
38
31
39 Currently, implementations expose the raw URL used to construct the
32 Currently, implementations expose the raw URL used to construct the
@@ -45,62 +38,53 b' class _basepeer(object):'
45 value.
38 value.
46 """
39 """
47
40
48 @abc.abstractmethod
41 def local():
49 def local(self):
50 """Returns a local repository instance.
42 """Returns a local repository instance.
51
43
52 If the peer represents a local repository, returns an object that
44 If the peer represents a local repository, returns an object that
53 can be used to interface with it. Otherwise returns ``None``.
45 can be used to interface with it. Otherwise returns ``None``.
54 """
46 """
55
47
56 @abc.abstractmethod
48 def peer():
57 def peer(self):
58 """Returns an object conforming to this interface.
49 """Returns an object conforming to this interface.
59
50
60 Most implementations will ``return self``.
51 Most implementations will ``return self``.
61 """
52 """
62
53
63 @abc.abstractmethod
54 def canpush():
64 def canpush(self):
65 """Returns a boolean indicating if this peer can be pushed to."""
55 """Returns a boolean indicating if this peer can be pushed to."""
66
56
67 @abc.abstractmethod
57 def close():
68 def close(self):
69 """Close the connection to this peer.
58 """Close the connection to this peer.
70
59
71 This is called when the peer will no longer be used. Resources
60 This is called when the peer will no longer be used. Resources
72 associated with the peer should be cleaned up.
61 associated with the peer should be cleaned up.
73 """
62 """
74
63
75 class _basewirecommands(object):
64 class ipeercommands(zi.Interface):
76 """Client-side interface for communicating over the wire protocol.
65 """Client-side interface for communicating over the wire protocol.
77
66
78 This interface is used as a gateway to the Mercurial wire protocol.
67 This interface is used as a gateway to the Mercurial wire protocol.
79 methods commonly call wire protocol commands of the same name.
68 methods commonly call wire protocol commands of the same name.
80 """
69 """
81 __metaclass__ = abc.ABCMeta
82
70
83 @abc.abstractmethod
71 def branchmap():
84 def branchmap(self):
85 """Obtain heads in named branches.
72 """Obtain heads in named branches.
86
73
87 Returns a dict mapping branch name to an iterable of nodes that are
74 Returns a dict mapping branch name to an iterable of nodes that are
88 heads on that branch.
75 heads on that branch.
89 """
76 """
90
77
91 @abc.abstractmethod
78 def capabilities():
92 def capabilities(self):
93 """Obtain capabilities of the peer.
79 """Obtain capabilities of the peer.
94
80
95 Returns a set of string capabilities.
81 Returns a set of string capabilities.
96 """
82 """
97
83
98 @abc.abstractmethod
84 def debugwireargs(one, two, three=None, four=None, five=None):
99 def debugwireargs(self, one, two, three=None, four=None, five=None):
100 """Used to facilitate debugging of arguments passed over the wire."""
85 """Used to facilitate debugging of arguments passed over the wire."""
101
86
102 @abc.abstractmethod
87 def getbundle(source, **kwargs):
103 def getbundle(self, source, **kwargs):
104 """Obtain remote repository data as a bundle.
88 """Obtain remote repository data as a bundle.
105
89
106 This command is how the bulk of repository data is transferred from
90 This command is how the bulk of repository data is transferred from
@@ -109,15 +93,13 b' class _basewirecommands(object):'
109 Returns a generator of bundle data.
93 Returns a generator of bundle data.
110 """
94 """
111
95
112 @abc.abstractmethod
96 def heads():
113 def heads(self):
114 """Determine all known head revisions in the peer.
97 """Determine all known head revisions in the peer.
115
98
116 Returns an iterable of binary nodes.
99 Returns an iterable of binary nodes.
117 """
100 """
118
101
119 @abc.abstractmethod
102 def known(nodes):
120 def known(self, nodes):
121 """Determine whether multiple nodes are known.
103 """Determine whether multiple nodes are known.
122
104
123 Accepts an iterable of nodes whose presence to check for.
105 Accepts an iterable of nodes whose presence to check for.
@@ -126,22 +108,19 b' class _basewirecommands(object):'
126 at that index is known to the peer.
108 at that index is known to the peer.
127 """
109 """
128
110
129 @abc.abstractmethod
111 def listkeys(namespace):
130 def listkeys(self, namespace):
131 """Obtain all keys in a pushkey namespace.
112 """Obtain all keys in a pushkey namespace.
132
113
133 Returns an iterable of key names.
114 Returns an iterable of key names.
134 """
115 """
135
116
136 @abc.abstractmethod
117 def lookup(key):
137 def lookup(self, key):
138 """Resolve a value to a known revision.
118 """Resolve a value to a known revision.
139
119
140 Returns a binary node of the resolved revision on success.
120 Returns a binary node of the resolved revision on success.
141 """
121 """
142
122
143 @abc.abstractmethod
123 def pushkey(namespace, key, old, new):
144 def pushkey(self, namespace, key, old, new):
145 """Set a value using the ``pushkey`` protocol.
124 """Set a value using the ``pushkey`` protocol.
146
125
147 Arguments correspond to the pushkey namespace and key to operate on and
126 Arguments correspond to the pushkey namespace and key to operate on and
@@ -151,15 +130,13 b' class _basewirecommands(object):'
151 namespace.
130 namespace.
152 """
131 """
153
132
154 @abc.abstractmethod
133 def stream_out():
155 def stream_out(self):
156 """Obtain streaming clone data.
134 """Obtain streaming clone data.
157
135
158 Successful result should be a generator of data chunks.
136 Successful result should be a generator of data chunks.
159 """
137 """
160
138
161 @abc.abstractmethod
139 def unbundle(bundle, heads, url):
162 def unbundle(self, bundle, heads, url):
163 """Transfer repository data to the peer.
140 """Transfer repository data to the peer.
164
141
165 This is how the bulk of data during a push is transferred.
142 This is how the bulk of data during a push is transferred.
@@ -167,17 +144,15 b' class _basewirecommands(object):'
167 Returns the integer number of heads added to the peer.
144 Returns the integer number of heads added to the peer.
168 """
145 """
169
146
170 class _baselegacywirecommands(object):
147 class ipeerlegacycommands(zi.Interface):
171 """Interface for implementing support for legacy wire protocol commands.
148 """Interface for implementing support for legacy wire protocol commands.
172
149
173 Wire protocol commands transition to legacy status when they are no longer
150 Wire protocol commands transition to legacy status when they are no longer
174 used by modern clients. To facilitate identifying which commands are
151 used by modern clients. To facilitate identifying which commands are
175 legacy, the interfaces are split.
152 legacy, the interfaces are split.
176 """
153 """
177 __metaclass__ = abc.ABCMeta
178
154
179 @abc.abstractmethod
155 def between(pairs):
180 def between(self, pairs):
181 """Obtain nodes between pairs of nodes.
156 """Obtain nodes between pairs of nodes.
182
157
183 ``pairs`` is an iterable of node pairs.
158 ``pairs`` is an iterable of node pairs.
@@ -186,8 +161,7 b' class _baselegacywirecommands(object):'
186 requested pair.
161 requested pair.
187 """
162 """
188
163
189 @abc.abstractmethod
164 def branches(nodes):
190 def branches(self, nodes):
191 """Obtain ancestor changesets of specific nodes back to a branch point.
165 """Obtain ancestor changesets of specific nodes back to a branch point.
192
166
193 For each requested node, the peer finds the first ancestor node that is
167 For each requested node, the peer finds the first ancestor node that is
@@ -196,23 +170,18 b' class _baselegacywirecommands(object):'
196 Returns an iterable of iterables with the resolved values for each node.
170 Returns an iterable of iterables with the resolved values for each node.
197 """
171 """
198
172
199 @abc.abstractmethod
173 def changegroup(nodes, kind):
200 def changegroup(self, nodes, kind):
201 """Obtain a changegroup with data for descendants of specified nodes."""
174 """Obtain a changegroup with data for descendants of specified nodes."""
202
175
203 @abc.abstractmethod
176 def changegroupsubset(bases, heads, kind):
204 def changegroupsubset(self, bases, heads, kind):
205 pass
177 pass
206
178
207 class peer(_basepeer, _basewirecommands):
179 class ipeerbase(ipeerconnection, ipeercommands):
208 """Unified interface and base class for peer repositories.
180 """Unified interface for peer repositories.
209
181
210 All peer instances must inherit from this class and conform to its
182 All peer instances must conform to this interface.
211 interface.
212 """
183 """
213
184 def iterbatch():
214 @abc.abstractmethod
215 def iterbatch(self):
216 """Obtain an object to be used for multiple method calls.
185 """Obtain an object to be used for multiple method calls.
217
186
218 Various operations call several methods on peer instances. If each
187 Various operations call several methods on peer instances. If each
@@ -236,7 +205,7 b' class peer(_basepeer, _basewirecommands)'
236 calls. However, they must all support this API.
205 calls. However, they must all support this API.
237 """
206 """
238
207
239 def capable(self, name):
208 def capable(name):
240 """Determine support for a named capability.
209 """Determine support for a named capability.
241
210
242 Returns ``False`` if capability not supported.
211 Returns ``False`` if capability not supported.
@@ -244,6 +213,21 b' class peer(_basepeer, _basewirecommands)'
244 Returns ``True`` if boolean capability is supported. Returns a string
213 Returns ``True`` if boolean capability is supported. Returns a string
245 if capability support is non-boolean.
214 if capability support is non-boolean.
246 """
215 """
216
217 def requirecap(name, purpose):
218 """Require a capability to be present.
219
220 Raises a ``CapabilityError`` if the capability isn't present.
221 """
222
223 class ipeerbaselegacycommands(ipeerbase, ipeerlegacycommands):
224 """Unified peer interface that supports legacy commands."""
225
226 @zi.implementer(ipeerbase)
227 class peer(object):
228 """Base class for peer repositories."""
229
230 def capable(self, name):
247 caps = self.capabilities()
231 caps = self.capabilities()
248 if name in caps:
232 if name in caps:
249 return True
233 return True
@@ -256,10 +240,6 b' class peer(_basepeer, _basewirecommands)'
256 return False
240 return False
257
241
258 def requirecap(self, name, purpose):
242 def requirecap(self, name, purpose):
259 """Require a capability to be present.
260
261 Raises a ``CapabilityError`` if the capability isn't present.
262 """
263 if self.capable(name):
243 if self.capable(name):
264 return
244 return
265
245
@@ -267,7 +247,8 b' class peer(_basepeer, _basewirecommands)'
267 _('cannot %s; remote repository does not support the %r '
247 _('cannot %s; remote repository does not support the %r '
268 'capability') % (purpose, name))
248 'capability') % (purpose, name))
269
249
270 class legacypeer(peer, _baselegacywirecommands):
250 @zi.implementer(ipeerbaselegacycommands)
251 class legacypeer(peer):
271 """peer but with support for legacy wire protocol commands."""
252 """peer but with support for legacy wire protocol commands."""
272
253
273 class completelocalrepository(zi.Interface):
254 class completelocalrepository(zi.Interface):
@@ -377,7 +377,7 b' class sshv1peer(wireproto.wirepeer):'
377 'batch',
377 'batch',
378 }
378 }
379
379
380 # Begin of _basepeer interface.
380 # Begin of ipeerconnection interface.
381
381
382 @util.propertycache
382 @util.propertycache
383 def ui(self):
383 def ui(self):
@@ -398,14 +398,14 b' class sshv1peer(wireproto.wirepeer):'
398 def close(self):
398 def close(self):
399 pass
399 pass
400
400
401 # End of _basepeer interface.
401 # End of ipeerconnection interface.
402
402
403 # Begin of _basewirecommands interface.
403 # Begin of ipeercommands interface.
404
404
405 def capabilities(self):
405 def capabilities(self):
406 return self._caps
406 return self._caps
407
407
408 # End of _basewirecommands interface.
408 # End of ipeercommands interface.
409
409
410 def _readerr(self):
410 def _readerr(self):
411 _forwardoutput(self.ui, self._pipee)
411 _forwardoutput(self.ui, self._pipee)
@@ -192,7 +192,7 b' class wirepeer(repository.legacypeer):'
192 See also httppeer.py and sshpeer.py for protocol-specific
192 See also httppeer.py and sshpeer.py for protocol-specific
193 implementations of this interface.
193 implementations of this interface.
194 """
194 """
195 # Begin of basewirepeer interface.
195 # Begin of ipeercommands interface.
196
196
197 def iterbatch(self):
197 def iterbatch(self):
198 return remoteiterbatcher(self)
198 return remoteiterbatcher(self)
@@ -353,9 +353,9 b' class wirepeer(repository.legacypeer):'
353 ret = bundle2.getunbundler(self.ui, stream)
353 ret = bundle2.getunbundler(self.ui, stream)
354 return ret
354 return ret
355
355
356 # End of basewirepeer interface.
356 # End of ipeercommands interface.
357
357
358 # Begin of baselegacywirepeer interface.
358 # Begin of ipeerlegacycommands interface.
359
359
360 def branches(self, nodes):
360 def branches(self, nodes):
361 n = encodelist(nodes)
361 n = encodelist(nodes)
@@ -391,7 +391,7 b' class wirepeer(repository.legacypeer):'
391 bases=bases, heads=heads)
391 bases=bases, heads=heads)
392 return changegroupmod.cg1unpacker(f, 'UN')
392 return changegroupmod.cg1unpacker(f, 'UN')
393
393
394 # End of baselegacywirepeer interface.
394 # End of ipeerlegacycommands interface.
395
395
396 def _submitbatch(self, req):
396 def _submitbatch(self, req):
397 """run batch request <req> on the server
397 """run batch request <req> on the server
@@ -25,35 +25,6 b' from mercurial import ('
25
25
26 rootdir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
26 rootdir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
27
27
28 def checkobject(o):
29 """Verify a constructed object conforms to interface rules.
30
31 An object must have __abstractmethods__ defined.
32
33 All "public" attributes of the object (attributes not prefixed with
34 an underscore) must be in __abstractmethods__ or appear on a base class
35 with __abstractmethods__.
36 """
37 name = o.__class__.__name__
38
39 allowed = set()
40 for cls in o.__class__.__mro__:
41 if not getattr(cls, '__abstractmethods__', set()):
42 continue
43
44 allowed |= cls.__abstractmethods__
45 allowed |= {a for a in dir(cls) if not a.startswith('_')}
46
47 if not allowed:
48 print('%s does not have abstract methods' % name)
49 return
50
51 public = {a for a in dir(o) if not a.startswith('_')}
52
53 for attr in sorted(public - allowed):
54 print('public attributes not in abstract interface: %s.%s' % (
55 name, attr))
56
57 def checkzobject(o):
28 def checkzobject(o):
58 """Verify an object with a zope interface."""
29 """Verify an object with a zope interface."""
59 ifaces = zi.providedBy(o)
30 ifaces = zi.providedBy(o)
@@ -108,16 +79,34 b' def main():'
108 # Needed so we can open a local repo with obsstore without a warning.
79 # Needed so we can open a local repo with obsstore without a warning.
109 ui.setconfig('experimental', 'evolution.createmarkers', True)
80 ui.setconfig('experimental', 'evolution.createmarkers', True)
110
81
111 checkobject(badpeer())
82 checkzobject(badpeer())
112 checkobject(httppeer.httppeer(None, None, None, dummyopener()))
83
113 checkobject(localrepo.localpeer(dummyrepo()))
84 ziverify.verifyClass(repository.ipeerbaselegacycommands,
114 checkobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, dummypipe(),
85 httppeer.httppeer)
115 dummypipe(), None, None))
86 checkzobject(httppeer.httppeer(None, None, None, dummyopener()))
116 checkobject(sshpeer.sshv2peer(ui, 'ssh://localhost/foo', None, dummypipe(),
87
117 dummypipe(), None, None))
88 ziverify.verifyClass(repository.ipeerbase,
118 checkobject(bundlerepo.bundlepeer(dummyrepo()))
89 localrepo.localpeer)
119 checkobject(statichttprepo.statichttppeer(dummyrepo()))
90 checkzobject(localrepo.localpeer(dummyrepo()))
120 checkobject(unionrepo.unionpeer(dummyrepo()))
91
92 ziverify.verifyClass(repository.ipeerbaselegacycommands,
93 sshpeer.sshv1peer)
94 checkzobject(sshpeer.sshv1peer(ui, 'ssh://localhost/foo', None, dummypipe(),
95 dummypipe(), None, None))
96
97 ziverify.verifyClass(repository.ipeerbaselegacycommands,
98 sshpeer.sshv2peer)
99 checkzobject(sshpeer.sshv2peer(ui, 'ssh://localhost/foo', None, dummypipe(),
100 dummypipe(), None, None))
101
102 ziverify.verifyClass(repository.ipeerbase, bundlerepo.bundlepeer)
103 checkzobject(bundlerepo.bundlepeer(dummyrepo()))
104
105 ziverify.verifyClass(repository.ipeerbase, statichttprepo.statichttppeer)
106 checkzobject(statichttprepo.statichttppeer(dummyrepo()))
107
108 ziverify.verifyClass(repository.ipeerbase, unionrepo.unionpeer)
109 checkzobject(unionrepo.unionpeer(dummyrepo()))
121
110
122 ziverify.verifyClass(repository.completelocalrepository,
111 ziverify.verifyClass(repository.completelocalrepository,
123 localrepo.localrepository)
112 localrepo.localrepository)
@@ -1,2 +1,2 b''
1 public attributes not in abstract interface: badpeer.badattribute
1 public attribute not declared in interfaces: badpeer.badattribute
2 public attributes not in abstract interface: badpeer.badmethod
2 public attribute not declared in interfaces: badpeer.badmethod
General Comments 0
You need to be logged in to leave comments. Login now