Add 'dest-path' to extend-project to support changing path

This allows us to move the repository to a new location in the source
tree without having to remove-project + add a new project tag.

Change-Id: I4dba6151842e57f6f2b8fe60cda260ecea68b7b4
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/310962
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Michael Kelly <mkelly@arista.com>
This commit is contained in:
Michael Kelly 2020-06-13 02:10:40 -07:00
parent b12c369e0b
commit 37c21c268b
4 changed files with 85 additions and 17 deletions

View File

@ -90,6 +90,7 @@ following DTD:
<!ELEMENT extend-project EMPTY> <!ELEMENT extend-project EMPTY>
<!ATTLIST extend-project name CDATA #REQUIRED> <!ATTLIST extend-project name CDATA #REQUIRED>
<!ATTLIST extend-project path CDATA #IMPLIED> <!ATTLIST extend-project path CDATA #IMPLIED>
<!ATTLIST extend-project dest-path CDATA #IMPLIED>
<!ATTLIST extend-project groups CDATA #IMPLIED> <!ATTLIST extend-project groups CDATA #IMPLIED>
<!ATTLIST extend-project revision CDATA #IMPLIED> <!ATTLIST extend-project revision CDATA #IMPLIED>
<!ATTLIST extend-project remote CDATA #IMPLIED> <!ATTLIST extend-project remote CDATA #IMPLIED>
@ -337,6 +338,11 @@ against changes to the original manifest.
Attribute `path`: If specified, limit the change to projects checked out Attribute `path`: If specified, limit the change to projects checked out
at the specified path, rather than all projects with the given name. at the specified path, rather than all projects with the given name.
Attribute `dest-path`: If specified, a path relative to the top directory
of the repo client where the Git working directory for this project
should be placed. This is used to move a project in the checkout by
overriding the existing `path` setting.
Attribute `groups`: List of additional groups to which this project Attribute `groups`: List of additional groups to which this project
belongs. Same syntax as the corresponding element of `project`. belongs. Same syntax as the corresponding element of `project`.

View File

@ -868,6 +868,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
'project: %s' % name) 'project: %s' % name)
path = node.getAttribute('path') path = node.getAttribute('path')
dest_path = node.getAttribute('dest-path')
groups = node.getAttribute('groups') groups = node.getAttribute('groups')
if groups: if groups:
groups = self._ParseList(groups) groups = self._ParseList(groups)
@ -876,6 +877,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
if remote: if remote:
remote = self._get_remote(node) remote = self._get_remote(node)
named_projects = self._projects[name]
if dest_path and not path and len(named_projects) > 1:
raise ManifestParseError('extend-project cannot use dest-path when '
'matching multiple projects: %s' % name)
for p in self._projects[name]: for p in self._projects[name]:
if path and p.relpath != path: if path and p.relpath != path:
continue continue
@ -889,6 +894,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
p.revisionId = None p.revisionId = None
if remote: if remote:
p.remote = remote.ToRemoteSpec(name) p.remote = remote.ToRemoteSpec(name)
if dest_path:
del self._paths[p.relpath]
relpath, worktree, gitdir, objdir, _ = self.GetProjectPaths(name, dest_path)
p.UpdatePaths(relpath, worktree, gitdir, objdir)
self._paths[p.relpath] = p
if node.nodeName == 'repo-hooks': if node.nodeName == 'repo-hooks':
# Only one project can be the hooks project # Only one project can be the hooks project
if repo_hooks_project is not None: if repo_hooks_project is not None:

View File

