mirror of
https://gerrit.googlesource.com/git-repo
synced 2025-06-28 20:17:26 +00:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
0458faa502 | |||
68d5d4dfe5 | |||
a3794e9c6f | |||
080877e413 |
@ -178,9 +178,7 @@ class Command(object):
|
||||
mp = manifest.manifestProject
|
||||
|
||||
if not groups:
|
||||
groups = mp.config.GetString('manifest.groups')
|
||||
if not groups:
|
||||
groups = 'default,platform-' + platform.system().lower()
|
||||
groups = manifest.GetGroupsStr()
|
||||
groups = [x for x in re.split(r'[,\s]+', groups) if x]
|
||||
|
||||
if not args:
|
||||
|
@ -252,12 +252,25 @@ name will be prefixed by the parent's.
|
||||
The project name must match the name Gerrit knows, if Gerrit is
|
||||
being used for code reviews.
|
||||
|
||||
"name" must not be empty, and may not be an absolute path or use "." or ".."
|
||||
path components. It is always interpreted relative to the remote's fetch
|
||||
settings, so if a different base path is needed, declare a different remote
|
||||
with the new settings needed.
|
||||
These restrictions are not enforced for [Local Manifests].
|
||||
|
||||
Attribute `path`: An optional path relative to the top directory
|
||||
of the repo client where the Git working directory for this project
|
||||
should be placed. If not supplied the project name is used.
|
||||
should be placed. If not supplied the project "name" is used.
|
||||
If the project has a parent element, its path will be prefixed
|
||||
by the parent's.
|
||||
|
||||
"path" may not be an absolute path or use "." or ".." path components.
|
||||
These restrictions are not enforced for [Local Manifests].
|
||||
|
||||
If you want to place files into the root of the checkout (e.g. a README or
|
||||
Makefile or another build script), use the [copyfile] or [linkfile] elements
|
||||
instead.
|
||||
|
||||
Attribute `remote`: Name of a previously defined remote element.
|
||||
If not supplied the remote given by the default element is used.
|
||||
|
||||
@ -419,12 +432,15 @@ target manifest to include - it must be a usable manifest on its own.
|
||||
Attribute `name`: the manifest to include, specified relative to
|
||||
the manifest repository's root.
|
||||
|
||||
"name" may not be an absolute path or use "." or ".." path components.
|
||||
These restrictions are not enforced for [Local Manifests].
|
||||
|
||||
Attribute `groups`: List of additional groups to which all projects
|
||||
in the included manifest belong. This appends and recurses, meaning
|
||||
all projects in sub-manifests carry all parent include groups.
|
||||
Same syntax as the corresponding element of `project`.
|
||||
|
||||
## Local Manifests
|
||||
## Local Manifests {#local-manifests}
|
||||
|
||||
Additional remotes and projects may be added through local manifest
|
||||
files stored in `$TOP_DIR/.repo/local_manifests/*.xml`.
|
||||
@ -452,3 +468,8 @@ Manifest files stored in `$TOP_DIR/.repo/local_manifests/*.xml` will
|
||||
be loaded in alphabetical order.
|
||||
|
||||
The legacy `$TOP_DIR/.repo/local_manifest.xml` path is no longer supported.
|
||||
|
||||
|
||||
[copyfile]: #Element-copyfile
|
||||
[linkfile]: #Element-linkfile
|
||||
[Local Manifests]: #local-manifests
|
||||
|
@ -235,7 +235,7 @@ class Superproject(object):
|
||||
self._superproject_path,
|
||||
file=sys.stderr)
|
||||
return None
|
||||
manifest_str = self._manifest.ToXml().toxml()
|
||||
manifest_str = self._manifest.ToXml(groups=self._manifest.GetGroupsStr()).toxml()
|
||||
manifest_path = self._manifest_path
|
||||
try:
|
||||
with open(manifest_path, 'w', encoding='utf-8') as fp:
|
||||
|
@ -77,22 +77,6 @@ def _set_project_revisions(projects):
|
||||
project.revisionExpr = revisionExpr
|
||||
|
||||
|
||||
def _manifest_groups(manifest):
|
||||
"""Returns the manifest group string that should be synced
|
||||
|
||||
This is the same logic used by Command.GetProjects(), which is used during
|
||||
repo sync
|
||||
|
||||
Args:
|
||||
manifest: The XmlManifest object
|
||||
"""
|
||||
mp = manifest.manifestProject
|
||||
groups = mp.config.GetString('manifest.groups')
|
||||
if not groups:
|
||||
groups = 'default,platform-' + platform.system().lower()
|
||||
return groups
|
||||
|
||||
|
||||
def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
|
||||
"""Generate a manifest for shafsd to use for this GITC client.
|
||||
|
||||
@ -107,7 +91,7 @@ def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
|
||||
if paths is None:
|
||||
paths = list(manifest.paths.keys())
|
||||
|
||||
groups = [x for x in re.split(r'[,\s]+', _manifest_groups(manifest)) if x]
|
||||
groups = [x for x in re.split(r'[,\s]+', manifest.GetGroupsStr()) if x]
|
||||
|
||||
# Convert the paths to projects, and filter them to the matched groups.
|
||||
projects = [manifest.paths[p] for p in paths]
|
||||
@ -166,7 +150,7 @@ def save_manifest(manifest, client_dir=None):
|
||||
else:
|
||||
manifest_file = os.path.join(client_dir, '.manifest')
|
||||
with open(manifest_file, 'w') as f:
|
||||
manifest.Save(f, groups=_manifest_groups(manifest))
|
||||
manifest.Save(f, groups=manifest.GetGroupsStr())
|
||||
# TODO(sbasi/jorg): Come up with a solution to remove the sleep below.
|
||||
# Give the GITC filesystem time to register the manifest changes.
|
||||
time.sleep(3)
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import xml.dom.minidom
|
||||
@ -604,6 +605,17 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
||||
def HasSubmodules(self):
|
||||
return self.manifestProject.config.GetBoolean('repo.submodules')
|
||||
|
||||
def GetDefaultGroupsStr(self):
|
||||
"""Returns the default group string for the platform."""
|
||||
return 'default,platform-' + platform.system().lower()
|
||||
|
||||
def GetGroupsStr(self):
|
||||
"""Returns the manifest group string that should be synced."""
|
||||
groups = self.manifestProject.config.GetString('manifest.groups')
|
||||
if not groups:
|
||||
groups = self.GetDefaultGroupsStr()
|
||||
return groups
|
||||
|
||||
def _Unload(self):
|
||||
self._loaded = False
|
||||
self._projects = {}
|
||||
@ -1027,7 +1039,8 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
||||
if not path:
|
||||
path = name
|
||||
else:
|
||||
msg = self._CheckLocalPath(path, dir_ok=True)
|
||||
# NB: The "." project is handled specially in Project.Sync_LocalHalf.
|
||||
msg = self._CheckLocalPath(path, dir_ok=True, cwd_dot_ok=True)
|
||||
if msg:
|
||||
raise ManifestInvalidPathError(
|
||||
'<project> invalid "path": %s: %s' % (path, msg))
|
||||
@ -1215,7 +1228,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
||||
# our constructed logic here. Especially since manifest authors only use
|
||||
# / in their paths.
|
||||
resep = re.compile(r'[/%s]' % re.escape(os.path.sep))
|
||||
parts = resep.split(path)
|
||||
# Strip off trailing slashes as those only produce '' elements, and we use
|
||||
# parts to look for individual bad components.
|
||||
parts = resep.split(path.rstrip('/'))
|
||||
|
||||
# Some people use src="." to create stable links to projects. Lets allow
|
||||
# that but reject all other uses of "." to keep things simple.
|
||||
|
17
project.py
17
project.py
@ -1227,6 +1227,18 @@ class Project(object):
|
||||
self.CleanPublishedCache(all_refs)
|
||||
revid = self.GetRevisionId(all_refs)
|
||||
|
||||
# Special case the root of the repo client checkout. Make sure it doesn't
|
||||
# contain files being checked out to dirs we don't allow.
|
||||
if self.relpath == '.':
|
||||
PROTECTED_PATHS = {'.repo'}
|
||||
paths = set(self.work_git.ls_tree('-z', '--name-only', '--', revid).split('\0'))
|
||||
bad_paths = paths & PROTECTED_PATHS
|
||||
if bad_paths:
|
||||
syncbuf.fail(self,
|
||||
'Refusing to checkout project that writes to protected '
|
||||
'paths: %s' % (', '.join(bad_paths),))
|
||||
return
|
||||
|
||||
def _doff():
|
||||
self._FastForward(revid)
|
||||
self._CopyAndLinkFiles()
|
||||
@ -1698,6 +1710,11 @@ class Project(object):
|
||||
if cb is None or name != cb:
|
||||
kill.append(name)
|
||||
|
||||
# Minor optimization: If there's nothing to prune, then don't try to read
|
||||
# any project state.
|
||||
if not kill and not cb:
|
||||
return []
|
||||
|
||||
rev = self.GetRevisionId(left)
|
||||
if cb is not None \
|
||||
and not self._revlist(HEAD + '...' + rev) \
|
||||
|
@ -267,7 +267,7 @@ to update the working directory files.
|
||||
|
||||
groups = [x for x in groups if x]
|
||||
groupstr = ','.join(groups)
|
||||
if opt.platform == 'auto' and groupstr == 'default,platform-' + platform.system().lower():
|
||||
if opt.platform == 'auto' and groupstr == self.manifest.GetDefaultGroupsStr():
|
||||
groupstr = None
|
||||
m.config.SetString('manifest.groups', groupstr)
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
"""Unittests for the git_superproject.py module."""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
@ -34,6 +35,7 @@ class SuperprojectTestCase(unittest.TestCase):
|
||||
self.manifest_file = os.path.join(
|
||||
self.repodir, manifest_xml.MANIFEST_FILE_NAME)
|
||||
os.mkdir(self.repodir)
|
||||
self.platform = platform.system().lower()
|
||||
|
||||
# The manifest parsing really wants a git repo currently.
|
||||
gitdir = os.path.join(self.repodir, 'manifests.git')
|
||||
@ -48,8 +50,8 @@ class SuperprojectTestCase(unittest.TestCase):
|
||||
<remote name="default-remote" fetch="http://localhost" />
|
||||
<default remote="default-remote" revision="refs/heads/main" />
|
||||
<superproject name="superproject"/>
|
||||
<project path="art" name="platform/art" />
|
||||
</manifest>
|
||||
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
||||
" /></manifest>
|
||||
""")
|
||||
self._superproject = git_superproject.Superproject(manifest, self.repodir)
|
||||
|
||||
@ -142,7 +144,8 @@ class SuperprojectTestCase(unittest.TestCase):
|
||||
'<?xml version="1.0" ?><manifest>' +
|
||||
'<remote name="default-remote" fetch="http://localhost"/>' +
|
||||
'<default remote="default-remote" revision="refs/heads/main"/>' +
|
||||
'<project name="platform/art" path="art" revision="ABCDEF"/>' +
|
||||
'<project name="platform/art" path="art" revision="ABCDEF" ' +
|
||||
'groups="notdefault,platform-' + self.platform + '"/>' +
|
||||
'<superproject name="superproject"/>' +
|
||||
'</manifest>')
|
||||
|
||||
@ -169,7 +172,8 @@ class SuperprojectTestCase(unittest.TestCase):
|
||||
'<remote name="default-remote" fetch="http://localhost"/>' +
|
||||
'<default remote="default-remote" revision="refs/heads/main"/>' +
|
||||
'<project name="platform/art" path="art" ' +
|
||||
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea"/>' +
|
||||
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" ' +
|
||||
'groups="notdefault,platform-' + self.platform + '"/>' +
|
||||
'<superproject name="superproject"/>' +
|
||||
'</manifest>')
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
"""Unittests for the manifest_xml.py module."""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
@ -31,6 +32,7 @@ INVALID_FS_PATHS = (
|
||||
'..',
|
||||
'../',
|
||||
'./',
|
||||
'.//',
|
||||
'foo/',
|
||||
'./foo',
|
||||
'../foo',
|
||||
@ -377,6 +379,11 @@ class ProjectElementTests(ManifestParseTestCase):
|
||||
self.assertCountEqual(
|
||||
result['extras'],
|
||||
['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path'])
|
||||
groupstr = 'default,platform-' + platform.system().lower()
|
||||
self.assertEqual(groupstr, manifest.GetGroupsStr())
|
||||
groupstr = 'g1,g2,g1'
|
||||
manifest.manifestProject.config.SetString('manifest.groups', groupstr)
|
||||
self.assertEqual(groupstr, manifest.GetGroupsStr())
|
||||
|
||||
def test_set_revision_id(self):
|
||||
"""Check setting of project's revisionId."""
|
||||
@ -421,6 +428,28 @@ class ProjectElementTests(ManifestParseTestCase):
|
||||
self.assertEqual(manifest.projects[0].objdir,
|
||||
os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
|
||||
|
||||
manifest = parse('a/path', 'foo//////')
|
||||
self.assertEqual(manifest.projects[0].gitdir,
|
||||
os.path.join(self.tempdir, '.repo/projects/foo.git'))
|
||||
self.assertEqual(manifest.projects[0].objdir,
|
||||
os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
|
||||
|
||||
def test_toplevel_path(self):
|
||||
"""Check handling of path=. specially."""
|
||||
def parse(name, path):
|
||||
return self.getXmlManifest(f"""
|
||||
<manifest>
|
||||
<remote name="default-remote" fetch="http://localhost" />
|
||||
<default remote="default-remote" revision="refs/heads/main" />
|
||||
<project name="{name}" path="{path}" />
|
||||
</manifest>
|
||||
""")
|
||||
|
||||
for path in ('.', './', './/', './//'):
|
||||
manifest = parse('server/path', path)
|
||||
self.assertEqual(manifest.projects[0].gitdir,
|
||||
os.path.join(self.tempdir, '.repo/projects/..git'))
|
||||
|
||||
def test_bad_path_name_checks(self):
|
||||
"""Check handling of bad path & name attributes."""
|
||||
def parse(name, path):
|
||||
@ -448,8 +477,11 @@ class ProjectElementTests(ManifestParseTestCase):
|
||||
|
||||
with self.assertRaises(error.ManifestInvalidPathError):
|
||||
parse(path, 'ok')
|
||||
with self.assertRaises(error.ManifestInvalidPathError):
|
||||
parse('ok', path)
|
||||
|
||||
# We have a dedicated test for path=".".
|
||||
if path not in {'.'}:
|
||||
with self.assertRaises(error.ManifestInvalidPathError):
|
||||
parse('ok', path)
|
||||
|
||||
|
||||
class SuperProjectElementTests(ManifestParseTestCase):
|
||||
|
Reference in New Issue
Block a user