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') | ||