diff options
| author | Michael Kelly <mkelly@arista.com> | 2021-06-30 01:58:28 -0700 |
|---|---|---|
| committer | Michael Kelly <mkelly@arista.com> | 2021-07-08 16:48:21 +0000 |
| commit | 06da9987f6be6ddc1637e8ae02646d6dfab09862 (patch) | |
| tree | be93f68a568f27341b61fa367a42dcdfe75df234 | |
| parent | 58929732123780497ba08ed9c2d24f4bc65971a1 (diff) | |
| download | git-repo-06da9987f6be6ddc1637e8ae02646d6dfab09862.tar.gz | |
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 <mkelly@arista.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
| -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, []) | ||
