From d21d5954d0c08b1c80b72c5f37becc2e58ec916a Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Wed, 8 Jun 2011 13:08:52 +0100 Subject: bitbake/server: Move server specific code into the server backend and create a server API Move the server implementation specific code into the server backend where it belongs and replace this with a set of object method calls which establish the server, detach it and then connect to it using appropriate IPC. Signed-off-by: Richard Purdie --- bin/bitbake | 65 ++++++++++++++++++++--------------------------- lib/bb/server/process.py | 66 +++++++++++++++++++++++++++++++++++++++++++++--- lib/bb/server/xmlrpc.py | 50 ++++++++++++++++++++++++++---------- 3 files changed, 125 insertions(+), 56 deletions(-) diff --git a/bin/bitbake b/bin/bitbake index c22e29ad1..1ed46d9b5 100755 --- a/bin/bitbake +++ b/bin/bitbake @@ -29,7 +29,6 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), import optparse import warnings -import signal from traceback import format_exception try: import bb @@ -40,10 +39,9 @@ import bb.msg from bb import cooker from bb import ui from bb import server -from bb.server.process import ProcessServer, ServerCommunicator, ProcessEventQueue - -from Queue import Empty -from multiprocessing import Queue, Pipe +#from bb.server import none +from bb.server import process +#from bb.server import xmlrpc __version__ = "1.13.0" logger = logging.getLogger("BitBake") @@ -175,6 +173,10 @@ Default BBFILES are the .bb files in the current directory.""") ui_main = get_ui(configuration) + # Save a logfile for cooker into the current working directory. When the + # server is daemonized this logfile will be truncated. + cooker_logfile = os.path.join(os.getcwd(), "cooker.log") + bb.utils.init_logger(bb.msg, configuration.verbose, configuration.debug, configuration.debug_domains) @@ -187,45 +189,32 @@ Default BBFILES are the .bb files in the current directory.""") # of the UIs (e.g. for DISPLAY, etc.) bb.utils.clean_environment() - # establish communication channels. We use bidirectional pipes for - # ui <--> server command/response pairs - # and a queue for server -> ui event notifications - # - ui_channel, server_channel = Pipe() - event_queue = ProcessEventQueue() + #server = bb.server.none.BitBakeServer() + server = bb.server.process.BitBakeServer() + #server = bb.server.xmlrpc.BitBakeServer() + + server.initServer() + idle = server.getServerIdleCB() - server = ProcessServer(server_channel, event_queue, configuration) - server.start() + cooker = bb.cooker.BBCooker(configuration, idle) + cooker.parseCommandLine() + + server.addcooker(cooker) + server.saveConnectionDetails() + server.detach(cooker_logfile) + + # Should no longer need to ever reference cooker + del cooker logger.removeHandler(handler) - def shutdown(force=False): - signal.signal(signal.SIGINT, signal.SIG_IGN) - server.stop() - if force: - server.join(0.5) - if server.is_alive(): - server.terminate() - server.join() - else: - server.join() - while True: - try: - event = event_queue.get(block=False) - except (Empty, IOError): - break - if isinstance(event, logging.LogRecord): - logger.handle(event) - ui_channel.close() - event_queue.close() - if force: - sys.exit(1) - - signal.signal(signal.SIGTERM, lambda i, s: shutdown(force=True)) + # Setup a connection to the server (cooker) + server_connection = server.establishConnection() + try: - return ui_main(ServerCommunicator(ui_channel), event_queue) + return server.launchUI(ui_main, server_connection.connection, server_connection.events) finally: - shutdown() + server_connection.terminate() return 1 diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py index a5239400c..44b8e4d49 100644 --- a/lib/bb/server/process.py +++ b/lib/bb/server/process.py @@ -29,7 +29,6 @@ import os import signal import sys import time -from bb.cooker import BBCooker from Queue import Empty from multiprocessing import Event, Process, util, Queue, Pipe, queues @@ -73,13 +72,11 @@ class ProcessServer(Process): profile_filename = "profile.log" profile_processed_filename = "profile.log.processed" - def __init__(self, command_channel, event_queue, configuration): + def __init__(self, command_channel, event_queue): Process.__init__(self) self.command_channel = command_channel self.event_queue = event_queue self.event = EventAdapter(event_queue) - self.configuration = configuration - self.cooker = BBCooker(configuration, self.register_idle_function) self._idlefunctions = {} self.event_handle = bb.event.register_UIHhandler(self) self.quit = False @@ -195,6 +192,35 @@ class ProcessServer(Process): 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 + + def terminate(self, force = False): + signal.signal(signal.SIGINT, signal.SIG_IGN) + self.procserver.stop() + if force: + self.procserver.join(0.5) + if self.procserver.is_alive(): + self.procserver.terminate() + self.procserver.join() + else: + self.procserver.join() + while True: + try: + event = self.server.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() + if force: + sys.exit(1) + # Wrap Queue to provide API which isn't server implementation specific class ProcessEventQueue(multiprocessing.queues.Queue): def waitEvent(self, timeout): @@ -210,4 +236,36 @@ class ProcessEventQueue(multiprocessing.queues.Queue): return None +class BitBakeServer(object): + def initServer(self): + # establish communication channels. We use bidirectional pipes for + # ui <--> server command/response pairs + # and a queue for server -> ui event notifications + # + 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 + + def detach(self, cooker_logfile): + self.server.start() + return + + def establishConnection(self): + self.connection = BitBakeServerConnection(self) + signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True)) + return self.connection + + def launchUI(self, uifunc, *args): + return bb.cooker.server_main(self.cooker, uifunc, *args) diff --git a/lib/bb/server/xmlrpc.py b/lib/bb/server/xmlrpc.py index c43c6cde6..a7ac969ae 100644 --- a/lib/bb/server/xmlrpc.py +++ b/lib/bb/server/xmlrpc.py @@ -122,8 +122,7 @@ def _create_server(host, port): return s class BitBakeServerCommands(): - def __init__(self, server, cooker): - self.cooker = cooker + def __init__(self, server): self.server = server def registerEventHandler(self, host, port): @@ -160,11 +159,11 @@ class BitBakeServerCommands(): """ return True -class BitBakeServer(SimpleXMLRPCServer): +class BitBakeXMLRPCServer(SimpleXMLRPCServer): # remove this when you're done with debugging # allow_reuse_address = True - def __init__(self, cooker, interface = ("localhost", 0)): + def __init__(self, interface = ("localhost", 0)): """ Constructor """ @@ -174,9 +173,12 @@ class BitBakeServer(SimpleXMLRPCServer): self._idlefuns = {} self.host, self.port = self.socket.getsockname() #self.register_introspection_functions() - commands = BitBakeServerCommands(self, cooker) - self.autoregister_all_functions(commands, "") + self.commands = BitBakeServerCommands(self) + self.autoregister_all_functions(self.commands, "") + + def addcooker(self, cooker): self.cooker = cooker + self.commands.cooker = cooker def autoregister_all_functions(self, context, prefix): """ @@ -244,14 +246,6 @@ class BitbakeServerInfo(): self.host = server.host self.port = server.port -class BitBakeServerFork(): - def __init__(self, cooker, server, serverinfo, logfile): - daemonize.createDaemon(server.serve_forever, logfile) - -class BitbakeUILauch(): - def launch(self, serverinfo, uifunc, *args): - return uifunc(*args) - class BitBakeServerConnection(): def __init__(self, serverinfo): self.connection = _create_server(serverinfo.host, serverinfo.port) @@ -271,3 +265,31 @@ class BitBakeServerConnection(): self.connection.terminateServer() except: pass + +class BitBakeServer(object): + def initServer(self): + self.server = BitBakeXMLRPCServer() + + 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) + + def detach(self, cooker_logfile): + daemonize.createDaemon(self.server.serve_forever, cooker_logfile) + del self.cooker + del self.server + + def establishConnection(self): + self.connection = BitBakeServerConnection(self.serverinfo) + return self.connection + + def launchUI(self, uifunc, *args): + return uifunc(*args) + + -- cgit 1.2.3-korg