mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
manifest: add support for groups in include
Attrib groups can now be added to manifest include, thus all projects in an included manifest file can easily be tagged with a group without modifying all projects in that manifest file. Include groups will add and recurse, meaning included manifest projects will carry all parent includes. Intentionally, no support added for group remove, to keep complexity down. Group handling for projects is untouched, meaning a group set on a project will still append to whatever was or was not inherited in parent manifest includes, resulting in union of groups inherited and set for the project itself. Test: manual multi-level manifest include structure, in serial and parallel, with different groups set on init Test: added unit tests to cover the inheritance Change-Id: Id2229aa6fd78d355ba598cc15c701b2ee71e5c6f Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/283587 Tested-by: Fredrik de Groot <fredrik.de.groot@volvocars.com> Reviewed-by: Mike Frysinger <vapier@google.com>
This commit is contained in:
parent
7f7acfe9fd
commit
352c93b680
@ -99,7 +99,8 @@ following DTD:
|
|||||||
<!ATTLIST repo-hooks enabled-list CDATA #REQUIRED>
|
<!ATTLIST repo-hooks enabled-list CDATA #REQUIRED>
|
||||||
|
|
||||||
<!ELEMENT include EMPTY>
|
<!ELEMENT include EMPTY>
|
||||||
<!ATTLIST include name CDATA #REQUIRED>
|
<!ATTLIST include name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST include groups CDATA #IMPLIED>
|
||||||
]>
|
]>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -368,6 +369,10 @@ target manifest to include - it must be a usable manifest on its own.
|
|||||||
Attribute `name`: the manifest to include, specified relative to
|
Attribute `name`: the manifest to include, specified relative to
|
||||||
the manifest repository's root.
|
the manifest repository's root.
|
||||||
|
|
||||||
|
Attribute `groups`: List of additional groups to which all projects
|
||||||
|
in the included manifest belong. This appends and recurses, meaning
|
||||||
|
all projects in sub-manifests carry all parent include groups.
|
||||||
|
Same syntax as the corresponding element of `project`.
|
||||||
|
|
||||||
## Local Manifests
|
## Local Manifests
|
||||||
|
|
||||||
|
@ -637,7 +637,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
|
|
||||||
self._loaded = True
|
self._loaded = True
|
||||||
|
|
||||||
def _ParseManifestXml(self, path, include_root):
|
def _ParseManifestXml(self, path, include_root, parent_groups=''):
|
||||||
try:
|
try:
|
||||||
root = xml.dom.minidom.parse(path)
|
root = xml.dom.minidom.parse(path)
|
||||||
except (OSError, xml.parsers.expat.ExpatError) as e:
|
except (OSError, xml.parsers.expat.ExpatError) as e:
|
||||||
@ -656,12 +656,17 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
for node in manifest.childNodes:
|
for node in manifest.childNodes:
|
||||||
if node.nodeName == 'include':
|
if node.nodeName == 'include':
|
||||||
name = self._reqatt(node, 'name')
|
name = self._reqatt(node, 'name')
|
||||||
|
include_groups = ''
|
||||||
|
if parent_groups:
|
||||||
|
include_groups = parent_groups
|
||||||
|
if node.hasAttribute('groups'):
|
||||||
|
include_groups = node.getAttribute('groups') + ',' + include_groups
|
||||||
fp = os.path.join(include_root, name)
|
fp = os.path.join(include_root, name)
|
||||||
if not os.path.isfile(fp):
|
if not os.path.isfile(fp):
|
||||||
raise ManifestParseError("include %s doesn't exist or isn't a file"
|
raise ManifestParseError("include %s doesn't exist or isn't a file"
|
||||||
% (name,))
|
% (name,))
|
||||||
try:
|
try:
|
||||||
nodes.extend(self._ParseManifestXml(fp, include_root))
|
nodes.extend(self._ParseManifestXml(fp, include_root, include_groups))
|
||||||
# should isolate this to the exact exception, but that's
|
# should isolate this to the exact exception, but that's
|
||||||
# tricky. actual parsing implementation may vary.
|
# tricky. actual parsing implementation may vary.
|
||||||
except (KeyboardInterrupt, RuntimeError, SystemExit):
|
except (KeyboardInterrupt, RuntimeError, SystemExit):
|
||||||
@ -670,6 +675,11 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
raise ManifestParseError(
|
raise ManifestParseError(
|
||||||
"failed parsing included manifest %s: %s" % (name, e))
|
"failed parsing included manifest %s: %s" % (name, e))
|
||||||
else:
|
else:
|
||||||
|
if parent_groups and node.nodeName == 'project':
|
||||||
|
nodeGroups = parent_groups
|
||||||
|
if node.hasAttribute('groups'):
|
||||||
|
nodeGroups = node.getAttribute('groups') + ',' + nodeGroups
|
||||||
|
node.setAttribute('groups', nodeGroups)
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
@ -235,3 +235,46 @@ class XmlManifestTests(unittest.TestCase):
|
|||||||
self.assertCountEqual(
|
self.assertCountEqual(
|
||||||
result['extras'],
|
result['extras'],
|
||||||
['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path'])
|
['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path'])
|
||||||
|
|
||||||
|
def test_include_levels(self):
|
||||||
|
root_m = os.path.join(self.manifest_dir, 'root.xml')
|
||||||
|
with open(root_m, 'w') as fp:
|
||||||
|
fp.write("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="test-remote" fetch="http://localhost" />
|
||||||
|
<default remote="test-remote" revision="refs/heads/main" />
|
||||||
|
<include name="level1.xml" groups="level1-group" />
|
||||||
|
<project name="root-name1" path="root-path1" />
|
||||||
|
<project name="root-name2" path="root-path2" groups="r2g1,r2g2" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
with open(os.path.join(self.manifest_dir, 'level1.xml'), 'w') as fp:
|
||||||
|
fp.write("""
|
||||||
|
<manifest>
|
||||||
|
<include name="level2.xml" groups="level2-group" />
|
||||||
|
<project name="level1-name1" path="level1-path1" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
with open(os.path.join(self.manifest_dir, 'level2.xml'), 'w') as fp:
|
||||||
|
fp.write("""
|
||||||
|
<manifest>
|
||||||
|
<project name="level2-name1" path="level2-path1" groups="l2g1,l2g2" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
include_m = manifest_xml.XmlManifest(self.repodir, root_m)
|
||||||
|
for proj in include_m.projects:
|
||||||
|
if proj.name == 'root-name1':
|
||||||
|
# Check include group not set on root level proj.
|
||||||
|
self.assertNotIn('level1-group', proj.groups)
|
||||||
|
if proj.name == 'root-name2':
|
||||||
|
# Check root proj group not removed.
|
||||||
|
self.assertIn('r2g1', proj.groups)
|
||||||
|
if proj.name == 'level1-name1':
|
||||||
|
# Check level1 proj has inherited group level 1.
|
||||||
|
self.assertIn('level1-group', proj.groups)
|
||||||
|
if proj.name == 'level2-name1':
|
||||||
|
# Check level2 proj has inherited group levels 1 and 2.
|
||||||
|
self.assertIn('level1-group', proj.groups)
|
||||||
|
self.assertIn('level2-group', proj.groups)
|
||||||
|
# Check level2 proj group not removed.
|
||||||
|
self.assertIn('l2g1', proj.groups)
|
||||||
|
Loading…
Reference in New Issue
Block a user