diff options
| -rw-r--r-- | docs/manifest-format.md | 27 | ||||
| -rw-r--r-- | manifest_xml.py | 37 | ||||
| -rw-r--r-- | tests/test_manifest_xml.py | 59 |
3 files changed, 123 insertions, 0 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md index ca385ba3..8e5e2874 100644 --- a/docs/manifest-format.md +++ b/docs/manifest-format.md | |||
| @@ -29,6 +29,7 @@ following DTD: | |||
| 29 | project*, | 29 | project*, |
| 30 | extend-project*, | 30 | extend-project*, |
| 31 | repo-hooks?, | 31 | repo-hooks?, |
| 32 | superproject?, | ||
| 32 | include*)> | 33 | include*)> |
| 33 | 34 | ||
| 34 | <!ELEMENT notice (#PCDATA)> | 35 | <!ELEMENT notice (#PCDATA)> |
| @@ -98,6 +99,10 @@ following DTD: | |||
| 98 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> | 99 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> |
| 99 | <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED> | 100 | <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED> |
| 100 | 101 | ||
| 102 | <!ELEMENT superproject (EMPTY)> | ||
| 103 | <!ATTLIST superproject name CDATA #REQUIRED> | ||
| 104 | <!ATTLIST superproject remote IDREF #IMPLIED> | ||
| 105 | |||
| 101 | <!ELEMENT include EMPTY> | 106 | <!ELEMENT include EMPTY> |
| 102 | <!ATTLIST include name CDATA #REQUIRED> | 107 | <!ATTLIST include name CDATA #REQUIRED> |
| 103 | <!ATTLIST include groups CDATA #IMPLIED> | 108 | <!ATTLIST include groups CDATA #IMPLIED> |
| @@ -377,6 +382,28 @@ defined `project` element. | |||
| 377 | 382 | ||
| 378 | Attribute `enabled-list`: List of hooks to use, whitespace or comma separated. | 383 | Attribute `enabled-list`: List of hooks to use, whitespace or comma separated. |
| 379 | 384 | ||
| 385 | ### Element superproject | ||
| 386 | |||
| 387 | *** | ||
| 388 | *Note*: This is currently a WIP. | ||
| 389 | *** | ||
| 390 | |||
| 391 | NB: See the [git superprojects documentation]( | ||
| 392 | https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects) for background | ||
| 393 | information. | ||
| 394 | |||
| 395 | This element is used to specify the URL of the superproject. It has "name" and | ||
| 396 | "remote" as atrributes. Only "name" is required while the others have | ||
| 397 | reasonable defaults. At most one superproject may be specified. | ||
| 398 | Attempting to redefine it will fail to parse. | ||
| 399 | |||
| 400 | Attribute `name`: A unique name for the superproject. This attribute has the | ||
| 401 | same meaning as project's name attribute. See the | ||
| 402 | [element project](#element-project) for more information. | ||
| 403 | |||
| 404 | Attribute `remote`: Name of a previously defined remote element. | ||
| 405 | If not supplied the remote given by the default element is used. | ||
| 406 | |||
| 380 | ### Element include | 407 | ### Element include |
| 381 | 408 | ||
| 382 | This element provides the capability of including another manifest | 409 | This element provides the capability of including another manifest |
diff --git a/manifest_xml.py b/manifest_xml.py index 9b7a81b3..eb8a98cc 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
| @@ -463,6 +463,19 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 463 | ' '.join(self._repo_hooks_project.enabled_repo_hooks)) | 463 | ' '.join(self._repo_hooks_project.enabled_repo_hooks)) |
| 464 | root.appendChild(e) | 464 | root.appendChild(e) |
| 465 | 465 | ||
| 466 | if self._superproject: | ||
| 467 | root.appendChild(doc.createTextNode('')) | ||
| 468 | e = doc.createElement('superproject') | ||
| 469 | e.setAttribute('name', self._superproject['name']) | ||
| 470 | remoteName = None | ||
| 471 | if d.remote: | ||
| 472 | remoteName = d.remote.name | ||
| 473 | remote = self._superproject.get('remote') | ||
| 474 | if not d.remote or remote.orig_name != remoteName: | ||
| 475 | remoteName = remote.orig_name | ||
| 476 | e.setAttribute('remote', remoteName) | ||
| 477 | root.appendChild(e) | ||
| 478 | |||
| 466 | return doc | 479 | return doc |
| 467 | 480 | ||
| 468 | def ToDict(self, **kwargs): | 481 | def ToDict(self, **kwargs): |
| @@ -473,6 +486,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 473 | 'default', | 486 | 'default', |
| 474 | 'manifest-server', | 487 | 'manifest-server', |
| 475 | 'repo-hooks', | 488 | 'repo-hooks', |
| 489 | 'superproject', | ||
| 476 | } | 490 | } |
| 477 | # Elements that may be repeated. | 491 | # Elements that may be repeated. |
| 478 | MULTI_ELEMENTS = { | 492 | MULTI_ELEMENTS = { |
| @@ -545,6 +559,11 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 545 | return self._repo_hooks_project | 559 | return self._repo_hooks_project |
| 546 | 560 | ||
| 547 | @property | 561 | @property |
| 562 | def superproject(self): | ||
| 563 | self._Load() | ||
| 564 | return self._superproject | ||
| 565 | |||
| 566 | @property | ||
| 548 | def notice(self): | 567 | def notice(self): |
| 549 | self._Load() | 568 | self._Load() |
| 550 | return self._notice | 569 | return self._notice |
| @@ -591,6 +610,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 591 | self._remotes = {} | 610 | self._remotes = {} |
| 592 | self._default = None | 611 | self._default = None |
| 593 | self._repo_hooks_project = None | 612 | self._repo_hooks_project = None |
| 613 | self._superproject = {} | ||
| 594 | self._notice = None | 614 | self._notice = None |
| 595 | self.branch = None | 615 | self.branch = None |
| 596 | self._manifest_server = None | 616 | self._manifest_server = None |
| @@ -793,6 +813,23 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 793 | 813 | ||
| 794 | # Store the enabled hooks in the Project object. | 814 | # Store the enabled hooks in the Project object. |
| 795 | self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks | 815 | self._repo_hooks_project.enabled_repo_hooks = enabled_repo_hooks |
| 816 | if node.nodeName == 'superproject': | ||
| 817 | name = self._reqatt(node, 'name') | ||
| 818 | # There can only be one superproject. | ||
| 819 | if self._superproject.get('name'): | ||
| 820 | raise ManifestParseError( | ||
| 821 | 'duplicate superproject in %s' % | ||
| 822 | (self.manifestFile)) | ||
| 823 | self._superproject['name'] = name | ||
| 824 | remote_name = node.getAttribute('remote') | ||
| 825 | if not remote_name: | ||
| 826 | remote = self._default.remote | ||
| 827 | else: | ||
| 828 | remote = self._get_remote(node) | ||
| 829 | if remote is None: | ||
| 830 | raise ManifestParseError("no remote for superproject %s within %s" % | ||
| 831 | (name, self.manifestFile)) | ||
| 832 | self._superproject['remote'] = remote.ToRemoteSpec(name) | ||
| 796 | if node.nodeName == 'remove-project': | 833 | if node.nodeName == 'remove-project': |
| 797 | name = self._reqatt(node, 'name') | 834 | name = self._reqatt(node, 'name') |
| 798 | 835 | ||
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py index d53ea568..e4adf3c9 100644 --- a/tests/test_manifest_xml.py +++ b/tests/test_manifest_xml.py | |||
| @@ -221,6 +221,65 @@ class XmlManifestTests(unittest.TestCase): | |||
| 221 | self.assertEqual(manifest.repo_hooks_project.name, 'repohooks') | 221 | self.assertEqual(manifest.repo_hooks_project.name, 'repohooks') |
| 222 | self.assertEqual(manifest.repo_hooks_project.enabled_repo_hooks, ['a', 'b']) | 222 | self.assertEqual(manifest.repo_hooks_project.enabled_repo_hooks, ['a', 'b']) |
| 223 | 223 | ||
| 224 | def test_superproject(self): | ||
| 225 | """Check superproject settings.""" | ||
| 226 | manifest = self.getXmlManifest(""" | ||
| 227 | <manifest> | ||
| 228 | <remote name="test-remote" fetch="http://localhost" /> | ||
| 229 | <default remote="test-remote" revision="refs/heads/main" /> | ||
| 230 | <superproject name="superproject"/> | ||
| 231 | </manifest> | ||
| 232 | """) | ||
| 233 | self.assertEqual(manifest.superproject['name'], 'superproject') | ||
| 234 | self.assertEqual(manifest.superproject['remote'].name, 'test-remote') | ||
| 235 | self.assertEqual( | ||
| 236 | manifest.ToXml().toxml(), | ||
| 237 | '<?xml version="1.0" ?><manifest>' + | ||
| 238 | '<remote name="test-remote" fetch="http://localhost"/>' + | ||
| 239 | '<default remote="test-remote" revision="refs/heads/main"/>' + | ||
| 240 | '<superproject name="superproject"/>' + | ||
| 241 | '</manifest>') | ||
| 242 | |||
| 243 | def test_superproject_with_remote(self): | ||
| 244 | """Check superproject settings.""" | ||
| 245 | manifest = self.getXmlManifest(""" | ||
| 246 | <manifest> | ||
| 247 | <remote name="default-remote" fetch="http://localhost" /> | ||
| 248 | <remote name="test-remote" fetch="http://localhost" /> | ||
| 249 | <default remote="default-remote" revision="refs/heads/main" /> | ||
| 250 | <superproject name="superproject" remote="test-remote"/> | ||
| 251 | </manifest> | ||
| 252 | """) | ||
| 253 | self.assertEqual(manifest.superproject['name'], 'superproject') | ||
| 254 | self.assertEqual(manifest.superproject['remote'].name, 'test-remote') | ||
| 255 | self.assertEqual( | ||
| 256 | manifest.ToXml().toxml(), | ||
| 257 | '<?xml version="1.0" ?><manifest>' + | ||
| 258 | '<remote name="default-remote" fetch="http://localhost"/>' + | ||
| 259 | '<remote name="test-remote" fetch="http://localhost"/>' + | ||
| 260 | '<default remote="default-remote" revision="refs/heads/main"/>' + | ||
| 261 | '<superproject name="superproject" remote="test-remote"/>' + | ||
| 262 | '</manifest>') | ||
| 263 | |||
| 264 | def test_superproject_with_defalut_remote(self): | ||
| 265 | """Check superproject settings.""" | ||
| 266 | manifest = self.getXmlManifest(""" | ||
| 267 | <manifest> | ||
| 268 | <remote name="default-remote" fetch="http://localhost" /> | ||
| 269 | <default remote="default-remote" revision="refs/heads/main" /> | ||
| 270 | <superproject name="superproject" remote="default-remote"/> | ||
| 271 | </manifest> | ||
| 272 | """) | ||
| 273 | self.assertEqual(manifest.superproject['name'], 'superproject') | ||
| 274 | self.assertEqual(manifest.superproject['remote'].name, 'default-remote') | ||
| 275 | self.assertEqual( | ||
| 276 | manifest.ToXml().toxml(), | ||
| 277 | '<?xml version="1.0" ?><manifest>' + | ||
| 278 | '<remote name="default-remote" fetch="http://localhost"/>' + | ||
| 279 | '<default remote="default-remote" revision="refs/heads/main"/>' + | ||
| 280 | '<superproject name="superproject"/>' + | ||
| 281 | '</manifest>') | ||
| 282 | |||
| 224 | def test_project_group(self): | 283 | def test_project_group(self): |
| 225 | """Check project group settings.""" | 284 | """Check project group settings.""" |
| 226 | manifest = self.getXmlManifest(""" | 285 | manifest = self.getXmlManifest(""" |
