diff options
| -rw-r--r-- | docs/manifest-format.md | 6 | ||||
| -rw-r--r-- | manifest_xml.py | 11 | ||||
| -rw-r--r-- | project.py | 39 | ||||
| -rw-r--r-- | tests/test_manifest_xml.py | 46 |
4 files changed, 85 insertions, 17 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md index ed297ae7..8e0049b3 100644 --- a/docs/manifest-format.md +++ b/docs/manifest-format.md | |||
| @@ -90,6 +90,7 @@ following DTD: | |||
| 90 | <!ELEMENT extend-project EMPTY> | 90 | <!ELEMENT extend-project EMPTY> |
| 91 | <!ATTLIST extend-project name CDATA #REQUIRED> | 91 | <!ATTLIST extend-project name CDATA #REQUIRED> |
| 92 | <!ATTLIST extend-project path CDATA #IMPLIED> | 92 | <!ATTLIST extend-project path CDATA #IMPLIED> |
| 93 | <!ATTLIST extend-project dest-path CDATA #IMPLIED> | ||
| 93 | <!ATTLIST extend-project groups CDATA #IMPLIED> | 94 | <!ATTLIST extend-project groups CDATA #IMPLIED> |
| 94 | <!ATTLIST extend-project revision CDATA #IMPLIED> | 95 | <!ATTLIST extend-project revision CDATA #IMPLIED> |
| 95 | <!ATTLIST extend-project remote CDATA #IMPLIED> | 96 | <!ATTLIST extend-project remote CDATA #IMPLIED> |
| @@ -337,6 +338,11 @@ against changes to the original manifest. | |||
| 337 | Attribute `path`: If specified, limit the change to projects checked out | 338 | Attribute `path`: If specified, limit the change to projects checked out |
| 338 | at the specified path, rather than all projects with the given name. | 339 | at the specified path, rather than all projects with the given name. |
| 339 | 340 | ||
| 341 | Attribute `dest-path`: If specified, a path relative to the top directory | ||
| 342 | of the repo client where the Git working directory for this project | ||
| 343 | should be placed. This is used to move a project in the checkout by | ||
| 344 | overriding the existing `path` setting. | ||
| 345 | |||
| 340 | Attribute `groups`: List of additional groups to which this project | 346 | Attribute `groups`: List of additional groups to which this project |
| 341 | belongs. Same syntax as the corresponding element of `project`. | 347 | belongs. Same syntax as the corresponding element of `project`. |
| 342 | 348 | ||
diff --git a/manifest_xml.py b/manifest_xml.py index 86f20202..39656975 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
| @@ -868,6 +868,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 868 | 'project: %s' % name) | 868 | 'project: %s' % name) |
| 869 | 869 | ||
| 870 | path = node.getAttribute('path') | 870 | path = node.getAttribute('path') |
| 871 | dest_path = node.getAttribute('dest-path') | ||
| 871 | groups = node.getAttribute('groups') | 872 | groups = node.getAttribute('groups') |
| 872 | if groups: | 873 | if groups: |
| 873 | groups = self._ParseList(groups) | 874 | groups = self._ParseList(groups) |
| @@ -876,6 +877,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 876 | if remote: | 877 | if remote: |
| 877 | remote = self._get_remote(node) | 878 | remote = self._get_remote(node) |
| 878 | 879 | ||
| 880 | named_projects = self._projects[name] | ||
| 881 | if dest_path and not path and len(named_projects) > 1: | ||
| 882 | raise ManifestParseError('extend-project cannot use dest-path when ' | ||
| 883 | 'matching multiple projects: %s' % name) | ||
| 879 | for p in self._projects[name]: | 884 | for p in self._projects[name]: |
| 880 | if path and p.relpath != path: | 885 | if path and p.relpath != path: |
| 881 | continue | 886 | continue |
| @@ -889,6 +894,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 889 | p.revisionId = None | 894 | p.revisionId = None |
| 890 | if remote: | 895 | if remote: |
| 891 | p.remote = remote.ToRemoteSpec(name) | 896 | p.remote = remote.ToRemoteSpec(name) |
| 897 | if dest_path: | ||
| 898 | del self._paths[p.relpath] | ||
| 899 | relpath, worktree, gitdir, objdir, _ = self.GetProjectPaths(name, dest_path) | ||
| 900 | p.UpdatePaths(relpath, worktree, gitdir, objdir) | ||
| 901 | self._paths[p.relpath] = p | ||
| 902 | |||
| 892 | if node.nodeName == 'repo-hooks': | 903 | if node.nodeName == 'repo-hooks': |
| 893 | # Only one project can be the hooks project | 904 | # Only one project can be the hooks project |
| 894 | if repo_hooks_project is not None: | 905 | if repo_hooks_project is not None: |
| @@ -519,13 +519,7 @@ class Project(object): | |||
| 519 | self.client = self.manifest = manifest | 519 | self.client = self.manifest = manifest |
| 520 | self.name = name | 520 | self.name = name |
| 521 | self.remote = remote | 521 | self.remote = remote |
| 522 | self.gitdir = gitdir.replace('\\', '/') | 522 | self.UpdatePaths(relpath, worktree, gitdir, objdir) |
| 523 | self.objdir = objdir.replace('\\', '/') | ||
| 524 | if worktree: | ||
| 525 | self.worktree = os.path.normpath(worktree).replace('\\', '/') | ||
| 526 | else: | ||
| 527 | self.worktree = None | ||
| 528 | self.relpath = relpath | ||
| 529 | self.revisionExpr = revisionExpr | 523 | self.revisionExpr = revisionExpr |
| 530 | 524 | ||
| 531 | if revisionId is None \ | 525 | if revisionId is None \ |
| @@ -556,16 +550,6 @@ class Project(object): | |||
| 556 | self.copyfiles = [] | 550 | self.copyfiles = [] |
| 557 | self.linkfiles = [] | 551 | self.linkfiles = [] |
| 558 | self.annotations = [] | 552 | self.annotations = [] |
| 559 | self.config = GitConfig.ForRepository(gitdir=self.gitdir, | ||
| 560 | defaults=self.client.globalConfig) | ||
| 561 | |||
| 562 | if self.worktree: | ||
| 563 | self.work_git = self._GitGetByExec(self, bare=False, gitdir=gitdir) | ||
| 564 | else: | ||
| 565 | self.work_git = None | ||
| 566 | self.bare_git = self._GitGetByExec(self, bare=True, gitdir=gitdir) | ||
| 567 | self.bare_ref = GitRefs(gitdir) | ||
| 568 | self.bare_objdir = self._GitGetByExec(self, bare=True, gitdir=objdir) | ||
| 569 | self.dest_branch = dest_branch | 553 | self.dest_branch = dest_branch |
| 570 | self.old_revision = old_revision | 554 | self.old_revision = old_revision |
| 571 | 555 | ||
| @@ -573,6 +557,27 @@ class Project(object): | |||
| 573 | # project containing repo hooks. | 557 | # project containing repo hooks. |
| 574 | self.enabled_repo_hooks = [] | 558 | self.enabled_repo_hooks = [] |
| 575 | 559 | ||
| 560 | def UpdatePaths(self, relpath, worktree, gitdir, objdir): | ||
| 561 | """Update paths used by this project""" | ||
| 562 | self.gitdir = gitdir.replace('\\', '/') | ||
| 563 | self.objdir = objdir.replace('\\', '/') | ||
| 564 | if worktree: | ||
| 565 | self.worktree = os.path.normpath(worktree).replace('\\', '/') | ||
| 566 | else: | ||
| 567 | self.worktree = None | ||
| 568 | self.relpath = relpath | ||
| 569 | |||
| 570 | self.config = GitConfig.ForRepository(gitdir=self.gitdir, | ||
| 571 | defaults=self.manifest.globalConfig) | ||
| 572 | |||
| 573 | if self.worktree: | ||
| 574 | self.work_git = self._GitGetByExec(self, bare=False, gitdir=self.gitdir) | ||
| 575 | else: | ||
| 576 | self.work_git = None | ||
| 577 | self.bare_git = self._GitGetByExec(self, bare=True, gitdir=self.gitdir) | ||
| 578 | self.bare_ref = GitRefs(self.gitdir) | ||
| 579 | self.bare_objdir = self._GitGetByExec(self, bare=True, gitdir=self.objdir) | ||
| 580 | |||
| 576 | @property | 581 | @property |
| 577 | def Derived(self): | 582 | def Derived(self): |
| 578 | return self.is_derived | 583 | return self.is_derived |
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py index ce422536..cb3eb855 100644 --- a/tests/test_manifest_xml.py +++ b/tests/test_manifest_xml.py | |||
| @@ -797,3 +797,49 @@ class RemoveProjectElementTests(ManifestParseTestCase): | |||
| 797 | </manifest> | 797 | </manifest> |
| 798 | """) | 798 | """) |
| 799 | self.assertEqual(manifest.projects, []) | 799 | self.assertEqual(manifest.projects, []) |
| 800 | |||
| 801 | |||
| 802 | class ExtendProjectElementTests(ManifestParseTestCase): | ||
| 803 | """Tests for <extend-project>.""" | ||
| 804 | |||
| 805 | def test_extend_project_dest_path_single_match(self): | ||
| 806 | manifest = self.getXmlManifest(""" | ||
| 807 | <manifest> | ||
| 808 | <remote name="default-remote" fetch="http://localhost" /> | ||
| 809 | <default remote="default-remote" revision="refs/heads/main" /> | ||
| 810 | <project name="myproject" /> | ||
| 811 | <extend-project name="myproject" dest-path="bar" /> | ||
| 812 | </manifest> | ||
| 813 | """) | ||
| 814 | self.assertEqual(len(manifest.projects), 1) | ||
| 815 | self.assertEqual(manifest.projects[0].relpath, 'bar') | ||
| 816 | |||
| 817 | def test_extend_project_dest_path_multi_match(self): | ||
| 818 | with self.assertRaises(manifest_xml.ManifestParseError): | ||
| 819 | manifest = self.getXmlManifest(""" | ||
| 820 | <manifest> | ||
| 821 | <remote name="default-remote" fetch="http://localhost" /> | ||
| 822 | <default remote="default-remote" revision="refs/heads/main" /> | ||
| 823 | <project name="myproject" path="x" /> | ||
| 824 | <project name="myproject" path="y" /> | ||
| 825 | <extend-project name="myproject" dest-path="bar" /> | ||
| 826 | </manifest> | ||
| 827 | """) | ||
| 828 | manifest.projects | ||
| 829 | |||
| 830 | def test_extend_project_dest_path_multi_match_path_specified(self): | ||
| 831 | manifest = self.getXmlManifest(""" | ||
| 832 | <manifest> | ||
| 833 | <remote name="default-remote" fetch="http://localhost" /> | ||
| 834 | <default remote="default-remote" revision="refs/heads/main" /> | ||
| 835 | <project name="myproject" path="x" /> | ||
| 836 | <project name="myproject" path="y" /> | ||
| 837 | <extend-project name="myproject" path="x" dest-path="bar" /> | ||
| 838 | </manifest> | ||
| 839 | """) | ||
| 840 | self.assertEqual(len(manifest.projects), 2) | ||
| 841 | if manifest.projects[0].relpath == 'y': | ||
| 842 | self.assertEqual(manifest.projects[1].relpath, 'bar') | ||
| 843 | else: | ||
| 844 | self.assertEqual(manifest.projects[0].relpath, 'bar') | ||
| 845 | self.assertEqual(manifest.projects[1].relpath, 'y') | ||
