diff options
-rw-r--r-- | docs/manifest-format.md | 4 | ||||
-rw-r--r-- | manifest_xml.py | 20 | ||||
-rw-r--r-- | tests/test_manifest_xml.py | 50 |
3 files changed, 64 insertions, 10 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md index 45fd615e..c3bfcff0 100644 --- a/docs/manifest-format.md +++ b/docs/manifest-format.md | |||
@@ -96,6 +96,7 @@ following DTD: | |||
96 | 96 | ||
97 | <!ELEMENT remove-project EMPTY> | 97 | <!ELEMENT remove-project EMPTY> |
98 | <!ATTLIST remove-project name CDATA #REQUIRED> | 98 | <!ATTLIST remove-project name CDATA #REQUIRED> |
99 | <!ATTLIST remove-project optional CDATA #IMPLIED> | ||
99 | 100 | ||
100 | <!ELEMENT repo-hooks EMPTY> | 101 | <!ELEMENT repo-hooks EMPTY> |
101 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> | 102 | <!ATTLIST repo-hooks in-project CDATA #REQUIRED> |
@@ -393,6 +394,9 @@ This element is mostly useful in a local manifest file, where | |||
393 | the user can remove a project, and possibly replace it with their | 394 | the user can remove a project, and possibly replace it with their |
394 | own definition. | 395 | own definition. |
395 | 396 | ||
397 | Attribute `optional`: Set to true to ignore remove-project elements with no | ||
398 | matching `project` element. | ||
399 | |||
396 | ### Element repo-hooks | 400 | ### Element repo-hooks |
397 | 401 | ||
398 | NB: See the [practical documentation](./repo-hooks.md) for using repo hooks. | 402 | NB: See the [practical documentation](./repo-hooks.md) for using repo hooks. |
diff --git a/manifest_xml.py b/manifest_xml.py index ab4be2f5..be74bf49 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -918,19 +918,19 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
918 | if node.nodeName == 'remove-project': | 918 | if node.nodeName == 'remove-project': |
919 | name = self._reqatt(node, 'name') | 919 | name = self._reqatt(node, 'name') |
920 | 920 | ||
921 | if name not in self._projects: | 921 | if name in self._projects: |
922 | for p in self._projects[name]: | ||
923 | del self._paths[p.relpath] | ||
924 | del self._projects[name] | ||
925 | |||
926 | # If the manifest removes the hooks project, treat it as if it deleted | ||
927 | # the repo-hooks element too. | ||
928 | if self._repo_hooks_project and (self._repo_hooks_project.name == name): | ||
929 | self._repo_hooks_project = None | ||
930 | elif not XmlBool(node, 'optional', False): | ||
922 | raise ManifestParseError('remove-project element specifies non-existent ' | 931 | raise ManifestParseError('remove-project element specifies non-existent ' |
923 | 'project: %s' % name) | 932 | 'project: %s' % name) |
924 | 933 | ||
925 | for p in self._projects[name]: | ||
926 | del self._paths[p.relpath] | ||
927 | del self._projects[name] | ||
928 | |||
929 | # If the manifest removes the hooks project, treat it as if it deleted | ||
930 | # the repo-hooks element too. | ||
931 | if self._repo_hooks_project and (self._repo_hooks_project.name == name): | ||
932 | self._repo_hooks_project = None | ||
933 | |||
934 | def _AddMetaProjectMirror(self, m): | 934 | def _AddMetaProjectMirror(self, m): |
935 | name = None | 935 | name = None |
936 | m_url = m.GetRemote(m.remote.name).url | 936 | m_url = m.GetRemote(m.remote.name).url |
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py index 55468b51..96ee4c4a 100644 --- a/tests/test_manifest_xml.py +++ b/tests/test_manifest_xml.py | |||
@@ -638,3 +638,53 @@ class RemoteElementTests(ManifestParseTestCase): | |||
638 | self.assertNotEqual(a, manifest_xml._Default()) | 638 | self.assertNotEqual(a, manifest_xml._Default()) |
639 | self.assertNotEqual(a, 123) | 639 | self.assertNotEqual(a, 123) |
640 | self.assertNotEqual(a, None) | 640 | self.assertNotEqual(a, None) |
641 | |||
642 | |||
643 | class RemoveProjectElementTests(ManifestParseTestCase): | ||
644 | """Tests for <remove-project>.""" | ||
645 | |||
646 | def test_remove_one_project(self): | ||
647 | manifest = self.getXmlManifest(""" | ||
648 | <manifest> | ||
649 | <remote name="default-remote" fetch="http://localhost" /> | ||
650 | <default remote="default-remote" revision="refs/heads/main" /> | ||
651 | <project name="myproject" /> | ||
652 | <remove-project name="myproject" /> | ||
653 | </manifest> | ||
654 | """) | ||
655 | self.assertEqual(manifest.projects, []) | ||
656 | |||
657 | def test_remove_one_project_one_remains(self): | ||
658 | manifest = self.getXmlManifest(""" | ||
659 | <manifest> | ||
660 | <remote name="default-remote" fetch="http://localhost" /> | ||
661 | <default remote="default-remote" revision="refs/heads/main" /> | ||
662 | <project name="myproject" /> | ||
663 | <project name="yourproject" /> | ||
664 | <remove-project name="myproject" /> | ||
665 | </manifest> | ||
666 | """) | ||
667 | |||
668 | self.assertEqual(len(manifest.projects), 1) | ||
669 | self.assertEqual(manifest.projects[0].name, 'yourproject') | ||
670 | |||
671 | def test_remove_one_project_doesnt_exist(self): | ||
672 | with self.assertRaises(manifest_xml.ManifestParseError): | ||
673 | manifest = self.getXmlManifest(""" | ||
674 | <manifest> | ||
675 | <remote name="default-remote" fetch="http://localhost" /> | ||
676 | <default remote="default-remote" revision="refs/heads/main" /> | ||
677 | <remove-project name="myproject" /> | ||
678 | </manifest> | ||
679 | """) | ||
680 | manifest.projects | ||
681 | |||
682 | def test_remove_one_optional_project_doesnt_exist(self): | ||
683 | manifest = self.getXmlManifest(""" | ||
684 | <manifest> | ||
685 | <remote name="default-remote" fetch="http://localhost" /> | ||
686 | <default remote="default-remote" revision="refs/heads/main" /> | ||
687 | <remove-project name="myproject" optional="true" /> | ||
688 | </manifest> | ||
689 | """) | ||
690 | self.assertEqual(manifest.projects, []) | ||