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:

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
  <default revision="platform/android/main" remote="intel"/>
  <include name="server.xml"/> <!-- The Server configuration -->
  <include name="aosp.xml" />  <!-- All the AOSP projects -->
  <include name="bsp.xml" />   <!-- The BSP projects that we release in source form -->
  <include name="bsp-priv.xml" /> <!-- The source of the BSP projects we release in binary form -->
</manifest>

Our release manifest will look like:

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
  <default revision="platform/android/release-ext" remote="intel"/>
  <include name="server.xml"/> <!-- The Server configuration -->
  <include name="aosp.xml" />  <!-- All the AOSP projects -->
  <include name="bsp.xml" />   <!-- The BSP projects that we release in source form -->
  <include name="bsp-ext.xml" /> <!-- The PREBUILT version of the BSP projects we release in binary form -->
</manifest>

And it is also easy to create and maintain feature branch with a manifest that looks like:

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
  <default revision="feature_branch_foobar" remote="intel"/>
  <include name="server.xml"/> <!-- The Server configuration -->
  <include name="aosp.xml" />  <!-- All the AOSP projects -->
  <include name="bsp.xml" />   <!-- The BSP projects that we release in source form -->
  <include name="bsp-priv.xml" /> <!-- The source of the BSP projects we release in binary form -->
</manifest>

Signed-off-by: Brian Harring <brian.harring@intel.com>
Signed-off-by: Pierre Tardy <pierre.tardy@intel.com>
Change-Id: I833a30d303039e485888768e6b81561b7665e89d
This commit is contained in:
Brian Harring 2011-04-28 05:04:41 -07:00 committed by Shawn O. Pearce
parent 3d125940f6
commit 2644874d9d
2 changed files with 44 additions and 8 deletions

View File

@ -63,6 +63,9 @@ following DTD:
<!ELEMENT repo-hooks (EMPTY)>
<!ATTLIST repo-hooks in-project CDATA #REQUIRED>
<!ATTLIST repo-hooks enabled-list CDATA #REQUIRED>
<!ELEMENT include (EMPTY)>
<!ATTLIST include name CDATA #REQUIRED>
]>
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
==============

View File

@ -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 <manifest> 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(
"no <manifest> in %s" %
self.manifestFile)
"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':