aboutsummaryrefslogtreecommitdiffstats
ModeNameSize
-rw-r--r--.gitignore165logstatsplain
-rw-r--r--LICENSE545logstatsplain
-rw-r--r--README495logstatsplain
d---------meta-hob109logstatsplain
d---------meta-skeleton158logstatsplain
d---------meta809logstatsplain
-rwxr-xr-xoe-init-build-env1531logstatsplain
d---------scripts2337logstatsplain
, "text/plain") self.send_header("Content-length", str(len(response))) self.end_headers() self.wfile.write(bytes(response, 'utf-8')) class XMLRPCProxyServer(BaseImplServer): """ not a real working server, but a stub for a proxy server connection """ def __init__(self, host, port, use_builtin_types=True): self.host = host self.port = port class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer): # remove this when you're done with debugging # allow_reuse_address = True def __init__(self, interface, single_use=False, idle_timeout=0): """ Constructor """ BaseImplServer.__init__(self) self.single_use = single_use # Use auto port configuration if (interface[1] == -1): interface = (interface[0], 0) SimpleXMLRPCServer.__init__(self, interface, requestHandler=BitBakeXMLRPCRequestHandler, logRequests=False, allow_none=True) self.host, self.port = self.socket.getsockname() self.connection_token = None #self.register_introspection_functions() self.commands = BitBakeServerCommands(self) self.autoregister_all_functions(self.commands, "") self.interface = interface self.time = time.time() self.idle_timeout = idle_timeout if idle_timeout: self.register_idle_function(self.handle_idle_timeout, self) self.heartbeat_seconds = 1 # default, BB_HEARTBEAT_EVENT will be checked once we have a datastore. self.next_heartbeat = time.time() def addcooker(self, cooker): BaseImplServer.addcooker(self, cooker) self.commands.cooker = cooker def autoregister_all_functions(self, context, prefix): """ Convenience method for registering all functions in the scope of this class that start with a common prefix """ methodlist = inspect.getmembers(context, inspect.ismethod) for name, method in methodlist: if name.startswith(prefix): self.register_function(method, name[len(prefix):]) def handle_idle_timeout(self, server, data, abort): if not abort: if time.time() - server.time > server.idle_timeout: server.quit = True print("Server idle timeout expired") return [] def serve_forever(self): heartbeat_event = self.cooker.data.getVar('BB_HEARTBEAT_EVENT') if heartbeat_event: try: self.heartbeat_seconds = float(heartbeat_event) except: # Throwing an exception here causes bitbake to hang. # Just warn about the invalid setting and continue bb.warn('Ignoring invalid BB_HEARTBEAT_EVENT=%s, must be a float specifying seconds.' % heartbeat_event) # Start the actual XMLRPC server bb.cooker.server_main(self.cooker, self._serve_forever) def _serve_forever(self): """ Serve Requests. Overloaded to honor a quit command """ self.quit = False while not self.quit: fds = [self] nextsleep = 0.1 for function, data in list(self._idlefuns.items()): retval = None try: retval = function(self, data, False) if retval is False: del self._idlefuns[function] elif retval is True: nextsleep = 0 elif isinstance(retval, float): if (retval < nextsleep): nextsleep = retval else: fds = fds + retval except SystemExit: raise except: import traceback traceback.print_exc() if retval == None: # the function execute failed; delete it del self._idlefuns[function] pass socktimeout = self.socket.gettimeout() or nextsleep socktimeout = min(socktimeout, nextsleep) # Mirror what BaseServer handle_request would do try: fd_sets = select.select(fds, [], [], socktimeout) if fd_sets[0] and self in fd_sets[0]: if self.idle_timeout: self.time = time.time() self._handle_request_noblock() except IOError: # we ignore interrupted calls pass # Create new heartbeat event? now = time.time() if now >= self.next_heartbeat: # We might have missed heartbeats. Just trigger once in # that case and continue after the usual delay. self.next_heartbeat += self.heartbeat_seconds if self.next_heartbeat <= now: self.next_heartbeat = now + self.heartbeat_seconds heartbeat = bb.event.HeartbeatEvent(now) bb.event.fire(heartbeat, self.cooker.data) if nextsleep and now + nextsleep > self.next_heartbeat: # Shorten timeout so that we we wake up in time for # the heartbeat. nextsleep = self.next_heartbeat - now # Tell idle functions we're exiting for function, data in list(self._idlefuns.items()): try: retval = function(self, data, True) except: pass self.server_close() return def set_connection_token(self, token): self.connection_token = token class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection): def __init__(self, serverImpl, clientinfo=("localhost", 0), observer_only = False, featureset = None): self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port) self.clientinfo = clientinfo self.serverImpl = serverImpl self.observer_only = observer_only if featureset: self.featureset = featureset else: self.featureset = [] def connect(self, token = None): if token is None: if self.observer_only: token = "observer" else: token = self.connection.addClient() if token is None: return None self.transport.set_connection_token(token) return self def setupEventQueue(self): self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo) for event in bb.event.ui_queue: self.events.queue_event(event) _, error = self.connection.runCommand(["setFeatures", self.featureset]) if error: # disconnect the client, we can't make the setFeature work self.connection.removeClient() # no need to log it here, the error shall be sent to the client raise BaseException(error) def removeClient(self): if not self.observer_only: self.connection.removeClient() def terminate(self): # Don't wait for server indefinitely import socket socket.setdefaulttimeout(2) try: self.events.system_quit() except: pass try: self.connection.removeClient() except: pass class BitBakeServer(BitBakeBaseServer): def initServer(self, interface = ("localhost", 0), single_use = False, idle_timeout=0): self.interface = interface self.serverImpl = XMLRPCServer(interface, single_use, idle_timeout) def detach(self): daemonize.createDaemon(self.serverImpl.serve_forever, "bitbake-cookerdaemon.log") del self.cooker def establishConnection(self, featureset): self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, self.interface, False, featureset) return self.connection.connect() def set_connection_token(self, token): self.connection.transport.set_connection_token(token) class BitBakeXMLRPCClient(BitBakeBaseServer): def __init__(self, observer_only = False, token = None): self.token = token self.observer_only = observer_only # if we need extra caches, just tell the server to load them all pass def saveConnectionDetails(self, remote): self.remote = remote def establishConnection(self, featureset): # The format of "remote" must be "server:port" try: [host, port] = self.remote.split(":") port = int(port) except Exception as e: bb.warn("Failed to read remote definition (%s)" % str(e)) raise e # We need our IP for the server connection. We get the IP # by trying to connect with the server try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect((host, port)) ip = s.getsockname()[0] s.close() except Exception as e: bb.warn("Could not create socket for %s:%s (%s)" % (host, port, str(e))) raise e try: self.serverImpl = XMLRPCProxyServer(host, port, use_builtin_types=True) self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0), self.observer_only, featureset) return self.connection.connect(self.token) except Exception as e: bb.warn("Could not connect to server at %s:%s (%s)" % (host, port, str(e))) raise e def endSession(self): self.connection.removeClient()