38
37
hooks: An instance of SmartServerHooks.
41
def __init__(self, backing_transport, host='127.0.0.1', port=0,
42
root_client_path='/'):
40
def __init__(self, backing_transport, host='127.0.0.1', port=0):
43
41
"""Construct a new server.
45
43
To actually start it running, call either start_background_thread or
48
:param backing_transport: The transport to serve.
49
46
:param host: Name of the interface to listen on.
50
47
:param port: TCP port to listen on, or 0 to allocate a transient port.
51
:param root_client_path: The client path that will correspond to root
54
49
# let connections timeout so that we get a chance to terminate
55
50
# Keep a reference to the exceptions we want to catch because the socket
67
62
self.backing_transport = backing_transport
68
63
self._started = threading.Event()
69
64
self._stopped = threading.Event()
70
self.root_client_path = root_client_path
73
67
self._should_terminate = False
74
# for hooks we are letting code know that a server has started (and
76
# There are three interesting urls:
77
# The URL the server can be contacted on. (e.g. bzr://host/)
78
# The URL that a commit done on the same machine as the server will
79
# have within the servers space. (e.g. file:///home/user/source)
80
# The URL that will be given to other hooks in the same process -
81
# the URL of the backing transport itself. (e.g. chroot+:///)
82
# We need all three because:
83
# * other machines see the first
84
# * local commits on this machine should be able to be mapped to
86
# * commits the server does itself need to be mapped across to this
88
# The latter two urls are different aliases to the servers url,
89
# so we group those in a list - as there might be more aliases
91
backing_urls = [self.backing_transport.base]
93
backing_urls.append(self.backing_transport.external_url())
94
except errors.InProcessTransport:
96
68
for hook in SmartTCPServer.hooks['server_started']:
97
hook(backing_urls, self.get_url())
69
hook(self.backing_transport.base, self.get_url())
98
70
self._started.set()
128
100
# ignore errors on close
130
102
for hook in SmartTCPServer.hooks['server_stopped']:
131
hook(backing_urls, self.get_url())
103
hook(self.backing_transport.base, self.get_url())
133
105
def get_url(self):
134
106
"""Return the url of the server"""
139
111
# propogates to the newly accepted socket.
140
112
conn.setblocking(True)
141
113
conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
142
handler = SmartServerSocketStreamMedium(
143
conn, self.backing_transport, self.root_client_path)
114
handler = SmartServerSocketStreamMedium(conn, self.backing_transport)
144
115
connection_thread = threading.Thread(None, handler.serve, name='smart-server-child')
145
116
connection_thread.setDaemon(True)
146
117
connection_thread.start()
192
163
Hooks.__init__(self)
193
164
# Introduced in 0.16:
194
165
# invoked whenever the server starts serving a directory.
195
# The api signature is (backing urls, public url).
166
# The api signature is (backing url, public url).
196
167
self['server_started'] = []
197
168
# Introduced in 0.16:
198
169
# invoked whenever the server stops serving a directory.
199
# The api signature is (backing urls, public url).
170
# The api signature is (backing url, public url).
200
171
self['server_stopped'] = []
202
173
SmartTCPServer.hooks = SmartServerHooks()
211
182
def __init__(self):
212
183
SmartTCPServer.__init__(self, None)
213
self.client_path_extra = None
215
185
def get_backing_transport(self, backing_transport_server):
216
186
"""Get a backing transport from a server we are decorating."""
217
187
return transport.get_transport(backing_transport_server.get_url())
219
def setUp(self, backing_transport_server=None,
220
client_path_extra='/extra/'):
221
"""Set up server for testing.
223
:param backing_transport_server: backing server to use. If not
224
specified, a LocalURLServer at the current working directory will
226
:param client_path_extra: a path segment starting with '/' to append to
227
the root URL for this server. For instance, a value of '/foo/bar/'
228
will mean the root of the backing transport will be published at a
229
URL like `bzr://127.0.0.1:nnnn/foo/bar/`, rather than
230
`bzr://127.0.0.1:nnnn/`. Default value is `extra`, so that tests
231
by default will fail unless they do the necessary path translation.
233
assert client_path_extra.startswith('/')
189
def setUp(self, backing_transport_server=None):
190
"""Set up server for testing"""
234
191
from bzrlib.transport.chroot import ChrootServer
235
192
if backing_transport_server is None:
236
193
from bzrlib.transport.local import LocalURLServer
240
197
self.chroot_server.setUp()
241
198
self.backing_transport = transport.get_transport(
242
199
self.chroot_server.get_url())
243
self.root_client_path = self.client_path_extra = client_path_extra
244
200
self.start_background_thread()
246
202
def tearDown(self):
247
203
self.stop_background_thread()
248
204
self.chroot_server.tearDown()
251
url = super(SmartTCPServer_for_testing, self).get_url()
252
assert url.endswith('/')
253
return url[:-1] + self.client_path_extra
255
206
def get_bogus_url(self):
256
207
"""Return a URL which will fail to connect"""
257
208
return 'bzr://127.0.0.1:1/'