@ -519,13 +519,7 @@ class Project(object):
self.client = self.manifest = manifest self.client = self.manifest = manifest
self.name = name self.name = name
self.remote = remote self.remote = remote
self.gitdir = gitdir.replace('\\', '/') self.UpdatePaths(relpath, worktree, gitdir, objdir)
self.objdir = objdir.replace('\\', '/')
if worktree:
self.worktree = os.path.normpath(worktree).replace('\\', '/')
else:
self.worktree = None
self.relpath = relpath
self.revisionExpr = revisionExpr self.revisionExpr = revisionExpr
if revisionId is None \ if revisionId is None \
@ -556,16 +550,6 @@ class Project(object):
self.copyfiles = [] self.copyfiles = []
self.linkfiles = [] self.linkfiles = []
self.annotations = [] self.annotations = []
self.config = GitConfig.ForRepository(gitdir=self.gitdir,
defaults=self.client.globalConfig)
if self.worktree:
self.work_git = self._GitGetByExec(self, bare=False, gitdir=gitdir)
else:
self.work_git = None
self.bare_git = self._GitGetByExec(self, bare=True, gitdir=gitdir)
self.bare_ref = GitRefs(gitdir)
self.bare_objdir = self._GitGetByExec(self, bare=True, gitdir=objdir)
self.dest_branch = dest_branch self.dest_branch = dest_branch
self.old_revision = old_revision self.old_revision = old_revision
@ -573,6 +557,27 @@ class Project(object):
# project containing repo hooks. # project containing repo hooks.
self.enabled_repo_hooks = [] self.enabled_repo_hooks = []
def UpdatePaths(self, relpath, worktree, gitdir, objdir):
"""Update paths used by this project"""
self.gitdir = gitdir.replace('\\', '/')
self.objdir = objdir.replace('\\', '/')
if worktree:
self.worktree = os.path.normpath(worktree).replace('\\', '/')
else:
self.worktree = None
self.relpath = relpath
self.config = GitConfig.ForRepository(gitdir=self.gitdir,
defaults=self.manifest.globalConfig)
if self.worktree:
self.work_git = self._GitGetByExec(self, bare=False, gitdir=self.gitdir)
else:
self.work_git = None
self.bare_git = self._GitGetByExec(self, bare=True, gitdir=self.gitdir)
self.bare_ref = GitRefs(self.gitdir)
self.bare_objdir = self._GitGetByExec(self, bare=True, gitdir=self.objdir)
@property @property
def Derived(self): def Derived(self):
return self.is_derived return self.is_derived

View File

@ -797,3 +797,49 @@ class RemoveProjectElementTests(ManifestParseTestCase):
</manifest> </manifest>
""") """)
self.assertEqual(manifest.projects, []) self.assertEqual(manifest.projects, [])
class ExtendProjectElementTests(ManifestParseTestCase):
"""Tests for <extend-project>."""
def test_extend_project_dest_path_single_match(self):
manifest = self.getXmlManifest("""
<manifest>
<remote name="default-remote" fetch="http://localhost" />
<default remote="default-remote" revision="refs/heads/main" />
<project name="myproject" />
<extend-project name="myproject" dest-path="bar" />
</manifest>
""")
self.assertEqual(len(manifest.projects), 1)
self.assertEqual(manifest.projects[0].relpath, 'bar')
def test_extend_project_dest_path_multi_match(self):
with self.assertRaises(manifest_xml.ManifestParseError):
manifest = self.getXmlManifest("""
<manifest>
<remote name="default-remote" fetch="http://localhost" />
<default remote="default-remote" revision="refs/heads/main" />
<project name="myproject" path="x" />
<project name="myproject" path="y" />
<extend-project name="myproject" dest-path="bar" />
</manifest>
""")
manifest.projects
def test_extend_project_dest_path_multi_match_path_specified(self):
manifest = self.getXmlManifest("""
<manifest>
<remote name="default-remote" fetch="http://localhost" />
<default remote="default-remote" revision="refs/heads/main" />
<project name="myproject" path="x" />
<project name="myproject" path="y" />
<extend-project name="myproject" path="x" dest-path="bar" />
</manifest>
""")
self.assertEqual(len(manifest.projects), 2)
if manifest.projects[0].relpath == 'y':
self.assertEqual(manifest.projects[1].relpath, 'bar')
else:
self.assertEqual(manifest.projects[0].relpath, 'bar')
self.assertEqual(manifest.projects[1].relpath, 'y')