diff --git a/src/west/manifest-schema.yml b/src/west/manifest-schema.yml index 13188a7..677725d 100644 --- a/src/west/manifest-schema.yml +++ b/src/west/manifest-schema.yml @@ -126,6 +126,10 @@ mapping: groups: required: false include: groups-schema + # Arbitrary project user data. + userdata: + required: false + type: any # If present, a list of project groups to enable and disable. Prefix # a group name with "-" to disable it; prefix with "+" to enable it. diff --git a/src/west/manifest.py b/src/west/manifest.py index ea84d5e..6a7c38a 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -645,6 +645,7 @@ class Project: an empty list. - ``submodules``: the project's submodules configuration; either a list of Submodule objects, or a boolean. + - ``userdata``: the parsed 'userdata' field in the manifest, or None ''' def __eq__(self, other): @@ -656,7 +657,8 @@ class Project: f'clone_depth={self.clone_depth}, ' f'west_commands={self.west_commands}, ' f'topdir={repr(self.topdir)}, ' - f'groups={self.groups})') + f'groups={repr(self.groups)}, ' + f'userdata={self.userdata})') def __str__(self): path_repr = repr(self.abspath or self.path) @@ -670,7 +672,8 @@ class Project: west_commands: Optional[WestCommandsType] = None, topdir: Optional[PathType] = None, remote_name: Optional[str] = None, - groups: Optional[GroupsType] = None): + groups: Optional[GroupsType] = None, + userdata: Optional[Any] = None): '''Project constructor. If *topdir* is ``None``, then absolute path attributes @@ -702,6 +705,7 @@ class Project: self.topdir = os.fspath(topdir) if topdir else None self.remote_name = remote_name or 'origin' self.groups: GroupsType = groups or [] + self.userdata: Any = userdata @property def path(self) -> str: @@ -2026,13 +2030,16 @@ class Manifest: self._malformed( f'project {name}: "groups" cannot be combined with "import"') + userdata = pd.get('userdata') + ret = Project(name, url, pd.get('revision', defaults.revision), path, submodules=self._load_submodules(pd.get('submodules'), f'project {name}'), clone_depth=pd.get('clone-depth'), west_commands=pd.get('west-commands'), topdir=self.topdir, remote_name=remote, - groups=groups) + groups=groups, + userdata=userdata) # Make sure the return Project's path does not escape the # workspace. We can't use escapes_directory() as that diff --git a/tests/test_manifest.py b/tests/test_manifest.py index a309754..8241e60 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -534,7 +534,7 @@ def test_project_repr(): west-commands: some-path/west-commands.yml ''') assert repr(m.projects[1]) == \ - 'Project("zephyr", "https://foo.com", revision="r", path=\'zephyr\', clone_depth=None, west_commands=[\'some-path/west-commands.yml\'], topdir=None, groups=[])' # noqa: E501 + 'Project("zephyr", "https://foo.com", revision="r", path=\'zephyr\', clone_depth=None, west_commands=[\'some-path/west-commands.yml\'], topdir=None, groups=[], userdata=None)' # noqa: E501 def test_project_sha(tmpdir): tmpdir = Path(os.fspath(tmpdir)) @@ -548,6 +548,26 @@ def test_project_sha(tmpdir): topdir=tmpdir.parent) assert project.sha(project.revision) == expected_sha +def test_project_userdata(tmpdir): + m = M('''\ + defaults: + remote: r + remotes: + - name: r + url-base: base + projects: + - name: foo + - name: bar + userdata: a-string + - name: baz + userdata: + key: value + ''') + foo, bar, baz = m.get_projects(['foo', 'bar', 'baz']) + assert foo.userdata is None + assert bar.userdata == 'a-string' + assert baz.userdata == {'key': 'value'} + def test_no_projects(): # An empty projects list is allowed.