import gear import sys import json import distbuild # Artifact build states. These are used to loosely track the state of the # remote cache. UNBUILT = 'not-built' BUILDING = 'building' BUILT = 'built' import logging logging.basicConfig() gear.Server() class theController(): def __init__(self): self.graph_client = BuildGraphClient(self) self.artifact = None def _process_build_graph(self, packet): print "Decoding artifact received" self.artifact = distbuild.decode_artifact_reference(job.data[-1]) print "Decoding artifact received done" # Mark everything as unbuilt to begin with. We'll query the actua # state from the cache in self._query_cache_state(). def set_initial_state(artifact): artifact.state = UNBUILT print "Setting them as unbuilt" self._map_build_graph(self.artifact, set_initial_state) print "Setting them as unbuilt done" def _map_build_graph(self, artifact, callback, components=[]): """Run callback on each artifact in the build graph and return result. If components is given, then only look at the components given and their dependencies. Also, return a list of the components after they have had callback called on them. """ result = [] mapped_components = [] done = set() if components: queue = list(components) else: queue = [artifact] while queue: a = queue.pop() if a not in done: result.append(callback(a)) queue.extend(a.dependencies) done.add(a) if a in components: mapped_components.append(a) return result, mapped_components def find_artifacts_that_are_ready_to_build(self, root_artifact, components=[]): '''Return unbuilt artifacts whose dependencies are all built. The 'root_artifact' parameter is expected to be a tree of ArtifactReference objects. These must have the 'state' attribute set to BUILT or UNBUILT. If 'components' is passed, then only those artifacts and their dependencies will be built. ''' def is_ready_to_build(artifact): return (artifact.state == UNBUILT and all(a.state == BUILT for a in artifact.dependencies)) artifacts, _ = self._map_build_graph(root_artifact, lambda a: a, components) return [a for a in artifacts if is_ready_to_build(a)] class BuildGraphClient(gear.Client): def __init__(self, controller): super(BuildGraphClient, self).__init__() self.controller = controller self.finished = False def handleWorkComplete(self, packet): job = super(BuildGraphClient, self).handleWorkComplete(packet) print "workcomplete" self.controller._process_build_graph(packet) return job def handleWorkData(self, packet): job = super(BuildGraphClient, self).handleWorkData(packet) print job.data[-1] job.data = [] return job def handleWorkFail(self, packet): job = super(BuildGraphClient, self).handleWorkFail(packet) print "workfail" return job def handleWorkException(self, packet): job = super(BuildGraphClient, self).handleWorkException(packet) print "workexception" return job def handleDisconnect(self, job): job = super(BuildGraphClient, self).handleDisconnect(job) print "disconnect" controller = theController() client = controller.graph_client client.addServer('localhost') client.waitForServer() # Wait for at least one server to be connected print "server connected" #job = gear.Job("reverse", "test string") build_graph_request = {} build_graph_request['repo'] = "baserock:baserock/definitions" build_graph_request['ref'] = "master" build_graph_request['system'] = "systems/minimal-system-x86_64-generic.morph" s=json.dumps(build_graph_request) print "Json produced: " print s job = gear.Job("build-graph", s) client.submitJob(job) # loop so that client doesn't die while True: import time time.sleep(2) if controller.artifact != None: to_build = controller.find_artifacts_that_are_ready_to_build(controller.artifact) print to_build exit(0)