spl-west-deps 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spl_west_deps-0.1.0/PKG-INFO +155 -0
- spl_west_deps-0.1.0/README.md +132 -0
- spl_west_deps-0.1.0/pyproject.toml +148 -0
- spl_west_deps-0.1.0/src/spl_west_deps/__init__.py +1 -0
- spl_west_deps-0.1.0/src/spl_west_deps/index.cmake +29 -0
- spl_west_deps-0.1.0/src/spl_west_deps/main.py +42 -0
- spl_west_deps-0.1.0/src/spl_west_deps/py.typed +0 -0
- spl_west_deps-0.1.0/src/spl_west_deps/west_installer.py +94 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spl-west-deps
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An spl-core build extension that installs the west dependencies of a variant
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Author: cuinixam
|
|
7
|
+
Author-email: cuinixam@gmail.com
|
|
8
|
+
Requires-Python: <4.0,>=3.10
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Natural Language :: English
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
18
|
+
Requires-Dist: py-app-dev (>=2.1,<3)
|
|
19
|
+
Requires-Dist: pypeline-runner (>=1.36,<2)
|
|
20
|
+
Requires-Dist: typer (>=0,<1)
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# spl-west-deps
|
|
24
|
+
|
|
25
|
+
An spl-core build extension that installs the [west](https://docs.zephyrproject.org/latest/develop/west/index.html)
|
|
26
|
+
dependencies of a variant.
|
|
27
|
+
|
|
28
|
+
The dependencies of an SPL are declared in west manifests: one at the project
|
|
29
|
+
root for what every variant needs, and one per variant for what that variant
|
|
30
|
+
adds or pins differently. The extension resolves both, installs them, and tells
|
|
31
|
+
CMake where they landed, so a variant can consume a dependency without any
|
|
32
|
+
consumer hard-coding the workspace layout.
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
The install itself is done by [pypeline](https://github.com/cuinixam/pypeline)'s
|
|
39
|
+
`WestInstall` step, which already merges several manifests, installs them and
|
|
40
|
+
reports where each dependency landed. This extension builds the execution context
|
|
41
|
+
that step reads, and turns its result into CMake variables.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Install this via pip (or your favorite package manager):
|
|
46
|
+
|
|
47
|
+
`pip install spl_west_deps`
|
|
48
|
+
|
|
49
|
+
Then, in the consuming spl-core project's `CMakeLists.txt`, after `spl.cmake` and
|
|
50
|
+
**before** the variant parts are included:
|
|
51
|
+
|
|
52
|
+
```cmake
|
|
53
|
+
include(".venv/Lib/site-packages/spl_west_deps/index.cmake")
|
|
54
|
+
|
|
55
|
+
include(${PROJECT_SOURCE_DIR}/variants/${VARIANT}/parts.cmake)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The order matters: `parts.cmake` calls `spl_add_component()` on components whose
|
|
59
|
+
sources come from the dependencies, so the dependencies must be installed first.
|
|
60
|
+
|
|
61
|
+
Remove any west step from the project's own pipeline when you enable this
|
|
62
|
+
extension. Two resolvers writing one workspace fight over the checkouts.
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
The extension needs no CMake target and no command of its own. It runs during the
|
|
67
|
+
CMake configuration and defines one variable per dependency:
|
|
68
|
+
|
|
69
|
+
| Dependency name in the manifest | CMake variable |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `brightness-controller` | `MODULE_BRIGHTNESS_CONTROLLER_PATH` |
|
|
72
|
+
|
|
73
|
+
A manifest project name is not a legal CMake identifier, so every character which
|
|
74
|
+
is not a letter or a digit becomes an underscore. A component consumes the
|
|
75
|
+
dependency through the variable and hardcodes no path:
|
|
76
|
+
|
|
77
|
+
```cmake
|
|
78
|
+
spl_add_source(${MODULE_BRIGHTNESS_CONTROLLER_PATH}/export/brightness_controller.c)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Manifests
|
|
82
|
+
|
|
83
|
+
| File | Scope |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `west.yaml` | Every variant |
|
|
86
|
+
| `variants/<VARIANT>/west.yaml` | That variant. Overrides the root manifest by project name |
|
|
87
|
+
|
|
88
|
+
An overlay can add a dependency and override one, but it cannot remove one. That
|
|
89
|
+
follows from merging by project name. So keep the root manifest to what every
|
|
90
|
+
variant needs.
|
|
91
|
+
|
|
92
|
+
Every dependency is installed under its revision, so two variants pinning one
|
|
93
|
+
dependency at two revisions get two checkouts instead of fighting over one:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
build/modules/brightness-controller/generated-code-v0.1.0/
|
|
97
|
+
build/modules/brightness-controller/generated-code-v0.5.0/
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## How it works
|
|
101
|
+
|
|
102
|
+
Unlike the other spl-core extensions, `index.cmake` does **not**
|
|
103
|
+
`cmake_language(DEFER ...)` its work to the end of the CMake configuration: the
|
|
104
|
+
dependency sources have to exist before the variant parts are processed. So the
|
|
105
|
+
file runs `spl_west_deps generate ...` while it is being included, then
|
|
106
|
+
`include()`s the generated `${CMAKE_BINARY_DIR}/spl_west_deps.cmake`.
|
|
107
|
+
|
|
108
|
+
The `generate` command:
|
|
109
|
+
|
|
110
|
+
1. Creates a pypeline `ExecutionContext` for the project.
|
|
111
|
+
2. Registers `variants/<VARIANT>/west.yaml` in the context's data registry, when
|
|
112
|
+
the variant has one. The `WestInstall` step merges the registered manifests
|
|
113
|
+
after the project root manifest, which is what makes the variant override it.
|
|
114
|
+
3. Instantiates `WestInstall` with `revision_scoped_paths` and runs it through
|
|
115
|
+
py-app-dev's `Executor`. The step is skipped while the manifests and the
|
|
116
|
+
installed directories are unchanged, so a repeated CMake configuration costs
|
|
117
|
+
nothing.
|
|
118
|
+
4. Reads the `ExternalProject` entries the step publishes and writes one
|
|
119
|
+
`set(MODULE_<NAME>_PATH ...)` per dependency.
|
|
120
|
+
|
|
121
|
+
Step 4 uses the step's `update_execution_context()`, which reads the step's
|
|
122
|
+
result file rather than its in-memory state. That is why the variables are
|
|
123
|
+
complete even on a run where the install was skipped.
|
|
124
|
+
|
|
125
|
+
## Start developing
|
|
126
|
+
|
|
127
|
+
The project is managed with [uv](https://docs.astral.sh/uv/) and orchestrated by
|
|
128
|
+
[pypeline](https://github.com/cuinixam/pypeline). Bootstrap the environment and
|
|
129
|
+
run the full pipeline (venv, pre-commit, tests) with:
|
|
130
|
+
|
|
131
|
+
```shell
|
|
132
|
+
pypeline run
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Committing changes
|
|
136
|
+
|
|
137
|
+
This repository uses [commitlint](https://github.com/conventional-changelog/commitlint) for checking if the commit message meets the [conventional commit format](https://www.conventionalcommits.org/en). Commit messages drive the automated release.
|
|
138
|
+
|
|
139
|
+
## Continuous integration & release
|
|
140
|
+
|
|
141
|
+
CI runs on **GitHub Actions** (`.github/workflows/ci.yml`): lint (pre-commit),
|
|
142
|
+
commitlint, a test matrix (Python 3.10/3.13 × Ubuntu/Windows), and a release job.
|
|
143
|
+
Releases are automated with [python-semantic-release](https://python-semantic-release.readthedocs.io/):
|
|
144
|
+
merging to `main` bumps the version from the conventional-commit history and
|
|
145
|
+
publishes to PyPI (trusted publishing) and GitHub Releases.
|
|
146
|
+
|
|
147
|
+
## Credits
|
|
148
|
+
|
|
149
|
+
[](https://github.com/copier-org/copier)
|
|
150
|
+
|
|
151
|
+
This package was created with
|
|
152
|
+
[Copier](https://copier.readthedocs.io/) and the
|
|
153
|
+
[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)
|
|
154
|
+
project template.
|
|
155
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# spl-west-deps
|
|
2
|
+
|
|
3
|
+
An spl-core build extension that installs the [west](https://docs.zephyrproject.org/latest/develop/west/index.html)
|
|
4
|
+
dependencies of a variant.
|
|
5
|
+
|
|
6
|
+
The dependencies of an SPL are declared in west manifests: one at the project
|
|
7
|
+
root for what every variant needs, and one per variant for what that variant
|
|
8
|
+
adds or pins differently. The extension resolves both, installs them, and tells
|
|
9
|
+
CMake where they landed, so a variant can consume a dependency without any
|
|
10
|
+
consumer hard-coding the workspace layout.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
The install itself is done by [pypeline](https://github.com/cuinixam/pypeline)'s
|
|
17
|
+
`WestInstall` step, which already merges several manifests, installs them and
|
|
18
|
+
reports where each dependency landed. This extension builds the execution context
|
|
19
|
+
that step reads, and turns its result into CMake variables.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Install this via pip (or your favorite package manager):
|
|
24
|
+
|
|
25
|
+
`pip install spl_west_deps`
|
|
26
|
+
|
|
27
|
+
Then, in the consuming spl-core project's `CMakeLists.txt`, after `spl.cmake` and
|
|
28
|
+
**before** the variant parts are included:
|
|
29
|
+
|
|
30
|
+
```cmake
|
|
31
|
+
include(".venv/Lib/site-packages/spl_west_deps/index.cmake")
|
|
32
|
+
|
|
33
|
+
include(${PROJECT_SOURCE_DIR}/variants/${VARIANT}/parts.cmake)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The order matters: `parts.cmake` calls `spl_add_component()` on components whose
|
|
37
|
+
sources come from the dependencies, so the dependencies must be installed first.
|
|
38
|
+
|
|
39
|
+
Remove any west step from the project's own pipeline when you enable this
|
|
40
|
+
extension. Two resolvers writing one workspace fight over the checkouts.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
The extension needs no CMake target and no command of its own. It runs during the
|
|
45
|
+
CMake configuration and defines one variable per dependency:
|
|
46
|
+
|
|
47
|
+
| Dependency name in the manifest | CMake variable |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `brightness-controller` | `MODULE_BRIGHTNESS_CONTROLLER_PATH` |
|
|
50
|
+
|
|
51
|
+
A manifest project name is not a legal CMake identifier, so every character which
|
|
52
|
+
is not a letter or a digit becomes an underscore. A component consumes the
|
|
53
|
+
dependency through the variable and hardcodes no path:
|
|
54
|
+
|
|
55
|
+
```cmake
|
|
56
|
+
spl_add_source(${MODULE_BRIGHTNESS_CONTROLLER_PATH}/export/brightness_controller.c)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Manifests
|
|
60
|
+
|
|
61
|
+
| File | Scope |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `west.yaml` | Every variant |
|
|
64
|
+
| `variants/<VARIANT>/west.yaml` | That variant. Overrides the root manifest by project name |
|
|
65
|
+
|
|
66
|
+
An overlay can add a dependency and override one, but it cannot remove one. That
|
|
67
|
+
follows from merging by project name. So keep the root manifest to what every
|
|
68
|
+
variant needs.
|
|
69
|
+
|
|
70
|
+
Every dependency is installed under its revision, so two variants pinning one
|
|
71
|
+
dependency at two revisions get two checkouts instead of fighting over one:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
build/modules/brightness-controller/generated-code-v0.1.0/
|
|
75
|
+
build/modules/brightness-controller/generated-code-v0.5.0/
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## How it works
|
|
79
|
+
|
|
80
|
+
Unlike the other spl-core extensions, `index.cmake` does **not**
|
|
81
|
+
`cmake_language(DEFER ...)` its work to the end of the CMake configuration: the
|
|
82
|
+
dependency sources have to exist before the variant parts are processed. So the
|
|
83
|
+
file runs `spl_west_deps generate ...` while it is being included, then
|
|
84
|
+
`include()`s the generated `${CMAKE_BINARY_DIR}/spl_west_deps.cmake`.
|
|
85
|
+
|
|
86
|
+
The `generate` command:
|
|
87
|
+
|
|
88
|
+
1. Creates a pypeline `ExecutionContext` for the project.
|
|
89
|
+
2. Registers `variants/<VARIANT>/west.yaml` in the context's data registry, when
|
|
90
|
+
the variant has one. The `WestInstall` step merges the registered manifests
|
|
91
|
+
after the project root manifest, which is what makes the variant override it.
|
|
92
|
+
3. Instantiates `WestInstall` with `revision_scoped_paths` and runs it through
|
|
93
|
+
py-app-dev's `Executor`. The step is skipped while the manifests and the
|
|
94
|
+
installed directories are unchanged, so a repeated CMake configuration costs
|
|
95
|
+
nothing.
|
|
96
|
+
4. Reads the `ExternalProject` entries the step publishes and writes one
|
|
97
|
+
`set(MODULE_<NAME>_PATH ...)` per dependency.
|
|
98
|
+
|
|
99
|
+
Step 4 uses the step's `update_execution_context()`, which reads the step's
|
|
100
|
+
result file rather than its in-memory state. That is why the variables are
|
|
101
|
+
complete even on a run where the install was skipped.
|
|
102
|
+
|
|
103
|
+
## Start developing
|
|
104
|
+
|
|
105
|
+
The project is managed with [uv](https://docs.astral.sh/uv/) and orchestrated by
|
|
106
|
+
[pypeline](https://github.com/cuinixam/pypeline). Bootstrap the environment and
|
|
107
|
+
run the full pipeline (venv, pre-commit, tests) with:
|
|
108
|
+
|
|
109
|
+
```shell
|
|
110
|
+
pypeline run
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Committing changes
|
|
114
|
+
|
|
115
|
+
This repository uses [commitlint](https://github.com/conventional-changelog/commitlint) for checking if the commit message meets the [conventional commit format](https://www.conventionalcommits.org/en). Commit messages drive the automated release.
|
|
116
|
+
|
|
117
|
+
## Continuous integration & release
|
|
118
|
+
|
|
119
|
+
CI runs on **GitHub Actions** (`.github/workflows/ci.yml`): lint (pre-commit),
|
|
120
|
+
commitlint, a test matrix (Python 3.10/3.13 × Ubuntu/Windows), and a release job.
|
|
121
|
+
Releases are automated with [python-semantic-release](https://python-semantic-release.readthedocs.io/):
|
|
122
|
+
merging to `main` bumps the version from the conventional-commit history and
|
|
123
|
+
publishes to PyPI (trusted publishing) and GitHub Releases.
|
|
124
|
+
|
|
125
|
+
## Credits
|
|
126
|
+
|
|
127
|
+
[](https://github.com/copier-org/copier)
|
|
128
|
+
|
|
129
|
+
This package was created with
|
|
130
|
+
[Copier](https://copier.readthedocs.io/) and the
|
|
131
|
+
[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)
|
|
132
|
+
project template.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "spl-west-deps"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "An spl-core build extension that installs the west dependencies of a variant"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "cuinixam", email = "cuinixam@gmail.com" },
|
|
9
|
+
]
|
|
10
|
+
requires-python = "<4.0,>=3.10"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Natural Language :: English",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3.10",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Software Development :: Build Tools",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
dependencies = [
|
|
24
|
+
"typer>=0,<1",
|
|
25
|
+
"py-app-dev>=2.1,<3",
|
|
26
|
+
# The WestInstall step, which owns the manifest merge and the west calls.
|
|
27
|
+
# 1.36 is the first version with revision-scoped install paths.
|
|
28
|
+
"pypeline-runner>=1.36,<2",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
spl_west_deps = "spl_west_deps.main:app"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"coverage>=7,<8",
|
|
37
|
+
"pytest>=9,<10",
|
|
38
|
+
"pytest-cov>=7,<8",
|
|
39
|
+
"pypeline-runner>=1,<2",
|
|
40
|
+
"pre-commit>=4,<5",
|
|
41
|
+
"ruff>=0,<1",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[build-system]
|
|
45
|
+
requires = ["poetry-core>=2,<3"]
|
|
46
|
+
build-backend = "poetry.core.masonry.api"
|
|
47
|
+
|
|
48
|
+
[tool.poetry]
|
|
49
|
+
packages = [{ include = "spl_west_deps", from = "src" }]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
target-version = "py310"
|
|
53
|
+
line-length = 180
|
|
54
|
+
lint.select = [
|
|
55
|
+
"B", # flake8-bugbear
|
|
56
|
+
"C4", # flake8-comprehensions
|
|
57
|
+
"S", # flake8-bandit
|
|
58
|
+
"F", # pyflake
|
|
59
|
+
"E", # pycodestyle
|
|
60
|
+
"W", # pycodestyle
|
|
61
|
+
"UP", # pyupgrade
|
|
62
|
+
"I", # isort
|
|
63
|
+
"RUF", # ruff specific
|
|
64
|
+
]
|
|
65
|
+
lint.ignore = [
|
|
66
|
+
"D203",
|
|
67
|
+
"D212",
|
|
68
|
+
"D100",
|
|
69
|
+
"D101",
|
|
70
|
+
"D102",
|
|
71
|
+
"D103",
|
|
72
|
+
"D104",
|
|
73
|
+
"D107",
|
|
74
|
+
"D401",
|
|
75
|
+
]
|
|
76
|
+
lint.per-file-ignores."bootstrap.py" = ["UP006", "UP035", "S603", "D200", "D205", "D417"]
|
|
77
|
+
lint.per-file-ignores."conftest.py" = ["D100"]
|
|
78
|
+
lint.per-file-ignores."setup.py" = ["D100"]
|
|
79
|
+
lint.per-file-ignores."tests/**/*" = ["D100", "D101", "D102", "D103", "D104", "S101"]
|
|
80
|
+
lint.isort.known-first-party = ["spl_west_deps", "tests"]
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
addopts = "-vv -Wdefault --cov=spl_west_deps --cov-report=term-missing:skip-covered --cov-report=xml -s"
|
|
84
|
+
pythonpath = ["src"]
|
|
85
|
+
testpaths = ["tests"]
|
|
86
|
+
|
|
87
|
+
[tool.coverage.run]
|
|
88
|
+
branch = true
|
|
89
|
+
|
|
90
|
+
[tool.coverage.report]
|
|
91
|
+
exclude_lines = [
|
|
92
|
+
"pragma: no cover",
|
|
93
|
+
"@overload",
|
|
94
|
+
"if TYPE_CHECKING",
|
|
95
|
+
"raise NotImplementedError",
|
|
96
|
+
'if __name__ == "__main__":',
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
[tool.mypy]
|
|
100
|
+
check_untyped_defs = true
|
|
101
|
+
disallow_any_generics = true
|
|
102
|
+
disallow_incomplete_defs = true
|
|
103
|
+
disallow_untyped_defs = true
|
|
104
|
+
mypy_path = "src/"
|
|
105
|
+
no_implicit_optional = true
|
|
106
|
+
show_error_codes = true
|
|
107
|
+
warn_unreachable = true
|
|
108
|
+
warn_unused_ignores = true
|
|
109
|
+
exclude = ['setup.py']
|
|
110
|
+
disable_error_code = ["import-untyped"]
|
|
111
|
+
|
|
112
|
+
[[tool.mypy.overrides]]
|
|
113
|
+
module = "tests.*"
|
|
114
|
+
allow_untyped_defs = true
|
|
115
|
+
|
|
116
|
+
[tool.semantic_release]
|
|
117
|
+
allow_zero_version = true
|
|
118
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
119
|
+
version_variables = [
|
|
120
|
+
"src/spl_west_deps/__init__.py:__version__",
|
|
121
|
+
]
|
|
122
|
+
build_command = """
|
|
123
|
+
pip install uv
|
|
124
|
+
uv lock
|
|
125
|
+
git add uv.lock
|
|
126
|
+
uv build
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
[tool.semantic_release.changelog]
|
|
130
|
+
exclude_commit_patterns = [
|
|
131
|
+
'''chore(?:\([^)]*?\))?: .+''',
|
|
132
|
+
'''ci(?:\([^)]*?\))?: .+''',
|
|
133
|
+
'''refactor(?:\([^)]*?\))?: .+''',
|
|
134
|
+
'''style(?:\([^)]*?\))?: .+''',
|
|
135
|
+
'''test(?:\([^)]*?\))?: .+''',
|
|
136
|
+
'''build\((?!deps\): .+)''',
|
|
137
|
+
'''Merged? .*''',
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
[tool.semantic_release.changelog.environment]
|
|
141
|
+
keep_trailing_newline = true
|
|
142
|
+
|
|
143
|
+
[tool.semantic_release.branches.main]
|
|
144
|
+
match = "main"
|
|
145
|
+
|
|
146
|
+
[tool.semantic_release.branches.noop]
|
|
147
|
+
match = "(?!main$)"
|
|
148
|
+
prerelease = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0" # Update as needed
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# There is no cmake_language(DEFER ...) here, unlike the other spl-core extensions.
|
|
2
|
+
# The dependency sources must exist before variants/${VARIANT}/parts.cmake calls
|
|
3
|
+
# spl_add_component(), so this runs while it is being included, not at the end of
|
|
4
|
+
# the CMake configuration. Include it before the variant parts.
|
|
5
|
+
|
|
6
|
+
set(WEST_DEPS_RUNNER spl_west_deps)
|
|
7
|
+
set(WEST_DEPS_CMAKE_FILE ${CMAKE_BINARY_DIR}/spl_west_deps.cmake)
|
|
8
|
+
|
|
9
|
+
execute_process(
|
|
10
|
+
COMMAND ${WEST_DEPS_RUNNER} generate --project-root-dir ${CMAKE_SOURCE_DIR} --variant ${VARIANT} --output-file ${WEST_DEPS_CMAKE_FILE}
|
|
11
|
+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
12
|
+
OUTPUT_VARIABLE output
|
|
13
|
+
ERROR_VARIABLE error
|
|
14
|
+
RESULT_VARIABLE result
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# print stdout/stderr
|
|
18
|
+
message(STATUS "STDERR: ${error}")
|
|
19
|
+
message(STATUS "STDOUT: ${output}")
|
|
20
|
+
|
|
21
|
+
# check if the command succeeded
|
|
22
|
+
if(result)
|
|
23
|
+
message(FATAL_ERROR "Installation of the West Dependencies extension failed.")
|
|
24
|
+
else()
|
|
25
|
+
message(STATUS "Installation of the West Dependencies extension was successful.")
|
|
26
|
+
endif()
|
|
27
|
+
|
|
28
|
+
# include the generated cmake file
|
|
29
|
+
include(${WEST_DEPS_CMAKE_FILE})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from py_app_dev.core.logging import logger
|
|
6
|
+
|
|
7
|
+
from spl_west_deps.west_installer import install_dependencies
|
|
8
|
+
|
|
9
|
+
package_name = "spl_west_deps"
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(name=package_name, help="An spl-core extension to install the west dependencies of a variant", add_completion=False)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.callback(invoke_without_command=True)
|
|
15
|
+
def version(version: bool = typer.Option(None, "--version", "-v", is_eager=True, help="Show version and exit.")) -> None:
|
|
16
|
+
"""Print package version and exit when --version supplied."""
|
|
17
|
+
if version:
|
|
18
|
+
from spl_west_deps import __version__
|
|
19
|
+
|
|
20
|
+
typer.echo(__version__)
|
|
21
|
+
raise typer.Exit()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.command()
|
|
25
|
+
def generate(
|
|
26
|
+
project_root_dir: Path = typer.Option(..., "--project-root-dir", help="The project root directory."), # noqa: B008
|
|
27
|
+
variant: str = typer.Option(..., "--variant", help="The variant of the project."),
|
|
28
|
+
output_file: Path = typer.Option(..., "--output-file", help="The CMake file to generate."), # noqa: B008
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Install the west dependencies of this variant and generate the CMake file."""
|
|
31
|
+
logger.info("[CLI] generate command invoked")
|
|
32
|
+
try:
|
|
33
|
+
install_dependencies(project_root_dir, variant, output_file)
|
|
34
|
+
logger.info("[CLI] generate command completed successfully")
|
|
35
|
+
except Exception as e:
|
|
36
|
+
logger.error(f"[CLI] generate command failed: {e}")
|
|
37
|
+
typer.echo(f"Error installing west dependencies: {e}", err=True)
|
|
38
|
+
sys.exit(1)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
app()
|
|
File without changes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Install the west dependencies of a variant and publish their locations to CMake.
|
|
2
|
+
|
|
3
|
+
The install itself is done by pypeline's ``WestInstall`` step, which already
|
|
4
|
+
merges several manifests, installs them and reports where each dependency
|
|
5
|
+
landed. This module only builds the execution context that step reads, and
|
|
6
|
+
turns its result into CMake variables.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from py_app_dev.core.exceptions import UserNotificationException
|
|
13
|
+
from py_app_dev.core.logging import logger
|
|
14
|
+
from py_app_dev.core.runnable import Executor
|
|
15
|
+
from pypeline.domain.execution_context import ExecutionContext
|
|
16
|
+
from pypeline.domain.external_project import ExternalProject
|
|
17
|
+
from pypeline.steps.west_install import WestInstall, WestManifestFile
|
|
18
|
+
|
|
19
|
+
#: Manifest file name, both at the project root and inside a variant directory.
|
|
20
|
+
MANIFEST_FILE_NAME = "west.yaml"
|
|
21
|
+
#: Directory holding the variant directories, relative to the project root.
|
|
22
|
+
VARIANTS_DIR_NAME = "variants"
|
|
23
|
+
#: Workspace the dependencies are installed into, relative to the project root.
|
|
24
|
+
#: Every variant shares it. Two variants pinning one dependency at two revisions
|
|
25
|
+
#: do not collide, because the revision is part of each install path.
|
|
26
|
+
WORKSPACE_DIR = "build/modules"
|
|
27
|
+
#: Name this package registers its data under, shown as the provider in the registry.
|
|
28
|
+
PROVIDER_NAME = "spl_west_deps"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def install_dependencies(project_root_dir: Path, variant: str, output_file: Path) -> None:
|
|
32
|
+
"""Install the west dependencies of the variant and write the CMake file."""
|
|
33
|
+
logger.info(f"Installing the west dependencies of variant {variant}")
|
|
34
|
+
execution_context = create_execution_context(project_root_dir, variant)
|
|
35
|
+
|
|
36
|
+
# The step collects its manifests in __init__, so the variant manifest must
|
|
37
|
+
# already be in the data registry by now.
|
|
38
|
+
step = WestInstall(
|
|
39
|
+
execution_context,
|
|
40
|
+
group_name=variant,
|
|
41
|
+
config={"workspace_dir": WORKSPACE_DIR, "revision_scoped_paths": True},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# The Executor skips the west calls while the manifests and the installed
|
|
45
|
+
# directories are unchanged. Without it every CMake configuration would
|
|
46
|
+
# fetch again, and CMake configures often.
|
|
47
|
+
exit_code = Executor(cache_dir=step.output_dir).execute(step)
|
|
48
|
+
if exit_code:
|
|
49
|
+
raise UserNotificationException(f"The WestInstall step failed with exit code {exit_code}.")
|
|
50
|
+
|
|
51
|
+
# Publishes one ExternalProject per dependency. It reads the step's result
|
|
52
|
+
# file, so the list is complete even when the step itself was skipped.
|
|
53
|
+
step.update_execution_context()
|
|
54
|
+
|
|
55
|
+
write_cmake_file(output_file, execution_context.data_registry.find_data(ExternalProject))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def create_execution_context(project_root_dir: Path, variant: str) -> ExecutionContext:
|
|
59
|
+
"""Create the execution context the WestInstall step runs in."""
|
|
60
|
+
execution_context = ExecutionContext(project_root_dir=project_root_dir)
|
|
61
|
+
|
|
62
|
+
variant_manifest = project_root_dir / VARIANTS_DIR_NAME / variant / MANIFEST_FILE_NAME
|
|
63
|
+
if variant_manifest.is_file():
|
|
64
|
+
logger.info(f"Found variant west manifest: {variant_manifest}")
|
|
65
|
+
# The step merges the project root manifest first and the registered
|
|
66
|
+
# manifests after it, so this one overrides the root by project name.
|
|
67
|
+
execution_context.data_registry.insert(WestManifestFile.from_file(variant_manifest), provider=PROVIDER_NAME)
|
|
68
|
+
else:
|
|
69
|
+
logger.info(f"Variant {variant} has no {MANIFEST_FILE_NAME}. Only the project root manifest is used.")
|
|
70
|
+
|
|
71
|
+
return execution_context
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cmake_variable_name(project_name: str) -> str:
|
|
75
|
+
"""Return the CMake variable holding a dependency's install path.
|
|
76
|
+
|
|
77
|
+
A manifest project name is not a legal CMake identifier (``-`` is the common
|
|
78
|
+
case), so every character which is not a letter or a digit becomes an
|
|
79
|
+
underscore: ``brightness-controller`` -> ``MODULE_BRIGHTNESS_CONTROLLER_PATH``.
|
|
80
|
+
"""
|
|
81
|
+
return f"MODULE_{re.sub(r'[^A-Z0-9]+', '_', project_name.upper())}_PATH"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def write_cmake_file(output_file: Path, projects: list[ExternalProject]) -> None:
|
|
85
|
+
"""Write the CMake file that ``index.cmake`` includes."""
|
|
86
|
+
lines = ["# West Dependencies Extension CMake Variables"]
|
|
87
|
+
for project in projects:
|
|
88
|
+
variable = cmake_variable_name(project.name)
|
|
89
|
+
logger.info(f"{variable} = {project.path}")
|
|
90
|
+
lines.append(f"set({variable} {project.path.as_posix()})")
|
|
91
|
+
|
|
92
|
+
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
output_file.write_text("\n".join(lines) + "\n")
|
|
94
|
+
logger.info(f"Generated CMake file at {output_file}")
|