+#
+# BitBake Base Server Code
+#
+# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
+# Copyright (C) 2006 - 2008 Richard Purdie
+# Copyright (C) 2013 Alexandru Damian
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+""" Base code for Bitbake server process
+
+Have a common base for that all Bitbake server classes ensures a consistent
+approach to the interface, and minimize risks associated with code duplication.
+
+"""
+
+""" BaseImplServer() the base class for all XXServer() implementations.
+
+ These classes contain the actual code that runs the server side, i.e.
+ listens for the commands and executes them. Although these implementations
+ contain all the data of the original bitbake command, i.e the cooker instance,
+ they may well run on a different process or even machine.
+
+"""
+
+class BaseImplServer():
+ def __init__(self):
+ self._idlefuns = {}
+
+ def addcooker(self, cooker):
+ self.cooker = cooker
+
+ def register_idle_function(self, function, data):
+ """Register a function to be called while the server is idle"""
+ assert hasattr(function, '__call__')
+ self._idlefuns[function] = data
+
+
+
+""" BitBakeBaseServerConnection class is the common ancestor to all
+ BitBakeServerConnection classes.
+
+ These classes control the remote server. The only command currently
+ implemented is the terminate() command.
+
+"""
+
+class BitBakeBaseServerConnection():
+ def __init__(self, serverImpl):
+ pass
+
+ def terminate(self):
+ pass
+
+
+""" BitBakeBaseServer class is the common ancestor to all Bitbake servers
+
+ Derive this class in order to implement a BitBakeServer which is the
+ controlling stub for the actual server implementation
+
+"""
+class BitBakeBaseServer(object):
+ def initServer(self):
+ self.serverImpl = None # we ensure a runtime crash if not overloaded
+ self.connection = None
+ return
+
+ def addcooker(self, cooker):
+ self.cooker = cooker
+ self.serverImpl.addcooker(cooker)
+
+ def getServerIdleCB(self):
+ return self.serverImpl.register_idle_function
+
+ def saveConnectionDetails(self):
+ return
+
+ def detach(self):
+ return
+
+ def establishConnection(self):
+ raise "Must redefine the %s.establishConnection()" % self.__class__.__name__
+
+ def endSession(self):
+ self.connection.terminate()
from Queue import Empty
from multiprocessing import Event, Process, util, Queue, Pipe, queues
+from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
+
logger = logging.getLogger('BitBake')
class ServerCommunicator():
print("EventAdapter puked: %s" % str(err))
-class ProcessServer(Process):
+class ProcessServer(Process, BaseImplServer):
profile_filename = "profile.log"
profile_processed_filename = "profile.log.processed"
def __init__(self, command_channel, event_queue):
+ BaseImplServer.__init__(self)
Process.__init__(self)
self.command_channel = command_channel
self.event_queue = event_queue
self.event = EventAdapter(event_queue)
- self._idlefunctions = {}
self.quit = False
self.keep_running = Event()
self.keep_running.set()
- def register_idle_function(self, function, data):
- """Register a function to be called while the server is idle"""
- assert hasattr(function, '__call__')
- self._idlefunctions[function] = data
-
def run(self):
for event in bb.event.ui_queue:
self.event_queue.put(event)
def idle_commands(self, delay):
nextsleep = delay
- for function, data in self._idlefunctions.items():
+ for function, data in self._idlefuns.items():
try:
retval = function(self, data, False)
if retval is False:
- del self._idlefunctions[function]
+ del self._idlefuns[function]
elif retval is True:
nextsleep = None
elif nextsleep is None:
if (2, 6, 0) <= sys.version_info < (2, 6, 3):
_bootstrap = bootstrap_2_6_6
-class BitBakeServerConnection():
- def __init__(self, server):
- self.server = server
- self.procserver = server.server
- self.connection = ServerCommunicator(server.ui_channel)
- self.events = server.event_queue
+class BitBakeProcessServerConnection(BitBakeBaseServerConnection):
+ def __init__(self, serverImpl, ui_channel, event_queue):
+ self.procserver = serverImpl
+ self.ui_channel = ui_channel
+ self.event_queue = event_queue
+ self.connection = ServerCommunicator(self.ui_channel)
+ self.events = self.event_queue
def terminate(self, force = False):
signal.signal(signal.SIGINT, signal.SIG_IGN)
self.procserver.join()
while True:
try:
- event = self.server.event_queue.get(block=False)
+ event = self.event_queue.get(block=False)
except (Empty, IOError):
break
if isinstance(event, logging.LogRecord):
logger.handle(event)
- self.server.ui_channel.close()
- self.server.event_queue.close()
+ self.ui_channel.close()
+ self.event_queue.close()
if force:
sys.exit(1)
return None
-class BitBakeServer(object):
+class BitBakeServer(BitBakeBaseServer):
def initServer(self):
# establish communication channels. We use bidirectional pipes for
# ui <--> server command/response pairs
#
self.ui_channel, self.server_channel = Pipe()
self.event_queue = ProcessEventQueue(0)
-
- self.server = ProcessServer(self.server_channel, self.event_queue)
-
- def addcooker(self, cooker):
- self.cooker = cooker
- self.server.cooker = cooker
-
- def getServerIdleCB(self):
- return self.server.register_idle_function
-
- def saveConnectionDetails(self):
- return
+ self.serverImpl = ProcessServer(self.server_channel, self.event_queue)
def detach(self):
- self.server.start()
+ self.serverImpl.start()
return
def establishConnection(self):
- self.connection = BitBakeServerConnection(self)
+ self.connection = BitBakeProcessServerConnection(self.serverImpl, self.ui_channel, self.event_queue)
signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True))
return self.connection
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import inspect, select
+from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
+
if sys.hexversion < 0x020600F0:
print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
sys.exit(1)
"""
Register a remote UI Event Handler
"""
- print "registering handler %s:%s" % (host,port)
connection = xmlrpclib.ServerProxy("http://%s:%d/" % (host, port), allow_none=True)
client_hash = "%s:%d" % (host, port)
if self.clients.has_key(client_hash):
"""
Unregister a remote UI Event Handler
"""
- print "unregistering handler %s:%s" % (host,port)
client_thread = self.clients[client_hash]
if client_thread:
bb.event.unregister_UIHhandler(self.clients_ui_ids[client_hash])
self.handle_request()
self.server_close()
-class BitBakeXMLRPCServer(SimpleXMLRPCServer):
+
+class XMLRPCProxyServer(BaseImplServer):
+ """ not a real working server, but a stub for a proxy server connection
+
+ """
+ def __init__(self, host, port):
+ self.host = host
+ self.port = port
+
+class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
# remove this when you're done with debugging
# allow_reuse_address = True
"""
Constructor
"""
+ BaseImplServer.__init__(self)
SimpleXMLRPCServer.__init__(self, interface,
requestHandler=BitBakeXMLRPCRequestHandler,
logRequests=False, allow_none=True)
- self._idlefuns = {}
self.host, self.port = self.socket.getsockname()
self.connection_token = None
#self.register_introspection_functions()
self.interface = interface
def addcooker(self, cooker):
- self.cooker = cooker
+ BaseImplServer.addcooker(self, cooker)
self.commands.cooker = cooker
def autoregister_all_functions(self, context, prefix):
if name.startswith(prefix):
self.register_function(method, name[len(prefix):])
- def register_idle_function(self, function, data):
- """Register a function to be called while the server is idle"""
- assert hasattr(function, '__call__')
- self._idlefuns[function] = data
def serve_forever(self):
# Create and run the event server controller in a separate thread
def set_connection_token(self, token):
self.connection_token = token
-class BitbakeServerInfo():
- def __init__(self, host, port):
- self.host = host
- self.port = port
-
-class BitBakeServerConnection():
- def __init__(self, serverinfo, clientinfo=("localhost", 0)):
- self.connection, self.transport = _create_server(serverinfo.host, serverinfo.port)
+class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
+ def __init__(self, serverImpl, clientinfo=("localhost", 0)):
+ self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port)
self.clientinfo = clientinfo
- self.serverinfo = serverinfo
+ self.serverImpl = serverImpl
def connect(self):
token = self.connection.addClient()
except:
pass
-class BitBakeServer(object):
+class BitBakeServer(BitBakeBaseServer):
def initServer(self, interface = ("localhost", 0)):
- self.server = BitBakeXMLRPCServer(interface)
-
- def addcooker(self, cooker):
- self.cooker = cooker
- self.server.addcooker(cooker)
-
- def getServerIdleCB(self):
- return self.server.register_idle_function
-
- def saveConnectionDetails(self):
- self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port)
+ self.serverImpl = XMLRPCServer(interface)
def detach(self):
- daemonize.createDaemon(self.server.serve_forever, "bitbake-cookerdaemon.log")
+ daemonize.createDaemon(self.serverImpl.serve_forever, "bitbake-cookerdaemon.log")
del self.cooker
- del self.server
def establishConnection(self):
- self.connection = BitBakeServerConnection(self.serverinfo)
+ self.connection = BitBakeXMLRPCServerConnection(self.serverImpl)
return self.connection.connect()
def set_connection_token(self, token):
self.connection.transport.set_connection_token(token)
- def endSession(self):
- self.connection.terminate()
-
-class BitBakeXMLRPCClient(object):
+class BitBakeXMLRPCClient(BitBakeBaseServer):
def __init__(self):
pass
s.close()
except:
return None
- self.serverinfo = BitbakeServerInfo(host, port)
- self.connection = BitBakeServerConnection(self.serverinfo, (ip, 0))
+ self.serverImpl = XMLRPCProxyServer(host, port)
+ self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0))
return self.connection.connect()
def endSession(self):