Mercurial > bitten > bitten-test
changeset 287:6abd43d0cd8a
The build slave now stores snapshot archives and the corresponding work directories in project folders of the main work folder, to keep build configurations from different projects that share the same name separate. This also requires transmitting the project name (simply the name of the environment directory) with the build initiation.
author | cmlenz |
---|---|
date | Sat, 15 Oct 2005 13:39:23 +0000 |
parents | 4fabcaf75787 |
children | a5ed3341d9a9 |
files | bitten/master.py bitten/slave.py bitten/util/beep.py bitten/util/xmlio.py |
diffstat | 4 files changed, 85 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/bitten/master.py +++ b/bitten/master.py @@ -198,8 +198,9 @@ else: self.send_snapshot(queue, build, snapshot) - self.channel.send_msg(beep.Payload(config.recipe), - handle_reply=handle_reply) + xml = xmlio.parse(config.recipe) + xml.attr['project'] = os.path.basename(queue.env.path) + self.channel.send_msg(beep.Payload(xml), handle_reply=handle_reply) def send_snapshot(self, queue, build, snapshot): timestamp_delta = 0 @@ -418,10 +419,16 @@ host = ip envs = [] + names = set() for arg in args: if not os.path.isdir(arg): log.warning('Ignoring %s: not a directory', arg) continue + name = os.path.basename(arg) + if name in names: + log.warning('Ignoring %s: duplicate project name "%s"', arg, name) + continue + names.add(name) env = Environment(arg) if BuildSystem(env): if env.needs_upgrade():
--- a/bitten/slave.py +++ b/bitten/slave.py @@ -60,7 +60,7 @@ def handle_connect(self): """Register with the build master.""" - self.recipe_xml = None + self.build_xml = None def handle_reply(cmd, msgno, ansno, payload): if cmd == 'ERR': @@ -99,34 +99,40 @@ elem = xmlio.parse(payload.body) if elem.name == 'build': # Received a build request - self.recipe_xml = elem + self.build_xml = elem xml = xmlio.Element('proceed') self.channel.send_rpy(msgno, beep.Payload(xml)) elif payload.content_type == 'application/zip': # Received snapshot archive for build + project_name = self.build_xml.attr.get('project', 'default') + project_dir = os.path.join(self.session.work_dir, project_name) + if not os.path.exists(project_dir): + os.mkdir(project_dir) + archive_name = payload.content_disposition if not archive_name: archive_name = 'snapshot.zip' - archive_path = os.path.join(self.session.work_dir, archive_name) + archive_path = os.path.join(project_dir, archive_name) archive_file = file(archive_path, 'wb') try: shutil.copyfileobj(payload.body, archive_file) finally: archive_file.close() - basedir = self.unpack_snapshot(msgno, archive_path) + basedir = self.unpack_snapshot(msgno, project_dir, archive_name) try: - recipe = Recipe(self.recipe_xml, basedir, self.config) + recipe = Recipe(self.build_xml, basedir, self.config) self.execute_build(msgno, recipe) finally: if not self.session.keep_files: shutil.rmtree(basedir) os.remove(archive_path) - def unpack_snapshot(self, msgno, path): + def unpack_snapshot(self, msgno, project_dir, archive_name): """Unpack a snapshot archive.""" + path = os.path.join(project_dir, archive_name) log.debug('Received snapshot archive: %s', path) try: zip_file = zipfile.ZipFile(path, 'r') @@ -142,7 +148,7 @@ if name.startswith('/') or '..' in name: continue names.append(os.path.normpath(name)) - fullpath = os.path.join(self.session.work_dir, name) + fullpath = os.path.join(project_dir, name) if name.endswith('/'): os.makedirs(fullpath) else: @@ -157,8 +163,7 @@ finally: zip_file.close() - basedir = os.path.join(self.session.work_dir, - os.path.commonprefix(names)) + basedir = os.path.join(project_dir, os.path.commonprefix(names)) log.debug('Unpacked snapshot to %s' % basedir) return basedir
--- a/bitten/util/beep.py +++ b/bitten/util/beep.py @@ -729,7 +729,7 @@ if data is None: data = '' - if isinstance(data, xmlio.Element): + if isinstance(data, (xmlio.Element, xmlio.ParsedElement)): self.body = StringIO(str(data)) elif isinstance(data, basestring): self.body = StringIO(data)
--- a/bitten/util/xmlio.py +++ b/bitten/util/xmlio.py @@ -17,6 +17,7 @@ from cStringIO import StringIO except ImportError: from StringIO import StringIO +from UserDict import DictMixin __all__ = ['Element', 'parse'] @@ -185,13 +186,71 @@ class ParsedElement(object): """Representation of an XML element that was parsed from a string or file. + + This class should not be used directly. Rather, XML text parsed using + `xmlio.parse()` will return an instance of this class. + + >>> xml = parse('<root/>') + >>> print xml.name + root + + Parsed elements can be serialized to a string using the `write()` method: + + >>> import sys + >>> parse('<root></root>').write(sys.stdout) + <root/> + + For convenience, this is also done when coercing the object to a string + using the builtin `str()` function, which is used when `print`ing an object: + + >>> print parse('<root></root>') + <root/> + + (Note that serializing the element will produce a normalized representation + that may not excatly match the input string.) + + Attributes are accessed via the `attr` member: + + >>> print parse('<root foo="bar"/>').attr['foo'] + bar + + Attributes can also be updated, added or removed: + + >>> xml = parse('<root foo="bar"/>') + >>> xml.attr['foo'] = 'baz' + >>> print xml + <root foo="baz"/> + + >>> del xml.attr['foo'] + >>> print xml + <root/> + + >>> xml.attr['foo'] = 'bar' + >>> print xml + <root foo="bar"/> """ __slots__ = ['_node', 'attr'] + class _Attrs(DictMixin): + """Simple wrapper around the element attributes to provide a dictionary + interface.""" + def __init__(self, node): + self._node = node + def __getitem__(self, name): + attr = self._node.getAttributeNode(name) + if not attr: + raise KeyError, name + return attr.value.encode() + def __setitem__(self, name, value): + self._node.setAttribute(name, value) + def __delitem__(self, name): + self._node.removeAttribute(name) + def keys(self): + return [name.encode() for name in self._node.attributes.keys()] + def __init__(self, node): self._node = node - self.attr = dict([(name.encode(), value.encode()) for name, value - in node.attributes.items()]) + self.attr = ParsedElement._Attrs(node) name = property(fget=lambda self: self._node.localName) namespace = property(fget=lambda self: self._node.namespaceURI)