From 06da9987f6be6ddc1637e8ae02646d6dfab09862 Mon Sep 17 00:00:00 2001 From: Michael Kelly Date: Wed, 30 Jun 2021 01:58:28 -0700 Subject: Gracefully ignore bad remove-project line Sometimes, we don't care if the remove project is referring to a non-existing project and we can just ignore it. This change allows us to ignore remove-project entries if the project that they refer to doesn't exist, making them effectively a no-op. Because this change breaks existing configuration, we allow this to be configuration controlled using the `optional` attribute in the remove-project tag. Change-Id: I6313a02983e81344eadcb4e47d7d6b037ee7420e Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/310964 Tested-by: Michael Kelly Reviewed-by: Mike Frysinger --- docs/manifest-format.md | 4 ++++ manifest_xml.py | 20 +++++++++---------- 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: + @@ -393,6 +394,9 @@ This element is mostly useful in a local manifest file, where the user can remove a project, and possibly replace it with their own definition. +Attribute `optional`: Set to true to ignore remove-project elements with no +matching `project` element. + ### Element repo-hooks 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 if node.nodeName == 'remove-project': name = self._reqatt(node, 'name') - if name not in self._projects: + if name in self._projects: + for p in self._projects[name]: + del self._paths[p.relpath] + del self._projects[name] + + # If the manifest removes the hooks project, treat it as if it deleted + # the repo-hooks element too. + if self._repo_hooks_project and (self._repo_hooks_project.name == name): + self._repo_hooks_project = None + elif not XmlBool(node, 'optional', False): raise ManifestParseError('remove-project element specifies non-existent ' 'project: %s' % name) - for p in self._projects[name]: - del self._paths[p.relpath] - del self._projects[name] - - # If the manifest removes the hooks project, treat it as if it deleted - # the repo-hooks element too. - if self._repo_hooks_project and (self._repo_hooks_project.name == name): - self._repo_hooks_project = None - def _AddMetaProjectMirror(self, m): name = None 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): self.assertNotEqual(a, manifest_xml._Default()) self.assertNotEqual(a, 123) self.assertNotEqual(a, None) + + +class RemoveProjectElementTests(ManifestParseTestCase): + """Tests for .""" + + def test_remove_one_project(self): + manifest = self.getXmlManifest(""" + + + + + + +""") + self.assertEqual(manifest.projects, []) + + def test_remove_one_project_one_remains(self): + manifest = self.getXmlManifest(""" + + + + + + + +""") + + self.assertEqual(len(manifest.projects), 1) + self.assertEqual(manifest.projects[0].name, 'yourproject') + + def test_remove_one_project_doesnt_exist(self): + with self.assertRaises(manifest_xml.ManifestParseError): + manifest = self.getXmlManifest(""" + + + + + +""") + manifest.projects + + def test_remove_one_optional_project_doesnt_exist(self): + manifest = self.getXmlManifest(""" + + + + + +""") + self.assertEqual(manifest.projects, []) -- cgit v1.2.3-54-g00ecf