From 2644874d9d3e6c16299a01acddf66cd99fd43414 Mon Sep 17 00:00:00 2001 From: Brian Harring Date: Thu, 28 Apr 2011 05:04:41 -0700 Subject: [PATCH] ManifestXml: add include support Having the ability to include other manifests is a very practical feature to ease the managment of manifest. It allows to divide a manifest into separate files, and create different environment depending on what we want to release You can have unlimited recursion of include, the manifest configs will simply be concatenated as if it was in a single file. command "repo manifest" will create a single manifest, and not recreate the manifest hierarchy for example: Our developement manifest will look like: Our release manifest will look like: And it is also easy to create and maintain feature branch with a manifest that looks like: Signed-off-by: Brian Harring Signed-off-by: Pierre Tardy Change-Id: I833a30d303039e485888768e6b81561b7665e89d --- docs/manifest-format.txt | 13 +++++++++++++ manifest_xml.py | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt index 53789651..9f4585b8 100644 --- a/docs/manifest-format.txt +++ b/docs/manifest-format.txt @@ -63,6 +63,9 @@ following DTD: + + + ]> A description of the elements and their attributes follows. @@ -192,6 +195,16 @@ This element is mostly useful in the local_manifest.xml, where the user can remove a project, and possibly replace it with their own definition. +Element include +--------------- + +This element provides the capability of including another manifest +file into the originating manifest. Normal rules apply for the +target manifest to include- it must be a usable manifest on it's own. + +Attribute `name`; the manifest to include, specified relative to +the manifest repositories root. + Local Manifest ============== diff --git a/manifest_xml.py b/manifest_xml.py index ca65e33f..2927fd1c 100644 --- a/manifest_xml.py +++ b/manifest_xml.py @@ -298,18 +298,41 @@ class XmlManifest(object): self._loaded = True - def _ParseManifest(self, is_root_file): - root = xml.dom.minidom.parse(self.manifestFile) + def _ParseManifestObject(self, path): + root = xml.dom.minidom.parse(path) if not root or not root.childNodes: - raise ManifestParseError( - "no root node in %s" % - self.manifestFile) + raise ManifestParseError("no root node in %s" % (path,)) config = root.childNodes[0] if config.nodeName != 'manifest': - raise ManifestParseError( - "no in %s" % - self.manifestFile) + raise ManifestParseError("no in %s" % (path,)) + + return config + + def _ParseManifest(self, is_root_file): + config = self._ParseManifestObject(self.manifestFile) + + for node in config.childNodes: + if node.nodeName == 'include': + name = self._reqatt(node, 'name') + fp = os.path.join(self.manifestProject.worktree, name) + if not os.path.isfile(fp): + raise ManifestParseError, \ + "include %s doesn't exist or isn't a file" % \ + (name,) + try: + subconfig = self._ParseManifestObject(fp) + # should isolate this to the exact exception, but that's + # tricky. actual parsing implementation may vary. + except (KeyboardInterrupt, RuntimeError, SystemExit): + raise + except Exception, e: + raise ManifestParseError( + "failed parsing included manifest %s: %s", (name, e)) + + for sub_node in subconfig.childNodes: + config.appendChild(sub_node.cloneNode(True)) + for node in config.childNodes: if node.nodeName == 'remove-project':